Compare commits

..

5 Commits

Author SHA1 Message Date
github-actions
56c9026299 Auto commit for release 'develop' on 2024-04-26 2024-04-26 06:18:27 +02:00
James Cole
021ddfc36b Clear out file to see if develop action picks it up correctly. 2024-04-26 06:13:03 +02:00
James Cole
feabfe54f0 First attempt at comma based preference collector 2024-04-26 05:31:02 +02:00
James Cole
565409b486 Remove address 2024-04-25 19:51:15 +02:00
James Cole
f57366da5f Add thanks file. 2024-04-25 19:49:58 +02:00
9 changed files with 418 additions and 81 deletions

195
THANKS.md Executable file
View File

@@ -0,0 +1,195 @@
# Thank you! :tada: :heart: :tada:
Over time, many people have contributed to Firefly III. Their efforts are not always visible, but always remembered and appreciated.
Please find below all the people who contributed to the Firefly III code. Their names are mentioned in the year of their first contribution.
## 2024
- imlonghao
- Rahman Yusuf
- Michael Thomas
- WardenJakx
- kuilin
- Stevie Robinson
- luzpaz
- Lemuel Roberto Bonifácio
- maureenferreira
## 2023
- tieu1991
- Maxco10
- zqye
- Mateus Pereira
- josephbadow
- Christian Desktop
- Edgars
- Hannah K
- noxonad
- Kaijia Feng
- Marc Ordinas i Llopis
- Kuba Turek
- Julien Stébenne
## 2022
- Johannes Zellner
- Janne Heß
- charlesteets
- Nathan PERIER
- Jan Willhaus
- canoine
- Rick Cuddy
- James
- Hugo Meyronneinc
- naveen
- neilnaveen
- naveensrinivasan
- Federico Micelli
- George Hahn
## 2021
- StillLoading
- Igor Rzegocki
- Lorenzo Breda
- Hosh
- Flightkick
- alex6480
- VREEdom
- Hamza FADIL
- Kasper Læssø Sørensen
- Alex
- Jeroen De Meerleer
- Ruben van Erk
- Fabian Zimmermann
- Mirko Berger
- KaihatsuOnline
- MihataBG
## 2020
- Hannes Körber
- Julien Cassagne
- bu4ak
- Viktor Yakovlev
- Oliver Kaufmann
- Arvind Chembarpu
- GrayStrider
- psychowood
- Hosh Sadiq
- emansih
- Aniruddha Maru
- johnny
- sephrat
- bpatath
- Florian Dupret
- Maxim Kurbatov
- Lucas Guima
- Sandro
- Ruben Verhoef
- Daniel Idzerda
- Calum Smith
- Agraphie
- Tomer Shvueli
- Tomer S
## 2019
- Pascal Jungblut
- Justyn Shull
- Timendum
- Nicolas Lœuillet
- Dominic Guhl
- Melroy van den Berg
- Henning Stein
- Jan Klepek
- Jonathan
- Geoffrey “Frogeye” Preud'homme
- Michael Fix
- Juraj Mlich
- Eddybrando Vásquez
- hulloanson
- Will Rouesnel
- lastlink
- Mr. Funk
- Simon Taddiken
- Joris
- Bastiaan Nijkamp
## 2018
- a1ex4
- Daniel Quah
- Marco Lourenço
- Dennis Enderink
- Luca Bognolo
- Mike Conway
- Ben
- Mathieu Post
- George Hertz
- HamuZ HamuZ
- David Meiseles
- Erik Gelderblom
- Luca Vallerini
- Clemens Wijnekus
- Jacob Weisz
- Mateusz Gozdek
- anmol26s
- Kevin Hellemun
- Shashank M Chakravarthy
- Nico Schreiner
- Paul Sohier
- Brenden Conte
- Ben Yanke
- Andrew Prokhorenkov
- devlearner
- Kelvin
- J'informatique
## 2017
- Victor Mosin
- Justin
- Hugo van Duijn
- Lukas Winkler
- Marcin Szymanski
- Jens Kat
- koziolek
- jleeong
- Simon Hanna
- richard & xeli.eu
- Sergey Besedin
- Welbert Serra
- Joris de Vries
- Patrick Kostjens
- Enrico Lamperti
- Christian Musa
- Enno Lohmeier
## 2016
- Sander
- Toon Schoenmakers
- Telyn
- Sander Kleykens
- Tom van der Werf
- Matthew Peck
- Sander Mulders
- Bonno Nachtegaal-Karels
- Niek Haarman
- Edwin
- Thijs Alkemade
- zjean
- Graham Miller
- Robert Horlings
- leander091
## 2015
- Antonio Spinelli
- Colin O'Dell
- RonaldvanMeer
- Richard Ebbers
- Balazs Varkonyi
- Niek van der Kooy
- Ilya Kil
## 2014
- Stewart Malik
- Graham Campbell
- Sander Dorigo
- James Cole
Thank you for all your support!

