From 723aa65e7a10409347eb6596e28faadc459f4f5c Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 10 Feb 2024 08:28:59 +0100 Subject: [PATCH] Inline edit for v2 --- .../List/TransactionController.php | 70 +++++++++-- .../Model/Transaction/ListByCountRequest.php | 107 ++++++++++++++++ .../Extensions/CollectorProperties.php | 3 + app/Helpers/Collector/GroupCollector.php | 24 ++++ .../Collector/GroupCollectorInterface.php | 10 ++ package-lock.json | 51 ++++++-- package.json | 4 + .../assets/v2/api/v2/model/transaction/get.js | 3 + resources/assets/v2/css/grid-ff3-theme.css | 24 ++++ .../assets/v2/pages/transactions/index.js | 119 +++++++++++++++++- .../support/ag-grid/TransactionDataSource.js | 100 +++++++++++++++ .../views/v2/transactions/index.blade.php | 18 +++ routes/api.php | 10 ++ vite.config.js | 2 +- 14 files changed, 517 insertions(+), 28 deletions(-) create mode 100644 app/Api/V2/Request/Model/Transaction/ListByCountRequest.php create mode 100644 resources/assets/v2/css/grid-ff3-theme.css create mode 100644 resources/assets/v2/support/ag-grid/TransactionDataSource.js diff --git a/app/Api/V2/Controllers/Transaction/List/TransactionController.php b/app/Api/V2/Controllers/Transaction/List/TransactionController.php index 8da62504a0..cdacd31f75 100644 --- a/app/Api/V2/Controllers/Transaction/List/TransactionController.php +++ b/app/Api/V2/Controllers/Transaction/List/TransactionController.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace FireflyIII\Api\V2\Controllers\Transaction\List; use FireflyIII\Api\V2\Controllers\Controller; +use FireflyIII\Api\V2\Request\Model\Transaction\ListByCountRequest; use FireflyIII\Api\V2\Request\Model\Transaction\ListRequest; use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Transformers\V2\TransactionGroupTransformer; @@ -34,24 +35,25 @@ use Illuminate\Http\JsonResponse; */ class TransactionController extends Controller { - public function list(ListRequest $request): JsonResponse + public function listByCount(ListByCountRequest $request): JsonResponse { + + // collect transactions: - $pageSize = $this->parameters->get('limit'); - $page = $request->getPage(); - $page = max($page, 1); + $pageSize = $this->parameters->get('limit'); + $page = $request->getPage(); + $page = max($page, 1); /** @var GroupCollectorInterface $collector */ $collector = app(GroupCollectorInterface::class); $collector->setUserGroup(auth()->user()->userGroup) - ->withAPIInformation() - ->setLimit($pageSize) - ->setPage($page) - ->setTypes($request->getTransactionTypes()) - ; + ->withAPIInformation() + ->setStartRow($request->getStartRow()) + ->setEndRow($request->getEndRow()) + ->setTypes($request->getTransactionTypes()); - $start = $this->parameters->get('start'); - $end = $this->parameters->get('end'); + $start = $this->parameters->get('start'); + $end = $this->parameters->get('end'); if (null !== $start) { $collector->setStart($start); } @@ -74,7 +76,49 @@ class TransactionController extends Controller return response() ->json($this->jsonApiList('transactions', $paginator, new TransactionGroupTransformer())) - ->header('Content-Type', self::CONTENT_TYPE) - ; + ->header('Content-Type', self::CONTENT_TYPE); + } + + + public function list(ListRequest $request): JsonResponse + { + // collect transactions: + $pageSize = $this->parameters->get('limit'); + $page = $request->getPage(); + $page = max($page, 1); + + /** @var GroupCollectorInterface $collector */ + $collector = app(GroupCollectorInterface::class); + $collector->setUserGroup(auth()->user()->userGroup) + ->withAPIInformation() + ->setLimit($pageSize) + ->setPage($page) + ->setTypes($request->getTransactionTypes()); + + $start = $this->parameters->get('start'); + $end = $this->parameters->get('end'); + if (null !== $start) { + $collector->setStart($start); + } + if (null !== $end) { + $collector->setEnd($end); + } + + // $collector->dumpQuery(); + // exit; + + $paginator = $collector->getPaginatedGroups(); + $params = $request->buildParams($pageSize); + $paginator->setPath( + sprintf( + '%s?%s', + route('api.v2.transactions.list'), + $params + ) + ); + + return response() + ->json($this->jsonApiList('transactions', $paginator, new TransactionGroupTransformer())) + ->header('Content-Type', self::CONTENT_TYPE); } } diff --git a/app/Api/V2/Request/Model/Transaction/ListByCountRequest.php b/app/Api/V2/Request/Model/Transaction/ListByCountRequest.php new file mode 100644 index 0000000000..b0f4c719cb --- /dev/null +++ b/app/Api/V2/Request/Model/Transaction/ListByCountRequest.php @@ -0,0 +1,107 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V2\Request\Model\Transaction; + +use Carbon\Carbon; +use FireflyIII\Support\Http\Api\TransactionFilter; +use FireflyIII\Support\Request\ChecksLogin; +use FireflyIII\Support\Request\ConvertsDataTypes; +use Illuminate\Foundation\Http\FormRequest; + +/** + * Class ListRequest + * Used specifically to list transactions. + */ +class ListByCountRequest extends FormRequest +{ + use ChecksLogin; + use ConvertsDataTypes; + use TransactionFilter; + + public function buildParams(): string + { + $array = [ + 'start_row' => $this->getStartRow(), + 'end_row' => $this->getEndRow(), + ]; + + $start = $this->getStartDate(); + $end = $this->getEndDate(); + if (null !== $start && null !== $end) { + $array['start'] = $start->format('Y-m-d'); + $array['end'] = $end->format('Y-m-d'); + } + + return http_build_query($array); + } + + public function getPage(): int + { + $page = $this->convertInteger('page'); + + return 0 === $page || $page > 65536 ? 1 : $page; + } + + public function getStartRow(): int + { + $startRow = $this->convertInteger('start_row'); + + return $startRow < 0 || $startRow > 4294967296 ? 0 : $startRow; + } + + public function getEndRow(): int + { + $endRow = $this->convertInteger('end_row'); + + return $endRow <= 0 || $endRow > 4294967296 ? 100 : $endRow; + } + + public function getStartDate(): ?Carbon + { + return $this->getCarbonDate('start'); + } + + public function getEndDate(): ?Carbon + { + return $this->getCarbonDate('end'); + } + + public function getTransactionTypes(): array + { + $type = (string)$this->get('type', 'default'); + + return $this->mapTransactionTypes($type); + } + + public function rules(): array + { + return [ + 'start' => 'date', + 'end' => 'date|after:start', + 'start_row' => 'integer|min:0|max:4294967296', + 'end_row' => 'integer|min:0|max:4294967296|gt:start_row', + ]; + } +} diff --git a/app/Helpers/Collector/Extensions/CollectorProperties.php b/app/Helpers/Collector/Extensions/CollectorProperties.php index ee48b0a766..b0ba86a713 100644 --- a/app/Helpers/Collector/Extensions/CollectorProperties.php +++ b/app/Helpers/Collector/Extensions/CollectorProperties.php @@ -50,6 +50,9 @@ trait CollectorProperties private array $postFilters; private HasMany $query; private array $stringFields; + + private ?int $startRow; + private ?int $endRow; /* * This array is used to collect ALL tags the user may search for (using 'setTags'). * This way the user can call 'setTags' multiple times and get a joined result. diff --git a/app/Helpers/Collector/GroupCollector.php b/app/Helpers/Collector/GroupCollector.php index eac4658d81..aa726ca89e 100644 --- a/app/Helpers/Collector/GroupCollector.php +++ b/app/Helpers/Collector/GroupCollector.php @@ -67,6 +67,8 @@ class GroupCollector implements GroupCollectorInterface $this->userGroup = null; $this->limit = null; $this->page = null; + $this->startRow = null; + $this->endRow = null; $this->hasAccountInfo = false; $this->hasCatInformation = false; @@ -473,6 +475,10 @@ class GroupCollector implements GroupCollectorInterface return $collection->slice($offset, $this->limit); } + // OR filter the array according to the start and end row variable + if (null !== $this->startRow && null !== $this->endRow) { + return $collection->slice((int)$this->startRow, (int)$this->endRow); + } return $collection; } @@ -486,6 +492,10 @@ class GroupCollector implements GroupCollectorInterface if (0 === $this->limit) { $this->setLimit(50); } + if(null !== $this->startRow && null !== $this->endRow) { + $total = (int)($this->endRow - $this->startRow); + return new LengthAwarePaginator($set, $this->total, $total, 1); + } return new LengthAwarePaginator($set, $this->total, $this->limit, $this->page); } @@ -1055,4 +1065,18 @@ class GroupCollector implements GroupCollectorInterface ->orderBy('transaction_journals.description', 'DESC') ->orderBy('source.amount', 'DESC'); } + + public function setEndRow(int $endRow): self + { + $this->endRow = $endRow; + return $this; + } + + public function setStartRow(int $startRow): self + { + $this->startRow = $startRow; + return $this; + } + + } diff --git a/app/Helpers/Collector/GroupCollectorInterface.php b/app/Helpers/Collector/GroupCollectorInterface.php index 232a09aa82..75639d6a4e 100644 --- a/app/Helpers/Collector/GroupCollectorInterface.php +++ b/app/Helpers/Collector/GroupCollectorInterface.php @@ -526,6 +526,16 @@ interface GroupCollectorInterface */ public function setPage(int $page): self; + /** + * Set the page to get. + */ + public function setStartRow(int $startRow): self; + + /** + * Set the page to get. + */ + public function setEndRow(int $endRow): self; + /** * Set the start and end time of the results to return. */ diff --git a/package-lock.json b/package-lock.json index 59e6bbcddd..4fe016789d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,10 @@ "packages": { "": { "dependencies": { + "@ag-grid-community/client-side-row-model": "^31.0.3", + "@ag-grid-community/core": "^31.0.3", + "@ag-grid-community/infinite-row-model": "^31.0.3", + "@ag-grid-community/styles": "^31.0.3", "@fortawesome/fontawesome-free": "^6.4.0", "@popperjs/core": "^2.11.8", "alpinejs": "^3.13.3", @@ -30,6 +34,32 @@ "vite-plugin-manifest-sri": "^0.1.0" } }, + "node_modules/@ag-grid-community/client-side-row-model": { + "version": "31.0.3", + "resolved": "https://registry.npmjs.org/@ag-grid-community/client-side-row-model/-/client-side-row-model-31.0.3.tgz", + "integrity": "sha512-GN5z9iRDefIzMShoHV9zfZWCtqlfyE4Ai4m0tlVmegMOOFeolgkvmcyO8RwlAXX5KPpEfSoC86JVPOzkgHegWA==", + "dependencies": { + "@ag-grid-community/core": "~31.0.3" + } + }, + "node_modules/@ag-grid-community/core": { + "version": "31.0.3", + "resolved": "https://registry.npmjs.org/@ag-grid-community/core/-/core-31.0.3.tgz", + "integrity": "sha512-xZEMMIp3zyLsFXg3p1xF62bhd5v2Sl5L3wou+GOdfNVHDLCN8TyPCXLpPgMzP4lHVsEQ6zLIxYTN+X3Vo8xBYQ==" + }, + "node_modules/@ag-grid-community/infinite-row-model": { + "version": "31.0.3", + "resolved": "https://registry.npmjs.org/@ag-grid-community/infinite-row-model/-/infinite-row-model-31.0.3.tgz", + "integrity": "sha512-xf4P1/i7hWA9DuOik/TeA2PSpk+UduPIlAWKptxqiZN/xZoi+Yp9v/RuFMB/0/6dxt6oySSCq2oFy6GYGKdy2A==", + "dependencies": { + "@ag-grid-community/core": "~31.0.3" + } + }, + "node_modules/@ag-grid-community/styles": { + "version": "31.0.3", + "resolved": "https://registry.npmjs.org/@ag-grid-community/styles/-/styles-31.0.3.tgz", + "integrity": "sha512-nHqPey0RWAyRARY/cPQbXaENKHt4C7de/uX3bhci539a6ykmATh/GPbYk+f/d+ajedCPe+sjlRqRWBRrR6nfcQ==" + }, "node_modules/@babel/runtime": { "version": "7.23.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", @@ -545,16 +575,10 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -567,6 +591,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -919,9 +946,9 @@ } }, "node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index f3036dadf3..738b5046b8 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,10 @@ "vite-plugin-manifest-sri": "^0.1.0" }, "dependencies": { + "@ag-grid-community/client-side-row-model": "^31.0.3", + "@ag-grid-community/core": "^31.0.3", + "@ag-grid-community/infinite-row-model": "^31.0.3", + "@ag-grid-community/styles": "^31.0.3", "@fortawesome/fontawesome-free": "^6.4.0", "@popperjs/core": "^2.11.8", "alpinejs": "^3.13.3", diff --git a/resources/assets/v2/api/v2/model/transaction/get.js b/resources/assets/v2/api/v2/model/transaction/get.js index 8ca626659e..7b1b7fc083 100644 --- a/resources/assets/v2/api/v2/model/transaction/get.js +++ b/resources/assets/v2/api/v2/model/transaction/get.js @@ -31,6 +31,9 @@ export default class Get { list(params) { return api.get('/api/v2/transactions', {params: params}); } + listByCount(params) { + return api.get('/api/v2/transactions-inf', {params: params}); + } show(id, params){ return api.get('/api/v2/transactions/' + id, {params: params}); } diff --git a/resources/assets/v2/css/grid-ff3-theme.css b/resources/assets/v2/css/grid-ff3-theme.css new file mode 100644 index 0000000000..a9c4a413f7 --- /dev/null +++ b/resources/assets/v2/css/grid-ff3-theme.css @@ -0,0 +1,24 @@ +/* + * grid-ff3-theme.css + * 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/. + */ + +/* ag-theme-acmecorp.css */ +.ag-theme-firefly-iii { + /* --ag-odd-row-background-color: #f00; */ +} diff --git a/resources/assets/v2/pages/transactions/index.js b/resources/assets/v2/pages/transactions/index.js index a18123b173..815b36c918 100644 --- a/resources/assets/v2/pages/transactions/index.js +++ b/resources/assets/v2/pages/transactions/index.js @@ -24,8 +24,110 @@ import i18next from "i18next"; import {format} from "date-fns"; import formatMoney from "../../util/format-money.js"; import Get from "../../api/v2/model/transaction/get.js"; +import Put from "../../api/v2/model/transaction/put.js"; + +import {createGrid, ModuleRegistry} from "@ag-grid-community/core"; + +import '@ag-grid-community/styles/ag-grid.css'; +import '@ag-grid-community/styles/ag-theme-alpine.css'; +import '../../css/grid-ff3-theme.css'; + +import TransactionDataSource from "../../support/ag-grid/TransactionDataSource.js"; +import {InfiniteRowModelModule} from '@ag-grid-community/infinite-row-model'; + +const ds = new TransactionDataSource(); +ds.setType('withdrawal'); + +document.addEventListener('cellEditRequest', () => { + console.log('Loaded through event listener.'); + //loadPage(); +}); +let rowImmutableStore = []; + +let dataTable; +const editableFields = ['description']; + +const onCellEditRequestMethod = (event) => { + const data = event.data; + console.log(event); + const field = event.colDef.field; + const newValue = event.newValue; + if(!editableFields.includes(field)) { + console.log('Field ' + field + ' is not editable.'); + return; + } + + console.log('New value for field "'+field+'" in transaction journal #' + data.transaction_journal_id + ' of group #'+data.id+' is "' + newValue + '"'); + data[field] = newValue; + let rowNode = dataTable.getRowNode(String(event.rowIndex)); + rowNode.updateData(data); + + // then push update to Firefly III over API: + let submission = { + transactions: [ + { + transaction_journal_id: data.transaction_journal_id, + } + ] + }; + submission.transactions[0][field] = newValue; + + let putter = new Put(); + putter.put(submission, {id: data.id}); +}; + + +const gridOptions = { + rowModelType: 'infinite', + datasource: ds, + onCellEditRequest: onCellEditRequestMethod, + readOnlyEdit: true, + // Row Data: The data to be displayed. + // rowData: [ + // { description: "Tesla", model: "Model Y", price: 64950, electric: true }, + // { description: "Ford", model: "F-Series", price: 33850, electric: false }, + // { description: "Toyota", model: "Corolla", price: 29600, electric: false }, + // ], + // Column Definitions: Defines & controls grid columns. + columnDefs: [ + { + field: "icon", + editable: false, + headerName: '', + sortable: false, + width: 40, + cellRenderer: function (params) { + return ''; + } + }, + { + field: "description", + cellDataType: 'text', + editable: true, + cellRenderer: function (params) { + if (params.getValue()) { + return '' + params.getValue() + ''; + } + return ''; + } + + }, + {field: "amount"}, + { + field: "date", + cellDataType: 'date', + }, + {field: "from"}, + {field: "to"}, + {field: "category"}, + {field: "budget"}, + ] +}; + + +ModuleRegistry.registerModules([InfiniteRowModelModule]); let index = function () { return { // notifications @@ -59,6 +161,8 @@ let index = function () { }, }, + table: null, + formatMoney(amount, currencyCode) { return formatMoney(amount, currencyCode); }, @@ -70,7 +174,12 @@ let index = function () { this.notifications.wait.text = i18next.t('firefly.wait_loading_data') // TODO need date range. // TODO handle page number - this.getTransactions(this.page); + //this.getTransactions(this.page); + + // Your Javascript code to create the grid + dataTable = createGrid(document.querySelector('#grid'), gridOptions); + + }, getTransactions(page) { const urlParts = window.location.href.split('/'); @@ -103,7 +212,10 @@ let index = function () { for (let ii in current.attributes.transactions) { if (current.attributes.transactions.hasOwnProperty(ii)) { let transaction = current.attributes.transactions[ii]; + + transaction.split = isSplit; + tranaction.icon = 'fa fa-solid fa-arrow-left'; transaction.firstSplit = firstSplit; transaction.group_title = current.attributes.group_title; transaction.id = current.id; @@ -114,14 +226,17 @@ let index = function () { // set firstSplit = false for next run if applicable. firstSplit = false; - console.log(transaction); + //console.log(transaction); this.transactions.push(transaction); + //this.gridOptions.rowData.push(transaction); } } } } // only now, disable wait thing. this.notifications.wait.show = false; + console.log('refresh!'); + //this.table.refreshCells(); }, } diff --git a/resources/assets/v2/support/ag-grid/TransactionDataSource.js b/resources/assets/v2/support/ag-grid/TransactionDataSource.js new file mode 100644 index 0000000000..182bcf58b9 --- /dev/null +++ b/resources/assets/v2/support/ag-grid/TransactionDataSource.js @@ -0,0 +1,100 @@ +/* + * TransactionDataSource.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 Get from "../../api/v2/model/transaction/get.js"; + +export default class TransactionDataSource { + constructor() { + this.type = 'all'; + this.rowCount = null; + } + + + rowCount() { + return this.rowCount; + } + + getRows(params) { + let getter = new Get(); + + getter.listByCount({start_row: params.startRow, end_row: params.endRow, type: this.type}).then(response => { + this.parseTransactions(response.data.data, params.successCallback); + + // set meta data + this.rowCount = response.data.meta.pagination.total; + }).catch(error => { + // todo this is auto generated + //this.notifications.wait.show = false; + //this.notifications.error.show = true; + //this.notifications.error.text = error.response.data.message; + console.log(error); + }); + } + + parseTransactions(data, callback) { + let transactions = []; + // no parse, just save + for (let i in data) { + if (data.hasOwnProperty(i)) { + let current = data[i]; + let isSplit = current.attributes.transactions.length > 1; + let firstSplit = true; + + // foreach on transactions, no matter how many. + for (let ii in current.attributes.transactions) { + if (current.attributes.transactions.hasOwnProperty(ii)) { + let transaction = current.attributes.transactions[ii]; + + + let entry = {}; + // split info + entry.split = isSplit; + entry.firstSplit = firstSplit; + + // group attributes + entry.group_title = current.attributes.group_title; + entry.created_at = current.attributes.created_at; + entry.updated_at = current.attributes.updated_at; + entry.user = current.attributes.user; + entry.user_group = current.attributes.user_group; + + // create actual transaction: + entry.id = parseInt(current.id); + entry.transaction_journal_id = parseInt(transaction.transaction_journal_id); + entry.icon = 'fa fa-solid fa-arrow-left'; + entry.date = new Date(transaction.date); + entry.description = transaction.description; + + // set firstSplit = false for next run if applicable. + firstSplit = false; + transactions.push(entry); + } + } + } + } + callback(transactions, false) + return transactions; + } + + setType(type) { + this.type = type; + } + +} diff --git a/resources/views/v2/transactions/index.blade.php b/resources/views/v2/transactions/index.blade.php index 58c0d0bbc9..c66e4259aa 100644 --- a/resources/views/v2/transactions/index.blade.php +++ b/resources/views/v2/transactions/index.blade.php @@ -45,6 +45,24 @@
+
+
+
+
+

Transactions

+
+
+
+
+
+
+
+ +
+
+
+ +
diff --git a/routes/api.php b/routes/api.php index f34a65def0..45fc67510f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -160,6 +160,16 @@ Route::group( Route::put('{userGroupTransaction}', ['uses' => 'UpdateController@update', 'as' => 'update']); } ); +Route::group( + [ + 'namespace' => 'FireflyIII\Api\V2\Controllers\Transaction\List', + 'prefix' => 'v2/transactions-inf', + 'as' => 'api.v2.transactions-inf.', + ], + static function (): void { + Route::get('', ['uses' => 'TransactionController@listByCount', 'as' => 'list-by-count']); + } +); // V2 API route for budgets and budget limits: // TODO Validate from here down. diff --git a/vite.config.js b/vite.config.js index fb69194c54..5fb9219b06 100644 --- a/vite.config.js +++ b/vite.config.js @@ -59,7 +59,7 @@ export default defineConfig({ server: { usePolling: true, - allowedHosts: '*.sd.local', + allowedHosts: '*.sd.internal', host: '0.0.0.0', hmr: {host}, cors: true