mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-05 12:12:18 +00:00
Group management code.
This commit is contained in:
@@ -130,7 +130,6 @@ class ReconcileController extends Controller
|
||||
$startDate = clone $start;
|
||||
$startDate->subDay();
|
||||
$startBalance = round(app('steam')->balance($account, $startDate), $currency->decimal_places);
|
||||
|
||||
$endBalance = round(app('steam')->balance($account, $end), $currency->decimal_places);
|
||||
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
|
||||
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);
|
||||
|
70
app/Http/Controllers/ObjectGroup/DeleteController.php
Normal file
70
app/Http/Controllers/ObjectGroup/DeleteController.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\ObjectGroup;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
||||
/**
|
||||
* Class DeleteController
|
||||
*/
|
||||
class DeleteController extends Controller
|
||||
{
|
||||
private ObjectGroupRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* PiggyBankController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-envelope-o');
|
||||
app('view')->share('title', (string) trans('firefly.object_groups_page_title'));
|
||||
|
||||
$this->repository = app(ObjectGroupRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a piggy bank.
|
||||
*
|
||||
* @param ObjectGroup $objectGroup
|
||||
*/
|
||||
public function delete(ObjectGroup $objectGroup)
|
||||
{
|
||||
$subTitle = (string) trans('firefly.delete_object_group', ['title' => $objectGroup->title]);
|
||||
$piggyBanks = $objectGroup->piggyBanks()->count();
|
||||
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('object-groups.delete.uri');
|
||||
|
||||
return view('object-groups.delete', compact('objectGroup', 'subTitle', 'piggyBanks'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the piggy bank.
|
||||
*
|
||||
* @param ObjectGroup $objectGroup
|
||||
*/
|
||||
public function destroy(ObjectGroup $objectGroup): RedirectResponse
|
||||
{
|
||||
session()->flash('success', (string) trans('firefly.deleted_object_group', ['title' => $objectGroup->title]));
|
||||
app('preferences')->mark();
|
||||
$this->repository->destroy($objectGroup);
|
||||
|
||||
return redirect($this->getPreviousUri('object-groups.delete.uri'));
|
||||
}
|
||||
|
||||
}
|
87
app/Http/Controllers/ObjectGroup/EditController.php
Normal file
87
app/Http/Controllers/ObjectGroup/EditController.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\ObjectGroup;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\ObjectGroupFormRequest;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
|
||||
|
||||
/**
|
||||
* Class EditController
|
||||
*/
|
||||
class EditController extends Controller
|
||||
{
|
||||
private ObjectGroupRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* PiggyBankController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-envelope-o');
|
||||
app('view')->share('title', (string) trans('firefly.object_groups_page_title'));
|
||||
|
||||
$this->repository = app(ObjectGroupRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit an object group.
|
||||
*
|
||||
* @param ObjectGroup $objectGroup
|
||||
*/
|
||||
public function edit(ObjectGroup $objectGroup)
|
||||
{
|
||||
$subTitle = (string) trans('firefly.edit_object_group', ['title' => $objectGroup->title]);
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
$targetDate = null;
|
||||
$startDate = null;
|
||||
|
||||
if (true !== session('object-groups.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('object-groups.edit.uri');
|
||||
}
|
||||
session()->forget('object-groups.edit.fromUpdate');
|
||||
|
||||
return view('object-groups.edit', compact('subTitle', 'subTitleIcon', 'objectGroup'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update a piggy bank.
|
||||
*
|
||||
* @param ObjectGroupFormRequest $request
|
||||
* @param ObjectGroup $objectGroup
|
||||
*/
|
||||
public function update(ObjectGroupFormRequest $request, ObjectGroup $objectGroup)
|
||||
{
|
||||
$data = $request->getObjectGroupData();
|
||||
$piggyBank = $this->repository->update($objectGroup, $data);
|
||||
|
||||
session()->flash('success', (string) trans('firefly.updated_object_group', ['title' => $objectGroup->title]));
|
||||
app('preferences')->mark();
|
||||
|
||||
$redirect = redirect($this->getPreviousUri('object-groups.edit.uri'));
|
||||
|
||||
if (1 === (int) $request->get('return_to_edit')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
session()->put('object-groups.edit.fromUpdate', true);
|
||||
|
||||
$redirect = redirect(route('object-groups.edit', [$piggyBank->id]));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
}
|
65
app/Http/Controllers/ObjectGroup/IndexController.php
Normal file
65
app/Http/Controllers/ObjectGroup/IndexController.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\ObjectGroup;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class IndexController
|
||||
*/
|
||||
class IndexController extends Controller
|
||||
{
|
||||
private ObjectGroupRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* IndexController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// translations:
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('mainTitleIcon', 'fa-envelope-o');
|
||||
app('view')->share('title', (string) trans('firefly.object_groups_page_title'));
|
||||
$this->repository = app(ObjectGroupRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->repository->sort();
|
||||
$subTitle = (string) trans('firefly.object_groups_index');
|
||||
$objectGroups = $this->repository->get();
|
||||
|
||||
return view('object-groups.index', compact('subTitle', 'objectGroups'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ObjectGroup $objectGroup
|
||||
*/
|
||||
public function setOrder(Request $request, ObjectGroup $objectGroup)
|
||||
{
|
||||
Log::debug(sprintf('Found object group #%d "%s"', $objectGroup->id, $objectGroup->title));
|
||||
$newOrder = (int) $request->get('order');
|
||||
$this->repository->setOrder($objectGroup, $newOrder);
|
||||
|
||||
return response()->json([]);
|
||||
}
|
||||
|
||||
}
|
75
app/Http/Requests/ObjectGroupFormRequest.php
Normal file
75
app/Http/Requests/ObjectGroupFormRequest.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* ObjectGroupFormRequest.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
|
||||
/**
|
||||
* Class ObjectGroupFormRequest.
|
||||
*/
|
||||
class ObjectGroupFormRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Verify the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow logged in users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data required by the controller.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getObjectGroupData(): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->string('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Rules for this request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
/** @var ObjectGroup $piggy */
|
||||
$objectGroup = $this->route()->parameter('objectGroup');
|
||||
|
||||
$titleRule = 'required|between:1,255|uniqueObjectGroup';
|
||||
|
||||
if (null !== $objectGroup) {
|
||||
$titleRule = sprintf('required|between:1,255|uniqueObjectGroup:%d', $objectGroup->id);
|
||||
}
|
||||
|
||||
return [
|
||||
'title' => $titleRule,
|
||||
];
|
||||
}
|
||||
}
|
@@ -5,6 +5,7 @@ namespace FireflyIII\Models;
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class ObjectGroup
|
||||
@@ -31,6 +32,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
class ObjectGroup extends Model
|
||||
{
|
||||
protected $fillable = ['title', 'order'];
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
|
||||
*/
|
||||
@@ -38,4 +40,25 @@ class ObjectGroup extends Model
|
||||
{
|
||||
return $this->morphedByMany(PiggyBank::class, 'object_groupable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Route binder. Converts the key in the URL to the specified object (or throw 404).
|
||||
*
|
||||
* @param string $value
|
||||
*
|
||||
* @throws NotFoundHttpException
|
||||
* @return ObjectGroup
|
||||
*/
|
||||
public static function routeBinder(string $value): ObjectGroup
|
||||
{
|
||||
if (auth()->check()) {
|
||||
$objectGroupId = (int) $value;
|
||||
$objectGroup = self::where('object_groups.id', $objectGroupId)
|
||||
->where('object_groups.user_id', auth()->user()->id)->first();
|
||||
if (null !== $objectGroup) {
|
||||
return $objectGroup;
|
||||
}
|
||||
}
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
}
|
||||
|
@@ -80,7 +80,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property-read int|null $piggy_bank_repetitions_count
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\ObjectGroup[] $objectGroups
|
||||
* @property-read int|null $object_groups_count
|
||||
* @property bool $encrypted
|
||||
*/
|
||||
class PiggyBank extends Model
|
||||
{
|
||||
|
@@ -6,14 +6,13 @@ namespace FireflyIII\Repositories\ObjectGroup;
|
||||
use DB;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class ObjectGroupRepository
|
||||
*/
|
||||
class ObjectGroupRepository implements ObjectGroupRepositoryInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -73,4 +72,37 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface
|
||||
$group->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function setOrder(ObjectGroup $objectGroup, int $order): ObjectGroup
|
||||
{
|
||||
$order = 0 === $order ? 1 : $order;
|
||||
$objectGroup->order = $order;
|
||||
$objectGroup->save();
|
||||
|
||||
Log::debug(sprintf('Objectgroup #%d order is now %d', $objectGroup->id, $order));
|
||||
|
||||
return $objectGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function update(ObjectGroup $objectGroup, array $data): ObjectGroup
|
||||
{
|
||||
$objectGroup->title = $data['title'];
|
||||
$objectGroup->save();
|
||||
|
||||
return $objectGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function destroy(ObjectGroup $objectGroup): void
|
||||
{
|
||||
$objectGroup->delete();
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Repositories\ObjectGroup;
|
||||
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
@@ -32,4 +33,25 @@ interface ObjectGroupRepositoryInterface
|
||||
*/
|
||||
public function sort(): void;
|
||||
|
||||
/**
|
||||
* @param ObjectGroup $objectGroup
|
||||
* @param int $index
|
||||
*
|
||||
* @return ObjectGroup
|
||||
*/
|
||||
public function setOrder(ObjectGroup $objectGroup, int $index): ObjectGroup;
|
||||
|
||||
/**
|
||||
* @param ObjectGroup $objectGroup
|
||||
* @param array $data
|
||||
*
|
||||
* @return ObjectGroup
|
||||
*/
|
||||
public function update(ObjectGroup $objectGroup, array $data): ObjectGroup;
|
||||
|
||||
/**
|
||||
* @param ObjectGroup $objectGroup
|
||||
*/
|
||||
public function destroy(ObjectGroup $objectGroup): void;
|
||||
|
||||
}
|
||||
|
@@ -505,6 +505,30 @@ class FireflyValidator extends Validator
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateUniqueObjectGroup($attribute, $value, $parameters): bool
|
||||
{
|
||||
$exclude = $parameters[0] ?? null;
|
||||
$query = DB::table('object_groups')
|
||||
->whereNull('object_groups.deleted_at')
|
||||
->where('object_groups.user_id', auth()->user()->id)
|
||||
->where('object_groups.title', $value);
|
||||
if (null !== $exclude) {
|
||||
$query->where('object_groups.id', '!=', (int) $exclude);
|
||||
}
|
||||
|
||||
return 0 === $query->count();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $attribute
|
||||
* @param $value
|
||||
* @param $parameters
|
||||
*
|
||||
* TODO this method does not need a for loop
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateUniquePiggyBankForUser($attribute, $value, $parameters): bool
|
||||
{
|
||||
$exclude = $parameters[0] ?? null;
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\LinkType;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
@@ -409,6 +410,7 @@ return [
|
||||
'transactionType' => TransactionTypeModel::class,
|
||||
'journalLink' => TransactionJournalLink::class,
|
||||
'currency' => TransactionCurrency::class,
|
||||
'objectGroup' => ObjectGroup::class,
|
||||
'piggyBank' => PiggyBank::class,
|
||||
'preference' => Preference::class,
|
||||
'tj' => TransactionJournal::class,
|
||||
|
@@ -14,7 +14,7 @@ class ChangesForV530 extends Migration
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('object_groupables');
|
||||
Schema::dropIfExists('object_groups');
|
||||
@@ -25,16 +25,18 @@ class ChangesForV530 extends Migration
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable('object_groups')) {
|
||||
Schema::create(
|
||||
'object_groups', static function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('user_id', false, true);
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
$table->string('title', 255);
|
||||
$table->mediumInteger('order', false, true)->default(0);
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
83
public/v1/js/ff/object-groups/index.js
vendored
Normal file
83
public/v1/js/ff/object-groups/index.js
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* index.js
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** global: token */
|
||||
var fixGroupHelper = function (e, tr) {
|
||||
"use strict";
|
||||
var $originals = tr.children();
|
||||
var $helper = tr.clone();
|
||||
$helper.children().each(function (index) {
|
||||
// Set helper cell sizes to match the original sizes
|
||||
$(this).width($originals.eq(index).width());
|
||||
});
|
||||
return $helper;
|
||||
};
|
||||
|
||||
$(function () {
|
||||
"use strict";
|
||||
|
||||
$('#sortable').find('tbody').sortable(
|
||||
{
|
||||
helper: fixGroupHelper,
|
||||
stop: stopSorting,
|
||||
items: 'tr.group-sortable',
|
||||
handle: '.group-handle',
|
||||
start: function (event, ui) {
|
||||
// Build a placeholder cell that spans all the cells in the row
|
||||
var cellCount = 0;
|
||||
$('td, th', ui.helper).each(function () {
|
||||
// For each TD or TH try and get it's colspan attribute, and add that or 1 to the total
|
||||
var colspan = 1;
|
||||
var colspanAttr = $(this).attr('colspan');
|
||||
if (colspanAttr > 1) {
|
||||
colspan = colspanAttr;
|
||||
}
|
||||
cellCount += colspan;
|
||||
});
|
||||
|
||||
// Add the placeholder UI - note that this is the item's content, so TD rather than TR
|
||||
ui.placeholder.html('<td colspan="' + cellCount + '"> </td>');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
function stopSorting() {
|
||||
"use strict";
|
||||
|
||||
$.each($('#sortable>tbody>tr.group-sortable'), function (i, v) {
|
||||
var holder = $(v);
|
||||
var index = i+1;
|
||||
var originalOrder = parseInt(holder.data('order'));
|
||||
var id = holder.data('id');
|
||||
var name = holder.data('name');
|
||||
|
||||
if (index === originalOrder) {
|
||||
// not changed, position is what it should be.
|
||||
return;
|
||||
}
|
||||
console.log('Group "'+name+'" has moved from position ' + originalOrder + ' to ' + index);
|
||||
|
||||
// update position:
|
||||
holder.data('order', index);
|
||||
$.post('groups/set-order/' + id, {order: index, _token: token});
|
||||
});
|
||||
}
|
2
public/v1/js/ff/piggy-banks/index.js
vendored
2
public/v1/js/ff/piggy-banks/index.js
vendored
@@ -101,7 +101,7 @@ function stopSorting() {
|
||||
}
|
||||
if (position < i) {
|
||||
// position is less.
|
||||
console.log('"' + name + '" ("' + objectGroupTitle + '") has moved up from position ' + originalOrder + ' to ' + (i + 1));
|
||||
console.log('"' + name + '" ("' + objectGroupTitle + '") has moved down from position ' + originalOrder + ' to ' + (i + 1));
|
||||
}
|
||||
if (position > i) {
|
||||
console.log('"' + name + '" ("' + objectGroupTitle + '") has moved up from position ' + originalOrder + ' to ' + (i + 1));
|
||||
|
@@ -59,4 +59,6 @@ return [
|
||||
'delete_journal_link' => 'Delete link between transactions',
|
||||
'telemetry_index' => 'Telemetry',
|
||||
'telemetry_view' => 'View telemetry',
|
||||
'edit_object_group' => 'Edit group ":title"',
|
||||
'delete_object_group' => 'Delete group ":title"',
|
||||
];
|
||||
|
@@ -1671,5 +1671,18 @@ return [
|
||||
'debug_pretty_table' => 'If you copy/paste the box below into a GitHub issue it will generate a table. Please do not surround this text with backticks or quotes.',
|
||||
'debug_additional_data' => 'You may also share the content of the box below. You can also copy-and-paste this into a new or existing <a href="https://github.com/firefly-iii/firefly-iii/issues">GitHub issue</a>. However, the content of this box may contain private information such as account names, transaction details or email addresses.',
|
||||
|
||||
// object groups
|
||||
'object_groups_menu_bar' => 'Groups',
|
||||
'object_groups_page_title' => 'Groups',
|
||||
'object_groups_breadcrumb' => 'Groups',
|
||||
'object_groups_index' => 'Overview',
|
||||
'object_groups' => 'Groups',
|
||||
'object_groups_empty_explain' => 'Some things in Firefly III can be divided into groups. Piggy banks for example, feature a "Group" field in the edit and create screens. When you set this field, you can edit the names and the order of the groups on this page. For more information, check out the help-pages in the top right corner, under the (?)-icon.',
|
||||
'object_group_title' => 'Title',
|
||||
'edit_object_group' => 'Edit group ":title"',
|
||||
'delete_object_group' => 'Edit group ":title"',
|
||||
'update_object_group' => 'Update group',
|
||||
'updated_object_group' => 'Succesfully updated group ":title"',
|
||||
'deleted_object_group' => 'Succesfully deleted group ":title"',
|
||||
|
||||
];
|
||||
|
@@ -137,6 +137,7 @@ return [
|
||||
'account_areYouSure' => 'Are you sure you want to delete the account named ":name"?',
|
||||
'bill_areYouSure' => 'Are you sure you want to delete the bill named ":name"?',
|
||||
'rule_areYouSure' => 'Are you sure you want to delete the rule titled ":title"?',
|
||||
'object_group_areYouSure' => 'Are you sure you want to delete the group titled ":title"?',
|
||||
'ruleGroup_areYouSure' => 'Are you sure you want to delete the rule group titled ":title"?',
|
||||
'budget_areYouSure' => 'Are you sure you want to delete the budget named ":name"?',
|
||||
'category_areYouSure' => 'Are you sure you want to delete the category named ":name"?',
|
||||
@@ -156,6 +157,7 @@ return [
|
||||
'also_delete_connections' => 'The only transaction linked with this link type will lose this connection.|All :count transactions linked with this link type will lose their connection.',
|
||||
'also_delete_rules' => 'The only rule connected to this rule group will be deleted as well.|All :count rules connected to this rule group will be deleted as well.',
|
||||
'also_delete_piggyBanks' => 'The only piggy bank connected to this account will be deleted as well.|All :count piggy bank connected to this account will be deleted as well.',
|
||||
'not_delete_piggy_banks' => 'The piggy bank connected to this group will not be deleted.|The :count piggy banks connected to this group will not be deleted.',
|
||||
'bill_keep_transactions' => 'The only transaction connected to this bill will not be deleted.|All :count transactions connected to this bill will be spared deletion.',
|
||||
'budget_keep_transactions' => 'The only transaction connected to this budget will not be deleted.|All :count transactions connected to this budget will be spared deletion.',
|
||||
'category_keep_transactions' => 'The only transaction connected to this category will not be deleted.|All :count transactions connected to this category will be spared deletion.',
|
||||
@@ -163,6 +165,8 @@ return [
|
||||
'tag_keep_transactions' => 'The only transaction connected to this tag will not be deleted.|All :count transactions connected to this tag will be spared deletion.',
|
||||
'check_for_updates' => 'Check for updates',
|
||||
|
||||
'delete_object_group' => 'Delete group ":title"',
|
||||
|
||||
'email' => 'Email address',
|
||||
'password' => 'Password',
|
||||
'password_confirmation' => 'Password (again)',
|
||||
|
@@ -130,6 +130,7 @@ return [
|
||||
'amount_zero' => 'The total amount cannot be zero.',
|
||||
'current_target_amount' => 'The current amount must be less than the target amount.',
|
||||
'unique_piggy_bank_for_user' => 'The name of the piggy bank must be unique.',
|
||||
'unique_object_group' => 'The group name must be unique',
|
||||
|
||||
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password-security',
|
||||
'valid_recurrence_rep_type' => 'Invalid repetition type for recurring transactions.',
|
||||
|
@@ -15,7 +15,7 @@
|
||||
{% if objectGroup.piggy_banks|length > 0 %}
|
||||
<tbody class="piggy-connected-list" {% if objectGroupOrder != 0 %}data-title="{{ objectGroup.object_group_title }}"{% else %}data-title=""{% endif %}>
|
||||
<tr>
|
||||
<td colspan="2">{% if objectGroupOrder != 0 %}<i class="fa fa-fw fa-bars group-handle"></i>{% endif %}</td>
|
||||
<td colspan="2"> </td>
|
||||
<td colspan="8"><small>{{ objectGroup.object_group_title }}</small></td>
|
||||
</tr>
|
||||
{% for piggy in objectGroup.piggy_banks %}
|
||||
|
42
resources/views/v1/object-groups/delete.twig
Normal file
42
resources/views/v1/object-groups/delete.twig
Normal file
@@ -0,0 +1,42 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, objectGroup) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form method="POST" action="{{ route('object-groups.destroy',objectGroup.id) }}" accept-charset="UTF-8" class="form-horizontal">
|
||||
<input name="_token" type="hidden" value="{{ csrf_token() }}">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-lg-offset-3 col-md-12 col-sm-12">
|
||||
<div class="box box-danger">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ trans('form.delete_object_group', {'title': objectGroup.title}) }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p class="text-danger">
|
||||
{{ trans('form.permDeleteWarning') }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ trans('form.object_group_areYouSure', {'title': objectGroup.title}) }}
|
||||
</p>
|
||||
|
||||
{% if piggyBanks > 0 %}
|
||||
<p>
|
||||
{{ Lang.choice('form.not_delete_piggy_banks', piggyBanks, {count: piggyBanks}) }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<input type="submit" name="submit" value="{{ trans('form.deletePermanently') }}" class="btn pull-right btn-danger"/>
|
||||
<a href="{{ URL.previous() }}" class="btn-default btn">{{ trans('form.cancel') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
58
resources/views/v1/object-groups/edit.twig
Normal file
58
resources/views/v1/object-groups/edit.twig
Normal file
@@ -0,0 +1,58 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.render(Route.getCurrentRoute.getName, objectGroup) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ Form.model(objectGroup, {'class' : 'form-horizontal','enctype': 'multipart/form-data','id' : 'update','url' : route('object-groups.update',objectGroup.id)}) }}
|
||||
|
||||
<input type="hidden" name="id" value="{{ objectGroup.id }}"/>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'mandatoryFields'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{{ ExpandedForm.text('title') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
|
||||
{# panel for options #}
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'options'|_ }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{{ ExpandedForm.optionsList('update','object group') }}
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-success pull-right">
|
||||
{{ 'update_object_group'|_ }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script type="text/javascript" src="v1/js/lib/modernizr-custom.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
||||
<script type="text/javascript" src="v1/js/lib/jquery-ui.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
||||
<script type="text/javascript" src="v1/js/ff/piggy-banks/create.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
||||
{# auto complete for object groups #}
|
||||
<script type="text/javascript" src="v1/js/lib/typeahead/typeahead.bundle.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
||||
<script type="text/javascript" src="v1/js/ff/object-groups/create-edit.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
<link href="v1/css/jquery-ui/jquery-ui.structure.min.css?v={{ FF_VERSION }}" type="text/css" rel="stylesheet" media="all">
|
||||
<link href="v1/css/jquery-ui/jquery-ui.theme.min.css?v={{ FF_VERSION }}" type="text/css" rel="stylesheet" media="all">
|
||||
{% endblock %}
|
74
resources/views/v1/object-groups/index.twig
Normal file
74
resources/views/v1/object-groups/index.twig
Normal file
@@ -0,0 +1,74 @@
|
||||
{% extends "./layout/default" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
{{ Breadcrumbs.render }}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ 'object_groups'|_ }}</h3>
|
||||
</div>
|
||||
{% if objectGroups|length == 0 %}
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
|
||||
<p>
|
||||
{{ 'object_groups_empty_explain'|_ }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if objectGroups|length > 0 %}
|
||||
<div class="box-body no-padding">
|
||||
<table class="table table-condensed" id="sortable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>
|
||||
{{ 'object_group_title'|_ }}
|
||||
</th>
|
||||
<th>
|
||||
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for objectGroup in objectGroups %}
|
||||
<tr class="group-sortable" data-id="{{ objectGroup.id }}" data-name="{{ objectGroup.title|escape('html') }}" data-order="{{ objectGroup.order }}">
|
||||
<td><i class="fa fa-fw fa-bars group-handle"></i></td>
|
||||
<td>
|
||||
<strong>{{ objectGroup.title }}</strong><br />
|
||||
|
||||
{% for piggyBank in objectGroup.piggyBanks %}
|
||||
- {{ 'piggy_bank'|_ }}: <a href="{{ route('piggy-banks.show', [piggyBank.id]) }}">{{ piggyBank.name }}</a><br>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a class="btn btn-default" href="{{ route('object-groups.edit', [objectGroup.id]) }}">
|
||||
<i class="fa fa-pencil"></i>
|
||||
</a>
|
||||
<a class="btn btn-danger" href="{{ route('object-groups.delete', [objectGroup.id]) }}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script src="v1/js/lib/jquery-ui.min.js?v={{ FF_VERSION }}" type="text/javascript" nonce="{{ JS_NONCE }}"></script>
|
||||
<script type="text/javascript" src="v1/js/ff/object-groups/index.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
|
||||
{% endblock %}
|
||||
{% block styles %}
|
||||
{% endblock %}
|
@@ -148,6 +148,12 @@
|
||||
<span>{{ 'tags'|_ }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="{{ activeRoutePartial('object-groups') }}">
|
||||
<a href="{{ route('object-groups.index') }}">
|
||||
<i class="fa fa-angle-right fa-fw"></i>
|
||||
<span>{{ 'object_groups_menu_bar'|_ }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\LinkType;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\Rule;
|
||||
@@ -1163,13 +1164,30 @@ try {
|
||||
}
|
||||
);
|
||||
|
||||
// SPLIT
|
||||
// object groups
|
||||
Breadcrumbs::register(
|
||||
'transactions.split.edit',
|
||||
static function (BreadcrumbsGenerator $breadcrumbs, TransactionJournal $journal) {
|
||||
$breadcrumbs->parent('transactions.show', $journal);
|
||||
$breadcrumbs->push(trans('breadcrumbs.edit_journal', ['description' => $journal->description]), route('transactions.split.edit', [$journal->id]));
|
||||
'object-groups.index',
|
||||
static function (BreadcrumbsGenerator $breadcrumbs): void {
|
||||
$breadcrumbs->parent('index');
|
||||
$breadcrumbs->push(trans('firefly.object_groups_breadcrumb'), route('object-groups.index'));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'object-groups.edit',
|
||||
static function (BreadcrumbsGenerator $breadcrumbs, ObjectGroup $objectGroup) {
|
||||
$breadcrumbs->parent('object-groups.index');
|
||||
$breadcrumbs->push(trans('breadcrumbs.edit_object_group', ['title' => $objectGroup->title]), route('object-groups.edit', [$objectGroup->id]));
|
||||
}
|
||||
);
|
||||
|
||||
Breadcrumbs::register(
|
||||
'object-groups.delete',
|
||||
static function (BreadcrumbsGenerator $breadcrumbs, ObjectGroup $objectGroup) {
|
||||
$breadcrumbs->parent('object-groups.index');
|
||||
$breadcrumbs->push(trans('breadcrumbs.delete_object_group', ['title' => $objectGroup->title]), route('object-groups.delete', [$objectGroup->id]));
|
||||
}
|
||||
);
|
||||
|
||||
} catch (DuplicateBreadcrumbException $e) {
|
||||
}
|
||||
|
@@ -547,6 +547,28 @@ Route::group(
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Object group controller.
|
||||
*/
|
||||
Route::group(
|
||||
['middleware' => 'user-full-auth', 'namespace' => 'FireflyIII\Http\Controllers', 'prefix' => 'groups', 'as' => 'object-groups.'],
|
||||
static function () {
|
||||
|
||||
// index
|
||||
Route::get('', ['uses' => 'ObjectGroup\IndexController@index', 'as' => 'index']);
|
||||
Route::post('set-order/{objectGroup}', ['uses' => 'ObjectGroup\IndexController@setOrder', 'as' => 'set-order']);
|
||||
|
||||
// edit
|
||||
Route::get('edit/{objectGroup}', ['uses' => 'ObjectGroup\EditController@edit', 'as' => 'edit']);
|
||||
Route::post('update/{objectGroup}', ['uses' => 'ObjectGroup\EditController@update', 'as' => 'update']);
|
||||
|
||||
// delete
|
||||
Route::get('delete/{objectGroup}', ['uses' => 'ObjectGroup\DeleteController@delete', 'as' => 'delete']);
|
||||
Route::post('destroy/{objectGroup}', ['uses' => 'ObjectGroup\DeleteController@destroy', 'as' => 'destroy']);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Help Controller.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user