View File

@@ -32,6 +32,7 @@ use FireflyIII\Models\Preference;
use FireflyIII\Transformers\PreferenceTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
@@ -97,6 +98,32 @@ class PreferencesController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* TODO This endpoint is not documented.
*
* Return a single preference by name.
*/
public function showList(Collection $collection): JsonResponse
{
$manager = $this->getManager();
$count = $collection->count();
$pageSize = $this->parameters->get('limit');
$preferences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($preferences, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.preferences.show-list').$this->buildParams());
/** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($preferences, $transformer, self::RESOURCE_KEY);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/preferences/storePreference

12
composer.lock generated
View File

@@ -5404,16 +5404,16 @@
},
{
"name": "spatie/laravel-html",
"version": "3.8.0",
"version": "3.9.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-html.git",
"reference": "f1dcd290b9feebf50ad6b5c8e5627b0bf87b7ebe"
"reference": "35802bd9b276ce08e1d9d15584b17fdef965063b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/f1dcd290b9feebf50ad6b5c8e5627b0bf87b7ebe",
"reference": "f1dcd290b9feebf50ad6b5c8e5627b0bf87b7ebe",
"url": "https://api.github.com/repos/spatie/laravel-html/zipball/35802bd9b276ce08e1d9d15584b17fdef965063b",
"reference": "35802bd9b276ce08e1d9d15584b17fdef965063b",
"shasum": ""
},
"require": {
@@ -5470,7 +5470,7 @@
"spatie"
],
"support": {
"source": "https://github.com/spatie/laravel-html/tree/3.8.0"
"source": "https://github.com/spatie/laravel-html/tree/3.9.0"
},
"funding": [
{
@@ -5478,7 +5478,7 @@
"type": "custom"
}
],
"time": "2024-04-24T12:52:13+00:00"
"time": "2024-04-25T08:07:39+00:00"
},
{
"name": "spatie/laravel-ignition",

View File

@@ -117,7 +117,7 @@ return [
'expression_engine' => false,
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2024-04-25',
'version' => 'develop/2024-04-26',
'api_version' => '2.0.14',
'db_version' => 24,

6
package-lock.json generated
View File

@@ -5095,9 +5095,9 @@
"dev": true
},
"node_modules/electron-to-chromium": {
"version": "1.4.748",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.748.tgz",
"integrity": "sha512-VWqjOlPZn70UZ8FTKUOkUvBLeTQ0xpty66qV0yJcAGY2/CthI4xyW9aEozRVtuwv3Kpf5xTesmJUcPwuJmgP4A==",
"version": "1.4.749",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.749.tgz",
"integrity": "sha512-LRMMrM9ITOvue0PoBrvNIraVmuDbJV5QC9ierz/z5VilMdPOVMjOtpICNld3PuXuTZ3CHH/UPxX9gHhAPwi+0Q==",
"dev": true
},
"node_modules/elliptic": {

View File

@@ -72,6 +72,12 @@ let index = function () {
page: 1,
filters: {
active: 'both',
name: null,
},
pageOptions: {
groupedAccounts: true,
sortingColumn: sortingColumn,
sortDirection: sortDirection,
},
// available columns:
@@ -131,8 +137,6 @@ let index = function () {
},
},
editors: {},
sortingColumn: sortingColumn,
sortDirection: sortDirection,
accounts: [],
accountRole(roleName) {
@@ -140,12 +144,20 @@ let index = function () {
},
sort(column) {
this.sortingColumn = column;
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
const url = './accounts/' + type + '?column=' + column + '&direction=' + this.sortDirection;
this.pageOptions.sortingColumn = column;
this.pageOptions.sortDirection = this.pageOptions.sortDirection === 'asc' ? 'desc' : 'asc';
const url = './accounts/' + type + '?column=' + column + '&direction=' + this.pageOptions.sortDirection;
window.history.pushState({}, "", url);
// get sort column
// TODO variable name in better place
const columnKey = 'acc_index_' + type + '_sc';
const directionKey = 'acc_index_' + type + '_sd';
setVariable(columnKey, this.pageOptions.sortingColumn);
setVariable(directionKey, this.pageOptions.sortDirection);
this.loadAccounts();
return false;
},
@@ -165,23 +177,53 @@ let index = function () {
}
}
console.log('New settings', newSettings);
setVariable('accts_columns_' + type, newSettings);
setVariable('acc_index_' + type + '_columns', newSettings);
},
init() {
this.notifications.wait.show = true;
this.notifications.wait.text = i18next.t('firefly.wait_loading_data')
this.notifications.wait.text = i18next.t('firefly.wait_loading_data');
const key = 'accts_columns_' + type;
// get column preference
// TODO key in better variable
const key = 'acc_index_' + type + '_columns';
const defaultValue = {"drag_and_drop": false};
// get sort column
const columnKey = 'acc_index_' + type + '_sc';
const columnDefault = '';
// get sort direction
const directionKey = 'acc_index_' + type + '_sd';
const directionDefault = '';
getVariable(key, defaultValue).then((response) => {
for (let k in response) {
if (response.hasOwnProperty(k) && this.tableColumns.hasOwnProperty(k)) {
this.tableColumns[k].enabled = response[k] ?? true;
}
}
}).then(() => {
}).
// get sorting preference, and overrule it if is not "" twice
then(() => {
return getVariable(columnKey, columnDefault).then((response) => {
console.log('Sorting column is "' + response + '"');
this.pageOptions.sortingColumn = '' === this.pageOptions.sortingColumn ? response : this.pageOptions.sortingColumn;
})
})
.
// get sorting preference, and overrule it if is not "" twice
then(() => {
return getVariable(directionKey, directionDefault).then((response) => {
console.log('Sorting direction is "' + response + '"');
this.pageOptions.sortDirection = '' === this.pageOptions.sortDirection ? response : this.pageOptions.sortDirection;
})
}).
then(() => {
this.loadAccounts();
});
@@ -230,7 +272,7 @@ let index = function () {
loadAccounts() {
// sort instructions
const sorting = [{column: this.sortingColumn, direction: this.sortDirection}];
const sorting = [{column: this.pageOptions.sortingColumn, direction: this.pageOptions.sortDirection}];
// get start and end from the store:
const start = new Date(window.store.get('start'));

View File

@@ -39,6 +39,10 @@ export function getVariable(name, defaultValue = null) {
return getter.getByName(name).then((response) => {
return Promise.resolve(parseResponse(name, response));
}).catch((error) => {
if('' === defaultValue) {
// do not try to store empty strings.
return Promise.resolve(defaultValue);
}
// preference does not exist (yet).
// POST it and then return it anyway.
let poster = (new Post);

View File

@@ -59,68 +59,103 @@
<td x-show="tableColumns.drag_and_drop.visible && tableColumns.drag_and_drop.enabled">
&nbsp;
</td>
<td x-show="tableColumns.active.visible && tableColumns.active.enabled">
<a href="#" x-on:click.prevent="sort('active')">Active?</a>
<em x-show="sortingColumn === 'active' && sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="sortingColumn === 'active' && sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
</td>
<td x-show="tableColumns.active.visible && tableColumns.active.enabled">&nbsp;</td>
<td x-show="tableColumns.name.visible && tableColumns.name.enabled">
<a href="#" x-on:click.prevent="sort('name')">Name</a>
<em x-show="sortingColumn === 'name' && sortDirection === 'asc'"
class="fa-solid fa-arrow-down-z-a"></em>
<em x-show="sortingColumn === 'name' && sortDirection === 'desc'"
class="fa-solid fa-arrow-up-z-a"></em>
<em>"Filtered"</em>
</td>
<td x-show="tableColumns.type.visible && tableColumns.type.enabled">Type</td>
<td x-show="tableColumns.type.visible && tableColumns.type.enabled">&nbsp;</td>
<td x-show="tableColumns.liability_type.visible && tableColumns.liability_type.enabled">
Liability type
&nbsp;
</td>
<td x-show="tableColumns.liability_direction.visible && tableColumns.liability_direction.enabled">
Liability direction
&nbsp;
</td>
<td x-show="tableColumns.liability_interest.visible && tableColumns.liability_interest.enabled">
Liability interest
&nbsp;
</td>
<td x-show="tableColumns.number.visible && tableColumns.number.enabled">
<a href="#" x-on:click.prevent="sort('iban')">Account number</a>
<em x-show="sortingColumn === 'iban' && sortDirection === 'asc'"
class="fa-solid fa-arrow-down-z-a"></em>
<em x-show="sortingColumn === 'iban' && sortDirection === 'desc'"
class="fa-solid fa-arrow-up-z-a"></em>
&nbsp;
</td>
<td x-show="tableColumns.current_balance.visible && tableColumns.current_balance.enabled">
<a href="#" x-on:click.prevent="sort('balance')">Current balance</a>
<em x-show="sortingColumn === 'balance' && sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="sortingColumn === 'balance' && sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
&nbsp;
</td>
<td x-show="tableColumns.amount_due.visible && tableColumns.amount_due.enabled">
<a href="#" x-on:click.prevent="sort('amount_due')">Amount due</a>
<em x-show="sortingColumn === 'amount_due' && sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="sortingColumn === 'amount_due' && sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
&nbsp;
</td>
<td x-show="tableColumns.last_activity.visible && tableColumns.last_activity.enabled">
<a href="#" x-on:click.prevent="sort('last_activity')">Last activity</a>
<em x-show="sortingColumn === 'last_activity' && sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="sortingColumn === 'last_activity' && sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
&nbsp;
</td>
<td x-show="tableColumns.balance_difference.visible && tableColumns.balance_difference.enabled">
<a href="#" x-on:click.prevent="sort('balance_difference')">Balance
difference</a>
<em x-show="sortingColumn === 'balance_difference' && sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="sortingColumn === 'balance_difference' && sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
&nbsp;
</td>
<td x-show="tableColumns.menu.visible && tableColumns.menu.enabled">&nbsp;</td>
</tr>
<tr>
<th x-show="tableColumns.drag_and_drop.visible && tableColumns.drag_and_drop.enabled">
&nbsp;
</th>
<th x-show="tableColumns.active.visible && tableColumns.active.enabled">
<a href="#" x-on:click.prevent="sort('active')">Active?</a>
<em x-show="pageOptions.sortingColumn === 'active' && pageOptions.sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="pageOptions.sortingColumn === 'active' && pageOptions.sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
</th>
<th x-show="tableColumns.name.visible && tableColumns.name.enabled">
<a href="#" x-on:click.prevent="sort('name')">Name</a>
<em x-show="pageOptions.sortingColumn === 'name' && pageOptions.sortDirection === 'asc'"
class="fa-solid fa-arrow-down-a-z"></em>
<em x-show="pageOptions.sortingColumn === 'name' && pageOptions.sortDirection === 'desc'"
class="fa-solid fa-arrow-down-z-a"></em>
</th>
<th x-show="tableColumns.type.visible && tableColumns.type.enabled">Type</th>
<th x-show="tableColumns.liability_type.visible && tableColumns.liability_type.enabled">
Liability type
</th>
<th x-show="tableColumns.liability_direction.visible && tableColumns.liability_direction.enabled">
Liability direction
</th>
<th x-show="tableColumns.liability_interest.visible && tableColumns.liability_interest.enabled">
Liability interest
</th>
<th x-show="tableColumns.number.visible && tableColumns.number.enabled">
<a href="#" x-on:click.prevent="sort('iban')">Account number</a>
<em x-show="pageOptions.sortingColumn === 'iban' && pageOptions.sortDirection === 'asc'"
class="fa-solid fa-arrow-down-z-a"></em>
<em x-show="pageOptions.sortingColumn === 'iban' && pageOptions.sortDirection === 'desc'"
class="fa-solid fa-arrow-up-z-a"></em>
</th>
<th x-show="tableColumns.current_balance.visible && tableColumns.current_balance.enabled">
<a href="#" x-on:click.prevent="sort('balance')">Current balance</a>
<em x-show="pageOptions.sortingColumn === 'balance' && pageOptions.sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="pageOptions.sortingColumn === 'balance' && pageOptions.sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
</th>
<th x-show="tableColumns.amount_due.visible && tableColumns.amount_due.enabled">
<a href="#" x-on:click.prevent="sort('amount_due')">Amount due</a>
<em x-show="pageOptions.sortingColumn === 'amount_due' && pageOptions.sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="pageOptions.sortingColumn === 'amount_due' && pageOptions.sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
</th>
<th x-show="tableColumns.last_activity.visible && tableColumns.last_activity.enabled">
<a href="#" x-on:click.prevent="sort('last_activity')">Last activity</a>
<em x-show="pageOptions.sortingColumn === 'last_activity' && pageOptions.sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="pageOptions.sortingColumn === 'last_activity' && pageOptions.sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
</th>
<th x-show="tableColumns.balance_difference.visible && tableColumns.balance_difference.enabled">
<a href="#" x-on:click.prevent="sort('balance_difference')">Balance
difference</a>
<em x-show="pageOptions.sortingColumn === 'balance_difference' && pageOptions.sortDirection === 'asc'"
class="fa-solid fa-arrow-down-wide-short"></em>
<em x-show="pageOptions.sortingColumn === 'balance_difference' && pageOptions.sortDirection === 'desc'"
class="fa-solid fa-arrow-up-wide-short"></em>
</th>
<th x-show="tableColumns.menu.visible && tableColumns.menu.enabled">&nbsp;</th>
</tr>
</thead>
<tbody>
<template x-for="(account, index) in accounts" :key="index">
@@ -268,30 +303,63 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h5>Visible columns</h5>
<div class="mb-2">
<template x-for="(column, key) in tableColumns" :key="key">
<div class="form-check" x-show="column.visible">
<div class="row mb-3">
<label for="inputEmail3" class="col-sm-4 col-form-label">Visible columns</label>
<div class="col-sm-8">
<template x-for="(column, key) in tableColumns" :key="key">
<div class="form-check form-switch form-check-inline" x-show="column.visible">
<label>
<input class="form-check-input" type="checkbox" x-model="column.enabled"
@change="saveColumnSettings"> <span
x-text="$t('list.'+key)"></span>
</label>
</div>
</template>
</div>
</div>
<div class="row mb-3">
<label for="inputEmail3" class="col-sm-4 col-form-label">Active accounts?</label>
<div class="col-sm-8">
<select x-model="filters.active" class="form-control">
<option value="active" label="Active accounts">Active accounts only</option>
<option value="inactive" label="Inactive accounts">Inactive accounts only
</option>
<option value="both" label="Both">All accounts</option>
</select>
<div id="emailHelp" class="form-text">TODO Bla bla bla.</div>
</div>
</div>
<div class="row mb-3">
<label for="inputEmail3" class="col-sm-4 col-form-label">Group accounts</label>
<div class="col-sm-8">
<div class="form-check form-switch">
<label>
<input class="form-check-input" type="checkbox" x-model="column.enabled"
@change="saveColumnSettings"> <span x-text="$t('list.'+key)"></span>
<input class="form-check-input" type="checkbox"
x-model="pageOptions.groupedAccounts"><span>Group accounts</span>
</label>
</div>
</template>
</div>
</div>
<h5>Options</h5>
<div class="mb-2">
<select x-model="filters.active" class="form-control">
<option value="active" label="Active accounts">Active accounts</option>
<option value="inactive" label="Inactive accounts">Inactive accounts</option>
<option value="both" label="Both">Both</option>
</select>
<div class="row mb-3">
<label for="inputEmail3" class="col-sm-4 col-form-label">Show info boxes</label>
<div class="col-sm-8">
<div class="form-check form-switch form-check-inline">
<label>
<input class="form-check-input" type="checkbox"> <span>Box A</span>
</label>
</div>
<div class="form-check form-switch form-check-inline">
<label>
<input class="form-check-input" type="checkbox"> <span>Box B</span>
</label>
</div>
<div class="form-check form-switch form-check-inline">
<label>
<input class="form-check-input" type="checkbox"> <span>Box C</span>
</label>
</div>
</div>
</div>
- Group accounts <br>
- default sort field<br>
- default sort direction<br>
- show info boxes (once they contain info)<br>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>

View File

@@ -818,6 +818,7 @@ Route::group(
static function (): void {
Route::get('', ['uses' => 'PreferencesController@index', 'as' => 'index']);
Route::post('', ['uses' => 'PreferencesController@store', 'as' => 'store']);
// Route::get('{preferenceList}', ['uses' => 'PreferencesController@showList', 'as' => 'show-list'])->where('preferenceList', ',+');
Route::get('{preference}', ['uses' => 'PreferencesController@show', 'as' => 'show']);
Route::put('{preference}', ['uses' => 'PreferencesController@update', 'as' => 'update']);
}