mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-07-28 00:09:56 -07:00
Other minification.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/*
|
||||
* CategoryController.php
|
||||
* Copyright (c) 2024 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\Api\V2\Controllers\Autocomplete;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Autocomplete\AutocompleteRequest;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Repositories\UserGroups\Category\CategoryRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class CategoryController
|
||||
*/
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
private CategoryRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* AccountController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(CategoryRepositoryInterface::class);
|
||||
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Documentation for this endpoint:
|
||||
* TODO list of checks
|
||||
* 1. use dates from ParameterBag
|
||||
* 2. Request validates dates
|
||||
* 3. Request includes user_group_id
|
||||
* 4. Endpoint is documented.
|
||||
* 5. Collector uses user_group_id
|
||||
*/
|
||||
public function categories(AutocompleteRequest $request): JsonResponse
|
||||
{
|
||||
$data = $request->getData();
|
||||
$result = $this->repository->searchCategory($data['query'], $this->parameters->get('limit'));
|
||||
$filtered = $result->map(
|
||||
static function (Category $item) {
|
||||
return [
|
||||
'id' => (string) $item->id,
|
||||
'name' => $item->name,
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
return response()->json($filtered);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/*
|
||||
* CategoryController.php
|
||||
* Copyright (c) 2024 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\Api\V2\Controllers\Autocomplete;
|
||||
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Autocomplete\AutocompleteRequest;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Repositories\UserGroups\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Category\CategoryRepositoryInterface;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class TagController
|
||||
*/
|
||||
class TagController extends Controller
|
||||
{
|
||||
private TagRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* AccountController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(TagRepositoryInterface::class);
|
||||
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
if (null !== $userGroup) {
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Documentation for this endpoint:
|
||||
* TODO list of checks
|
||||
* 1. use dates from ParameterBag
|
||||
* 2. Request validates dates
|
||||
* 3. Request includes user_group_id
|
||||
* 4. Endpoint is documented.
|
||||
* 5. Collector uses user_group_id
|
||||
*/
|
||||
public function tags(AutocompleteRequest $request): JsonResponse
|
||||
{
|
||||
$data = $request->getData();
|
||||
$result = $this->repository->searchTag($data['query'], $this->parameters->get('limit'));
|
||||
$filtered = $result->map(
|
||||
static function (Tag $item) {
|
||||
return [
|
||||
'id' => (string) $item->id,
|
||||
'name' => $item->tag,
|
||||
'value' => (string) $item->id,
|
||||
'label' => $item->tag,
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
return response()->json($filtered);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ use FireflyIII\Repositories\Category\NoCategoryRepository;
|
||||
use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\OperationsRepository;
|
||||
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Category\CategoryRepository as UserGroupCategoryRepository;
|
||||
use FireflyIII\Repositories\UserGroups\Category\CategoryRepositoryInterface as UserGroupCategoryRepositoryInterface;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
@@ -61,6 +63,20 @@ class CategoryServiceProvider extends ServiceProvider
|
||||
}
|
||||
);
|
||||
|
||||
// phpstan does not understand reference to 'auth'.
|
||||
$this->app->bind(
|
||||
UserGroupCategoryRepositoryInterface::class,
|
||||
static function (Application $app) {
|
||||
/** @var UserGroupCategoryRepository $repository */
|
||||
$repository = app(UserGroupCategoryRepository::class);
|
||||
if ($app->auth->check()) { // @phpstan-ignore-line
|
||||
$repository->setUser(auth()->user());
|
||||
}
|
||||
|
||||
return $repository;
|
||||
}
|
||||
);
|
||||
|
||||
$this->app->bind(
|
||||
OperationsRepositoryInterface::class,
|
||||
static function (Application $app) {
|
||||
|
||||
@@ -27,6 +27,8 @@ use FireflyIII\Repositories\Tag\OperationsRepository;
|
||||
use FireflyIII\Repositories\Tag\OperationsRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepository;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroups\Tag\TagRepository as UserGroupTagRepository;
|
||||
use FireflyIII\Repositories\UserGroups\Tag\TagRepositoryInterface as UserGroupTagRepositoryInterface;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
@@ -59,6 +61,20 @@ class TagServiceProvider extends ServiceProvider
|
||||
}
|
||||
);
|
||||
|
||||
$this->app->bind(
|
||||
UserGroupTagRepositoryInterface::class,
|
||||
static function (Application $app) {
|
||||
/** @var UserGroupTagRepository $repository */
|
||||
$repository = app(UserGroupTagRepository::class);
|
||||
|
||||
if ($app->auth->check()) { // @phpstan-ignore-line (phpstan does not understand the reference to auth)
|
||||
$repository->setUser(auth()->user());
|
||||
}
|
||||
|
||||
return $repository;
|
||||
}
|
||||
);
|
||||
|
||||
$this->app->bind(
|
||||
OperationsRepositoryInterface::class,
|
||||
static function (Application $app) {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/*
|
||||
* CategoryRepository.php
|
||||
* Copyright (c) 2024 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\Repositories\UserGroups\Category;
|
||||
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class CategoryRepository implements CategoryRepositoryInterface
|
||||
{
|
||||
use UserGroupTrait;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function searchCategory(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->userGroup->categories();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%%%s%%', $query));
|
||||
}
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/*
|
||||
* CategoryRepositoryInterface.php
|
||||
* Copyright (c) 2024 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\Repositories\UserGroups\Category;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface CategoryRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Search for a category using wild cards. Uses the database, so case sensitive.
|
||||
*
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function searchCategory(string $query, int $limit): Collection;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/*
|
||||
* TagRepository.php
|
||||
* Copyright (c) 2024 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\Repositories\UserGroups\Tag;
|
||||
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class TagRepository
|
||||
*/
|
||||
class TagRepository implements TagRepositoryInterface
|
||||
{
|
||||
use UserGroupTrait;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function searchTag(string $query): Collection
|
||||
{
|
||||
$query = sprintf('%%%s%%', $query);
|
||||
$search = $this->user->tags();
|
||||
if ('' !== $query) {
|
||||
$search->where('tag', 'LIKE', $query);
|
||||
}
|
||||
return $search->get(['tags.*']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
* TagRepositoryInterface.php
|
||||
* Copyright (c) 2024 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\Repositories\UserGroups\Tag;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface TagRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Find one or more tags based on the query.
|
||||
*/
|
||||
public function searchTag(string $query): Collection;
|
||||
|
||||
}
|
||||
@@ -106,9 +106,9 @@ class PiggyBankTransformer extends AbstractTransformer
|
||||
$id = (int)$entry->object_group_id;
|
||||
$order = $entry->order;
|
||||
$this->groups[$piggyBankId] = [
|
||||
'object_group_id' => $id,
|
||||
'object_group_id' => (string) $id,
|
||||
'object_group_title' => $entry->title,
|
||||
'object_group_order' => $order,
|
||||
'object_group_order' => (int) $order,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Generated
+9
-3
@@ -10,6 +10,7 @@
|
||||
"alpinejs": "^3.13.3",
|
||||
"bootstrap": "^5.3.0",
|
||||
"bootstrap5-autocomplete": "^1.1.22",
|
||||
"bootstrap5-tags": "^1.6.15",
|
||||
"chart.js": "^4.4.0",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-chart-sankey": "^0.12.0",
|
||||
@@ -491,6 +492,11 @@
|
||||
"resolved": "https://registry.npmjs.org/bootstrap5-autocomplete/-/bootstrap5-autocomplete-1.1.25.tgz",
|
||||
"integrity": "sha512-6Z7vzlVBJduPUi7U1MPRBzoXmJf8ob9tGcUNxxos6qU1bbjPX7Li30r1Dhtk55hSBfPmVuN7p6zahF7G38xtWA=="
|
||||
},
|
||||
"node_modules/bootstrap5-tags": {
|
||||
"version": "1.6.15",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap5-tags/-/bootstrap5-tags-1.6.15.tgz",
|
||||
"integrity": "sha512-dQ1UpkP049OksrnwXr6g3JMz2S7+reAJnxxzCCf+f2F2/BtDtOHepQQjQ3QOPsFTYycS45p7wrWNM3bDnQMtYw=="
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
@@ -638,9 +644,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.3",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
|
||||
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
|
||||
"version": "1.15.4",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"alpinejs": "^3.13.3",
|
||||
"bootstrap": "^5.3.0",
|
||||
"bootstrap5-autocomplete": "^1.1.22",
|
||||
"bootstrap5-tags": "^1.6.15",
|
||||
"chart.js": "^4.4.0",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-chart-sankey": "^0.12.0",
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,7 +1,14 @@
|
||||
{
|
||||
"_load-translations-36a0ce82.js": {
|
||||
"file": "assets/load-translations-36a0ce82.js",
|
||||
"integrity": "sha384-wTRO7jAxX9xxNgWUuXNrrSBjAyE0lWGOi3yVQ6S03bEYCk04Tc1C4BrVqHlnDSZL"
|
||||
"_get-81296add.js": {
|
||||
"file": "assets/get-81296add.js",
|
||||
"imports": [
|
||||
"_vendor-a1812e4c.js"
|
||||
],
|
||||
"integrity": "sha384-M+BAywPbHrOwlgtpdSO5UBNfYxe17K8369Ahh4qYQCxX5oZC2W1trl8zHRV9r2t4"
|
||||
},
|
||||
"_vendor-a1812e4c.js": {
|
||||
"file": "assets/vendor-a1812e4c.js",
|
||||
"integrity": "sha384-2dMX4JO7IblsxMPq8LWcAad57Ek9CjK147pQCo6WlNUHOu2+xfXTOhFKceSCNkDU"
|
||||
},
|
||||
"node_modules/@fortawesome/fontawesome-free/webfonts/fa-brands-400.ttf": {
|
||||
"file": "assets/fa-brands-400-5656d596.ttf",
|
||||
@@ -34,22 +41,24 @@
|
||||
"integrity": "sha384-YxWlWCDksuL6Ljn1HkJNPH8l+jSRIWPpMpPw3pFa0QnmLXjwV/uPwpDm/b9vn/o1"
|
||||
},
|
||||
"resources/assets/v2/pages/dashboard/dashboard.js": {
|
||||
"file": "assets/dashboard-9f02f998.js",
|
||||
"file": "assets/dashboard-ada6c7cd.js",
|
||||
"imports": [
|
||||
"_load-translations-36a0ce82.js"
|
||||
"_get-81296add.js",
|
||||
"_vendor-a1812e4c.js"
|
||||
],
|
||||
"isEntry": true,
|
||||
"src": "resources/assets/v2/pages/dashboard/dashboard.js",
|
||||
"integrity": "sha384-mH/cboBLbKf0nKndnDaPzbF4ogflUacPt4Meytovf5d92Z6dytPdAXaUTPhWb89+"
|
||||
"integrity": "sha384-OnpPqpRCVbvhxqcX6plPs/9kJW5KcvuxSwl/NlYRA4DvIyVdZmZIMEcv/sUlygZS"
|
||||
},
|
||||
"resources/assets/v2/pages/transactions/create.js": {
|
||||
"file": "assets/create-8d2b7efc.js",
|
||||
"file": "assets/create-f052c3bb.js",
|
||||
"imports": [
|
||||
"_load-translations-36a0ce82.js"
|
||||
"_get-81296add.js",
|
||||
"_vendor-a1812e4c.js"
|
||||
],
|
||||
"isEntry": true,
|
||||
"src": "resources/assets/v2/pages/transactions/create.js",
|
||||
"integrity": "sha384-AoSn0ASKb6wASHs6lp71iR/Siw9t2xU67Aos2Eq/osFPlEyJ58N7gHUoowy56/8z"
|
||||
"integrity": "sha384-XdxhJ+VVga9b+RXvInTL51SXgzLh5aVvFOciuoP6M+LbyE7Ckhi7Vsc5hamU9yfS"
|
||||
},
|
||||
"resources/assets/v2/sass/app.scss": {
|
||||
"file": "assets/app-fb7b26ec.css",
|
||||
|
||||
@@ -12500,6 +12500,12 @@ textarea.form-control-lg {
|
||||
container: sidebar/inline-size;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
-webkit-appearance: auto;
|
||||
-moz-appearance: auto;
|
||||
appearance: auto;
|
||||
}
|
||||
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--lte-sidebar-width: 250px;
|
||||
@@ -14291,7 +14297,7 @@ html.maximized-card {
|
||||
}
|
||||
.col-xl-3 .small-box h3, .col-xl-3 .small-box .h3, .col-lg-3 .small-box h3, .col-lg-3 .small-box .h3, .col-md-3 .small-box h3, .col-md-3 .small-box .h3 {
|
||||
/* changed: font from 2.2rem to 1.5vw */
|
||||
font-size: 1.5vw;
|
||||
font-size: 1.5vwb;
|
||||
}
|
||||
}
|
||||
.small-box p {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* AdminLTE v4.0.0-alpha3 (https://adminlte.io)
|
||||
* Copyright 2014-2023 Colorlib <https://colorlib.com>
|
||||
* Copyright 2014-2024 Colorlib <https://colorlib.com>
|
||||
* Licensed under MIT (https://github.com/ColorlibHQ/AdminLTE/blob/master/LICENSE)
|
||||
*/
|
||||
(function (global, factory) {
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -288,7 +288,6 @@ export default {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
console.log('here we are');
|
||||
let journalId = parseInt(prompt('Enter a transaction ID'));
|
||||
if (journalId !== null && journalId > 0 && journalId <= 16777216) {
|
||||
console.log('OK 1');
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* post.js
|
||||
* Copyright (c) 2024 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/>.
|
||||
*/
|
||||
|
||||
import {api} from "../../../boot/axios";
|
||||
|
||||
export default class Post {
|
||||
post(fileName, attachableType, attachableId) {
|
||||
let url = '/api/v1/attachments';
|
||||
return api.post(url, {filename: fileName, attachable_type: attachableType, attachable_id: attachableId});
|
||||
}
|
||||
|
||||
upload(id, data) {
|
||||
let url = './api/v1/attachments/' + id + '/upload';
|
||||
return axios.post(url, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* list.js
|
||||
* Copyright (c) 2022 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/>.
|
||||
*/
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
import format from "date-fns/format";
|
||||
|
||||
export default class Get {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
* @returns {Promise<AxiosResponse<any>>}
|
||||
*/
|
||||
list(params) {
|
||||
return api.get('/api/v2/budgets', {params: params});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -188,7 +188,6 @@ export default () => ({
|
||||
let start = new Date(window.store.get('start'));
|
||||
let end = new Date(window.store.get('end'));
|
||||
|
||||
console.log('here we are');
|
||||
const cacheValid = window.store.get('cacheValid');
|
||||
let cachedData = window.store.get(getCacheKey('subscriptions-data-dashboard', start, end));
|
||||
|
||||
|
||||
@@ -25,18 +25,141 @@ import {parseFromEntries} from "./shared/parse-from-entries.js";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
import Autocomplete from "bootstrap5-autocomplete";
|
||||
import Post from "../../api/v2/model/transaction/post.js";
|
||||
import AttachmentPost from "../../api/v1/attachments/post.js";
|
||||
|
||||
import Get from "../../api/v2/model/currency/get.js";
|
||||
import BudgetGet from "../../api/v2/model/budget/get.js";
|
||||
import PiggyBankGet from "../../api/v2/model/piggy-bank/get.js";
|
||||
import SubscriptionGet from "../../api/v2/model/subscription/get.js";
|
||||
import {getVariable} from "../../store/get-variable.js";
|
||||
import {I18n} from "i18n-js";
|
||||
import {loadTranslations} from "../../support/load-translations.js";
|
||||
import Tags from "bootstrap5-tags";
|
||||
|
||||
let i18n;
|
||||
|
||||
const urls = {
|
||||
description: '/api/v2/autocomplete/transaction-descriptions',
|
||||
account: '/api/v2/autocomplete/accounts',
|
||||
category: '/api/v2/autocomplete/categories',
|
||||
tag: '/api/v2/autocomplete/tags',
|
||||
};
|
||||
|
||||
let uploadAttachments = function (id, transactions) {
|
||||
console.log('Now in uploadAttachments');
|
||||
// reverse list of transactions?
|
||||
transactions = transactions.reverse();
|
||||
// array of all files to be uploaded:
|
||||
let toBeUploaded = [];
|
||||
let count = 0;
|
||||
// array with all file data.
|
||||
let fileData = [];
|
||||
|
||||
// all attachments
|
||||
let attachments = document.querySelectorAll('input[name="attachments[]"]');
|
||||
console.log(attachments);
|
||||
// loop over all attachments, and add references to this array:
|
||||
for (const key in attachments) {
|
||||
if (attachments.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
|
||||
console.log('Now at attachment #' + key);
|
||||
for (const fileKey in attachments[key].files) {
|
||||
if (attachments[key].files.hasOwnProperty(fileKey) && /^0$|^[1-9]\d*$/.test(fileKey) && fileKey <= 4294967294) {
|
||||
// include journal thing.
|
||||
console.log('Will upload #' + fileKey + ' from attachment #' + key + ' to transaction #' + transactions[key].transaction_journal_id);
|
||||
toBeUploaded.push({
|
||||
journal: transactions[key].transaction_journal_id, file: attachments[key].files[fileKey]
|
||||
});
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('Found ' + count + ' attachments.');
|
||||
|
||||
// loop all uploads.
|
||||
for (const key in toBeUploaded) {
|
||||
if (toBeUploaded.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
|
||||
console.log('Create file reader for file #' + key);
|
||||
// create file reader thing that will read all of these uploads
|
||||
(function (f, key) {
|
||||
let fileReader = new FileReader();
|
||||
fileReader.onloadend = function (evt) {
|
||||
if (evt.target.readyState === FileReader.DONE) { // DONE == 2
|
||||
console.log('Done reading file #' + key);
|
||||
fileData.push({
|
||||
name: toBeUploaded[key].file.name,
|
||||
journal: toBeUploaded[key].journal,
|
||||
content: new Blob([evt.target.result])
|
||||
});
|
||||
if (fileData.length === count) {
|
||||
console.log('Done reading file #' + key);
|
||||
uploadFiles(fileData, id);
|
||||
}
|
||||
}
|
||||
};
|
||||
fileReader.readAsArrayBuffer(f.file);
|
||||
})(toBeUploaded[key], key,);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
let uploadFiles = function (fileData, id) {
|
||||
let count = fileData.length;
|
||||
let uploads = 0;
|
||||
console.log('Will now upload ' + count + ' file(s) to journal with id #' + id);
|
||||
|
||||
for (const key in fileData) {
|
||||
if (fileData.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
|
||||
console.log('Creating attachment #' + key);
|
||||
|
||||
let poster = new AttachmentPost();
|
||||
poster.post(fileData[key].name, 'TransactionJournal', fileData[key].journal).then(response => {
|
||||
let attachmentId = parseInt(response.data.data.id);
|
||||
console.log('Created attachment #' + attachmentId + ' for key #' + key);
|
||||
console.log('Uploading attachment #' + key);
|
||||
poster.upload(attachmentId, fileData[key].content).then(attachmentResponse => {
|
||||
// console.log('Uploaded attachment #' + key);
|
||||
uploads++;
|
||||
if (uploads === count) {
|
||||
// finally we can redirect the user onwards.
|
||||
console.log('FINAL UPLOAD, redirect user to new transaction or reset form or whatever.');
|
||||
const event = new CustomEvent('upload-success', {some: 'details'});
|
||||
document.dispatchEvent(event);
|
||||
return;
|
||||
}
|
||||
console.log('Upload complete!');
|
||||
// return true here.
|
||||
}).catch(error => {
|
||||
console.error('Could not upload');
|
||||
console.error(error);
|
||||
// console.log('Uploaded attachment #' + key);
|
||||
uploads++;
|
||||
if (uploads === count) {
|
||||
// finally we can redirect the user onwards.
|
||||
console.log('FINAL UPLOAD, redirect user to new transaction or reset form or whatever.');
|
||||
//this.redirectUser(groupId, transactionData);
|
||||
}
|
||||
// console.log('Upload complete!');
|
||||
// return false;
|
||||
// return false here
|
||||
});
|
||||
}).catch(error => {
|
||||
console.error('Could not create upload.');
|
||||
console.error(error);
|
||||
uploads++;
|
||||
if (uploads === count) {
|
||||
// finally we can redirect the user onwards.
|
||||
// console.log('FINAL UPLOAD');
|
||||
console.log('FINAL UPLOAD, redirect user to new transaction or reset form or whatever.');
|
||||
// this.redirectUser(groupId, transactionData);
|
||||
}
|
||||
// console.log('Upload complete!');
|
||||
//return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let transactions = function () {
|
||||
return {
|
||||
count: 0,
|
||||
@@ -44,22 +167,34 @@ let transactions = function () {
|
||||
transactionType: 'unknown',
|
||||
showSuccessMessage: false,
|
||||
showErrorMessage: false,
|
||||
entries: [],
|
||||
loadingCurrencies: true,
|
||||
defaultCurrency: {},
|
||||
entries: [], // loading things
|
||||
loadingCurrencies: true,
|
||||
loadingBudgets: true,
|
||||
loadingPiggyBanks: true,
|
||||
loadingSubscriptions: true,
|
||||
|
||||
// data sets
|
||||
enabledCurrencies: [],
|
||||
nativeCurrencies: [],
|
||||
foreignCurrencies: [],
|
||||
budgets: [],
|
||||
piggyBanks: {},
|
||||
subscriptions: [],
|
||||
|
||||
foreignAmountEnabled: true,
|
||||
filters: {
|
||||
source: [],
|
||||
destination: [],
|
||||
source: [], destination: [],
|
||||
},
|
||||
errorMessageText: '',
|
||||
successMessageLink: '#',
|
||||
successMessageText: '',
|
||||
successMessageText: '', // error and success messages:
|
||||
showError: false,
|
||||
showSuccess: false,
|
||||
showWaitMessage: false,
|
||||
|
||||
// four buttons
|
||||
returnHereButton: false,
|
||||
returnHereButton: true,
|
||||
resetButton: false,
|
||||
resetButtonEnabled: false,
|
||||
rulesButton: true,
|
||||
@@ -68,6 +203,10 @@ let transactions = function () {
|
||||
// state of the form
|
||||
submitting: false,
|
||||
|
||||
// used to display the success message
|
||||
newGroupTitle: '',
|
||||
newGroupId: 0,
|
||||
|
||||
|
||||
detectTransactionType() {
|
||||
const sourceType = this.entries[0].source_account.type ?? 'unknown';
|
||||
@@ -85,7 +224,8 @@ let transactions = function () {
|
||||
// this also locks the amount into the amount of the source account
|
||||
// and the foreign amount (if different) in that of the destination account.
|
||||
console.log('filter down currencies for transfer.');
|
||||
|
||||
this.filterNativeCurrencies(this.entries[0].source_account.currency_code);
|
||||
this.filterForeignCurrencies(this.entries[0].destination_account.currency_code);
|
||||
return;
|
||||
}
|
||||
// withdrawals:
|
||||
@@ -124,17 +264,47 @@ let transactions = function () {
|
||||
},
|
||||
selectSourceAccount(item, ac) {
|
||||
const index = parseInt(ac._searchInput.attributes['data-index'].value);
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].source_account =
|
||||
{
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
alpine_name: item.name,
|
||||
type: item.type,
|
||||
currency_code: item.currency_code,
|
||||
};
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].source_account = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
alpine_name: item.name,
|
||||
type: item.type,
|
||||
currency_code: item.currency_code,
|
||||
};
|
||||
console.log('Changed source account into a known ' + item.type.toLowerCase());
|
||||
document.querySelector('#form')._x_dataStack[0].detectTransactionType();
|
||||
},
|
||||
filterForeignCurrencies(code) {
|
||||
console.log('filterForeignCurrencies("' + code + '")');
|
||||
let list = [];
|
||||
let currency;
|
||||
for (let i in this.enabledCurrencies) {
|
||||
if (this.enabledCurrencies.hasOwnProperty(i)) {
|
||||
let current = this.enabledCurrencies[i];
|
||||
if (current.code === code) {
|
||||
currency = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
list.push(currency);
|
||||
this.foreignCurrencies = list;
|
||||
// is he source account currency anyway:
|
||||
if (1 === list.length && list[0].code === this.entries[0].source_account.currency_code) {
|
||||
console.log('Foreign currency is same as source currency. Disable foreign amount.');
|
||||
this.foreignAmountEnabled = false;
|
||||
}
|
||||
if (1 === list.length && list[0].code !== this.entries[0].source_account.currency_code) {
|
||||
console.log('Foreign currency is NOT same as source currency. Enable foreign amount.');
|
||||
this.foreignAmountEnabled = true;
|
||||
}
|
||||
|
||||
// this also forces the currency_code on ALL entries.
|
||||
for (let i in this.entries) {
|
||||
if (this.entries.hasOwnProperty(i)) {
|
||||
this.entries[i].foreign_currency_code = code;
|
||||
}
|
||||
}
|
||||
},
|
||||
filterNativeCurrencies(code) {
|
||||
console.log('filterNativeCurrencies("' + code + '")');
|
||||
let list = [];
|
||||
@@ -169,22 +339,28 @@ let transactions = function () {
|
||||
},
|
||||
selectDestAccount(item, ac) {
|
||||
const index = parseInt(ac._searchInput.attributes['data-index'].value);
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].destination_account =
|
||||
{
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
alpine_name: item.name,
|
||||
type: item.type,
|
||||
currency_code: item.currency_code,
|
||||
};
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].destination_account = {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
alpine_name: item.name,
|
||||
type: item.type,
|
||||
currency_code: item.currency_code,
|
||||
};
|
||||
console.log('Changed destination account into a known ' + item.type.toLowerCase());
|
||||
document.querySelector('#form')._x_dataStack[0].detectTransactionType();
|
||||
},
|
||||
loadCurrencies() {
|
||||
this.enabledCurrencies = [];
|
||||
this.nativeCurrencies = [];
|
||||
this.foreignCurrencies = [];
|
||||
|
||||
this.foreignCurrencies.push({
|
||||
id: 0, name: '(no foreign currency)', code: '', default: false, symbol: '', decimal_places: 2,
|
||||
});
|
||||
|
||||
console.log('Loading user currencies.');
|
||||
let params = {
|
||||
page: 1,
|
||||
limit: 1337
|
||||
page: 1, limit: 1337
|
||||
};
|
||||
let getter = new Get();
|
||||
getter.list({}).then((response) => {
|
||||
@@ -208,11 +384,123 @@ let transactions = function () {
|
||||
}
|
||||
this.enabledCurrencies.push(obj);
|
||||
this.nativeCurrencies.push(obj);
|
||||
this.foreignCurrencies.push(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.loadingCurrencies = false;
|
||||
console.log(this.enabledCurrencies);
|
||||
});
|
||||
},
|
||||
loadBudgets() {
|
||||
this.budgets = [];
|
||||
|
||||
this.budgets.push({
|
||||
id: 0, name: '(no budget)',
|
||||
});
|
||||
|
||||
console.log('Loading user budgets.');
|
||||
let params = {
|
||||
page: 1, limit: 1337
|
||||
};
|
||||
let getter = new BudgetGet();
|
||||
getter.list({}).then((response) => {
|
||||
for (let i in response.data.data) {
|
||||
if (response.data.data.hasOwnProperty(i)) {
|
||||
let current = response.data.data[i];
|
||||
let obj = {
|
||||
id: current.id, name: current.attributes.name,
|
||||
};
|
||||
this.budgets.push(obj);
|
||||
}
|
||||
}
|
||||
this.loadingBudgets = false;
|
||||
console.log(this.budgets);
|
||||
});
|
||||
},
|
||||
loadPiggyBanks() {
|
||||
this.piggyBanks = {};
|
||||
let tempObject = {
|
||||
'0': {
|
||||
id: 0, name: '(no group)', order: 0, piggyBanks: [{
|
||||
id: 0, name: '(no piggy bank)', order: 0,
|
||||
}]
|
||||
}
|
||||
};
|
||||
console.log('Loading user piggy banks.');
|
||||
let params = {
|
||||
page: 1, limit: 1337
|
||||
};
|
||||
let getter = new PiggyBankGet();
|
||||
getter.list({}).then((response) => {
|
||||
for (let i in response.data.data) {
|
||||
if (response.data.data.hasOwnProperty(i)) {
|
||||
let current = response.data.data[i];
|
||||
let objectGroupId = current.attributes.object_group_id ?? '0';
|
||||
let objectGroupTitle = current.attributes.object_group_title ?? '(no group)';
|
||||
let piggyBank = {
|
||||
id: current.id, name: current.attributes.name, order: current.attributes.order,
|
||||
};
|
||||
if (!tempObject.hasOwnProperty(objectGroupId)) {
|
||||
tempObject[objectGroupId] = {
|
||||
id: objectGroupId,
|
||||
name: objectGroupTitle,
|
||||
order: current.attributes.object_group_order ?? 0,
|
||||
piggyBanks: []
|
||||
};
|
||||
}
|
||||
tempObject[objectGroupId].piggyBanks.push(piggyBank);
|
||||
tempObject[objectGroupId].piggyBanks.sort((a, b) => a.order - b.order);
|
||||
}
|
||||
}
|
||||
//tempObject.sort((a,b) => a.order - b.order);
|
||||
this.loadingPiggyBanks = false;
|
||||
this.piggyBanks = Object.keys(tempObject).sort().reduce((obj, key) => {
|
||||
obj[key] = tempObject[key];
|
||||
return obj;
|
||||
}, {});
|
||||
});
|
||||
},
|
||||
loadSubscriptions() {
|
||||
this.subscriptions = {};
|
||||
let tempObject = {
|
||||
'0': {
|
||||
id: 0, name: '(no group)', order: 0, subscriptions: [{
|
||||
id: 0, name: '(no subscription)', order: 0,
|
||||
}]
|
||||
}
|
||||
};
|
||||
console.log('Loading user suscriptions.');
|
||||
let params = {
|
||||
page: 1, limit: 1337
|
||||
};
|
||||
let getter = new SubscriptionGet();
|
||||
getter.list({}).then((response) => {
|
||||
for (let i in response.data.data) {
|
||||
if (response.data.data.hasOwnProperty(i)) {
|
||||
let current = response.data.data[i];
|
||||
let objectGroupId = current.attributes.object_group_id ?? '0';
|
||||
let objectGroupTitle = current.attributes.object_group_title ?? '(no group)';
|
||||
let piggyBank = {
|
||||
id: current.id, name: current.attributes.name, order: current.attributes.order,
|
||||
};
|
||||
if (!tempObject.hasOwnProperty(objectGroupId)) {
|
||||
tempObject[objectGroupId] = {
|
||||
id: objectGroupId,
|
||||
name: objectGroupTitle,
|
||||
order: current.attributes.object_group_order ?? 0,
|
||||
subscriptions: []
|
||||
};
|
||||
}
|
||||
tempObject[objectGroupId].subscriptions.push(piggyBank);
|
||||
tempObject[objectGroupId].subscriptions.sort((a, b) => a.order - b.order);
|
||||
}
|
||||
}
|
||||
//tempObject.sort((a,b) => a.order - b.order);
|
||||
this.loadingSubscriptions = false;
|
||||
this.subscriptions = Object.keys(tempObject).sort().reduce((obj, key) => {
|
||||
obj[key] = tempObject[key];
|
||||
return obj;
|
||||
}, {});
|
||||
});
|
||||
},
|
||||
changeSourceAccount(item, ac) {
|
||||
@@ -225,11 +513,9 @@ let transactions = function () {
|
||||
document.querySelector('#form')._x_dataStack[0].detectTransactionType();
|
||||
return;
|
||||
}
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].source_account =
|
||||
{
|
||||
name: ac._searchInput.value,
|
||||
alpine_name: ac._searchInput.value,
|
||||
};
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].source_account = {
|
||||
name: ac._searchInput.value, alpine_name: ac._searchInput.value,
|
||||
};
|
||||
|
||||
console.log('Changed source account into a unknown account called "' + ac._searchInput.value + '"');
|
||||
document.querySelector('#form')._x_dataStack[0].detectTransactionType();
|
||||
@@ -246,20 +532,32 @@ let transactions = function () {
|
||||
document.querySelector('#form')._x_dataStack[0].detectTransactionType();
|
||||
return;
|
||||
}
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].destination_account =
|
||||
{
|
||||
name: ac._searchInput.value,
|
||||
alpine_name: ac._searchInput.value,
|
||||
};
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].destination_account = {
|
||||
name: ac._searchInput.value, alpine_name: ac._searchInput.value,
|
||||
};
|
||||
console.log('Changed destination account into a unknown account called "' + ac._searchInput.value + '"');
|
||||
document.querySelector('#form')._x_dataStack[0].detectTransactionType();
|
||||
}
|
||||
},
|
||||
changeCategory(item, ac) {
|
||||
const index = parseInt(ac._searchInput.attributes['data-index'].value);
|
||||
if (typeof item !== 'undefined' && item.name) {
|
||||
//this.entries[0].category_name = object.name;
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].category_name = item.name;
|
||||
return;
|
||||
}
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].category_name = ac._searchInput.value;
|
||||
},
|
||||
|
||||
|
||||
// error and success messages:
|
||||
showError: false,
|
||||
showSuccess: false,
|
||||
changeDescription(item, ac) {
|
||||
const index = parseInt(ac._searchInput.attributes['data-index'].value);
|
||||
if (typeof item !== 'undefined' && item.description) {
|
||||
//this.entries[0].category_name = object.name;
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].description = item.description;
|
||||
return;
|
||||
}
|
||||
document.querySelector('#form')._x_dataStack[0].$data.entries[index].description = ac._searchInput.value;
|
||||
},
|
||||
|
||||
addedSplit() {
|
||||
console.log('addedSplit');
|
||||
@@ -285,6 +583,20 @@ let transactions = function () {
|
||||
}
|
||||
});
|
||||
|
||||
Autocomplete.init("input.ac-category", {
|
||||
server: urls.category,
|
||||
fetchOptions: {
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content
|
||||
}
|
||||
},
|
||||
valueField: "id",
|
||||
labelField: "name",
|
||||
highlightTyped: true,
|
||||
onSelectItem: this.changeCategory,
|
||||
onChange: this.changeCategory,
|
||||
});
|
||||
|
||||
Autocomplete.init("input.ac-dest", {
|
||||
server: urls.account,
|
||||
serverParams: {
|
||||
@@ -316,11 +628,17 @@ let transactions = function () {
|
||||
valueField: "id",
|
||||
labelField: "description",
|
||||
highlightTyped: true,
|
||||
onSelectItem: console.log,
|
||||
onSelectItem: this.changeDescription,
|
||||
onChange: this.changeDescription,
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
processUpload(event) {
|
||||
console.log('I am ALSO event listener for upload-success!');
|
||||
console.log(event);
|
||||
this.showBarOrRedirect();
|
||||
},
|
||||
|
||||
init() {
|
||||
Promise.all([getVariable('language', 'en_US')]).then((values) => {
|
||||
@@ -333,6 +651,14 @@ let transactions = function () {
|
||||
|
||||
});
|
||||
this.loadCurrencies();
|
||||
this.loadBudgets();
|
||||
this.loadPiggyBanks();
|
||||
this.loadSubscriptions();
|
||||
|
||||
document.addEventListener('upload-success', (event) => {
|
||||
this.processUpload(event);
|
||||
});
|
||||
|
||||
|
||||
// source can never be expense account
|
||||
this.filters.source = ['Asset account', 'Loan', 'Debt', 'Mortgage', 'Revenue account'];
|
||||
@@ -340,54 +666,72 @@ let transactions = function () {
|
||||
this.filters.destination = ['Expense account', 'Loan', 'Debt', 'Mortgage', 'Asset account'];
|
||||
},
|
||||
submitTransaction() {
|
||||
// reset all views:
|
||||
this.submitting = true;
|
||||
this.showSuccessMessage = false;
|
||||
this.showErrorMessage = false;
|
||||
this.showWaitmessage = false;
|
||||
this.detectTransactionType();
|
||||
|
||||
// parse transaction:
|
||||
let transactions = parseFromEntries(this.entries, this.transactionType);
|
||||
let submission = {
|
||||
// todo process all options
|
||||
group_title: null,
|
||||
fire_webhooks: false,
|
||||
apply_rules: false,
|
||||
transactions: transactions
|
||||
group_title: null, fire_webhooks: false, apply_rules: false, transactions: transactions
|
||||
};
|
||||
if (transactions.length > 1) {
|
||||
// todo improve me
|
||||
submission.group_title = transactions[0].description;
|
||||
}
|
||||
|
||||
// submit the transaction. Multi-stage process thing going on here!
|
||||
let poster = new Post();
|
||||
console.log(submission);
|
||||
poster.post(submission).then((response) => {
|
||||
this.submitting = false;
|
||||
console.log(response);
|
||||
const id = parseInt(response.data.data.id);
|
||||
if (this.returnHereButton) {
|
||||
// todo create success banner
|
||||
this.showSuccessMessage = true;
|
||||
this.successMessageLink = 'transactions/show/' + id;
|
||||
this.successMessageText = i18n.t('firefly.stored_journal_js', {description: submission.group_title ?? submission.transactions[0].description});
|
||||
// todo clear out form if necessary
|
||||
if(this.resetButton) {
|
||||
this.entries = [];
|
||||
this.addSplit();
|
||||
this.totalAmount = 0;
|
||||
}
|
||||
}
|
||||
// submission was a success.
|
||||
this.newGroupId = parseInt(response.data.data.id);
|
||||
this.newGroupTitle = submission.group_title ?? submission.transactions[0].description
|
||||
const attachmentCount = uploadAttachments(this.newGroupId, response.data.data.attributes.transactions);
|
||||
|
||||
if (!this.returnHereButton) {
|
||||
window.location = 'transactions/show/' + id + '?transaction_group_id=' + id + '&message=created';
|
||||
// upload transactions? then just show the wait message and do nothing else.
|
||||
if (attachmentCount > 0) {
|
||||
this.showWaitMessage = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// if not, respond to user options:
|
||||
this.showBarOrRedirect();
|
||||
}).catch((error) => {
|
||||
this.submitting = false;
|
||||
console.log(error);
|
||||
// todo put errors in form
|
||||
this.parseErrors(error.response.data);
|
||||
if (typeof error.response !== 'undefined') {
|
||||
this.parseErrors(error.response.data);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
},
|
||||
showBarOrRedirect() {
|
||||
this.showWaitMessage = false;
|
||||
this.submitting = false;
|
||||
if (this.returnHereButton) {
|
||||
// todo create success banner
|
||||
this.showSuccessMessage = true;
|
||||
this.successMessageLink = 'transactions/show/' + this.newGroupId;
|
||||
this.successMessageText = i18n.t('firefly.stored_journal_js', {description: this.newGroupTitle});
|
||||
// todo clear out form if necessary
|
||||
if (this.resetButton) {
|
||||
this.entries = [];
|
||||
this.addSplit();
|
||||
this.totalAmount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.returnHereButton) {
|
||||
window.location = 'transactions/show/' + this.newGroupId + '?transaction_group_id=' + this.newGroupId + '&message=created';
|
||||
}
|
||||
},
|
||||
parseErrors(data) {
|
||||
this.setDefaultErrors();
|
||||
this.showErrorMessage = true;
|
||||
@@ -421,27 +765,22 @@ let transactions = function () {
|
||||
break;
|
||||
case 'source_name':
|
||||
case 'source_id':
|
||||
this.entries[transactionIndex].errors.source_account =
|
||||
this.entries[transactionIndex].errors.source_account.concat(data.errors[key]);
|
||||
this.entries[transactionIndex].errors.source_account = this.entries[transactionIndex].errors.source_account.concat(data.errors[key]);
|
||||
break;
|
||||
case 'destination_name':
|
||||
case 'destination_id':
|
||||
this.entries[transactionIndex].errors.destination_account =
|
||||
this.entries[transactionIndex].errors.destination_account.concat(data.errors[key]);
|
||||
this.entries[transactionIndex].errors.destination_account = this.entries[transactionIndex].errors.destination_account.concat(data.errors[key]);
|
||||
break;
|
||||
case 'foreign_amount':
|
||||
case 'foreign_currency_id':
|
||||
this.entries[transactionIndex].errors.foreign_amount =
|
||||
this.entries[transactionIndex].errors.foreign_amount.concat(data.errors[key]);
|
||||
this.entries[transactionIndex].errors.foreign_amount = this.entries[transactionIndex].errors.foreign_amount.concat(data.errors[key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// unique some things
|
||||
if (typeof this.entries[transactionIndex] !== 'undefined') {
|
||||
this.entries[transactionIndex].errors.source_account =
|
||||
Array.from(new Set(this.entries[transactionIndex].errors.source_account));
|
||||
this.entries[transactionIndex].errors.destination_account =
|
||||
Array.from(new Set(this.entries[transactionIndex].errors.destination_account));
|
||||
this.entries[transactionIndex].errors.source_account = Array.from(new Set(this.entries[transactionIndex].errors.source_account));
|
||||
this.entries[transactionIndex].errors.destination_account = Array.from(new Set(this.entries[transactionIndex].errors.destination_account));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -452,6 +791,22 @@ let transactions = function () {
|
||||
},
|
||||
addSplit() {
|
||||
this.entries.push(createEmptySplit());
|
||||
setTimeout(() => {
|
||||
Tags.init('select.ac-tags', {
|
||||
allowClear: true,
|
||||
server: urls.tag,
|
||||
liveServer: true,
|
||||
clearEnd: true,
|
||||
notFoundMessage: '(nothing found)',
|
||||
noCache: true,
|
||||
fetchOptions: {
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 250);
|
||||
|
||||
},
|
||||
removeSplit(index) {
|
||||
this.entries.splice(index, 1);
|
||||
@@ -476,6 +831,15 @@ function loadPage() {
|
||||
Alpine.start();
|
||||
}
|
||||
|
||||
document.addEventListener('upload-success', (event) => {
|
||||
console.log('I am event listener for upload-success');
|
||||
console.log(event);
|
||||
//Alpine.
|
||||
});
|
||||
|
||||
|
||||
// <button x-data @click="$dispatch('custom-event', 'Hello World!')">
|
||||
|
||||
// wait for load until bootstrapped event is received.
|
||||
document.addEventListener('firefly-iii-bootstrapped', () => {
|
||||
console.log('Loaded through event listener.');
|
||||
|
||||
@@ -38,16 +38,27 @@ export function createEmptySplit() {
|
||||
// amount information:
|
||||
amount: '',
|
||||
currency_code: 'EUR',
|
||||
foreign_amount: '',
|
||||
foreign_currency_code: '',
|
||||
|
||||
// source and destination
|
||||
source_account: getAccount(),
|
||||
destination_account: getAccount(),
|
||||
|
||||
// meta data information:
|
||||
budget_id: null,
|
||||
category_name: '',
|
||||
piggy_bank_id: null,
|
||||
|
||||
// date and time
|
||||
date: formatted,
|
||||
|
||||
errors: {
|
||||
'amount': [],
|
||||
'foreign_amount': [],
|
||||
'budget_id': [],
|
||||
'category_name': [],
|
||||
'piggy_bank_id': [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,12 +31,36 @@ export function parseFromEntries(entries, transactionType) {
|
||||
|
||||
// fields for transaction
|
||||
current.description = entry.description;
|
||||
|
||||
// source and destination
|
||||
current.source_name = entry.source_account.name;
|
||||
current.destination_name = entry.destination_account.name;
|
||||
|
||||
// amount information:
|
||||
current.amount = entry.amount;
|
||||
current.date = entry.date;
|
||||
current.currency_code = entry.currency_code;
|
||||
|
||||
|
||||
// dates
|
||||
current.date = entry.date;
|
||||
|
||||
// meta
|
||||
current.budget_id = entry.budget_id;
|
||||
current.category_name = entry.category_name;
|
||||
current.piggy_bank_id = entry.piggy_bank_id;
|
||||
|
||||
// if foreign amount currency code is set:
|
||||
if (typeof entry.foreign_currency_code !== 'undefined' && '' !== entry.foreign_currency_code.toString()) {
|
||||
current.foreign_currency_code = entry.foreign_currency_code;
|
||||
if(typeof entry.foreign_amount !== 'undefined' && '' !== entry.foreign_amount.toString()) {
|
||||
current.foreign_amount = entry.foreign_amount;
|
||||
}
|
||||
if(typeof entry.foreign_amount === 'undefined' || '' === entry.foreign_amount.toString()) {
|
||||
delete current.foreign_amount;
|
||||
delete current.foreign_currency_code;
|
||||
}
|
||||
}
|
||||
|
||||
// if ID is set:
|
||||
if (typeof entry.source_account.id !== 'undefined' && '' !== entry.source_account.id.toString()) {
|
||||
current.source_id = entry.source_account.id;
|
||||
|
||||
@@ -15,7 +15,14 @@
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="showErrorMessage">
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert" x-text="errorMessageText">
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert"
|
||||
x-text="errorMessageText">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="showWaitMessage">
|
||||
<div class="alert alert-info alert-dismissible fade show" role="alert">
|
||||
<em class="fa-solid fa-spinner fa-spin"></em> Please wait for the attachments to upload.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -56,12 +63,12 @@
|
||||
<div class="tab-content" id="splitTabsContent">
|
||||
<template x-for="transaction,index in entries">
|
||||
<div
|
||||
:class="{'tab-pane fade pt-2':true, 'show active': index ===0}"
|
||||
:id="'split-'+index+'-pane'"
|
||||
role="tabpanel"
|
||||
:aria-labelledby="'split-'+index+'-tab'"
|
||||
tabindex="0"
|
||||
x-init="addedSplit()"
|
||||
:class="{'tab-pane fade pt-2':true, 'show active': index ===0}"
|
||||
:id="'split-'+index+'-pane'"
|
||||
role="tabpanel"
|
||||
:aria-labelledby="'split-'+index+'-tab'"
|
||||
tabindex="0"
|
||||
x-init="addedSplit()"
|
||||
>
|
||||
<div class="row mb-2">
|
||||
<div class="col-xl-6 col-lg-6 col-md-12 col-xs-12 mb-2">
|
||||
@@ -77,19 +84,21 @@
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<em
|
||||
title="TODO explain me"
|
||||
class="fa-solid fa-font"></em>
|
||||
class="fa-solid fa-font"></em>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control ac-description"
|
||||
:id="'description_' + index"
|
||||
@change="detectTransactionType"
|
||||
x-model="transaction.description"
|
||||
:data-index="index"
|
||||
placeholder="{{ __('firefly.description') }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label :for="'source_' + index" class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<label :for="'source_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-arrow-right"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
@@ -103,7 +112,8 @@
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label :for ="'dest_' + index" class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<label :for="'dest_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
@@ -140,16 +150,19 @@
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-3">
|
||||
<template x-if="loadingCurrencies">
|
||||
<span class="form-control-plaintext"><em class="fa-solid fa-spinner fa-spin"></em></span>
|
||||
<span class="form-control-plaintext"><em
|
||||
class="fa-solid fa-spinner fa-spin"></em></span>
|
||||
</template>
|
||||
<template x-if="!loadingCurrencies">
|
||||
<select class="form-control" :id="'currency_code_' + index"
|
||||
x-model="transaction.currency_code"
|
||||
>
|
||||
<template x-for="currency in nativeCurrencies">
|
||||
<option :selected="currency.id == defaultCurrency.id" :label="currency.name" :value="currency.code" x-text="currency.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
<select class="form-control" :id="'currency_code_' + index"
|
||||
x-model="transaction.currency_code"
|
||||
>
|
||||
<template x-for="currency in nativeCurrencies">
|
||||
<option :selected="currency.id == defaultCurrency.id"
|
||||
:label="currency.name" :value="currency.code"
|
||||
x-text="currency.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</template>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
@@ -161,13 +174,54 @@
|
||||
@change="changedAmount"
|
||||
placeholder="0.00">
|
||||
<template x-if="transaction.errors.amount.length > 0">
|
||||
<div class="invalid-feedback" x-text="transaction.errors.amount[0]"></div>
|
||||
<div class="invalid-feedback"
|
||||
x-text="transaction.errors.amount[0]"></div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
amount card
|
||||
<template x-if="foreignAmountEnabled">
|
||||
<div class="row mb-3">
|
||||
<div class="col-sm-3">
|
||||
<label class="form-label"> </label>
|
||||
<template x-if="loadingCurrencies">
|
||||
<span class="form-control-plaintext"><em
|
||||
class="fa-solid fa-spinner fa-spin"></em></span>
|
||||
</template>
|
||||
<template x-if="!loadingCurrencies">
|
||||
<select class="form-control"
|
||||
:id="'foreign_currency_code_' + index"
|
||||
x-model="transaction.foreign_currency_code"
|
||||
>
|
||||
<template x-for="currency in foreignCurrencies">
|
||||
<option :label="currency.name" :value="currency.code"
|
||||
x-text="currency.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</template>
|
||||
</div>
|
||||
<div class="col-sm-9">
|
||||
<template x-if="transactionType != 'transfer'">
|
||||
<label class="small form-label">Amount in foreign amount, if
|
||||
any</label>
|
||||
</template>
|
||||
<template x-if="transactionType == 'transfer'">
|
||||
<label class="small form-label">Amount in currency of destination
|
||||
account</label>
|
||||
</template>
|
||||
<input type="number" step="any" min="0"
|
||||
:id="'amount_' + index"
|
||||
:data-index="index"
|
||||
:class="{'is-invalid': transaction.errors.foreign_amount.length > 0, 'input-mask' : true, 'form-control': true}"
|
||||
x-model="transaction.foreign_amount" data-inputmask="currency"
|
||||
@change="changedAmount"
|
||||
placeholder="0.00">
|
||||
<template x-if="transaction.errors.foreign_amount.length > 0">
|
||||
<div class="invalid-feedback"
|
||||
x-text="transaction.errors.foreign_amount[0]"></div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -179,10 +233,129 @@
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
important meta info card
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
important meta info card
|
||||
<template x-if="transactionType != 'deposit' && transactionType != 'transfer'">
|
||||
<div class="row mb-3">
|
||||
<label :for="'budget_id_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-chart-pie"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<template x-if="loadingBudgets">
|
||||
<span class="form-control-plaintext"><em
|
||||
class="fa-solid fa-spinner fa-spin"></em></span>
|
||||
</template>
|
||||
<template x-if="!loadingBudgets">
|
||||
<select class="form-control"
|
||||
:id="'budget_id_' + index"
|
||||
x-model="transaction.budget_id"
|
||||
>
|
||||
<template x-for="budget in budgets">
|
||||
<option :label="budget.name" :value="budget.id"
|
||||
x-text="budget.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="row mb-3">
|
||||
<label :for="'category_name_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-bookmark"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="search"
|
||||
class="form-control ac-category"
|
||||
:id="'category_name_' + index"
|
||||
x-model="transaction.category_name"
|
||||
:data-index="index"
|
||||
placeholder="{{ __('firefly.category') }}">
|
||||
</div>
|
||||
</div>
|
||||
<template x-if="transactionType != 'deposit' && transactionType != 'withdrawal'">
|
||||
<div class="row mb-3">
|
||||
<label :for="'piggy_bank_id_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-piggy-bank"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<template x-if="loadingPiggyBanks">
|
||||
<span class="form-control-plaintext"><em
|
||||
class="fa-solid fa-spinner fa-spin"></em></span>
|
||||
</template>
|
||||
<template x-if="!loadingPiggyBanks">
|
||||
<select class="form-control"
|
||||
:id="'piggy_bank_id_' + index"
|
||||
x-model="transaction.piggy_bank_id">
|
||||
<template x-for="group in piggyBanks">
|
||||
<optgroup :label="group.name">
|
||||
<template x-for="piggyBank in group.piggyBanks">
|
||||
<option :label="piggyBank.name"
|
||||
:value="piggyBank.id"
|
||||
x-text="piggyBank.name"></option>
|
||||
</template>
|
||||
</optgroup>
|
||||
</template>
|
||||
</select>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="transactionType != 'transfer' && transactionType != 'deposit'">
|
||||
<div class="row mb-3">
|
||||
<label :for="'bill_id_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-calendar"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<template x-if="loadingSubscriptions">
|
||||
<span class="form-control-plaintext"><em
|
||||
class="fa-solid fa-spinner fa-spin"></em></span>
|
||||
</template>
|
||||
<template x-if="!loadingSubscriptions">
|
||||
<select class="form-control"
|
||||
:id="'bill_id_' + index"
|
||||
x-model="transaction.bill_id">
|
||||
<template x-for="group in subscriptions">
|
||||
<optgroup :label="group.name">
|
||||
<template x-for="subscription in group.subscriptions">
|
||||
<option :label="subscription.name"
|
||||
:value="subscription.id"
|
||||
x-text="subscription.name"></option>
|
||||
</template>
|
||||
</optgroup>
|
||||
</template>
|
||||
</select>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="row mb-3">
|
||||
<label :for="'tags_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-tag"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<select
|
||||
class="form-select ac-tags"
|
||||
:id="'tags_' + index"
|
||||
:name="'tags['+index+'][]'"
|
||||
multiple>
|
||||
<option value="">Type a tag...</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label :for="'notes_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-font"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" :id="'notes_' + index"
|
||||
x-model="transaction.notes"
|
||||
placeholder="{{ __('firefly.notes') }}"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -195,7 +368,32 @@
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
Less important meta
|
||||
<div class="row mb-3">
|
||||
<label :for="'attachments_' + index"
|
||||
class="col-sm-1 col-form-label d-none d-sm-block">
|
||||
<i class="fa-solid fa-file-import"></i>
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="file" multiple
|
||||
class="form-control attachments"
|
||||
:id="'attachments_' + index"
|
||||
:data-index="index"
|
||||
name="attachments[]"
|
||||
placeholder="{{ __('firefly.category') }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Attachments<br>
|
||||
Internal ref<br>
|
||||
External URL<br>
|
||||
Location<br>
|
||||
Links?<br>
|
||||
Date 1<br>
|
||||
Date 2<br>
|
||||
Date 3<br>
|
||||
Date 4<br>
|
||||
Date 5<br>
|
||||
Date 6<br>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
Less important meta
|
||||
@@ -214,28 +412,32 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" x-model="returnHereButton" type="checkbox" id="returnButton">
|
||||
<input class="form-check-input" x-model="returnHereButton" type="checkbox"
|
||||
id="returnButton">
|
||||
<label class="form-check-label" for="returnButton">
|
||||
Return here to create a new transaction
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" x-model="resetButton" type="checkbox" id="resetButton" :disabled="!returnHereButton">
|
||||
<input class="form-check-input" x-model="resetButton" type="checkbox"
|
||||
id="resetButton" :disabled="!returnHereButton">
|
||||
<label class="form-check-label" for="resetButton">
|
||||
Reset the form after returning
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="rulesButton" :checked="rulesButton">
|
||||
<input class="form-check-input" type="checkbox" id="rulesButton"
|
||||
:checked="rulesButton">
|
||||
<label class="form-check-label" for="rulesButton">
|
||||
Run rules on this transaction
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="webhookButton" :checked="webhookButton">
|
||||
<input class="form-check-input" type="checkbox" id="webhookButton"
|
||||
:checked="webhookButton">
|
||||
<label class="form-check-label" for="webhookButton">
|
||||
Run webhooks on this transaction
|
||||
</label>
|
||||
@@ -248,7 +450,8 @@
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<template x-if="0 !== index">
|
||||
<button :disabled="submitting" class="btn btn-danger" @click="removeSplit(index)">Remove this split
|
||||
<button :disabled="submitting" class="btn btn-danger" @click="removeSplit(index)">
|
||||
Remove this split
|
||||
</button>
|
||||
</template>
|
||||
<button class="btn btn-info" :disabled="submitting">Add another split</button>
|
||||
|
||||
@@ -64,6 +64,8 @@ Route::group(
|
||||
// Auto complete routes
|
||||
Route::get('accounts', ['uses' => 'AccountController@accounts', 'as' => 'accounts']);
|
||||
Route::get('transaction-descriptions', ['uses' => 'TransactionController@transactionDescriptions', 'as' => 'transaction-descriptions']);
|
||||
Route::get('categories', ['uses' => 'CategoryController@categories', 'as' => 'categories']);
|
||||
Route::get('tags', ['uses' => 'TagController@tags', 'as' => 'tags']);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -24,7 +24,20 @@ import manifestSRI from 'vite-plugin-manifest-sri';
|
||||
|
||||
const host = '127.0.0.1';
|
||||
|
||||
function manualChunks(id) {
|
||||
if (id.includes('node_modules')) {
|
||||
return 'vendor';
|
||||
}
|
||||
};
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks,
|
||||
},
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
laravel({
|
||||
input: [
|
||||
@@ -35,6 +48,7 @@ export default defineConfig({
|
||||
refresh: true,
|
||||
}),
|
||||
manifestSRI(),
|
||||
|
||||
],
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user