Compare commits

...

60 Commits

Author SHA1 Message Date
github-actions
cefbaafa19 Auto commit for release 'develop' on 2024-04-22 2024-04-22 05:11:03 +02:00
James Cole
a8c88800c4 Fix column 2024-04-21 19:49:28 +02:00
github-actions
9d1a127200 Auto commit for release 'develop' on 2024-04-21 2024-04-21 17:23:16 +02:00
James Cole
3fdde2d1c8 Removed for now, needs dynamic configuration. 2024-04-21 17:18:35 +02:00
James Cole
cdc0b8dd2c Add index options 2024-04-21 17:09:15 +02:00
James Cole
1a1e06e6e8 Fix tests 2024-04-21 07:07:06 +02:00
James Cole
6d39b8468c Add two buttons and options for them 2024-04-21 06:57:57 +02:00
James Cole
bdee3947b2 Add debugbar settings 2024-04-21 06:56:14 +02:00
James Cole
2317037655 Clean up transactions, first attempt at navigation. 2024-04-21 06:26:17 +02:00
James Cole
dcea6b757b Better button response in category overview. 2024-04-20 17:08:30 +02:00
James Cole
bd7fe92818 Expand accounts page. 2024-04-20 16:18:41 +02:00
James Cole
850e47d8db Fix https://github.com/firefly-iii/firefly-iii/issues/8776 2024-04-20 08:15:17 +02:00
James Cole
96fe62400f Fix undefined index 2024-04-20 07:38:05 +02:00
James Cole
5d07fcdcb6 Add user roles. 2024-04-20 07:36:53 +02:00
James Cole
fd5d2d57a8 Fix https://github.com/firefly-iii/firefly-iii/issues/8804 2024-04-20 07:19:15 +02:00
James Cole
8e7d42201f Merge branch 'main' into develop 2024-04-20 07:18:51 +02:00
James Cole
f26bd3cb31 Fix https://github.com/firefly-iii/firefly-iii/issues/8613 2024-04-19 19:59:42 +02:00
James Cole
36915cdace Fix https://github.com/firefly-iii/firefly-iii/issues/8752 2024-04-19 19:58:32 +02:00
James Cole
8a5cecd2a0 Fix https://github.com/firefly-iii/firefly-iii/issues/8781 2024-04-19 19:58:09 +02:00
James Cole
78da1b22bb Update vite.config.js
Signed-off-by: James Cole <james@firefly-iii.org>
2024-04-19 08:28:31 +02:00
github-actions
6d970a9794 Auto commit for release 'develop' on 2024-04-18 2024-04-18 10:25:45 +02:00
Sander D
8bb7739f05 Update release.yml
Signed-off-by: Sander D <git@sanderdorigo.nl>
2024-04-18 10:20:47 +02:00
James Cole
7788bb4b33 Update composer.lock 2024-04-18 09:52:01 +02:00
James Cole
2ecb4bb3b7 Update composer.json 2024-04-18 09:51:45 +02:00
James Cole
4a783d3c3c Drop a specific preference from the return of Firefly III 2024-04-18 05:54:57 +02:00
github-actions
e16645ae87 Auto commit for release 'develop' on 2024-04-18 2024-04-18 05:09:58 +02:00
github-actions
9d3189be7e Auto commit for release 'develop' on 2024-04-15 2024-04-15 07:59:54 +02:00
James Cole
07fca78293 Merge pull request #8791 from firefly-iii/dependabot/npm_and_yarn/develop/i18next-23.11.2
Bump i18next from 23.11.1 to 23.11.2
2024-04-15 07:55:47 +02:00
James Cole
82080501c7 Merge pull request #8790 from firefly-iii/dependabot/npm_and_yarn/develop/sass-1.75.0
Bump sass from 1.74.1 to 1.75.0
2024-04-15 07:55:37 +02:00
James Cole
d93d6bfc66 Update phpcs.sh
Signed-off-by: James Cole <james@firefly-iii.org>
2024-04-15 07:54:52 +02:00
dependabot[bot]
a41326ef94 Bump i18next from 23.11.1 to 23.11.2
Bumps [i18next](https://github.com/i18next/i18next) from 23.11.1 to 23.11.2.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v23.11.1...v23.11.2)

---
updated-dependencies:
- dependency-name: i18next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 03:55:25 +00:00
dependabot[bot]
90b77845c3 Bump sass from 1.74.1 to 1.75.0
Bumps [sass](https://github.com/sass/dart-sass) from 1.74.1 to 1.75.0.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.74.1...1.75.0)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 03:55:12 +00:00
James Cole
57af80d820 Merge pull request #8788 from firefly-iii/dependabot/composer/develop/larastan/larastan-2.9.4 2024-04-15 05:45:30 +02:00
James Cole
fc4d5a1dfd Merge pull request #8787 from firefly-iii/dependabot/composer/develop/phpunit/phpunit-10.5.18 2024-04-15 05:45:21 +02:00
dependabot[bot]
8ab9ab8d21 Bump larastan/larastan from 2.9.2 to 2.9.4
Bumps [larastan/larastan](https://github.com/larastan/larastan) from 2.9.2 to 2.9.4.
- [Release notes](https://github.com/larastan/larastan/releases)
- [Changelog](https://github.com/larastan/larastan/blob/2.x/RELEASE.md)
- [Commits](https://github.com/larastan/larastan/compare/v2.9.2...v2.9.4)

---
updated-dependencies:
- dependency-name: larastan/larastan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 03:01:51 +00:00
dependabot[bot]
75674b5793 Bump phpunit/phpunit from 10.5.17 to 10.5.18
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.5.17 to 10.5.18.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.5.18/ChangeLog-10.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.5.17...10.5.18)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-15 03:01:41 +00:00
James Cole
a7d6f26051 Sign release 2024-04-14 13:34:41 +02:00
James Cole
eb540ce148 New PR template 2024-04-14 13:32:56 +02:00
James Cole
a3077fe43b Merge branch 'main' into develop 2024-04-14 08:52:38 +02:00
James Cole
63bb84d375 Workflow runs on "main" 2024-04-14 08:52:27 +02:00
James Cole
e5f5aa628e Small changes in CI script and vite config 2024-04-14 08:51:59 +02:00
James Cole
c54f84dc8e Fix https://github.com/firefly-iii/firefly-iii/issues/8779 2024-04-13 05:50:26 +02:00
github-actions
c2e562623c Auto commit for release 'develop' on 2024-04-11 2024-04-11 05:10:20 +02:00
James Cole
c8d5e8a9dc Add roles 2024-04-10 19:45:08 +02:00
James Cole
963f017be3 Merge branch 'main' into develop 2024-04-08 07:46:41 +02:00
James Cole
0e0eeb736f Point to single source of truth for view name. 2024-04-08 07:45:58 +02:00
James Cole
e8d9b8fa49 Merge pull request #8768 from firefly-iii/dependabot/github_actions/github/command-1.1.1
Bump github/command from 1.1.0 to 1.1.1
2024-04-08 07:39:05 +02:00
James Cole
c166b9242e Merge pull request #8766 from firefly-iii/dependabot/npm_and_yarn/develop/date-fns-3.6.0
Bump date-fns from 2.30.0 to 3.6.0
2024-04-08 07:34:35 +02:00
dependabot[bot]
8ff8efced2 Bump date-fns from 2.30.0 to 3.6.0
Bumps [date-fns](https://github.com/date-fns/date-fns) from 2.30.0 to 3.6.0.
- [Release notes](https://github.com/date-fns/date-fns/releases)
- [Changelog](https://github.com/date-fns/date-fns/blob/main/CHANGELOG.md)
- [Commits](https://github.com/date-fns/date-fns/compare/v2.30.0...v3.6.0)

---
updated-dependencies:
- dependency-name: date-fns
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 04:54:48 +00:00
James Cole
0b4fb9a806 Revert to v8, also update other packages. 2024-04-08 06:53:51 +02:00
James Cole
ba9fef9410 Merge pull request #8765 from firefly-iii/dependabot/npm_and_yarn/develop/laravel-vite-plugin-1.0.2
Bump laravel-vite-plugin from 0.8.1 to 1.0.2
2024-04-08 06:29:54 +02:00
James Cole
f7d94d17cd Merge pull request #8764 from firefly-iii/dependabot/npm_and_yarn/develop/vue-i18n-9.11.0
Bump vue-i18n from 8.28.2 to 9.11.0
2024-04-08 06:23:42 +02:00
dependabot[bot]
1fea9c6817 Bump github/command from 1.1.0 to 1.1.1
Bumps [github/command](https://github.com/github/command) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/github/command/releases)
- [Commits](https://github.com/github/command/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: github/command
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 04:03:50 +00:00
dependabot[bot]
a88c8bedbe Bump laravel-vite-plugin from 0.8.1 to 1.0.2
Bumps [laravel-vite-plugin](https://github.com/laravel/vite-plugin) from 0.8.1 to 1.0.2.
- [Release notes](https://github.com/laravel/vite-plugin/releases)
- [Changelog](https://github.com/laravel/vite-plugin/blob/1.x/CHANGELOG.md)
- [Upgrade guide](https://github.com/laravel/vite-plugin/blob/1.x/UPGRADE.md)
- [Commits](https://github.com/laravel/vite-plugin/compare/v0.8.1...v1.0.2)

---
updated-dependencies:
- dependency-name: laravel-vite-plugin
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 03:27:28 +00:00
dependabot[bot]
fbf3468053 Bump vue-i18n from 8.28.2 to 9.11.0
Bumps [vue-i18n](https://github.com/intlify/vue-i18n-next/tree/HEAD/packages/vue-i18n) from 8.28.2 to 9.11.0.
- [Release notes](https://github.com/intlify/vue-i18n-next/releases)
- [Changelog](https://github.com/intlify/vue-i18n-next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n-next/commits/v9.11.0/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 03:27:11 +00:00
github-actions
2a3ba9799e Auto commit for release 'develop' on 2024-04-08 2024-04-08 05:09:59 +02:00
James Cole
d121aad28f Check the directory, not the file. 2024-04-07 16:27:15 +02:00
github-actions
dc808fa807 Auto commit for release 'develop' on 2024-04-07 2024-04-07 16:22:39 +02:00
James Cole
a1be6ff62b Limit the number of error messages Firefly III will send. 2024-04-07 16:12:41 +02:00
James Cole
20dc5b0256 Fix layout errors. 2024-04-07 15:57:51 +02:00
128 changed files with 2184 additions and 1231 deletions

View File

@@ -226,16 +226,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.52.1", "version": "v3.54.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "6e77207f0d851862ceeb6da63e6e22c01b1587bc" "reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/6e77207f0d851862ceeb6da63e6e22c01b1587bc", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2aecbc8640d7906c38777b3dcab6f4ca79004d08",
"reference": "6e77207f0d851862ceeb6da63e6e22c01b1587bc", "reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -259,6 +259,7 @@
}, },
"require-dev": { "require-dev": {
"facile-it/paraunit": "^1.3 || ^2.0", "facile-it/paraunit": "^1.3 || ^2.0",
"infection/infection": "^0.27.11",
"justinrainbow/json-schema": "^5.2", "justinrainbow/json-schema": "^5.2",
"keradus/cli-executor": "^2.1", "keradus/cli-executor": "^2.1",
"mikey179/vfsstream": "^1.6.11", "mikey179/vfsstream": "^1.6.11",
@@ -306,7 +307,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.52.1" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.54.0"
}, },
"funding": [ "funding": [
{ {
@@ -314,7 +315,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-03-19T21:02:43+00:00" "time": "2024-04-17T08:12:13+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",

View File

@@ -20,23 +20,8 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
# Install composer packages
#composer install --no-scripts --no-ansi
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# enable test .env file.
# cp .ci/.env.ci .env
OUTPUT_FORMAT=txt
EXTRA_PARAMS=""
if [[ $GITHUB_ACTIONS = "true" ]]
then
OUTPUT_FORMAT=txt
EXTRA_PARAMS=""
fi
# clean up php code # clean up php code
cd $SCRIPT_DIR/php-cs-fixer cd $SCRIPT_DIR/php-cs-fixer
composer update --quiet composer update --quiet
@@ -44,8 +29,8 @@ rm -f .php-cs-fixer.cache
PHP_CS_FIXER_IGNORE_ENV=true PHP_CS_FIXER_IGNORE_ENV=true
./vendor/bin/php-cs-fixer fix \ ./vendor/bin/php-cs-fixer fix \
--config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \ --config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php \
--format=$OUTPUT_FORMAT \ --format=txt \
--allow-risky=yes $EXTRA_PARAMS --allow-risky=yes
EXIT_CODE=$? EXIT_CODE=$?

View File

@@ -1,13 +1,13 @@
<!-- <!--
Thank you for submitting new code to Firefly III, or any of the related projects. Please read the following rules carefully. Thank you for submitting new code to Firefly III, or any of the related projects. Please read the following rules carefully.
- Do not submit solutions for problems that are not already reported in an issue - Please do not submit solutions for problems that are not already reported in an issue.
- Firefly III can't be your learning experience. If you're new to all of this, please go be new somewhere else - Unfortunately, Firefly III can't be your learning experience. If you're new to all of this, please open an issue first.
- Do not open PRs to "discuss" possible solutions or to "get feedback" on your code. I don't have time for that. - Please do not open PRs to "discuss" possible solutions or to "get feedback" on your code. I simply don't have time for that.
- Pull requests for the MAIN branch will be closed. - Pull requests for the MAIN branch will be closed.
- DO NOT include translated strings in your PR. - DO NOT include translated strings in your PR.
Perhaps open an issue first, before you open a PR? If it feels necessary to open an issue first, please do so, before you open a PR.
See also: https://docs.firefly-iii.org/explanation/support/#contributing-code See also: https://docs.firefly-iii.org/explanation/support/#contributing-code

View File

@@ -13,7 +13,7 @@ jobs:
close_duplicates: close_duplicates:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: github/command@v1.1.0 - uses: github/command@v1.1.1
id: command id: command
with: with:
allowed_contexts: "issue" allowed_contexts: "issue"

View File

@@ -51,7 +51,7 @@ jobs:
CROWDIN_TOKEN: ${{ secrets.CROWDIN_TOKEN }} CROWDIN_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
- name: Cleanup translations - name: Cleanup translations
id: cleanup-transactions id: cleanup-transactions
uses: JC5/firefly-iii-dev@v38 uses: JC5/firefly-iii-dev@main
with: with:
action: 'ff3:crowdin-warning' action: 'ff3:crowdin-warning'
output: '' output: ''
@@ -60,7 +60,7 @@ jobs:
GH_TOKEN: '' GH_TOKEN: ''
- name: Cleanup changelog - name: Cleanup changelog
id: cleanup-changelog id: cleanup-changelog
uses: JC5/firefly-iii-dev@v38 uses: JC5/firefly-iii-dev@main
with: with:
action: 'ff3:changelog' action: 'ff3:changelog'
output: '' output: ''
@@ -69,7 +69,7 @@ jobs:
GH_TOKEN: ${{ secrets.CHANGELOG_TOKEN }} GH_TOKEN: ${{ secrets.CHANGELOG_TOKEN }}
- name: Extract changelog - name: Extract changelog
id: extract-changelog id: extract-changelog
uses: JC5/firefly-iii-dev@v38 uses: JC5/firefly-iii-dev@main
with: with:
action: 'ff3:extract-changelog' action: 'ff3:extract-changelog'
output: 'output' output: 'output'
@@ -78,7 +78,7 @@ jobs:
GH_TOKEN: "" GH_TOKEN: ""
- name: Replace version - name: Replace version
id: replace-version id: replace-version
uses: JC5/firefly-iii-dev@v38 uses: JC5/firefly-iii-dev@main
with: with:
action: 'ff3:version' action: 'ff3:version'
output: '' output: ''
@@ -88,7 +88,7 @@ jobs:
FF_III_VERSION: ${{ github.event_name == 'schedule' && 'develop' || github.event.inputs.version }} FF_III_VERSION: ${{ github.event_name == 'schedule' && 'develop' || github.event.inputs.version }}
- name: Generate JSON v1 - name: Generate JSON v1
id: json-v1 id: json-v1
uses: JC5/firefly-iii-dev@v38 uses: JC5/firefly-iii-dev@main
with: with:
action: 'ff3:json-translations v1' action: 'ff3:json-translations v1'
output: '' output: ''
@@ -97,7 +97,7 @@ jobs:
GH_TOKEN: '' GH_TOKEN: ''
- name: Generate JSON v2 - name: Generate JSON v2
id: json-v2 id: json-v2
uses: JC5/firefly-iii-dev@v38 uses: JC5/firefly-iii-dev@main
with: with:
action: 'ff3:json-translations v2' action: 'ff3:json-translations v2'
output: '' output: ''
@@ -106,7 +106,7 @@ jobs:
GH_TOKEN: '' GH_TOKEN: ''
- name: Code cleanup - name: Code cleanup
id: code-cleanup id: code-cleanup
uses: JC5/firefly-iii-dev@v38 uses: JC5/firefly-iii-dev@main
with: with:
action: 'ff3:code' action: 'ff3:code'
output: '' output: ''
@@ -122,10 +122,14 @@ jobs:
- name: Run CI - name: Run CI
run: | run: |
rm -rf vendor composer.lock rm -rf vendor composer.lock
composer validate --strict
composer update --no-dev --no-scripts --no-plugins -q composer update --no-dev --no-scripts --no-plugins -q
sudo chown -R runner:docker resources/lang sudo chown -R runner:docker resources/lang
.ci/phpcs.sh .ci/phpcs.sh
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}
- name: Release - name: Release
run: | run: |
# do some configuration # do some configuration
@@ -141,7 +145,6 @@ jobs:
tarName=FireflyIII-$version.tar.gz tarName=FireflyIII-$version.tar.gz
# update composer (again) # update composer (again)
composer validate --strict
composer update --no-dev --no-scripts --no-plugins composer update --no-dev --no-scripts --no-plugins
composer dump-autoload composer dump-autoload
@@ -191,6 +194,10 @@ jobs:
sha256sum -b $zipName > $zipName.sha256 sha256sum -b $zipName > $zipName.sha256
sha256sum -b $tarName > $tarName.sha256 sha256sum -b $tarName > $tarName.sha256
# add signatures:
gpg --armor --detach-sign $zipName
gpg --armor --detach-sign $tarName
# create a development (nightly) release: # create a development (nightly) release:
if [[ "develop" == "$version" ]]; then if [[ "develop" == "$version" ]]; then
echo 'Develop release.' echo 'Develop release.'
@@ -198,7 +205,7 @@ jobs:
rm output.txt rm output.txt
echo "Bi-weekly development release of Firefly III with the latest fixes, translations and features. Docker users can find this release under the \`develop\` tag." >> output.txt echo "Bi-weekly development release of Firefly III with the latest fixes, translations and features. Docker users can find this release under the \`develop\` tag." >> output.txt
echo "" >> output.txt echo "" >> output.txt
echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible." >> output.txt echo "This release was created on **$(date +'%Y-%m-%d')** and may contain unexpected bugs. Data loss is rare but is not impossible. The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)." >> output.txt
echo "" >> output.txt echo "" >> output.txt
echo "* Please read the installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt echo "* Please read the installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
@@ -221,6 +228,10 @@ jobs:
gh release upload $releaseName $zipName.sha256 gh release upload $releaseName $zipName.sha256
gh release upload $releaseName $tarName.sha256 gh release upload $releaseName $tarName.sha256
# add signatures to release
gh release upload $releaseName $zipName.asc
gh release upload $releaseName $tarName.asc
# get current HEAD and add as file to the release # get current HEAD and add as file to the release
HEAD=$(git rev-parse HEAD) HEAD=$(git rev-parse HEAD)
echo $HEAD > HEAD.txt echo $HEAD > HEAD.txt
@@ -234,6 +245,7 @@ jobs:
echo '' >> output.txt echo '' >> output.txt
echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt echo "* Installation instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/installation/docker/), [Portainer](https://docs.firefly-iii.org/how-to/firefly-iii/installation/portainer/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/installation/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/installation/self-managed/)" >> output.txt
echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt echo "* Or read the upgrade instructions for [Docker](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/docker/), [Kubernetes](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/kubernetes/) or [self-managed servers](https://docs.firefly-iii.org/how-to/firefly-iii/upgrade/self-managed/)" >> output.txt
echo "* The releases are signed, and you can verify them using the [Firefly III releases PGP key](https://docs.firefly-iii.org/explanation/more-information/signatures/)."
echo "Create default release." echo "Create default release."
git tag -a $releaseName -m "Here be changelog" git tag -a $releaseName -m "Here be changelog"
@@ -248,6 +260,10 @@ jobs:
gh release upload $releaseName $zipName.sha256 gh release upload $releaseName $zipName.sha256
gh release upload $releaseName $tarName.sha256 gh release upload $releaseName $tarName.sha256
# add signatures to release
gh release upload $releaseName $zipName.asc
gh release upload $releaseName $tarName.asc
# get current HEAD and add as file to the release # get current HEAD and add as file to the release
HEAD=$(git rev-parse HEAD) HEAD=$(git rev-parse HEAD)
echo $HEAD > HEAD.txt echo $HEAD > HEAD.txt

View File

@@ -73,7 +73,8 @@ class UpdateController extends Controller
$data = $request->getAll(); $data = $request->getAll();
// Fixes 8750. // Fixes 8750.
foreach ($data['transactions'] as $index => $info) { $transactions = $data['transactions'] ?? [];
foreach ($transactions as $index => $info) {
unset($data['transactions'][$index]['type']); unset($data['transactions'][$index]['type']);
} }

View File

@@ -84,6 +84,10 @@ class PreferencesController extends Controller
{ {
$manager = $this->getManager(); $manager = $this->getManager();
if ('currencyPreference' === $preference->name) {
throw new FireflyException('Please use api/v1/currencies/default instead.');
}
/** @var PreferenceTransformer $transformer */ /** @var PreferenceTransformer $transformer */
$transformer = app(PreferenceTransformer::class); $transformer = app(PreferenceTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);
@@ -103,6 +107,11 @@ class PreferencesController extends Controller
{ {
$manager = $this->getManager(); $manager = $this->getManager();
$data = $request->getAll(); $data = $request->getAll();
if ('currencyPreference' === $data['name']) {
throw new FireflyException('Please use api/v1/currencies/default instead.');
}
$pref = app('preferences')->set($data['name'], $data['data']); $pref = app('preferences')->set($data['name'], $data['data']);
/** @var PreferenceTransformer $transformer */ /** @var PreferenceTransformer $transformer */
@@ -122,6 +131,10 @@ class PreferencesController extends Controller
*/ */
public function update(PreferenceUpdateRequest $request, Preference $preference): JsonResponse public function update(PreferenceUpdateRequest $request, Preference $preference): JsonResponse
{ {
if ('currencyPreference' === $preference->name) {
throw new FireflyException('Please use api/v1/currencies/default instead.');
}
$manager = $this->getManager(); $manager = $this->getManager();
$data = $request->getAll(); $data = $request->getAll();
$pref = app('preferences')->set($preference->name, $data['data']); $pref = app('preferences')->set($preference->name, $data['data']);

View File

@@ -71,8 +71,9 @@ class StoreRequest extends FormRequest
if (is_array($triggers)) { if (is_array($triggers)) {
foreach ($triggers as $trigger) { foreach ($triggers as $trigger) {
$return[] = [ $return[] = [
'type' => $trigger['type'], 'type' => $trigger['type'] ?? '',
'value' => $trigger['value'], 'value' => $trigger['value'] ?? null,
'prohibited' => $this->convertBoolean((string)($trigger['prohibited'] ?? 'false')),
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')), 'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')), 'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
]; ];

View File

@@ -81,10 +81,12 @@ class UpdateRequest extends FormRequest
if (is_array($triggers)) { if (is_array($triggers)) {
foreach ($triggers as $trigger) { foreach ($triggers as $trigger) {
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true; $active = array_key_exists('active', $trigger) ? $trigger['active'] : true;
$prohibited = array_key_exists('prohibited', $trigger) ? $trigger['prohibited'] : false;
$stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false; $stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false;
$return[] = [ $return[] = [
'type' => $trigger['type'], 'type' => $trigger['type'],
'value' => $trigger['value'], 'value' => $trigger['value'],
'prohibited' => $prohibited,
'active' => $active, 'active' => $active,
'stop_processing' => $stopProcessing, 'stop_processing' => $stopProcessing,
]; ];

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V2\Controllers\Chart;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Api\V2\Controllers\Controller; use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Chart\BalanceChartRequest; use FireflyIII\Api\V2\Request\Chart\BalanceChartRequest;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
@@ -42,6 +43,7 @@ use Illuminate\Support\Collection;
class BalanceController extends Controller class BalanceController extends Controller
{ {
use CleansChartData; use CleansChartData;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/** /**
* The code is practically a duplicate of ReportController::operations. * The code is practically a duplicate of ReportController::operations.

View File

@@ -122,6 +122,9 @@ class Controller extends BaseController
$obj = null; $obj = null;
} }
} }
if (null !== $date && 'end' === $field) {
$obj->endOfDay();
}
$bag->set($field, $obj); $bag->set($field, $obj);
} }

View File

@@ -25,7 +25,6 @@ namespace FireflyIII\Api\V2\Controllers\Model\Account;
use FireflyIII\Api\V2\Controllers\Controller; use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Model\Account\IndexRequest; use FireflyIII\Api\V2\Request\Model\Account\IndexRequest;
use FireflyIII\Api\V2\Request\Model\Transaction\InfiniteListRequest;
use FireflyIII\Enums\UserRoleEnum; use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface; use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Transformers\V2\AccountTransformer; use FireflyIII\Transformers\V2\AccountTransformer;
@@ -58,7 +57,7 @@ class IndexController extends Controller
} }
/** /**
* TODO see autocomplete/accountcontroller for list. * TODO see autocomplete/account controller for list.
*/ */
public function index(IndexRequest $request): JsonResponse public function index(IndexRequest $request): JsonResponse
{ {
@@ -80,25 +79,4 @@ class IndexController extends Controller
->header('Content-Type', self::CONTENT_TYPE) ->header('Content-Type', self::CONTENT_TYPE)
; ;
} }
public function infiniteList(InfiniteListRequest $request): JsonResponse
{
$this->repository->resetAccountOrder();
// get accounts of the specified type, and return.
$types = $request->getAccountTypes();
// get from repository
$accounts = $this->repository->getAccountsInOrder($types, $request->getSortInstructions('accounts'), $request->getStartRow(), $request->getEndRow());
$total = $this->repository->countAccounts($types);
$count = $request->getEndRow() - $request->getStartRow();
$paginator = new LengthAwarePaginator($accounts, $total, $count, $this->parameters->get('page'));
$transformer = new AccountTransformer();
$transformer->setParameters($this->parameters); // give params to transformer
return response()
->json($this->jsonApiList(self::RESOURCE_KEY, $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE)
;
}
} }

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V2\Request\Chart; namespace FireflyIII\Api\V2\Request\Chart;
use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait; use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes; use FireflyIII\Support\Request\ConvertsDataTypes;
@@ -39,6 +40,7 @@ class BalanceChartRequest extends FormRequest
use ChecksLogin; use ChecksLogin;
use ConvertsDataTypes; use ConvertsDataTypes;
use ValidatesUserGroupTrait; use ValidatesUserGroupTrait;
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
/** /**
* Get all data from the request. * Get all data from the request.

View File

@@ -44,14 +44,11 @@ class IndexRequest extends FormRequest
public function getAccountTypes(): array public function getAccountTypes(): array
{ {
$type = (string)$this->get('type', 'default'); $type = (string) $this->get('type', 'default');
return $this->mapAccountTypes($type); return $this->mapAccountTypes($type);
} }
/**
* Get all data from the request.
*/
public function getDate(): Carbon public function getDate(): Carbon
{ {
return $this->getCarbonDate('date'); return $this->getCarbonDate('date');
@@ -63,7 +60,9 @@ class IndexRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'date' => 'date|after:1900-01-01|before:2099-12-31', 'date' => 'date|after:1900-01-01|before:2099-12-31',
'start' => 'date|after:1900-01-01|before:2099-12-31|before:end|required_with:end',
'end' => 'date|after:1900-01-01|before:2099-12-31|after:start|required_with:start',
]; ];
} }
} }

View File

@@ -106,7 +106,7 @@ class ShowController extends Controller
$periods = $this->getAccountPeriodOverview($account, $firstTransaction, $end); $periods = $this->getAccountPeriodOverview($account, $firstTransaction, $end);
// if layout = v2, overrule the page title. // if layout = v2, overrule the page title.
if ('v1' !== config('firefly.layout')) { if ('v1' !== config('view.layout')) {
$subTitle = (string)trans('firefly.all_journals_for_account', ['name' => $account->name]); $subTitle = (string)trans('firefly.all_journals_for_account', ['name' => $account->name]);
} }

View File

@@ -31,6 +31,7 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View; use Illuminate\View\View;
/** /**
@@ -106,6 +107,8 @@ class ForgotPasswordController extends Controller
} }
$host = request()->host(); $host = request()->host();
if ($configuredHost !== $host) { if ($configuredHost !== $host) {
Log::error(sprintf('Host header is "%s", APP_URL is "%s".', $host, $configuredHost));
throw new FireflyException('The Host-header does not match the host in the APP_URL environment variable. Please make sure these match. See also: https://bit.ly/FF3-host-header'); throw new FireflyException('The Host-header does not match the host in the APP_URL environment variable. Please make sure these match. See also: https://bit.ly/FF3-host-header');
} }
} }

View File

@@ -70,7 +70,7 @@ abstract class Controller extends BaseController
$logoutUrl = config('firefly.custom_logout_url'); $logoutUrl = config('firefly.custom_logout_url');
// overrule v2 layout back to v1. // overrule v2 layout back to v1.
if ('true' === request()->get('force_default_layout') && 'v2' === config('firefly.layout')) { if ('true' === request()->get('force_default_layout') && 'v2' === config('view.layout')) {
app('view')->getFinder()->setPaths([realpath(base_path('resources/views'))]); // @phpstan-ignore-line app('view')->getFinder()->setPaths([realpath(base_path('resources/views'))]); // @phpstan-ignore-line
} }

View File

@@ -25,6 +25,7 @@ namespace FireflyIII\Http\Middleware;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Vite; use Illuminate\Support\Facades\Vite;
use Barryvdh\Debugbar\Facades\Debugbar;
/** /**
* Class SecureHeaders * Class SecureHeaders
@@ -43,6 +44,9 @@ class SecureHeaders
// generate and share nonce. // generate and share nonce.
$nonce = base64_encode(random_bytes(16)); $nonce = base64_encode(random_bytes(16));
Vite::useCspNonce($nonce); Vite::useCspNonce($nonce);
if (class_exists('Barryvdh\Debugbar\Facades\Debugbar')) {
Debugbar::getJavascriptRenderer()->setCspNonce($nonce);
}
app('view')->share('JS_NONCE', $nonce); app('view')->share('JS_NONCE', $nonce);
$response = $next($request); $response = $next($request);
@@ -55,14 +59,29 @@ class SecureHeaders
"base-uri 'self'", "base-uri 'self'",
"font-src 'self' data:", "font-src 'self' data:",
sprintf("connect-src 'self' %s", $trackingScriptSrc), sprintf("connect-src 'self' %s", $trackingScriptSrc),
sprintf("img-src 'self' 'nonce-%1s'", $nonce), sprintf("img-src 'self' data: 'nonce-%1s' ", $nonce),
"manifest-src 'self'", "manifest-src 'self'",
]; ];
// overrule in development mode
if (true === env('IS_LOCAL_DEV')) {
$csp = [
"default-src 'none'",
"object-src 'none'",
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s' https://firefly.sd.internal/_debugbar/assets", $nonce),
"style-src 'unsafe-inline' 'self' https://10.0.0.15:5173/",
"base-uri 'self'",
"font-src 'self' data: https://10.0.0.15:5173/",
sprintf("connect-src 'self' %s https://10.0.0.15:5173/ wss://10.0.0.15:5173/", $trackingScriptSrc),
sprintf("img-src 'self' data: 'nonce-%1s'", $nonce),
"manifest-src 'self'",
];
}
$route = $request->route(); $route = $request->route();
$customUrl = ''; $customUrl = '';
$authGuard = (string)config('firefly.authentication_guard'); $authGuard = (string) config('firefly.authentication_guard');
$logoutUrl = (string)config('firefly.custom_logout_url'); $logoutUrl = (string) config('firefly.custom_logout_url');
if ('remote_user_guard' === $authGuard && '' !== $logoutUrl) { if ('remote_user_guard' === $authGuard && '' !== $logoutUrl) {
$customUrl = $logoutUrl; $customUrl = $logoutUrl;
} }
@@ -110,8 +129,8 @@ class SecureHeaders
*/ */
private function getTrackingScriptSource(): string private function getTrackingScriptSource(): string
{ {
if ('' !== (string)config('firefly.tracker_site_id') && '' !== (string)config('firefly.tracker_url')) { if ('' !== (string) config('firefly.tracker_site_id') && '' !== (string) config('firefly.tracker_url')) {
return (string)config('firefly.tracker_url'); return (string) config('firefly.tracker_url');
} }
return ''; return '';

View File

@@ -27,6 +27,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Message; use Illuminate\Mail\Message;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Symfony\Component\Mailer\Exception\TransportException; use Symfony\Component\Mailer\Exception\TransportException;
/** /**
@@ -68,6 +69,14 @@ class MailError extends Job implements ShouldQueue
$args['user'] = $this->userData; $args['user'] = $this->userData;
$args['ip'] = $this->ipAddress; $args['ip'] = $this->ipAddress;
$args['token'] = config('firefly.ipinfo_token'); $args['token'] = config('firefly.ipinfo_token');
// limit number of error mails that can be sent.
if ($this->reachedLimit()) {
Log::info('MailError: reached limit, not sending email.');
return;
}
if ($this->attempts() < 3 && '' !== $email) { if ($this->attempts() < 3 && '' !== $email) {
try { try {
\Mail::send( \Mail::send(
@@ -96,4 +105,62 @@ class MailError extends Job implements ShouldQueue
} }
} }
} }
private function reachedLimit(): bool
{
Log::debug('reachedLimit()');
$types = [
'5m' => ['limit' => 5, 'reset' => 5 * 60],
'1h' => ['limit' => 15, 'reset' => 60 * 60],
'24h' => ['limit' => 15, 'reset' => 24 * 60 * 60],
];
$file = storage_path('framework/cache/error-count.json');
$directory = storage_path('framework/cache');
$limits = [];
if (!is_writable($directory)) {
Log::error(sprintf('MailError: cannot write to "%s", cannot rate limit errors!', $directory));
return false;
}
if (!file_exists($file)) {
Log::debug(sprintf('Wrote new file in "%s"', $file));
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
}
if (file_exists($file)) {
Log::debug(sprintf('Read file in "%s"', $file));
$limits = json_decode(file_get_contents($file), true);
}
// limit reached?
foreach ($types as $type => $info) {
Log::debug(sprintf('Now checking limit "%s"', $type), $info);
if (!isset($limits[$type])) {
Log::debug(sprintf('Limit "%s" reset to zero, did not exist yet.', $type));
$limits[$type] = [
'time' => time(),
'sent' => 0,
];
}
if (time() - $limits[$type]['time'] > $info['reset']) {
Log::debug(sprintf('Time past for this limit is %d seconds, exceeding %d seconds. Reset to zero.', time() - $limits[$type]['time'], $info['reset']));
$limits[$type] = [
'time' => time(),
'sent' => 0,
];
}
if ($limits[$type]['sent'] > $info['limit']) {
Log::warning(sprintf('Sent %d emails in %s, return true.', $limits[$type]['sent'], $type));
return true;
}
++$limits[$type]['sent'];
}
file_put_contents($file, json_encode($limits, JSON_PRETTY_PRINT));
Log::debug('No limits reached, return FALSE.');
return false;
}
} }

View File

@@ -295,4 +295,16 @@ class UserGroupRepository implements UserGroupRepositoryInterface
$this->user->user_group_id = $userGroup->id; $this->user->user_group_id = $userGroup->id;
$this->user->save(); $this->user->save();
} }
#[\Override]
public function getMembershipsFromGroupId(int $groupId): Collection
{
return $this->user->groupMemberships()->where('user_group_id', $groupId)->get();
}
#[\Override]
public function getById(int $id): ?UserGroup
{
return UserGroup::find($id);
}
} }

View File

@@ -36,8 +36,12 @@ interface UserGroupRepositoryInterface
{ {
public function destroy(UserGroup $userGroup): void; public function destroy(UserGroup $userGroup): void;
public function getMembershipsFromGroupId(int $groupId): Collection;
public function get(): Collection; public function get(): Collection;
public function getById(int $id): ?UserGroup;
public function getAll(): Collection; public function getAll(): Collection;
public function setUser(null|Authenticatable|User $user): void; public function setUser(null|Authenticatable|User $user): void;

View File

@@ -27,11 +27,13 @@ namespace FireflyIII\Repositories\UserGroups\Account;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta; use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Services\Internal\Update\AccountUpdateService; use FireflyIII\Services\Internal\Update\AccountUpdateService;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait; use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
/** /**
* Class AccountRepository * Class AccountRepository
@@ -121,7 +123,7 @@ class AccountRepository implements AccountRepositoryInterface
if (!in_array($type, $list, true)) { if (!in_array($type, $list, true)) {
return null; return null;
} }
$currencyId = (int)$this->getMetaValue($account, 'currency_id'); $currencyId = (int) $this->getMetaValue($account, 'currency_id');
if ($currencyId > 0) { if ($currencyId > 0) {
return TransactionCurrency::find($currencyId); return TransactionCurrency::find($currencyId);
} }
@@ -143,7 +145,7 @@ class AccountRepository implements AccountRepositoryInterface
return null; return null;
} }
if (1 === $result->count()) { if (1 === $result->count()) {
return (string)$result->first()->data; return (string) $result->first()->data;
} }
return null; return null;
@@ -228,7 +230,7 @@ class AccountRepository implements AccountRepositoryInterface
continue; continue;
} }
if ($index !== (int)$account->order) { if ($index !== (int) $account->order) {
app('log')->debug(sprintf('Account #%d ("%s"): order should %d be but is %d.', $account->id, $account->name, $index, $account->order)); app('log')->debug(sprintf('Account #%d ("%s"): order should %d be but is %d.', $account->id, $account->name, $index, $account->order));
$account->order = $index; $account->order = $index;
$account->save(); $account->save();
@@ -305,4 +307,34 @@ class AccountRepository implements AccountRepositoryInterface
return $service->update($account, $data); return $service->update($account, $data);
} }
#[\Override]
public function getMetaValues(Collection $accounts, array $fields): Collection
{
$query = AccountMeta::whereIn('account_id', $accounts->pluck('id')->toArray());
if (count($fields) > 0) {
$query->whereIn('name', $fields);
}
return $query->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data']);
}
#[\Override]
public function getAccountTypes(Collection $accounts): Collection
{
return AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id')
->whereIn('accounts.id', $accounts->pluck('id')->toArray())
->get(['accounts.id', 'account_types.type'])
;
}
#[\Override]
public function getLastActivity(Collection $accounts): array
{
return Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
->groupBy('transactions.account_id')
->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) as date_max')])->toArray() // @phpstan-ignore-line
;
}
} }

View File

@@ -37,6 +37,12 @@ interface AccountRepositoryInterface
{ {
public function countAccounts(array $types): int; public function countAccounts(array $types): int;
public function getAccountTypes(Collection $accounts): Collection;
public function getLastActivity(Collection $accounts): array;
public function getMetaValues(Collection $accounts, array $fields): Collection;
public function find(int $accountId): ?Account; public function find(int $accountId): ?Account;
public function findByAccountNumber(string $number, array $types): ?Account; public function findByAccountNumber(string $number, array $types): ?Account;

View File

@@ -24,12 +24,13 @@ declare(strict_types=1);
namespace FireflyIII\Support\Http\Api; namespace FireflyIII\Support\Http\Api;
use FireflyIII\Enums\UserRoleEnum; use FireflyIII\Enums\UserRoleEnum;
use FireflyIII\Models\GroupMembership;
use FireflyIII\Models\UserGroup; use FireflyIII\Models\UserGroup;
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
/** /**
* Trait ValidatesUserGroupTrait * Trait ValidatesUserGroupTrait
@@ -42,63 +43,64 @@ trait ValidatesUserGroupTrait
*/ */
protected function validateUserGroup(Request $request): UserGroup protected function validateUserGroup(Request $request): UserGroup
{ {
app('log')->debug(sprintf('validateUserGroup: %s', static::class)); Log::debug(sprintf('validateUserGroup: %s', static::class));
if (!auth()->check()) { if (!auth()->check()) {
app('log')->debug('validateUserGroup: user is not logged in, return NULL.'); Log::debug('validateUserGroup: user is not logged in, return NULL.');
throw new AuthenticationException(); throw new AuthenticationException();
} }
/** @var User $user */ /** @var User $user */
$user = auth()->user(); $user = auth()->user();
$groupId = 0; $groupId = 0;
if (!$request->has('user_group_id')) { if (!$request->has('user_group_id')) {
$groupId = $user->user_group_id; $groupId = $user->user_group_id;
app('log')->debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId)); Log::debug(sprintf('validateUserGroup: no user group submitted, use default group #%d.', $groupId));
} }
if ($request->has('user_group_id')) { if ($request->has('user_group_id')) {
$groupId = (int)$request->get('user_group_id'); $groupId = (int) $request->get('user_group_id');
app('log')->debug(sprintf('validateUserGroup: user group submitted, search for memberships in group #%d.', $groupId)); Log::debug(sprintf('validateUserGroup: user group submitted, search for memberships in group #%d.', $groupId));
} }
/** @var null|GroupMembership $membership */ /** @var UserGroupRepositoryInterface $repository */
$membership = $user->groupMemberships()->where('user_group_id', $groupId)->first(); $repository = app(UserGroupRepositoryInterface::class);
$repository->setUser($user);
$memberships = $repository->getMembershipsFromGroupId($groupId);
if (null === $membership) { if (0 === $memberships->count()) {
app('log')->debug(sprintf('validateUserGroup: user has no access to group #%d.', $groupId)); Log::debug(sprintf('validateUserGroup: user has no access to group #%d.', $groupId));
throw new AuthorizationException((string)trans('validation.no_access_group')); throw new AuthorizationException((string) trans('validation.no_access_group'));
} }
// need to get the group from the membership: // need to get the group from the membership:
/** @var null|UserGroup $group */ $group = $repository->getById($groupId);
$group = $membership->userGroup;
if (null === $group) { if (null === $group) {
app('log')->debug(sprintf('validateUserGroup: group #%d does not exist.', $groupId)); Log::debug(sprintf('validateUserGroup: group #%d does not exist.', $groupId));
throw new AuthorizationException((string)trans('validation.belongs_user_or_user_group')); throw new AuthorizationException((string) trans('validation.belongs_user_or_user_group'));
} }
app('log')->debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $groupId, $group->title)); Log::debug(sprintf('validateUserGroup: validate access of user to group #%d ("%s").', $groupId, $group->title));
$roles = property_exists($this, 'acceptedRoles') ? $this->acceptedRoles : []; $roles = property_exists($this, 'acceptedRoles') ? $this->acceptedRoles : [];
if (0 === count($roles)) { if (0 === count($roles)) {
app('log')->debug('validateUserGroup: no roles defined, so no access.'); Log::debug('validateUserGroup: no roles defined, so no access.');
throw new AuthorizationException((string)trans('validation.no_accepted_roles_defined')); throw new AuthorizationException((string) trans('validation.no_accepted_roles_defined'));
} }
app('log')->debug(sprintf('validateUserGroup: have %d roles to check.', count($roles)), $roles); Log::debug(sprintf('validateUserGroup: have %d roles to check.', count($roles)), $roles);
/** @var UserRoleEnum $role */ /** @var UserRoleEnum $role */
foreach ($roles as $role) { foreach ($roles as $role) {
if ($user->hasRoleInGroupOrOwner($group, $role)) { if ($user->hasRoleInGroupOrOwner($group, $role)) {
app('log')->debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId)); Log::debug(sprintf('validateUserGroup: User has role "%s" in group #%d, return the group.', $role->value, $groupId));
return $group; return $group;
} }
app('log')->debug(sprintf('validateUserGroup: User does NOT have role "%s" in group #%d, continue searching.', $role->value, $groupId)); Log::debug(sprintf('validateUserGroup: User does NOT have role "%s" in group #%d, continue searching.', $role->value, $groupId));
} }
app('log')->debug('validateUserGroup: User does NOT have enough rights to access endpoint.'); Log::debug('validateUserGroup: User does NOT have enough rights to access endpoint.');
throw new AuthorizationException((string)trans('validation.belongs_user_or_user_group')); throw new AuthorizationException((string) trans('validation.belongs_user_or_user_group'));
} }
} }

View File

@@ -464,14 +464,15 @@ class Navigation
$increment = 'addDay'; $increment = 'addDay';
$format = $this->preferredCarbonFormat($start, $end); $format = $this->preferredCarbonFormat($start, $end);
$displayFormat = (string)trans('config.month_and_day_js', [], $locale); $displayFormat = (string)trans('config.month_and_day_js', [], $locale);
$diff = $start->diffInMonths($end, true);
// increment by month (for year) // increment by month (for year)
if ($start->diffInMonths($end, true) > 1) { if ($diff >= 1.0001) {
$increment = 'addMonth'; $increment = 'addMonth';
$displayFormat = (string)trans('config.month_js'); $displayFormat = (string)trans('config.month_js');
} }
// increment by year (for multi-year) // increment by year (for multi-year)
if ($start->diffInMonths($end, true) > 12) { if ($diff >= 12.0001) {
$increment = 'addYear'; $increment = 'addYear';
$displayFormat = (string)trans('config.year_js'); $displayFormat = (string)trans('config.year_js');
} }
@@ -494,11 +495,15 @@ class Navigation
public function preferredCarbonFormat(Carbon $start, Carbon $end): string public function preferredCarbonFormat(Carbon $start, Carbon $end): string
{ {
$format = 'Y-m-d'; $format = 'Y-m-d';
if ((int)$start->diffInMonths($end, true) > 1) { $diff = $start->diffInMonths($end, true);
Log::debug(sprintf('preferredCarbonFormat(%s, %s) = %f', $start->format('Y-m-d'), $end->format('Y-m-d'), $diff));
if ($diff >= 1.001) {
Log::debug(sprintf('Return Y-m because %s', $diff));
$format = 'Y-m'; $format = 'Y-m';
} }
if ((int)$start->diffInMonths($end, true) > 12) { if ($diff >= 12.001) {
Log::debug(sprintf('Return Y because %s', $diff));
$format = 'Y'; $format = 'Y';
} }

View File

@@ -44,6 +44,7 @@ class Preferences
} }
return Preference::where('user_id', $user->id) return Preference::where('user_id', $user->id)
->where('name', '!=', 'currencyPreference')
->where(function (Builder $q) use ($user): void { ->where(function (Builder $q) use ($user): void {
$q->whereNull('user_group_id'); $q->whereNull('user_group_id');
$q->orWhere('user_group_id', $user->user_group_id); $q->orWhere('user_group_id', $user->user_group_id);

View File

@@ -159,6 +159,10 @@ class OperatorQuerySearch implements SearchInterface
foreach ($query1->getNodes() as $searchNode) { foreach ($query1->getNodes() as $searchNode) {
$this->handleSearchNode($searchNode); $this->handleSearchNode($searchNode);
} }
// add missing information
$this->collector->withBillInformation();
$this->collector->setSearchWords($this->words); $this->collector->setSearchWords($this->words);
$this->collector->excludeSearchWords($this->prohibitedWords); $this->collector->excludeSearchWords($this->prohibitedWords);
} }

View File

@@ -49,6 +49,7 @@ class Translation extends AbstractExtension
{ {
return [ return [
$this->journalLinkTranslation(), $this->journalLinkTranslation(),
$this->laravelTranslation(),
]; ];
} }
@@ -68,4 +69,19 @@ class Translation extends AbstractExtension
['is_safe' => ['html']] ['is_safe' => ['html']]
); );
} }
public function laravelTranslation(): TwigFunction
{
return new TwigFunction(
'__',
static function (string $key) {
$translation = trans($key);
if ($key === $translation) {
return $key;
}
return $translation;
}
);
}
} }

View File

@@ -34,8 +34,7 @@ use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
*/ */
class RuleTransformer extends AbstractTransformer class RuleTransformer extends AbstractTransformer
{ {
/** @var RuleRepositoryInterface */ private RuleRepositoryInterface $ruleRepository;
private $ruleRepository;
/** /**
* CurrencyTransformer constructor. * CurrencyTransformer constructor.
@@ -109,8 +108,16 @@ class RuleTransformer extends AbstractTransformer
if ('user_action' === $ruleTrigger->trigger_type) { if ('user_action' === $ruleTrigger->trigger_type) {
continue; continue;
} }
$triggerType = (string) $ruleTrigger->trigger_type;
$triggerValue = (string)$ruleTrigger->trigger_value; $triggerValue = (string)$ruleTrigger->trigger_value;
$needsContext = config(sprintf('search.operators.%s.needs_context', $ruleTrigger->trigger_type), true); $prohibited = false;
if (str_starts_with($triggerType, '-')) {
$prohibited = true;
$triggerType = substr($triggerType, 1);
}
$needsContext = config(sprintf('search.operators.%s.needs_context', $triggerType), true);
if (false === $needsContext) { if (false === $needsContext) {
$triggerValue = 'true'; $triggerValue = 'true';
} }
@@ -119,8 +126,9 @@ class RuleTransformer extends AbstractTransformer
'id' => (string)$ruleTrigger->id, 'id' => (string)$ruleTrigger->id,
'created_at' => $ruleTrigger->created_at->toAtomString(), 'created_at' => $ruleTrigger->created_at->toAtomString(),
'updated_at' => $ruleTrigger->updated_at->toAtomString(), 'updated_at' => $ruleTrigger->updated_at->toAtomString(),
'type' => $ruleTrigger->trigger_type, 'type' => $triggerType,
'value' => $triggerValue, 'value' => $triggerValue,
'prohibited' => $prohibited,
'order' => $ruleTrigger->order, 'order' => $ruleTrigger->order,
'active' => $ruleTrigger->active, 'active' => $ruleTrigger->active,
'stop_processing' => $ruleTrigger->stop_processing, 'stop_processing' => $ruleTrigger->stop_processing,

View File

@@ -27,13 +27,12 @@ namespace FireflyIII\Transformers\V2;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account; use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface; use FireflyIII\Repositories\UserGroups\Currency\CurrencyRepositoryInterface;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log;
/** /**
* Class AccountTransformer * Class AccountTransformer
@@ -42,118 +41,45 @@ class AccountTransformer extends AbstractTransformer
{ {
private array $accountMeta; private array $accountMeta;
private array $accountTypes; private array $accountTypes;
private array $balances; private array $balanceDifferences;
private array $convertedBalances; private array $convertedBalances;
private array $currencies; private array $currencies;
private TransactionCurrency $default; private TransactionCurrency $default;
private array $lastActivity; private array $lastActivity;
/** /**
* @throws FireflyException * This method collects meta-data for one or all accounts in the transformer's collection.
*/ */
public function collectMetaData(Collection $objects): Collection public function collectMetaData(Collection $objects): Collection
{ {
// TODO separate methods $this->currencies = [];
$this->currencies = []; $this->accountMeta = [];
$this->accountMeta = []; $this->accountTypes = [];
$this->accountTypes = []; $this->lastActivity = [];
$this->lastActivity = []; $this->convertedBalances = [];
$this->balances = app('steam')->balancesByAccounts($objects, $this->getDate()); $this->balanceDifferences = [];
$this->convertedBalances = app('steam')->balancesByAccountsConverted($objects, $this->getDate());
/** @var CurrencyRepositoryInterface $repository */ // get balances of all accounts
$repository = app(CurrencyRepositoryInterface::class); $this->getMetaBalances($objects);
$this->default = app('amount')->getDefaultCurrency();
// get currencies: // get default currency:
$accountIds = $objects->pluck('id')->toArray(); $this->getDefaultCurrency();
// TODO move query to repository
$meta = AccountMeta::whereIn('account_id', $accountIds) // collect currency and other meta-data:
->whereIn('name', ['currency_id', 'account_role', 'account_number']) $this->collectAccountMetaData($objects);
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])
;
$currencyIds = $meta->where('name', 'currency_id')->pluck('data')->toArray();
$currencies = $repository->getByIds($currencyIds);
foreach ($currencies as $currency) {
$id = $currency->id;
$this->currencies[$id] = $currency;
}
foreach ($meta as $entry) {
$id = $entry->account_id;
$this->accountMeta[$id][$entry->name] = $entry->data;
}
// get account types: // get account types:
// select accounts.id, account_types.type from account_types left join accounts on accounts.account_type_id = account_types.id; $this->collectAccountTypes($objects);
// TODO move query to repository
$accountTypes = AccountType::leftJoin('accounts', 'accounts.account_type_id', '=', 'account_types.id')
->whereIn('accounts.id', $accountIds)
->get(['accounts.id', 'account_types.type'])
;
/** @var AccountType $row */ // get last activity:
foreach ($accountTypes as $row) { $this->getLastActivity($objects);
$this->accountTypes[$row->id] = (string)config(sprintf('firefly.shortNamesByFullName.%s', $row->type));
// TODO add balance difference
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$this->getBalanceDifference($objects, $this->parameters->get('start'), $this->parameters->get('end'));
} }
// get last activity return $this->sortAccounts($objects);
// TODO move query to repository
$array = Transaction::whereIn('account_id', $accountIds)
->leftJoin('transaction_journals', 'transaction_journals.id', 'transactions.transaction_journal_id')
->groupBy('transactions.account_id')
->get(['transactions.account_id', DB::raw('MAX(transaction_journals.date) as date_max')])->toArray() // @phpstan-ignore-line
;
foreach ($array as $row) {
$this->lastActivity[(int)$row['account_id']] = Carbon::parse($row['date_max'], config('app.timezone'));
}
// TODO needs separate method.
/** @var null|array $sort */
$sort = $this->parameters->get('sort');
if (null !== $sort && count($sort) > 0) {
foreach ($sort as $column => $direction) {
// account_number + iban
if ('iban' === $column) {
$meta = $this->accountMeta;
$objects = $objects->sort(function (Account $left, Account $right) use ($meta, $direction) {
$leftIban = trim(sprintf('%s%s', $left->iban, $meta[$left->id]['account_number'] ?? ''));
$rightIban = trim(sprintf('%s%s', $right->iban, $meta[$right->id]['account_number'] ?? ''));
if ('asc' === $direction) {
return strcasecmp($leftIban, $rightIban);
}
return strcasecmp($rightIban, $leftIban);
});
}
if ('balance' === $column) {
$balances = $this->convertedBalances;
$objects = $objects->sort(function (Account $left, Account $right) use ($balances, $direction) {
$leftBalance = (float)($balances[$left->id]['native_balance'] ?? 0);
$rightBalance = (float)($balances[$right->id]['native_balance'] ?? 0);
if ('asc' === $direction) {
return $leftBalance <=> $rightBalance;
}
return $rightBalance <=> $leftBalance;
});
}
if ('last_activity' === $column) {
$dates = $this->lastActivity;
$objects = $objects->sort(function (Account $left, Account $right) use ($dates, $direction) {
$leftDate = $dates[$left->id] ?? Carbon::create(1900, 1, 1, 0, 0, 0);
$rightDate = $dates[$right->id] ?? Carbon::create(1900, 1, 1, 0, 0, 0);
if ('asc' === $direction) {
return $leftDate->gt($rightDate) ? 1 : -1;
}
return $rightDate->gt($leftDate) ? 1 : -1;
});
}
}
}
// $objects = $objects->sortByDesc('name');
return $objects;
} }
private function getDate(): Carbon private function getDate(): Carbon
@@ -171,44 +97,56 @@ class AccountTransformer extends AbstractTransformer
*/ */
public function transform(Account $account): array public function transform(Account $account): array
{ {
$id = $account->id; $id = $account->id;
// various meta // various meta
$accountRole = $this->accountMeta[$id]['account_role'] ?? null; $accountRole = $this->accountMeta[$id]['account_role'] ?? null;
$accountType = $this->accountTypes[$id]; $accountType = $this->accountTypes[$id];
$order = $account->order; $order = $account->order;
// no currency? use default // no currency? use default
$currency = $this->default; $currency = $this->default;
if (array_key_exists($id, $this->accountMeta) && 0 !== (int)($this->accountMeta[$id]['currency_id'] ?? 0)) { if (array_key_exists($id, $this->accountMeta) && 0 !== (int) ($this->accountMeta[$id]['currency_id'] ?? 0)) {
$currency = $this->currencies[(int)$this->accountMeta[$id]['currency_id']]; $currency = $this->currencies[(int) $this->accountMeta[$id]['currency_id']];
} }
// amounts and calculation. // amounts and calculation.
$balance = $this->balances[$id] ?? null; $balance = $this->balances[$id]['balance'] ?? null;
$nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null; $nativeBalance = $this->convertedBalances[$id]['native_balance'] ?? null;
// no order for some accounts: // no order for some accounts:
if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], true)) { if (!in_array(strtolower($accountType), ['liability', 'liabilities', 'asset'], true)) {
$order = null; $order = null;
} }
// balance difference
$diffStart = null;
$diffEnd = null;
$balanceDiff = null;
$nativeBalanceDiff = null;
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$diffStart = $this->parameters->get('start')->toAtomString();
$diffEnd = $this->parameters->get('end')->toAtomString();
$balanceDiff = $this->balanceDifferences[$id]['balance'] ?? null;
$nativeBalanceDiff = $this->balanceDifferences[$id]['native_balance'] ?? null;
}
return [ return [
'id' => (string)$account->id, 'id' => (string) $account->id,
'created_at' => $account->created_at->toAtomString(), 'created_at' => $account->created_at->toAtomString(),
'updated_at' => $account->updated_at->toAtomString(), 'updated_at' => $account->updated_at->toAtomString(),
'active' => $account->active, 'active' => $account->active,
'order' => $order, 'order' => $order,
'name' => $account->name, 'name' => $account->name,
'iban' => '' === (string)$account->iban ? null : $account->iban, 'iban' => '' === (string) $account->iban ? null : $account->iban,
'account_number' => $this->accountMeta[$id]['account_number'] ?? null, 'account_number' => $this->accountMeta[$id]['account_number'] ?? null,
'type' => strtolower($accountType), 'type' => strtolower($accountType),
'account_role' => $accountRole, 'account_role' => $accountRole,
'currency_id' => (string)$currency->id, 'currency_id' => (string) $currency->id,
'currency_code' => $currency->code, 'currency_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
'native_currency_id' => (string)$this->default->id, 'native_currency_id' => (string) $this->default->id,
'native_currency_code' => $this->default->code, 'native_currency_code' => $this->default->code,
'native_currency_symbol' => $this->default->symbol, 'native_currency_symbol' => $this->default->symbol,
'native_currency_decimal_places' => $this->default->decimal_places, 'native_currency_decimal_places' => $this->default->decimal_places,
@@ -218,6 +156,12 @@ class AccountTransformer extends AbstractTransformer
'native_current_balance' => $nativeBalance, 'native_current_balance' => $nativeBalance,
'current_balance_date' => $this->getDate()->endOfDay()->toAtomString(), 'current_balance_date' => $this->getDate()->endOfDay()->toAtomString(),
// balance difference
'balance_difference' => $balanceDiff,
'native_balance_difference' => $nativeBalanceDiff,
'balance_difference_start' => $diffStart,
'balance_difference_end' => $diffEnd,
// more meta // more meta
'last_activity' => array_key_exists($id, $this->lastActivity) ? $this->lastActivity[$id]->toAtomString() : null, 'last_activity' => array_key_exists($id, $this->lastActivity) ? $this->lastActivity[$id]->toAtomString() : null,
@@ -246,4 +190,179 @@ class AccountTransformer extends AbstractTransformer
], ],
]; ];
} }
private function getMetaBalances(Collection $accounts): void
{
try {
$this->convertedBalances = app('steam')->balancesByAccountsConverted($accounts, $this->getDate());
} catch (FireflyException $e) {
Log::error($e->getMessage());
}
}
private function getDefaultCurrency(): void
{
$this->default = app('amount')->getDefaultCurrency();
}
private function collectAccountMetaData(Collection $accounts): void
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$metaFields = $accountRepository->getMetaValues($accounts, ['currency_id', 'account_role', 'account_number']);
$currencyIds = $metaFields->where('name', 'currency_id')->pluck('data')->toArray();
$currencies = $repository->getByIds($currencyIds);
foreach ($currencies as $currency) {
$id = $currency->id;
$this->currencies[$id] = $currency;
}
foreach ($metaFields as $entry) {
$id = $entry->account_id;
$this->accountMeta[$id][$entry->name] = $entry->data;
}
}
private function collectAccountTypes(Collection $accounts): void
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$accountTypes = $accountRepository->getAccountTypes($accounts);
/** @var AccountType $row */
foreach ($accountTypes as $row) {
$this->accountTypes[$row->id] = (string) config(sprintf('firefly.shortNamesByFullName.%s', $row->type));
}
}
private function getLastActivity(Collection $accounts): void
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$lastActivity = $accountRepository->getLastActivity($accounts);
foreach ($lastActivity as $row) {
$this->lastActivity[(int) $row['account_id']] = Carbon::parse($row['date_max'], config('app.timezone'));
}
}
private function sortAccounts(Collection $accounts): Collection
{
/** @var null|array $sort */
$sort = $this->parameters->get('sort');
if (null === $sort || 0 === count($sort)) {
return $accounts;
}
/**
* @var string $column
* @var string $direction
*/
foreach ($sort as $column => $direction) {
// account_number + iban
if ('iban' === $column) {
$accounts = $this->sortByIban($accounts, $direction);
}
if ('balance' === $column) {
$accounts = $this->sortByBalance($accounts, $direction);
}
if ('last_activity' === $column) {
$accounts = $this->sortByLastActivity($accounts, $direction);
}
if ('balance_difference' === $column) {
$accounts = $this->sortByBalanceDifference($accounts, $direction);
}
}
return $accounts;
}
private function sortByIban(Collection $accounts, string $direction): Collection
{
$meta = $this->accountMeta;
return $accounts->sort(function (Account $left, Account $right) use ($meta, $direction) {
$leftIban = trim(sprintf('%s%s', $left->iban, $meta[$left->id]['account_number'] ?? ''));
$rightIban = trim(sprintf('%s%s', $right->iban, $meta[$right->id]['account_number'] ?? ''));
if ('asc' === $direction) {
return strcasecmp($leftIban, $rightIban);
}
return strcasecmp($rightIban, $leftIban);
});
}
private function sortByBalance(Collection $accounts, string $direction): Collection
{
$balances = $this->convertedBalances;
return $accounts->sort(function (Account $left, Account $right) use ($balances, $direction) {
$leftBalance = (float) ($balances[$left->id]['native_balance'] ?? 0);
$rightBalance = (float) ($balances[$right->id]['native_balance'] ?? 0);
if ('asc' === $direction) {
return $leftBalance <=> $rightBalance;
}
return $rightBalance <=> $leftBalance;
});
}
private function sortByLastActivity(Collection $accounts, string $direction): Collection
{
$dates = $this->lastActivity;
return $accounts->sort(function (Account $left, Account $right) use ($dates, $direction) {
$leftDate = $dates[$left->id] ?? Carbon::create(1900, 1, 1, 0, 0, 0);
$rightDate = $dates[$right->id] ?? Carbon::create(1900, 1, 1, 0, 0, 0);
if ('asc' === $direction) {
return $leftDate->gt($rightDate) ? 1 : -1;
}
return $rightDate->gt($leftDate) ? 1 : -1;
});
}
private function getBalanceDifference(Collection $accounts, Carbon $start, Carbon $end): void
{
// collect balances, start and end for both native and converted.
// yes the b is usually used for boolean by idiots but here it's for balance.
$bStart = [];
$bEnd = [];
try {
$bStart = app('steam')->balancesByAccountsConverted($accounts, $start);
$bEnd = app('steam')->balancesByAccountsConverted($accounts, $end);
} catch (FireflyException $e) {
Log::error($e->getMessage());
}
/** @var Account $account */
foreach ($accounts as $account) {
$id = $account->id;
if (array_key_exists($id, $bStart) && array_key_exists($id, $bEnd)) {
$this->balanceDifferences[$id] = [
'balance' => bcsub($bEnd[$id]['balance'], $bStart[$id]['balance']),
'native_balance' => bcsub($bEnd[$id]['native_balance'], $bStart[$id]['native_balance']),
];
}
}
}
private function sortByBalanceDifference(Collection $accounts, string $direction): Collection
{
$balances = $this->balanceDifferences;
return $accounts->sort(function (Account $left, Account $right) use ($balances, $direction) {
$leftBalance = (float) ($balances[$left->id]['native_balance'] ?? 0);
$rightBalance = (float) ($balances[$right->id]['native_balance'] ?? 0);
if ('asc' === $direction) {
return $leftBalance <=> $rightBalance;
}
return $rightBalance <=> $leftBalance;
});
}
} }

View File

@@ -381,10 +381,7 @@ class User extends Authenticatable
$dbRolesTitles = $dbRoles->pluck('title')->toArray(); $dbRolesTitles = $dbRoles->pluck('title')->toArray();
/** @var Collection $groupMemberships */ /** @var Collection $groupMemberships */
$groupMemberships = $this->groupMemberships() $groupMemberships = $this->groupMemberships()->whereIn('user_role_id', $dbRolesIds)->where('user_group_id', $userGroup->id)->get();
->whereIn('user_role_id', $dbRolesIds)
->where('user_group_id', $userGroup->id)->get()
;
if (0 === $groupMemberships->count()) { if (0 === $groupMemberships->count()) {
app('log')->error(sprintf( app('log')->error(sprintf(
'User #%d "%s" does not have roles %s in user group #%d "%s"', 'User #%d "%s" does not have roles %s in user group #%d "%s"',

View File

@@ -101,6 +101,7 @@
"psr/log": "<4", "psr/log": "<4",
"ramsey/uuid": "^4.7", "ramsey/uuid": "^4.7",
"rcrowe/twigbridge": "^0.14", "rcrowe/twigbridge": "^0.14",
"twig/twig": "3.8.0",
"spatie/laravel-html": "^3.2", "spatie/laravel-html": "^3.2",
"spatie/laravel-ignition": "^2", "spatie/laravel-ignition": "^2",
"spatie/period": "^2.4", "spatie/period": "^2.4",

190
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "90c32aa5ed2c60408abbdd7edf8100db", "content-hash": "be35d14f371e7f8bc178ae6f7a615e5c",
"packages": [ "packages": [
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@@ -1670,16 +1670,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v11.2.0", "version": "v11.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "a1750156b671f37cba702380107e2d22161c31e3" "reference": "c1dc67c28811dc5be524a30b18f29ce62126716a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/a1750156b671f37cba702380107e2d22161c31e3", "url": "https://api.github.com/repos/laravel/framework/zipball/c1dc67c28811dc5be524a30b18f29ce62126716a",
"reference": "a1750156b671f37cba702380107e2d22161c31e3", "reference": "c1dc67c28811dc5be524a30b18f29ce62126716a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1698,7 +1698,7 @@
"fruitcake/php-cors": "^1.3", "fruitcake/php-cors": "^1.3",
"guzzlehttp/guzzle": "^7.8", "guzzlehttp/guzzle": "^7.8",
"guzzlehttp/uri-template": "^1.0", "guzzlehttp/uri-template": "^1.0",
"laravel/prompts": "^0.1.15", "laravel/prompts": "^0.1.18",
"laravel/serializable-closure": "^1.3", "laravel/serializable-closure": "^1.3",
"league/commonmark": "^2.2.1", "league/commonmark": "^2.2.1",
"league/flysystem": "^3.8.0", "league/flysystem": "^3.8.0",
@@ -1871,20 +1871,20 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2024-04-02T14:01:33+00:00" "time": "2024-04-16T14:38:51+00:00"
}, },
{ {
"name": "laravel/passport", "name": "laravel/passport",
"version": "v12.0.2", "version": "v12.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/passport.git", "url": "https://github.com/laravel/passport.git",
"reference": "21099f1aff81706781578a19335d8a4c7c96422a" "reference": "ff4742c71c58a4941b8738496ba96dabdf5e395b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/passport/zipball/21099f1aff81706781578a19335d8a4c7c96422a", "url": "https://api.github.com/repos/laravel/passport/zipball/ff4742c71c58a4941b8738496ba96dabdf5e395b",
"reference": "21099f1aff81706781578a19335d8a4c7c96422a", "reference": "ff4742c71c58a4941b8738496ba96dabdf5e395b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1947,20 +1947,20 @@
"issues": "https://github.com/laravel/passport/issues", "issues": "https://github.com/laravel/passport/issues",
"source": "https://github.com/laravel/passport" "source": "https://github.com/laravel/passport"
}, },
"time": "2024-03-21T18:44:57+00:00" "time": "2024-04-15T18:49:04+00:00"
}, },
{ {
"name": "laravel/prompts", "name": "laravel/prompts",
"version": "v0.1.17", "version": "v0.1.19",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/prompts.git", "url": "https://github.com/laravel/prompts.git",
"reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5" "reference": "0ab75ac3434d9f610c5691758a6146a3d1940c18"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5", "url": "https://api.github.com/repos/laravel/prompts/zipball/0ab75ac3434d9f610c5691758a6146a3d1940c18",
"reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5", "reference": "0ab75ac3434d9f610c5691758a6146a3d1940c18",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2002,22 +2002,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/laravel/prompts/issues", "issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.1.17" "source": "https://github.com/laravel/prompts/tree/v0.1.19"
}, },
"time": "2024-03-13T16:05:43+00:00" "time": "2024-04-16T14:20:35+00:00"
}, },
{ {
"name": "laravel/sanctum", "name": "laravel/sanctum",
"version": "v4.0.1", "version": "v4.0.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/sanctum.git", "url": "https://github.com/laravel/sanctum.git",
"reference": "d1de99bf8d31199aaf93881561622489ab91ba58" "reference": "9cfc0ce80cabad5334efff73ec856339e8ec1ac1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/d1de99bf8d31199aaf93881561622489ab91ba58", "url": "https://api.github.com/repos/laravel/sanctum/zipball/9cfc0ce80cabad5334efff73ec856339e8ec1ac1",
"reference": "d1de99bf8d31199aaf93881561622489ab91ba58", "reference": "9cfc0ce80cabad5334efff73ec856339e8ec1ac1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2068,7 +2068,7 @@
"issues": "https://github.com/laravel/sanctum/issues", "issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum" "source": "https://github.com/laravel/sanctum"
}, },
"time": "2024-03-19T20:09:38+00:00" "time": "2024-04-10T19:39:58+00:00"
}, },
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
@@ -2324,16 +2324,16 @@
}, },
{ {
"name": "lcobucci/jwt", "name": "lcobucci/jwt",
"version": "5.2.0", "version": "5.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/lcobucci/jwt.git", "url": "https://github.com/lcobucci/jwt.git",
"reference": "0ba88aed12c04bd2ed9924f500673f32b67a6211" "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/0ba88aed12c04bd2ed9924f500673f32b67a6211", "url": "https://api.github.com/repos/lcobucci/jwt/zipball/08071d8d2c7f4b00222cc4b1fb6aa46990a80f83",
"reference": "0ba88aed12c04bd2ed9924f500673f32b67a6211", "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2381,7 +2381,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/lcobucci/jwt/issues", "issues": "https://github.com/lcobucci/jwt/issues",
"source": "https://github.com/lcobucci/jwt/tree/5.2.0" "source": "https://github.com/lcobucci/jwt/tree/5.3.0"
}, },
"funding": [ "funding": [
{ {
@@ -2393,7 +2393,7 @@
"type": "patreon" "type": "patreon"
} }
], ],
"time": "2023-11-20T21:17:42+00:00" "time": "2024-04-11T23:07:54+00:00"
}, },
{ {
"name": "league/commonmark", "name": "league/commonmark",
@@ -2728,16 +2728,16 @@
}, },
{ {
"name": "league/flysystem", "name": "league/flysystem",
"version": "3.26.0", "version": "3.27.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/flysystem.git", "url": "https://github.com/thephpleague/flysystem.git",
"reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be" "reference": "4729745b1ab737908c7d055148c9a6b3e959832f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/072735c56cc0da00e10716dd90d5a7f7b40b36be", "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4729745b1ab737908c7d055148c9a6b3e959832f",
"reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be", "reference": "4729745b1ab737908c7d055148c9a6b3e959832f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2802,7 +2802,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/flysystem/issues", "issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.26.0" "source": "https://github.com/thephpleague/flysystem/tree/3.27.0"
}, },
"funding": [ "funding": [
{ {
@@ -2814,7 +2814,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-03-25T11:49:53+00:00" "time": "2024-04-07T19:17:50+00:00"
}, },
{ {
"name": "league/flysystem-local", "name": "league/flysystem-local",
@@ -3265,16 +3265,16 @@
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "3.5.0", "version": "3.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Seldaek/monolog.git", "url": "https://github.com/Seldaek/monolog.git",
"reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448" "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448", "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654",
"reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448", "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3297,7 +3297,7 @@
"phpstan/phpstan": "^1.9", "phpstan/phpstan": "^1.9",
"phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-strict-rules": "^1.4", "phpstan/phpstan-strict-rules": "^1.4",
"phpunit/phpunit": "^10.1", "phpunit/phpunit": "^10.5.17",
"predis/predis": "^1.1 || ^2", "predis/predis": "^1.1 || ^2",
"ruflin/elastica": "^7", "ruflin/elastica": "^7",
"symfony/mailer": "^5.4 || ^6", "symfony/mailer": "^5.4 || ^6",
@@ -3350,7 +3350,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/Seldaek/monolog/issues", "issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/3.5.0" "source": "https://github.com/Seldaek/monolog/tree/3.6.0"
}, },
"funding": [ "funding": [
{ {
@@ -3362,20 +3362,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-10-27T15:32:31+00:00" "time": "2024-04-12T21:02:21+00:00"
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "3.2.4", "version": "3.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/briannesbitt/Carbon.git", "url": "https://github.com/briannesbitt/Carbon.git",
"reference": "82c28278c1c8f7b82dcdab25692237f052ffc8d8" "reference": "7219739c4e01d4680c980545821733b6ed8ee880"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/82c28278c1c8f7b82dcdab25692237f052ffc8d8", "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7219739c4e01d4680c980545821733b6ed8ee880",
"reference": "82c28278c1c8f7b82dcdab25692237f052ffc8d8", "reference": "7219739c4e01d4680c980545821733b6ed8ee880",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3468,7 +3468,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-04-05T09:58:10+00:00" "time": "2024-04-18T16:35:06+00:00"
}, },
{ {
"name": "nette/schema", "name": "nette/schema",
@@ -5320,16 +5320,16 @@
}, },
{ {
"name": "spatie/ignition", "name": "spatie/ignition",
"version": "1.13.1", "version": "1.13.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/spatie/ignition.git", "url": "https://github.com/spatie/ignition.git",
"reference": "889bf1dfa59e161590f677728b47bf4a6893983b" "reference": "952798e239d9969e4e694b124c2cc222798dbb28"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/spatie/ignition/zipball/889bf1dfa59e161590f677728b47bf4a6893983b", "url": "https://api.github.com/repos/spatie/ignition/zipball/952798e239d9969e4e694b124c2cc222798dbb28",
"reference": "889bf1dfa59e161590f677728b47bf4a6893983b", "reference": "952798e239d9969e4e694b124c2cc222798dbb28",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -5399,7 +5399,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-03-29T14:03:47+00:00" "time": "2024-04-16T08:49:17+00:00"
}, },
{ {
"name": "spatie/laravel-html", "name": "spatie/laravel-html",
@@ -5481,16 +5481,16 @@
}, },
{ {
"name": "spatie/laravel-ignition", "name": "spatie/laravel-ignition",
"version": "2.5.1", "version": "2.5.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/spatie/laravel-ignition.git", "url": "https://github.com/spatie/laravel-ignition.git",
"reference": "0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9" "reference": "c93fcadcc4629775c839ac9a90916f07a660266f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9", "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/c93fcadcc4629775c839ac9a90916f07a660266f",
"reference": "0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9", "reference": "c93fcadcc4629775c839ac9a90916f07a660266f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -5500,7 +5500,7 @@
"illuminate/support": "^10.0|^11.0", "illuminate/support": "^10.0|^11.0",
"php": "^8.1", "php": "^8.1",
"spatie/flare-client-php": "^1.3.5", "spatie/flare-client-php": "^1.3.5",
"spatie/ignition": "^1.13", "spatie/ignition": "^1.13.2",
"symfony/console": "^6.2.3|^7.0", "symfony/console": "^6.2.3|^7.0",
"symfony/var-dumper": "^6.2.3|^7.0" "symfony/var-dumper": "^6.2.3|^7.0"
}, },
@@ -5569,7 +5569,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-04-02T06:30:22+00:00" "time": "2024-04-16T08:57:16+00:00"
}, },
{ {
"name": "spatie/period", "name": "spatie/period",
@@ -8900,16 +8900,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "barryvdh/laravel-debugbar", "name": "barryvdh/laravel-debugbar",
"version": "v3.13.3", "version": "v3.13.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git", "url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "241e9bddb04ab42a04a5fe8b2b9654374c864229" "reference": "00201bcd1eaf9b1d3debddcdc13c219e4835fb61"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/241e9bddb04ab42a04a5fe8b2b9654374c864229", "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/00201bcd1eaf9b1d3debddcdc13c219e4835fb61",
"reference": "241e9bddb04ab42a04a5fe8b2b9654374c864229", "reference": "00201bcd1eaf9b1d3debddcdc13c219e4835fb61",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -8968,7 +8968,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues", "issues": "https://github.com/barryvdh/laravel-debugbar/issues",
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.13.3" "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.13.4"
}, },
"funding": [ "funding": [
{ {
@@ -8980,7 +8980,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-04-04T02:42:49+00:00" "time": "2024-04-10T09:15:45+00:00"
}, },
{ {
"name": "barryvdh/laravel-ide-helper", "name": "barryvdh/laravel-ide-helper",
@@ -9507,16 +9507,16 @@
}, },
{ {
"name": "larastan/larastan", "name": "larastan/larastan",
"version": "v2.9.2", "version": "v2.9.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/larastan/larastan.git", "url": "https://github.com/larastan/larastan.git",
"reference": "a79b46b96060504b400890674b83f66aa7f5db6d" "reference": "101f1a4470f87326f4d3995411d28679d8800abe"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/larastan/larastan/zipball/a79b46b96060504b400890674b83f66aa7f5db6d", "url": "https://api.github.com/repos/larastan/larastan/zipball/101f1a4470f87326f4d3995411d28679d8800abe",
"reference": "a79b46b96060504b400890674b83f66aa7f5db6d", "reference": "101f1a4470f87326f4d3995411d28679d8800abe",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9529,15 +9529,15 @@
"illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.0", "illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.0",
"illuminate/support": "^9.52.16 || ^10.28.0 || ^11.0", "illuminate/support": "^9.52.16 || ^10.28.0 || ^11.0",
"php": "^8.0.2", "php": "^8.0.2",
"phpmyadmin/sql-parser": "^5.8.2", "phpmyadmin/sql-parser": "^5.9.0",
"phpstan/phpstan": "^1.10.50" "phpstan/phpstan": "^1.10.66"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^12.0", "doctrine/coding-standard": "^12.0",
"nikic/php-parser": "^4.17.1", "nikic/php-parser": "^4.19.1",
"orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.0", "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.2",
"orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.0", "orchestra/testbench": "^7.33.0 || ^8.13.0 || ^9.0.3",
"phpunit/phpunit": "^9.6.13 || ^10.5" "phpunit/phpunit": "^9.6.13 || ^10.5.16"
}, },
"suggest": { "suggest": {
"orchestra/testbench": "Using Larastan for analysing a package needs Testbench" "orchestra/testbench": "Using Larastan for analysing a package needs Testbench"
@@ -9585,7 +9585,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/larastan/larastan/issues", "issues": "https://github.com/larastan/larastan/issues",
"source": "https://github.com/larastan/larastan/tree/v2.9.2" "source": "https://github.com/larastan/larastan/tree/v2.9.5"
}, },
"funding": [ "funding": [
{ {
@@ -9605,7 +9605,7 @@
"type": "patreon" "type": "patreon"
} }
], ],
"time": "2024-02-27T03:16:03+00:00" "time": "2024-04-16T19:13:34+00:00"
}, },
{ {
"name": "maximebf/debugbar", "name": "maximebf/debugbar",
@@ -10285,16 +10285,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.66", "version": "1.10.67",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "94779c987e4ebd620025d9e5fdd23323903950bd" "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/94779c987e4ebd620025d9e5fdd23323903950bd", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/16ddbe776f10da6a95ebd25de7c1dbed397dc493",
"reference": "94779c987e4ebd620025d9e5fdd23323903950bd", "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10337,13 +10337,9 @@
{ {
"url": "https://github.com/phpstan", "url": "https://github.com/phpstan",
"type": "github" "type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
"type": "tidelift"
} }
], ],
"time": "2024-03-28T16:17:31+00:00" "time": "2024-04-16T07:22:02+00:00"
}, },
{ {
"name": "phpstan/phpstan-deprecation-rules", "name": "phpstan/phpstan-deprecation-rules",
@@ -10395,16 +10391,16 @@
}, },
{ {
"name": "phpstan/phpstan-strict-rules", "name": "phpstan/phpstan-strict-rules",
"version": "1.5.3", "version": "1.5.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git", "url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "568210bd301f94a0d4b1e5a0808c374c1b9cf11b" "reference": "2e193a07651a6f4be3baa44ddb21d822681f5918"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/568210bd301f94a0d4b1e5a0808c374c1b9cf11b", "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/2e193a07651a6f4be3baa44ddb21d822681f5918",
"reference": "568210bd301f94a0d4b1e5a0808c374c1b9cf11b", "reference": "2e193a07651a6f4be3baa44ddb21d822681f5918",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10438,9 +10434,9 @@
"description": "Extra strict and opinionated rules for PHPStan", "description": "Extra strict and opinionated rules for PHPStan",
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues", "issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.3" "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.5"
}, },
"time": "2024-04-06T07:43:25+00:00" "time": "2024-04-19T15:12:26+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@@ -10765,16 +10761,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "10.5.17", "version": "10.5.19",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "c1f736a473d21957ead7e94fcc029f571895abf5" "reference": "c726f0de022368f6ed103e452a765d3304a996a4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1f736a473d21957ead7e94fcc029f571895abf5", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c726f0de022368f6ed103e452a765d3304a996a4",
"reference": "c1f736a473d21957ead7e94fcc029f571895abf5", "reference": "c726f0de022368f6ed103e452a765d3304a996a4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -10846,7 +10842,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy", "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.17" "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.19"
}, },
"funding": [ "funding": [
{ {
@@ -10862,7 +10858,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-04-05T04:39:01+00:00" "time": "2024-04-17T14:06:18+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

326
config/debugbar.php Normal file
View File

@@ -0,0 +1,326 @@
<?php
declare(strict_types=1);
return [
/*
|--------------------------------------------------------------------------
| Debugbar Settings
|--------------------------------------------------------------------------
|
| Debugbar is enabled by default, when debug is set to true in app.php.
| You can override the value by setting enable to true or false instead of null.
|
| You can provide an array of URI's that must be ignored (eg. 'api/*')
|
*/
'enabled' => env('DEBUGBAR_ENABLED', null),
'except' => [
'telescope*',
'horizon*',
],
/*
|--------------------------------------------------------------------------
| Storage settings
|--------------------------------------------------------------------------
|
| DebugBar stores data for session/ajax requests.
| You can disable this, so the debugbar stores data in headers/session,
| but this can cause problems with large data collectors.
| By default, file storage (in the storage folder) is used. Redis and PDO
| can also be used. For PDO, run the package migrations first.
|
| Warning: Enabling storage.open will allow everyone to access previous
| request, do not enable open storage in publicly available environments!
| Specify a callback if you want to limit based on IP or authentication.
| Leaving it to null will allow localhost only.
*/
'storage' => [
'enabled' => true,
'open' => env('DEBUGBAR_OPEN_STORAGE'), // bool/callback.
'driver' => 'file', // redis, file, pdo, socket, custom
'path' => storage_path('debugbar'), // For file driver
'connection' => null, // Leave null for default connection (Redis/PDO)
'provider' => '', // Instance of StorageInterface for custom driver
'hostname' => '127.0.0.1', // Hostname to use with the "socket" driver
'port' => 2304, // Port to use with the "socket" driver
],
/*
|--------------------------------------------------------------------------
| Editor
|--------------------------------------------------------------------------
|
| Choose your preferred editor to use when clicking file name.
|
| Supported: "phpstorm", "vscode", "vscode-insiders", "vscode-remote",
| "vscode-insiders-remote", "vscodium", "textmate", "emacs",
| "sublime", "atom", "nova", "macvim", "idea", "netbeans",
| "xdebug", "espresso"
|
*/
'editor' => env('DEBUGBAR_EDITOR') ?: env('IGNITION_EDITOR', 'phpstorm'),
/*
|--------------------------------------------------------------------------
| Remote Path Mapping
|--------------------------------------------------------------------------
|
| If you are using a remote dev server, like Laravel Homestead, Docker, or
| even a remote VPS, it will be necessary to specify your path mapping.
|
| Leaving one, or both of these, empty or null will not trigger the remote
| URL changes and Debugbar will treat your editor links as local files.
|
| "remote_sites_path" is an absolute base path for your sites or projects
| in Homestead, Vagrant, Docker, or another remote development server.
|
| Example value: "/home/vagrant/Code"
|
| "local_sites_path" is an absolute base path for your sites or projects
| on your local computer where your IDE or code editor is running on.
|
| Example values: "/Users/<name>/Code", "C:\Users\<name>\Documents\Code"
|
*/
'remote_sites_path' => env('DEBUGBAR_REMOTE_SITES_PATH'),
'local_sites_path' => env('DEBUGBAR_LOCAL_SITES_PATH', env('IGNITION_LOCAL_SITES_PATH')),
/*
|--------------------------------------------------------------------------
| Vendors
|--------------------------------------------------------------------------
|
| Vendor files are included by default, but can be set to false.
| This can also be set to 'js' or 'css', to only include javascript or css vendor files.
| Vendor files are for css: font-awesome (including fonts) and highlight.js (css files)
| and for js: jquery and highlight.js
| So if you want syntax highlighting, set it to true.
| jQuery is set to not conflict with existing jQuery scripts.
|
*/
'include_vendors' => true,
/*
|--------------------------------------------------------------------------
| Capture Ajax Requests
|--------------------------------------------------------------------------
|
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
| you can use this option to disable sending the data through the headers.
|
| Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools.
|
| Note for your request to be identified as ajax requests they must either send the header
| X-Requested-With with the value XMLHttpRequest (most JS libraries send this), or have application/json as a Accept header.
|
| By default `ajax_handler_auto_show` is set to true allowing ajax requests to be shown automatically in the Debugbar.
| Changing `ajax_handler_auto_show` to false will prevent the Debugbar from reloading.
*/
'capture_ajax' => true,
'add_ajax_timing' => false,
'ajax_handler_auto_show' => true,
'ajax_handler_enable_tab' => true,
/*
|--------------------------------------------------------------------------
| Custom Error Handler for Deprecated warnings
|--------------------------------------------------------------------------
|
| When enabled, the Debugbar shows deprecated warnings for Symfony components
| in the Messages tab.
|
*/
'error_handler' => false,
/*
|--------------------------------------------------------------------------
| Clockwork integration
|--------------------------------------------------------------------------
|
| The Debugbar can emulate the Clockwork headers, so you can use the Chrome
| Extension, without the server-side code. It uses Debugbar collectors instead.
|
*/
'clockwork' => false,
/*
|--------------------------------------------------------------------------
| DataCollectors
|--------------------------------------------------------------------------
|
| Enable/disable DataCollectors
|
*/
'collectors' => [
'phpinfo' => true, // Php version
'messages' => true, // Messages
'time' => true, // Time Datalogger
'memory' => true, // Memory usage
'exceptions' => true, // Exception displayer
'log' => true, // Logs from Monolog (merged in messages if enabled)
'db' => true, // Show database (PDO) queries and bindings
'views' => true, // Views with their data
'route' => true, // Current route information
'auth' => false, // Display Laravel authentication status
'gate' => true, // Display Laravel Gate checks
'session' => true, // Display session data
'symfony_request' => true, // Only one can be enabled..
'mail' => true, // Catch mail messages
'laravel' => false, // Laravel version and environment
'events' => false, // All events fired
'default_request' => false, // Regular or special Symfony request logger
'logs' => false, // Add the latest log messages
'files' => false, // Show the included files
'config' => false, // Display config settings
'cache' => false, // Display cache events
'models' => true, // Display models
'livewire' => true, // Display Livewire (when available)
'jobs' => false, // Display dispatched jobs
],
/*
|--------------------------------------------------------------------------
| Extra options
|--------------------------------------------------------------------------
|
| Configure some DataCollectors
|
*/
'options' => [
'time' => [
'memory_usage' => false, // Calculated by subtracting memory start and end, it may be inaccurate
],
'messages' => [
'trace' => true, // Trace the origin of the debug message
],
'memory' => [
'reset_peak' => false, // run memory_reset_peak_usage before collecting
'with_baseline' => false, // Set boot memory usage as memory peak baseline
'precision' => 0, // Memory rounding precision
],
'auth' => [
'show_name' => true, // Also show the users name/email in the debugbar
'show_guards' => true, // Show the guards that are used
],
'db' => [
'with_params' => true, // Render SQL with the parameters substituted
'backtrace' => true, // Use a backtrace to find the origin of the query in your files.
'backtrace_exclude_paths' => [], // Paths to exclude from backtrace. (in addition to defaults)
'timeline' => false, // Add the queries to the timeline
'duration_background' => true, // Show shaded background on each query relative to how long it took to execute.
'explain' => [ // Show EXPLAIN output on queries
'enabled' => false,
'types' => ['SELECT'], // Deprecated setting, is always only SELECT
],
'hints' => false, // Show hints for common mistakes
'show_copy' => false, // Show copy button next to the query,
'slow_threshold' => false, // Only track queries that last longer than this time in ms
'memory_usage' => false, // Show queries memory usage
'soft_limit' => 100, // After the soft limit, no parameters/backtrace are captured
'hard_limit' => 500, // After the hard limit, queries are ignored
],
'mail' => [
'timeline' => false, // Add mails to the timeline
'show_body' => true,
],
'views' => [
'timeline' => false, // Add the views to the timeline (Experimental)
'data' => false, // true for all data, 'keys' for only names, false for no parameters.
'group' => 50, // Group duplicate views. Pass value to auto-group, or true/false to force
'exclude_paths' => [ // Add the paths which you don't want to appear in the views
'vendor/filament', // Exclude Filament components by default
],
],
'route' => [
'label' => true, // show complete route on bar
],
'session' => [
'hiddens' => [], // hides sensitive values using array paths
],
'symfony_request' => [
'hiddens' => [], // hides sensitive values using array paths, example: request_request.password
],
'events' => [
'data' => false, // collect events data, listeners
],
'logs' => [
'file' => null,
],
'cache' => [
'values' => true, // collect cache values
],
],
/*
|--------------------------------------------------------------------------
| Inject Debugbar in Response
|--------------------------------------------------------------------------
|
| Usually, the debugbar is added just before </body>, by listening to the
| Response after the App is done. If you disable this, you have to add them
| in your template yourself. See http://phpdebugbar.com/docs/rendering.html
|
*/
'inject' => true,
/*
|--------------------------------------------------------------------------
| DebugBar route prefix
|--------------------------------------------------------------------------
|
| Sometimes you want to set route prefix to be used by DebugBar to load
| its resources from. Usually the need comes from misconfigured web server or
| from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97
|
*/
'route_prefix' => '_debugbar',
/*
|--------------------------------------------------------------------------
| DebugBar route middleware
|--------------------------------------------------------------------------
|
| Additional middleware to run on the Debugbar routes
*/
'route_middleware' => [],
/*
|--------------------------------------------------------------------------
| DebugBar route domain
|--------------------------------------------------------------------------
|
| By default DebugBar route served from the same domain that request served.
| To override default domain, specify it as a non-empty value.
*/
'route_domain' => null,
/*
|--------------------------------------------------------------------------
| DebugBar theme
|--------------------------------------------------------------------------
|
| Switches between light and dark theme. If set to auto it will respect system preferences
| Possible values: auto, light, dark
*/
'theme' => env('DEBUGBAR_THEME', 'auto'),
/*
|--------------------------------------------------------------------------
| Backtrace stack limit
|--------------------------------------------------------------------------
|
| By default, the DebugBar limits the number of frames returned by the 'debug_backtrace()' function.
| If you need larger stacktraces, you can increase this number. Setting it to 0 will result in no limit.
*/
'debug_backtrace_limit' => 50,
];

View File

@@ -117,8 +117,8 @@ return [
'expression_engine' => false, 'expression_engine' => false,
// see cer.php for exchange rates feature flag. // see cer.php for exchange rates feature flag.
], ],
'version' => 'develop/2024-04-07', 'version' => 'develop/2024-04-22',
'api_version' => '2.0.13', 'api_version' => '2.0.14',
'db_version' => 24, 'db_version' => 24,
// generic settings // generic settings
@@ -206,7 +206,6 @@ return [
// web configuration: // web configuration:
'trusted_proxies' => env('TRUSTED_PROXIES', ''), 'trusted_proxies' => env('TRUSTED_PROXIES', ''),
'layout' => envNonEmpty('FIREFLY_III_LAYOUT', 'v1'),
// map configuration // map configuration
'default_location' => [ 'default_location' => [
@@ -925,7 +924,7 @@ return [
'sorting' => [ 'sorting' => [
'allowed' => [ 'allowed' => [
'transactions' => ['description', 'amount'], 'transactions' => ['description', 'amount'],
'accounts' => ['name', 'active', 'iban', 'balance', 'last_activity'], 'accounts' => ['name', 'active', 'iban', 'balance', 'last_activity', 'balance_difference'],
], ],
], ],
]; ];

691
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -22,95 +22,10 @@ var count = 0;
$(document).ready(function () { $(document).ready(function () {
updateListButtons(); updateListButtons();
addSort();
$('.clone-transaction').click(cloneTransaction); $('.clone-transaction').click(cloneTransaction);
$('.clone-transaction-and-edit').click(cloneTransactionAndEdit); $('.clone-transaction-and-edit').click(cloneTransactionAndEdit);
}); });
var fixHelper = function (e, tr) {
"use strict";
var $originals = tr.children();
var $helper = tr.clone();
$helper.children().each(function (index) {
// Set helper cell sizes to match the original sizes
$(this).width($originals.eq(index).width());
});
return $helper;
};
/**
*
*/
function addSort() {
if (typeof $(".table-sortable>tbody").sortable !== "undefined") {
$('.table-sortable>tbody').sortable(
{
items: "tr:not(.unsortable)",
handle: '.object-handle',
stop: sortStop,
start: function (event, ui) {
// Build a placeholder cell that spans all the cells in the row
var cellCount = 0;
$('td, th', ui.helper).each(function () {
// For each TD or TH try and get it's colspan attribute, and add that or 1 to the total
var colspan = 1;
var colspanAttr = $(this).attr('colspan');
if (colspanAttr > 1) {
colspan = colspanAttr;
}
cellCount += colspan;
});
// Add the placeholder UI - note that this is the item's content, so TD rather than TR
ui.placeholder.html('<td colspan="' + cellCount + '">&nbsp;</td>');
}
}
);
}
}
/**
*
* @param event
* @param ui
* @returns {boolean|undefined}
*/
function sortStop(event, ui) {
"use strict";
var current = $(ui.item);
var thisDate = current.data('date');
var originalBG = current.css('backgroundColor');
if (current.prev().data('date') !== thisDate && current.next().data('date') !== thisDate) {
// animate something with color:
current.animate({backgroundColor: "#d9534f"}, 200, function () {
$(this).animate({backgroundColor: originalBG}, 200);
return undefined;
});
return false;
}
//return false;
// do update
var list = $('tr[data-date="' + thisDate + '"]');
var submit = [];
$.each(list, function (i, v) {
var row = $(v);
var id = row.data('id');
submit.push(id);
});
// do extra animation when done?
$.post('transactions/reorder', {items: submit, date: thisDate, _token: token});
current.animate({backgroundColor: "#5cb85c"}, 200, function () {
$(this).animate({backgroundColor: originalBG}, 200);
return undefined;
});
return undefined;
}
/** /**
* *

View File

@@ -103,6 +103,12 @@
.skin-firefly-iii .btn-info { .skin-firefly-iii .btn-info {
color: #fff; color: #fff;
} }
.skin-firefly-iii .btn-danger {
color: #fff;
}
.skin-firefly-iii .btn-warning {
color: #fff;
}
.skin-firefly-iii .btn-default { .skin-firefly-iii .btn-default {
background-color: #55606a; background-color: #55606a;
color: #bec5cb; color: #bec5cb;
@@ -251,6 +257,11 @@
} }
.skin-firefly-iii .table > thead > tr > th, .skin-firefly-iii .table > thead > tr > th,
.skin-firefly-iii .table > tbody > tr > th, .skin-firefly-iii .table > tbody > tr > th,
.skin-firefly-iii .table > tfoot > tr > th {
border-bottom: 2px #c9d1d9 solid;
}
.skin-firefly-iii .table > thead > tr > th,
.skin-firefly-iii .table > tbody > tr > th,
.skin-firefly-iii .table > tfoot > tr > th, .skin-firefly-iii .table > tfoot > tr > th,
.skin-firefly-iii .table > thead > tr > td, .skin-firefly-iii .table > thead > tr > td,
.skin-firefly-iii .table > tbody > tr > td, .skin-firefly-iii .table > tbody > tr > td,
@@ -480,6 +491,7 @@
.skin-firefly-iii .nav-tabs-custom > .nav-tabs > li.active > a { .skin-firefly-iii .nav-tabs-custom > .nav-tabs > li.active > a {
border-left-color: #353c42; border-left-color: #353c42;
border-right-color: #353c42; border-right-color: #353c42;
color: #bec5cb;
} }
.skin-firefly-iii .nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type.active > a { .skin-firefly-iii .nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type.active > a {
border-left-color: #353c42; border-left-color: #353c42;
@@ -511,7 +523,7 @@
background-color: #272c30; background-color: #272c30;
} }
.skin-firefly-iii .input-group .input-group-addon { .skin-firefly-iii .input-group .input-group-addon {
border-right: 1px solid #272c30; border: 1px solid #272c30;
} }
.skin-firefly-iii .form-control { .skin-firefly-iii .form-control {
border-color: #272c30; border-color: #272c30;

File diff suppressed because one or more lines are too long

View File

@@ -15,22 +15,22 @@
}, },
"firefly": { "firefly": {
"spent": "Gastat", "spent": "Gastat",
"administration_owner": "Administration owner: {{email}}", "administration_owner": "Propietari de l'administraci\u00f3: {{email}}",
"administration_you": "Your role: {{role}}", "administration_you": "El teu rol: {{role}}",
"administration_role_owner": "Owner", "administration_role_owner": "Propietari",
"administration_role_ro": "Read-only", "administration_role_ro": "Nom\u00e9s de lectura",
"administration_role_mng_trx": "Manage transactions", "administration_role_mng_trx": "Gestionar transaccions",
"administration_role_mng_meta": "Manage classification and meta-data", "administration_role_mng_meta": "Gestionar classificaci\u00f3 i meta-dades",
"administration_role_mng_budgets": "Manage budgets", "administration_role_mng_budgets": "Gestionar pressupostos",
"administration_role_mng_piggies": "Manage piggy banks", "administration_role_mng_piggies": "Administra guardioles",
"administration_role_mng_subscriptions": "Manage subscriptions", "administration_role_mng_subscriptions": "Gestionar subscripcions",
"administration_role_mng_rules": "Manage rules", "administration_role_mng_rules": "Gestionar normes",
"administration_role_mng_recurring": "Manage recurring transactions ", "administration_role_mng_recurring": "Gestionar transaccions recurrents ",
"administration_role_mng_webhooks": "Manage webhooks", "administration_role_mng_webhooks": "Gestionar Webhooks",
"administration_role_mng_currencies": "Manage currencies", "administration_role_mng_currencies": "Gestionar divises",
"administration_role_view_reports": "View reports", "administration_role_view_reports": "Veure informes",
"administration_role_full": "Full access", "administration_role_full": "Acc\u00e9s total",
"new_administration_created": "New financial administration \"{{title}}\" has been created", "new_administration_created": "S'ha creat una nova administraci\u00f3 financera \"{{title}}\"",
"left": "Queda", "left": "Queda",
"paid": "Pagat", "paid": "Pagat",
"errors_submission_v2": "Hi ha hagut un error amb el teu enviament. Per favor, comprova els seg\u00fcents errors: {{errorMessage}}", "errors_submission_v2": "Hi ha hagut un error amb el teu enviament. Per favor, comprova els seg\u00fcents errors: {{errorMessage}}",

View File

@@ -15,22 +15,22 @@
}, },
"firefly": { "firefly": {
"spent": "Gastat", "spent": "Gastat",
"administration_owner": "Administration owner: {{email}}", "administration_owner": "Propietari de l'administraci\u00f3: {{email}}",
"administration_you": "Your role: {{role}}", "administration_you": "El teu rol: {{role}}",
"administration_role_owner": "Owner", "administration_role_owner": "Propietari",
"administration_role_ro": "Read-only", "administration_role_ro": "Nom\u00e9s de lectura",
"administration_role_mng_trx": "Manage transactions", "administration_role_mng_trx": "Gestionar transaccions",
"administration_role_mng_meta": "Manage classification and meta-data", "administration_role_mng_meta": "Gestionar classificaci\u00f3 i meta-dades",
"administration_role_mng_budgets": "Manage budgets", "administration_role_mng_budgets": "Gestionar pressupostos",
"administration_role_mng_piggies": "Manage piggy banks", "administration_role_mng_piggies": "Administra guardioles",
"administration_role_mng_subscriptions": "Manage subscriptions", "administration_role_mng_subscriptions": "Gestionar subscripcions",
"administration_role_mng_rules": "Manage rules", "administration_role_mng_rules": "Gestionar normes",
"administration_role_mng_recurring": "Manage recurring transactions ", "administration_role_mng_recurring": "Gestionar transaccions recurrents ",
"administration_role_mng_webhooks": "Manage webhooks", "administration_role_mng_webhooks": "Gestionar Webhooks",
"administration_role_mng_currencies": "Manage currencies", "administration_role_mng_currencies": "Gestionar divises",
"administration_role_view_reports": "View reports", "administration_role_view_reports": "Veure informes",
"administration_role_full": "Full access", "administration_role_full": "Acc\u00e9s total",
"new_administration_created": "New financial administration \"{{title}}\" has been created", "new_administration_created": "S'ha creat una nova administraci\u00f3 financera \"{{title}}\"",
"left": "Queda", "left": "Queda",
"paid": "Pagat", "paid": "Pagat",
"errors_submission_v2": "Hi ha hagut un error amb el teu enviament. Per favor, comprova els seg\u00fcents errors: {{errorMessage}}", "errors_submission_v2": "Hi ha hagut un error amb el teu enviament. Per favor, comprova els seg\u00fcents errors: {{errorMessage}}",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "do MMMM yyyy @ HH:mm:ss", "date_time_fns": "do MMMM yyyy @ HH:mm:ss",
"month_and_day_fns": "d MMMM y", "month_and_day_fns": "d MMMM y",
"does_not_exist": "(config.does_not_exist)", "does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm" "date_time_fns_short": "do MMMM yyyy @ HH:mm"
}, },
"form": { "form": {
"title": "Titolo" "title": "Titolo"
@@ -17,10 +17,10 @@
"spent": "Speso", "spent": "Speso",
"administration_owner": "Administration owner: {{email}}", "administration_owner": "Administration owner: {{email}}",
"administration_you": "Your role: {{role}}", "administration_you": "Your role: {{role}}",
"administration_role_owner": "Owner", "administration_role_owner": "Proprietario",
"administration_role_ro": "Read-only", "administration_role_ro": "Sola lettura",
"administration_role_mng_trx": "Manage transactions", "administration_role_mng_trx": "Gestisci le transazioni",
"administration_role_mng_meta": "Manage classification and meta-data", "administration_role_mng_meta": "Gestisci classificazione e meta-dati",
"administration_role_mng_budgets": "Manage budgets", "administration_role_mng_budgets": "Manage budgets",
"administration_role_mng_piggies": "Manage piggy banks", "administration_role_mng_piggies": "Manage piggy banks",
"administration_role_mng_subscriptions": "Manage subscriptions", "administration_role_mng_subscriptions": "Manage subscriptions",
@@ -48,7 +48,7 @@
"unknown_dest_plain": "Conto di destinazione sconosciuto", "unknown_dest_plain": "Conto di destinazione sconosciuto",
"unknown_any_plain": "Conto sconosciuto", "unknown_any_plain": "Conto sconosciuto",
"unknown_budget_plain": "Nessun budget", "unknown_budget_plain": "Nessun budget",
"stored_journal_js": "Successfully created new transaction \"{{description}}\"", "stored_journal_js": "Nuova transazione \"{{description}} \" creata con successo",
"wait_loading_transaction": "Attendi il caricamento del modello", "wait_loading_transaction": "Attendi il caricamento del modello",
"nothing_found": "(nessun risultato)", "nothing_found": "(nessun risultato)",
"wait_loading_data": "Ti preghiamo di attendere il caricamento delle tue informazioni...", "wait_loading_data": "Ti preghiamo di attendere il caricamento delle tue informazioni...",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "do MMMM yyyy @ HH:mm:ss", "date_time_fns": "do MMMM yyyy @ HH:mm:ss",
"month_and_day_fns": "d MMMM y", "month_and_day_fns": "d MMMM y",
"does_not_exist": "(config.does_not_exist)", "does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm" "date_time_fns_short": "do MMMM yyyy @ HH:mm"
}, },
"form": { "form": {
"title": "Titolo" "title": "Titolo"
@@ -17,10 +17,10 @@
"spent": "Speso", "spent": "Speso",
"administration_owner": "Administration owner: {{email}}", "administration_owner": "Administration owner: {{email}}",
"administration_you": "Your role: {{role}}", "administration_you": "Your role: {{role}}",
"administration_role_owner": "Owner", "administration_role_owner": "Proprietario",
"administration_role_ro": "Read-only", "administration_role_ro": "Sola lettura",
"administration_role_mng_trx": "Manage transactions", "administration_role_mng_trx": "Gestisci le transazioni",
"administration_role_mng_meta": "Manage classification and meta-data", "administration_role_mng_meta": "Gestisci classificazione e meta-dati",
"administration_role_mng_budgets": "Manage budgets", "administration_role_mng_budgets": "Manage budgets",
"administration_role_mng_piggies": "Manage piggy banks", "administration_role_mng_piggies": "Manage piggy banks",
"administration_role_mng_subscriptions": "Manage subscriptions", "administration_role_mng_subscriptions": "Manage subscriptions",
@@ -48,7 +48,7 @@
"unknown_dest_plain": "Conto di destinazione sconosciuto", "unknown_dest_plain": "Conto di destinazione sconosciuto",
"unknown_any_plain": "Conto sconosciuto", "unknown_any_plain": "Conto sconosciuto",
"unknown_budget_plain": "Nessun budget", "unknown_budget_plain": "Nessun budget",
"stored_journal_js": "Successfully created new transaction \"{{description}}\"", "stored_journal_js": "Nuova transazione \"{{description}} \" creata con successo",
"wait_loading_transaction": "Attendi il caricamento del modello", "wait_loading_transaction": "Attendi il caricamento del modello",
"nothing_found": "(nessun risultato)", "nothing_found": "(nessun risultato)",
"wait_loading_data": "Ti preghiamo di attendere il caricamento delle tue informazioni...", "wait_loading_data": "Ti preghiamo di attendere il caricamento delle tue informazioni...",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "dd 'de' MMMM 'de' yyyy, '\u00e0s' HH:mm:ss", "date_time_fns": "dd 'de' MMMM 'de' yyyy, '\u00e0s' HH:mm:ss",
"month_and_day_fns": "d [de] MMMM [de] y", "month_and_day_fns": "d [de] MMMM [de] y",
"does_not_exist": "(config.does_not_exist)", "does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm" "date_time_fns_short": "dd\/MMM\/yyyy HH:mm"
}, },
"form": { "form": {
"title": "T\u00edtulo" "title": "T\u00edtulo"
@@ -15,25 +15,25 @@
}, },
"firefly": { "firefly": {
"spent": "Gasto", "spent": "Gasto",
"administration_owner": "Administration owner: {{email}}", "administration_owner": "Propriet\u00e1rio da administra\u00e7\u00e3o: {{email}}",
"administration_you": "Your role: {{role}}", "administration_you": "Sua fun\u00e7\u00e3o: {{role}}",
"administration_role_owner": "Owner", "administration_role_owner": "Propriet\u00e1rio",
"administration_role_ro": "Read-only", "administration_role_ro": "Somente leitura",
"administration_role_mng_trx": "Manage transactions", "administration_role_mng_trx": "Gerenciar transa\u00e7\u00f5es",
"administration_role_mng_meta": "Manage classification and meta-data", "administration_role_mng_meta": "Gerenciar classifica\u00e7\u00e3o e metadados",
"administration_role_mng_budgets": "Manage budgets", "administration_role_mng_budgets": "Gerenciar or\u00e7amentos",
"administration_role_mng_piggies": "Manage piggy banks", "administration_role_mng_piggies": "Gerenciar cofrinhos",
"administration_role_mng_subscriptions": "Manage subscriptions", "administration_role_mng_subscriptions": "Gerenciar assinaturas",
"administration_role_mng_rules": "Manage rules", "administration_role_mng_rules": "Gerenciar regras",
"administration_role_mng_recurring": "Manage recurring transactions ", "administration_role_mng_recurring": "Gerenciar transa\u00e7\u00f5es recorrentes ",
"administration_role_mng_webhooks": "Manage webhooks", "administration_role_mng_webhooks": "Gerenciar webhooks",
"administration_role_mng_currencies": "Manage currencies", "administration_role_mng_currencies": "Gerenciar moedas",
"administration_role_view_reports": "View reports", "administration_role_view_reports": "Ver relat\u00f3rios",
"administration_role_full": "Full access", "administration_role_full": "Acesso completo",
"new_administration_created": "New financial administration \"{{title}}\" has been created", "new_administration_created": "Nova administra\u00e7\u00e3o financeira \"{{title}}\" foi criada",
"left": "Restante", "left": "Restante",
"paid": "Pago", "paid": "Pago",
"errors_submission_v2": "There was something wrong with your submission. Please check out the errors below: {{errorMessage}}", "errors_submission_v2": "Algo deu errado com seu envio. Por favor, verifique os erros abaixo: {{errorMessage}}",
"unpaid": "N\u00e3o pago", "unpaid": "N\u00e3o pago",
"default_group_title_name_plain": "sem grupo", "default_group_title_name_plain": "sem grupo",
"subscriptions_in_group": "Assinaturas no grupo \"%{title}\"", "subscriptions_in_group": "Assinaturas no grupo \"%{title}\"",
@@ -48,7 +48,7 @@
"unknown_dest_plain": "Conta de destino desconhecida", "unknown_dest_plain": "Conta de destino desconhecida",
"unknown_any_plain": "Conta desconhecida", "unknown_any_plain": "Conta desconhecida",
"unknown_budget_plain": "Nenhum or\u00e7amento", "unknown_budget_plain": "Nenhum or\u00e7amento",
"stored_journal_js": "Successfully created new transaction \"{{description}}\"", "stored_journal_js": "Transa\u00e7\u00e3o \"{{description}}\" criada com sucesso",
"wait_loading_transaction": "Por favor, aguarde o formul\u00e1rio carregar", "wait_loading_transaction": "Por favor, aguarde o formul\u00e1rio carregar",
"nothing_found": "(nada encontrado)", "nothing_found": "(nada encontrado)",
"wait_loading_data": "Por favor, aguarde suas informa\u00e7\u00f5es serem carregadas...", "wait_loading_data": "Por favor, aguarde suas informa\u00e7\u00f5es serem carregadas...",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "DO [de] MMMM YYYY, @ HH:mm:ss", "date_time_fns": "DO [de] MMMM YYYY, @ HH:mm:ss",
"month_and_day_fns": "d MMMM y", "month_and_day_fns": "d MMMM y",
"does_not_exist": "(config.does_not_exist)", "does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm" "date_time_fns_short": "do MMMM yyyy @ HH:mm"
}, },
"form": { "form": {
"title": "T\u00edtulo" "title": "T\u00edtulo"

View File

@@ -4,7 +4,7 @@
"date_time_fns": "dd 'de' MMMM 'de' yyyy, '\u00e0s' HH:mm:ss", "date_time_fns": "dd 'de' MMMM 'de' yyyy, '\u00e0s' HH:mm:ss",
"month_and_day_fns": "d [de] MMMM [de] y", "month_and_day_fns": "d [de] MMMM [de] y",
"does_not_exist": "(config.does_not_exist)", "does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm" "date_time_fns_short": "dd\/MMM\/yyyy HH:mm"
}, },
"form": { "form": {
"title": "T\u00edtulo" "title": "T\u00edtulo"
@@ -15,25 +15,25 @@
}, },
"firefly": { "firefly": {
"spent": "Gasto", "spent": "Gasto",
"administration_owner": "Administration owner: {{email}}", "administration_owner": "Propriet\u00e1rio da administra\u00e7\u00e3o: {{email}}",
"administration_you": "Your role: {{role}}", "administration_you": "Sua fun\u00e7\u00e3o: {{role}}",
"administration_role_owner": "Owner", "administration_role_owner": "Propriet\u00e1rio",
"administration_role_ro": "Read-only", "administration_role_ro": "Somente leitura",
"administration_role_mng_trx": "Manage transactions", "administration_role_mng_trx": "Gerenciar transa\u00e7\u00f5es",
"administration_role_mng_meta": "Manage classification and meta-data", "administration_role_mng_meta": "Gerenciar classifica\u00e7\u00e3o e metadados",
"administration_role_mng_budgets": "Manage budgets", "administration_role_mng_budgets": "Gerenciar or\u00e7amentos",
"administration_role_mng_piggies": "Manage piggy banks", "administration_role_mng_piggies": "Gerenciar cofrinhos",
"administration_role_mng_subscriptions": "Manage subscriptions", "administration_role_mng_subscriptions": "Gerenciar assinaturas",
"administration_role_mng_rules": "Manage rules", "administration_role_mng_rules": "Gerenciar regras",
"administration_role_mng_recurring": "Manage recurring transactions ", "administration_role_mng_recurring": "Gerenciar transa\u00e7\u00f5es recorrentes ",
"administration_role_mng_webhooks": "Manage webhooks", "administration_role_mng_webhooks": "Gerenciar webhooks",
"administration_role_mng_currencies": "Manage currencies", "administration_role_mng_currencies": "Gerenciar moedas",
"administration_role_view_reports": "View reports", "administration_role_view_reports": "Ver relat\u00f3rios",
"administration_role_full": "Full access", "administration_role_full": "Acesso completo",
"new_administration_created": "New financial administration \"{{title}}\" has been created", "new_administration_created": "Nova administra\u00e7\u00e3o financeira \"{{title}}\" foi criada",
"left": "Restante", "left": "Restante",
"paid": "Pago", "paid": "Pago",
"errors_submission_v2": "There was something wrong with your submission. Please check out the errors below: {{errorMessage}}", "errors_submission_v2": "Algo deu errado com seu envio. Por favor, verifique os erros abaixo: {{errorMessage}}",
"unpaid": "N\u00e3o pago", "unpaid": "N\u00e3o pago",
"default_group_title_name_plain": "sem grupo", "default_group_title_name_plain": "sem grupo",
"subscriptions_in_group": "Assinaturas no grupo \"%{title}\"", "subscriptions_in_group": "Assinaturas no grupo \"%{title}\"",
@@ -48,7 +48,7 @@
"unknown_dest_plain": "Conta de destino desconhecida", "unknown_dest_plain": "Conta de destino desconhecida",
"unknown_any_plain": "Conta desconhecida", "unknown_any_plain": "Conta desconhecida",
"unknown_budget_plain": "Nenhum or\u00e7amento", "unknown_budget_plain": "Nenhum or\u00e7amento",
"stored_journal_js": "Successfully created new transaction \"{{description}}\"", "stored_journal_js": "Transa\u00e7\u00e3o \"{{description}}\" criada com sucesso",
"wait_loading_transaction": "Por favor, aguarde o formul\u00e1rio carregar", "wait_loading_transaction": "Por favor, aguarde o formul\u00e1rio carregar",
"nothing_found": "(nada encontrado)", "nothing_found": "(nada encontrado)",
"wait_loading_data": "Por favor, aguarde suas informa\u00e7\u00f5es serem carregadas...", "wait_loading_data": "Por favor, aguarde suas informa\u00e7\u00f5es serem carregadas...",

View File

@@ -4,7 +4,7 @@
"date_time_fns": "DO [de] MMMM YYYY, @ HH:mm:ss", "date_time_fns": "DO [de] MMMM YYYY, @ HH:mm:ss",
"month_and_day_fns": "d MMMM y", "month_and_day_fns": "d MMMM y",
"does_not_exist": "(config.does_not_exist)", "does_not_exist": "(config.does_not_exist)",
"date_time_fns_short": "MMMM do, yyyy @ HH:mm" "date_time_fns_short": "do MMMM yyyy @ HH:mm"
}, },
"form": { "form": {
"title": "T\u00edtulo" "title": "T\u00edtulo"

View File

@@ -30,7 +30,7 @@
"administration_role_mng_currencies": "Upravljanje valut", "administration_role_mng_currencies": "Upravljanje valut",
"administration_role_view_reports": "Prikaz poro\u010dil", "administration_role_view_reports": "Prikaz poro\u010dil",
"administration_role_full": "Neomejen dostop", "administration_role_full": "Neomejen dostop",
"new_administration_created": "New financial administration \"{{title}}\" has been created", "new_administration_created": "Ustvarjena je bila nova finan\u010dna administracija \"{{title}}\"",
"left": "Preostalo", "left": "Preostalo",
"paid": "Pla\u010dano", "paid": "Pla\u010dano",
"errors_submission_v2": "Nekaj je bilo narobe z va\u0161o oddajo. Preverite spodnje napake: {{errorMessage}}", "errors_submission_v2": "Nekaj je bilo narobe z va\u0161o oddajo. Preverite spodnje napake: {{errorMessage}}",

View File

@@ -30,7 +30,7 @@
"administration_role_mng_currencies": "Upravljanje valut", "administration_role_mng_currencies": "Upravljanje valut",
"administration_role_view_reports": "Prikaz poro\u010dil", "administration_role_view_reports": "Prikaz poro\u010dil",
"administration_role_full": "Neomejen dostop", "administration_role_full": "Neomejen dostop",
"new_administration_created": "New financial administration \"{{title}}\" has been created", "new_administration_created": "Ustvarjena je bila nova finan\u010dna administracija \"{{title}}\"",
"left": "Preostalo", "left": "Preostalo",
"paid": "Pla\u010dano", "paid": "Pla\u010dano",
"errors_submission_v2": "Nekaj je bilo narobe z va\u0161o oddajo. Preverite spodnje napake: {{errorMessage}}", "errors_submission_v2": "Nekaj je bilo narobe z va\u0161o oddajo. Preverite spodnje napake: {{errorMessage}}",

View File

@@ -10,7 +10,7 @@
"prod": "mix --production" "prod": "mix --production"
}, },
"dependencies": { "dependencies": {
"date-fns": "^2.30.0", "date-fns": "^3.6.0",
"stream-browserify": "^3.0.0" "stream-browserify": "^3.0.0"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -5,8 +5,8 @@
"flash_warning": "Aten\u00e7\u00e3o!", "flash_warning": "Aten\u00e7\u00e3o!",
"flash_success": "Sucesso!", "flash_success": "Sucesso!",
"close": "Fechar", "close": "Fechar",
"select_dest_account": "Please select or type a valid destination account name", "select_dest_account": "Por favor, selecione ou digite um nome de conta de destino v\u00e1lido",
"select_source_account": "Please select or type a valid source account name", "select_source_account": "Por favor, selecione ou digite um nome de conta de origem v\u00e1lido",
"split_transaction_title": "Descri\u00e7\u00e3o da transa\u00e7\u00e3o dividida", "split_transaction_title": "Descri\u00e7\u00e3o da transa\u00e7\u00e3o dividida",
"errors_submission": "Algo deu errado com seu envio. Por favor, verifique os erros abaixo.", "errors_submission": "Algo deu errado com seu envio. Por favor, verifique os erros abaixo.",
"split": "Dividir", "split": "Dividir",

View File

@@ -20,6 +20,7 @@
let mix = require('laravel-mix'); let mix = require('laravel-mix');
mix.webpackConfig({ mix.webpackConfig({
resolve: { resolve: {
alias: { alias: {

View File

@@ -1,18 +1,19 @@
{ {
"name": "v2", "name": "v2",
"private": true, "private": true,
"type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build --emptyOutDir",
"postinstall": "patch-package --error-on-fail" "postinstall": "patch-package --error-on-fail"
}, },
"devDependencies": { "devDependencies": {
"axios": "^1.6.8", "axios": "^1.6.8",
"laravel-vite-plugin": "^0.8.1", "laravel-vite-plugin": "^1.0.2",
"patch-package": "^8.0.0", "patch-package": "^8.0.0",
"sass": "^1.72.0", "sass": "^1.75.0",
"vite": "^4.5.3", "vite": "^5",
"vite-plugin-manifest-sri": "^0.1.0" "vite-plugin-manifest-sri": "^0.2.0"
}, },
"dependencies": { "dependencies": {
"@ag-grid-community/client-side-row-model": "^31.0.3", "@ag-grid-community/client-side-row-model": "^31.0.3",
@@ -30,7 +31,7 @@
"chartjs-adapter-date-fns": "^3.0.0", "chartjs-adapter-date-fns": "^3.0.0",
"chartjs-chart-sankey": "^0.12.0", "chartjs-chart-sankey": "^0.12.0",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"i18next": "^23.10.1", "i18next": "^23.11.2",
"i18next-chained-backend": "^4.6.2", "i18next-chained-backend": "^4.6.2",
"i18next-http-backend": "^2.4.2", "i18next-http-backend": "^2.4.2",
"i18next-localstorage-backend": "^4.2.0", "i18next-localstorage-backend": "^4.2.0",

View File

@@ -30,6 +30,11 @@ import '../../css/grid-ff3-theme.css';
import Get from "../../api/v2/model/account/get.js"; import Get from "../../api/v2/model/account/get.js";
import Put from "../../api/v2/model/account/put.js"; import Put from "../../api/v2/model/account/put.js";
import AccountRenderer from "../../support/renderers/AccountRenderer.js"; import AccountRenderer from "../../support/renderers/AccountRenderer.js";
import {showInternalsButton} from "../../support/page-settings/show-internals-button.js";
import {showWizardButton} from "../../support/page-settings/show-wizard-button.js";
import {getVariable} from "../../store/get-variable.js";
import {setVariable} from "../../store/set-variable.js";
// set type from URL // set type from URL
const beforeQuery = window.location.href.split('?'); const beforeQuery = window.location.href.split('?');
@@ -47,6 +52,9 @@ sortingColumn = params.column ?? '';
sortDirection = params.direction ?? ''; sortDirection = params.direction ?? '';
showInternalsButton();
showWizardButton();
let index = function () { let index = function () {
return { return {
// notifications // notifications
@@ -59,10 +67,64 @@ let index = function () {
show: false, text: '', show: false, text: '',
} }
}, totalPages: 1, page: 1, // available columns: },
totalPages: 1,
page: 1,
// available columns:
// visible is hard coded, enabled is user-configurable.
tableColumns: { tableColumns: {
drag_and_drop: {
visible: true,
enabled: true,
},
active: {
visible: true,
enabled: true,
},
name: { name: {
enabled: true visible: true,
enabled: true,
},
type: {
visible: true,
enabled: true,
},
liability_type: {
visible: type === 'liabilities',
enabled: true,
},
liability_direction: {
visible: type === 'liabilities',
enabled: true,
},
liability_interest: {
visible: type === 'liabilities',
enabled: true,
},
number: {
visible: true,
enabled: true,
},
current_balance: {
visible: type !== 'liabilities',
enabled: true,
},
amount_due: {
visible: type === 'liabilities',
enabled: true,
},
last_activity: {
visible: true,
enabled: true,
},
balance_difference: {
visible: true,
enabled: true,
},
menu: {
visible: true,
enabled: true,
}, },
}, },
editors: {}, editors: {},
@@ -77,7 +139,7 @@ let index = function () {
sort(column) { sort(column) {
this.sortingColumn = column; this.sortingColumn = column;
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc'; this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
const url = './accounts/'+type+'?column='+column+'&direction='+this.sortDirection; const url = './accounts/' + type + '?column=' + column + '&direction=' + this.sortDirection;
window.history.pushState({}, "", url); window.history.pushState({}, "", url);
@@ -92,11 +154,34 @@ let index = function () {
format(date) { format(date) {
return format(date, i18next.t('config.date_time_fns')); return format(date, i18next.t('config.date_time_fns'));
}, },
saveColumnSettings() {
let newSettings = {};
for (let key in this.tableColumns) {
if (this.tableColumns.hasOwnProperty(key)) {
newSettings[key] = this.tableColumns[key].enabled;
}
}
console.log('New settings', newSettings);
setVariable('accts_columns_' + type, newSettings);
},
init() { init() {
this.notifications.wait.show = true; 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')
this.loadAccounts();
const key = 'accts_columns_' + type;
const defaultValue = {"drag_and_drop": false};
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(() => {
this.loadAccounts();
});
}, },
renderObjectValue(field, account) { renderObjectValue(field, account) {
let renderer = new AccountRenderer(); let renderer = new AccountRenderer();
@@ -140,14 +225,33 @@ let index = function () {
this.accounts[index].nameEditorVisible = true; this.accounts[index].nameEditorVisible = true;
}, },
loadAccounts() { loadAccounts() {
// sort instructions
const sorting = [{column: this.sortingColumn, direction: this.sortDirection}];
// get start and end from the store:
const start = new Date(window.store.get('start'));
const end = new Date(window.store.get('end'));
let params = {
sorting: sorting,
type: type,
page: this.page,
start: start,
end: end
};
if(!this.tableColumns.balance_difference.enabled){
delete params.start;
delete params.end;
}
this.notifications.wait.show = true; 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')
this.accounts = []; this.accounts = [];
// sort instructions
// &sorting[0][column]=description&sorting[0][direction]=asc
const sorting = [{column: this.sortingColumn, direction: this.sortDirection}];
// one page only.o // one page only.o
(new Get()).index({sorting: sorting, type: type, page: this.page}).then(response => { (new Get()).index(params).then(response => {
for (let i = 0; i < response.data.data.length; i++) { for (let i = 0; i < response.data.data.length; i++) {
if (response.data.data.hasOwnProperty(i)) { if (response.data.data.hasOwnProperty(i)) {
let current = response.data.data[i]; let current = response.data.data[i];
@@ -165,7 +269,10 @@ let index = function () {
native_current_balance: current.attributes.native_current_balance, native_current_balance: current.attributes.native_current_balance,
native_currency_code: current.attributes.native_currency_code, native_currency_code: current.attributes.native_currency_code,
last_activity: null === current.attributes.last_activity ? '' : format(new Date(current.attributes.last_activity), i18next.t('config.month_and_day_fns')), last_activity: null === current.attributes.last_activity ? '' : format(new Date(current.attributes.last_activity), i18next.t('config.month_and_day_fns')),
balance_difference: current.attributes.balance_difference,
native_balance_difference: current.attributes.native_balance_difference
}; };
console.log(current.attributes.balance_difference);
this.accounts.push(account); this.accounts.push(account);
} }
} }

View File

@@ -23,6 +23,7 @@ import {format} from "date-fns";
import {getVariable} from "../../store/get-variable.js"; import {getVariable} from "../../store/get-variable.js";
import formatMoney from "../../util/format-money.js"; import formatMoney from "../../util/format-money.js";
import {getCacheKey} from "../../support/get-cache-key.js"; import {getCacheKey} from "../../support/get-cache-key.js";
import {cleanupCache} from "../../support/cleanup-cache.js";
let afterPromises = false; let afterPromises = false;
export default () => ({ export default () => ({
@@ -38,6 +39,7 @@ export default () => ({
const start = new Date(window.store.get('start')); const start = new Date(window.store.get('start'));
const end = new Date(window.store.get('end')); const end = new Date(window.store.get('end'));
const boxesCacheKey = getCacheKey('dashboard-boxes-data', start, end); const boxesCacheKey = getCacheKey('dashboard-boxes-data', start, end);
cleanupCache();
const cacheValid = window.store.get('cacheValid'); const cacheValid = window.store.get('cacheValid');
let cachedData = window.store.get(boxesCacheKey); let cachedData = window.store.get(boxesCacheKey);

View File

@@ -69,6 +69,7 @@ let transactions = function () {
resetButton: false, resetButton: false,
rulesButton: true, rulesButton: true,
webhooksButton: true, webhooksButton: true,
categorySelectVisible: false
}, },
// form behaviour during transaction // form behaviour during transaction
@@ -343,7 +344,13 @@ let transactions = function () {
// destination can never be revenue account // destination can never be revenue account
this.filters.destination = ['Expense account', 'Loan', 'Debt', 'Mortgage', 'Asset account']; this.filters.destination = ['Expense account', 'Loan', 'Debt', 'Mortgage', 'Asset account'];
}, },
keyUpFromCategory(e) {
if (e.key === 'Enter' && false === this.formStates.categorySelectVisible) {
this.submitTransaction();
return;
}
this.formStates.categorySelectVisible = document.querySelector('input.ac-category').nextSibling.classList.contains('show');
},
submitTransaction() { submitTransaction() {
// reset all messages: // reset all messages:
this.notifications.error.show = false; this.notifications.error.show = false;
@@ -422,7 +429,10 @@ let transactions = function () {
if (this.formStates.returnHereButton) { if (this.formStates.returnHereButton) {
this.notifications.success.show = true; this.notifications.success.show = true;
this.notifications.success.url = 'transactions/show/' + this.groupProperties.id; this.notifications.success.url = 'transactions/show/' + this.groupProperties.id;
this.notifications.success.text = i18next.t('firefly.stored_journal_js', {description: this.groupProperties.title, interpolation: { escapeValue: false }}); this.notifications.success.text = i18next.t('firefly.stored_journal_js', {
description: this.groupProperties.title,
interpolation: {escapeValue: false}
});
this.formStates.isSubmitting = false; this.formStates.isSubmitting = false;
// reset group title again // reset group title again
this.groupProperties.title = null; this.groupProperties.title = null;

View File

@@ -72,12 +72,15 @@ let transactions = function () {
resetButton: true, resetButton: true,
rulesButton: true, rulesButton: true,
webhooksButton: true, webhooksButton: true,
}, },
// form behaviour during transaction // form behaviour during transaction
formBehaviour: { formBehaviour: {
formType: 'edit', formType: 'edit',
foreignCurrencyEnabled: true, foreignCurrencyEnabled: true,
categorySelectVisible: false,
}, },
// form data (except transactions) is stored in formData // form data (except transactions) is stored in formData
@@ -111,6 +114,14 @@ let transactions = function () {
} }
}, },
keyUpFromCategory(e) {
if (e.key === 'Enter' && false === this.formBehaviour.categorySelectVisible) {
this.submitTransaction();
return;
}
this.formBehaviour.categorySelectVisible = document.querySelector('input.ac-category').nextSibling.classList.contains('show');
},
// submit the transaction form. // submit the transaction form.
// TODO pretty much duplicate of create.js // TODO pretty much duplicate of create.js
submitTransaction() { submitTransaction() {

View File

@@ -23,217 +23,12 @@ import dates from "../shared/dates.js";
import i18next from "i18next"; import i18next from "i18next";
import {format} from "date-fns"; import {format} from "date-fns";
import formatMoney from "../../util/format-money.js"; import formatMoney from "../../util/format-money.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-grid.css';
import '@ag-grid-community/styles/ag-theme-alpine.css'; import '@ag-grid-community/styles/ag-theme-alpine.css';
import '../../css/grid-ff3-theme.css'; import '../../css/grid-ff3-theme.css';
import Get from "../../api/v2/model/transaction/get.js";
import AmountEditor from "../../support/ag-grid/AmountEditor.js";
import TransactionDataSource from "../../support/ag-grid/TransactionDataSource.js";
import {InfiniteRowModelModule} from '@ag-grid-community/infinite-row-model';
import DateTimeEditor from "../../support/ag-grid/DateTimeEditor.js";
const ds = new TransactionDataSource();
// set type from URL
const urlParts = window.location.href.split('/');
const type = urlParts[urlParts.length - 1];
ds.setType(type);
let dataTable;
const editableFields = ['description', 'amount', 'date'];
const onCellEditRequestMethod = (event) => {
console.log('onCellEditRequestMethod');
const data = event.data;
const field = event.colDef.field;
let newValue = event.newValue;
if (!editableFields.includes(field)) {
console.log('Field ' + field + ' is not editable.');
return;
}
// this needs to be better
if ('amount' === field) {
newValue = event.newValue.amount;
console.log('New value is now' + newValue);
}
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,
cacheOverflowSize: 1,
cacheBlockSize: 20,
onCellEditRequest: onCellEditRequestMethod,
readOnlyEdit: true,
getRowId: function (params) {
console.log('getRowId', params.data.id);
return params.data.id;
},
// 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) {
if (params.getValue()) {
return '<a href="./transactions/show/' + parseInt(params.value.id) + '"><em class="' + params.value.classes + '"></em></a>';
}
return '';
}
},
{
field: "description",
cellDataType: 'text',
editable: true,
// cellRenderer: function (params) {
// if (params.getValue()) {
// return '<a href="#">' + params.getValue() + '</a>';
// }
// return '';
// }
},
{
field: "amount",
editable: function (params) {
// only when NO foreign amount.
return null === params.data.amount.foreign_amount && null === params.data.amount.foreign_currency_code;
},
cellEditor: AmountEditor,
cellRenderer(params) {
if (params.getValue()) {
let returnString = '';
let amount = parseFloat(params.getValue().amount);
let obj = params.getValue();
let stringClass = 'text-danger';
if (obj.type === 'withdrawal') {
amount = amount * -1;
}
if (obj.type === 'deposit') {
stringClass = 'text-success';
}
if (obj.type === 'transfer') {
stringClass = 'text-info';
}
returnString += '<span class="' + stringClass + '">' + formatMoney(amount, params.getValue().currency_code) + '</span>';
// foreign amount:
if (obj.foreign_amount) {
let foreignAmount = parseFloat(params.getValue().foreign_amount);
if (obj.type === 'withdrawal') {
foreignAmount = foreignAmount * -1;
}
returnString += ' (<span class="' + stringClass + '">' + formatMoney(foreignAmount, obj.foreign_currency_code) + '</span>)';
}
return returnString;
}
return '';
}
},
{
field: "date",
editable: true,
cellDataType: 'date',
cellEditor: DateTimeEditor,
cellEditorPopup: true,
cellEditorPopupPosition: 'under',
cellRenderer(params) {
if (params.getValue()) {
return format(params.getValue(), i18next.t('config.date_time_fns_short'));
}
return '';
}
},
{
field: "from",
cellDataType: 'text',
cellRenderer: function (params) {
if (params.getValue()) {
let obj = params.getValue();
return '<a href="./accounts/show/' + obj.id + '">' + obj.name + '</a>';
}
return '';
}
},
{
field: "to",
cellDataType: 'text',
cellRenderer: function (params) {
if (params.getValue()) {
let obj = params.getValue();
return '<a href="./accounts/show/' + obj.id + '">' + obj.name + '</a>';
}
return '';
}
},
{
field: "category",
cellDataType: 'text',
cellRenderer: function (params) {
if (params.getValue()) {
let obj = params.getValue();
if (null !== obj.id) {
return '<a href="./categories/show/' + obj.id + '">' + obj.name + '</a>';
}
}
return '';
}
},
{
field: "budget",
cellDataType: 'text',
cellRenderer: function (params) {
if (params.getValue()) {
let obj = params.getValue();
if (null !== obj.id) {
return '<a href="./budgets/show/' + obj.id + '">' + obj.name + '</a>';
}
}
return '';
}
},
]
};
ModuleRegistry.registerModules([InfiniteRowModelModule]);
let index = function () { let index = function () {
return { return {
// notifications // notifications
@@ -276,36 +71,56 @@ let index = function () {
return format(date, i18next.t('config.date_time_fns')); return format(date, i18next.t('config.date_time_fns'));
}, },
init() { init() {
this.notifications.wait.show = true;
this.notifications.wait.text = i18next.t('firefly.wait_loading_data')
// TODO need date range. // TODO need date range.
// TODO handle page number // TODO handle page number
//this.getTransactions(this.page); this.getTransactions(this.page);``
// Your Javascript code to create the grid // Your Javascript code to create the grid
dataTable = createGrid(document.querySelector('#grid'), gridOptions); // dataTable = createGrid(document.querySelector('#grid'), gridOptions);
}, },
// getTransactions(page) { getTransactions(page) {
// const urlParts = window.location.href.split('/'); this.notifications.wait.show = true;
// const type = urlParts[urlParts.length - 1]; this.notifications.wait.text = i18next.t('firefly.wait_loading_data')
// let getter = new Get(); this.transactions = [];
// const urlParts = window.location.href.split('/');
// getter.list({page: page, type: type}).then(response => { const type = urlParts[urlParts.length - 1];
// this.parseTransactions(response.data.data) let getter = new Get();
//
// // set meta data getter.list({page: page, type: type}).then(response => {
// this.totalPages = response.data.meta.pagination.total_pages; this.parseTransactions(response.data.data)
// this.perPage = response.data.meta.pagination.per_page;
// this.page = response.data.meta.pagination.current_page; // set meta data
// }).catch(error => { this.totalPages = response.data.meta.pagination.total_pages;
// // to do this is auto generated this.perPage = response.data.meta.pagination.per_page;
// this.notifications.wait.show = false; this.page = response.data.meta.pagination.current_page;
// this.notifications.error.show = true; }).catch(error => {
// this.notifications.error.text = error.response.data.message; // to do this is auto generated
// }); this.notifications.wait.show = false;
// }, this.notifications.error.show = true;
this.notifications.error.text = error.response.data.message;
});
},
previousPage() {
if(this.page > 1) {
this.page--;
}
this.getTransactions(this.page);
},
nextPage() {
if(this.page < this.totalPages) {
this.page++;
}
this.getTransactions(this.page);
},
gotoPage(i) {
if(i > 0 && i <= this.totalPages) {
this.page = i;
}
this.getTransactions(this.page);
},
parseTransactions(data) { parseTransactions(data) {
// no parse, just save // no parse, just save
for (let i in data) { for (let i in data) {
@@ -321,7 +136,7 @@ let index = function () {
transaction.split = isSplit; transaction.split = isSplit;
tranaction.icon = 'fa fa-solid fa-arrow-left'; transaction.icon = 'fa fa-solid fa-arrow-left';
transaction.firstSplit = firstSplit; transaction.firstSplit = firstSplit;
transaction.group_title = current.attributes.group_title; transaction.group_title = current.attributes.group_title;
transaction.id = current.id; transaction.id = current.id;

View File

@@ -22,31 +22,27 @@ import Get from "../api/v1/preferences/index.js";
import Post from "../api/v1/preferences/post.js"; import Post from "../api/v1/preferences/post.js";
export function getVariable(name, defaultValue = null) { export function getVariable(name, defaultValue = null) {
const validCache = window.store.get('cacheValid'); const validCache = window.store.get('cacheValid');
// currently unused, window.X can be used by the blade template // currently unused, window.X can be used by the blade template
// to make things available quicker than if the store has to grab it through the API. // to make things available quicker than if the store has to grab it through the API.
// then again, it's not that slow. // then again, it's not that slow.
if (validCache && window.hasOwnProperty(name)) { if (validCache && window.hasOwnProperty(name)) {
// console.log('Get from window');
return Promise.resolve(window[name]); return Promise.resolve(window[name]);
} }
// load from store2, if it's present. // load from store2, if it's present.
const fromStore = window.store.get(name); const fromStore = window.store.get(name);
if (validCache && typeof fromStore !== 'undefined') { if (validCache && typeof fromStore !== 'undefined') {
// console.log('Get "' + name + '" from store');
return Promise.resolve(fromStore); return Promise.resolve(fromStore);
} }
let getter = (new Get); let getter = (new Get);
return getter.getByName(name).then((response) => { return getter.getByName(name).then((response) => {
// console.log('Get "' + name + '" from API');
return Promise.resolve(parseResponse(name, response)); return Promise.resolve(parseResponse(name, response));
}).catch(() => { }).catch((error) => {
// preference does not exist (yet). // preference does not exist (yet).
// POST it and then return it anyway. // POST it and then return it anyway.
let poster = (new Post); let poster = (new Post);
poster.post(name, defaultValue).then((response) => { return poster.post(name, defaultValue).then((response) => {
return Promise.resolve(parseResponse(name, response)); return Promise.resolve(parseResponse(name, response));
}); });
}); });
@@ -55,7 +51,6 @@ export function getVariable(name, defaultValue = null) {
export function parseResponse(name, response) { export function parseResponse(name, response) {
let value = response.data.data.attributes.data; let value = response.data.data.attributes.data;
window.store.set(name, value); window.store.set(name, value);
// console.log('Store "' + name + '" in localStorage');
return value; return value;
} }

View File

@@ -0,0 +1,34 @@
/*
* load-translations.js
* Copyright (c) 2023 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 {format} from "date-fns";
import store from "store";
function cleanupCache() {
const localValue = store.get('lastActivity');
store.each(function(value, key) {
if(key.startsWith('dcx') && !key.includes(localValue)) {
store.remove(key);
}
});
}
export {cleanupCache};

View File

@@ -23,7 +23,7 @@ import store from "store";
function getCacheKey(string, start, end) { function getCacheKey(string, start, end) {
const localValue = store.get('lastActivity'); const localValue = store.get('lastActivity');
const cacheKey = format(start, 'y-MM-dd') + '_' + format(end, 'y-MM-dd') + '_' + string + localValue; const cacheKey = 'dcx' + format(start, 'yMMdd')+ format(end, 'yMMdd') + string + localValue;
console.log('getCacheKey: ' + cacheKey); console.log('getCacheKey: ' + cacheKey);
return String(cacheKey); return String(cacheKey);
} }

View File

@@ -0,0 +1,25 @@
/*
* show-internals-button.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/.
*/
export function showInternalsButton() {
console.log('showInternalsButton');
document.querySelector('.toggle-page-internals').classList.remove('d-none')
}

View File

@@ -0,0 +1,24 @@
/*
* show-settings-button.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/.
*/
export function showWizardButton() {
document.querySelector('.toggle-page-wizard').classList.remove('d-none')
}

View File

@@ -21,6 +21,7 @@
import {defineConfig} from 'vite'; import {defineConfig} from 'vite';
import laravel from 'laravel-vite-plugin'; import laravel from 'laravel-vite-plugin';
import manifestSRI from 'vite-plugin-manifest-sri'; import manifestSRI from 'vite-plugin-manifest-sri';
import * as fs from "fs";
const host = '127.0.0.1'; const host = '127.0.0.1';
@@ -65,20 +66,23 @@ export default defineConfig({
publicDirectory: '../../../public', publicDirectory: '../../../public',
refresh: true, refresh: true,
}), }),
//manifestSRI(), manifestSRI(),
], ],
server: { server: {
usePolling: true, usePolling: true,
allowedHosts: '*.sd.internal', watch: {
host: '0.0.0.0', usePolling: true,
hmr: {host}, },
cors: true host: '10.0.0.15',
// hmr: {
// protocol: 'wss',
// },
// https: { // https: {
// key: fs.readFileSync(`/Users/sander/Sites/vm/tls-certificates/wildcard.sd.local.key`), // key: fs.readFileSync(`/sites/vm/tls-certificates/wildcard.sd.internal.key`),
// cert: fs.readFileSync(`/Users/sander/Sites/vm/tls-certificates/wildcard.sd.local.crt`), // cert: fs.readFileSync(`/sites/vm/tls-certificates/wildcard.sd.internal.crt`),
// }, // },
}, },
}); });

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Изход', 'logout' => 'Изход',
'logout_other_sessions' => 'Изход от всички други сесии', 'logout_other_sessions' => 'Изход от всички други сесии',
'toggleNavigation' => 'Превключване на навигацията', 'toggleNavigation' => 'Превключване на навигацията',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Търсене...', 'searchPlaceholder' => 'Търсене...',
'version' => 'Версия', 'version' => 'Версия',
'dashboard' => 'Основно табло', 'dashboard' => 'Основно табло',

View File

@@ -1419,34 +1419,34 @@ return [
// Financial administrations // Financial administrations
'administration_index' => 'Administració financera', 'administration_index' => 'Administració financera',
'administrations_index_menu' => 'Administració financera', 'administrations_index_menu' => 'Administració financera',
'administrations_breadcrumb' => 'Financial administrations', 'administrations_breadcrumb' => 'Administracions financeres',
'administrations_page_title' => 'Financial administrations', 'administrations_page_title' => 'Administracions financeres',
'administrations_page_sub_title' => 'Overview', 'administrations_page_sub_title' => 'Visió general',
'create_administration' => 'Create new administration', 'create_administration' => 'Crea una nova administració',
'administration_owner' => 'Administration owner: {{email}}', 'administration_owner' => 'Propietari de l\'administració: {{email}}',
'administration_you' => 'Your role: {{role}}', 'administration_you' => 'El teu rol: {{role}}',
'other_users_in_admin' => 'Other users in this administration', 'other_users_in_admin' => 'Altres usuaris a aquesta administració',
'administrations_create_breadcrumb' => 'Create new financial administration', 'administrations_create_breadcrumb' => 'Crea una nova administració financera',
'administrations_page_create_sub_title' => 'Create new financial administration', 'administrations_page_create_sub_title' => 'Crea una nova administració financera',
'basic_administration_information' => 'Basic administration information', 'basic_administration_information' => 'Informació de l\'administració bàsica',
'new_administration_created' => 'New financial administration "{{title}}" has been created', 'new_administration_created' => 'S\'ha creat una nova administració financera "{{title}}"',
'edit_administration_breadcrumb' => 'Edit financial administration ":title"', 'edit_administration_breadcrumb' => 'Edita l\'administració financera ":title"',
'administrations_page_edit_sub_title' => 'Edit financial administration ":title"', 'administrations_page_edit_sub_title' => 'Edita l\'administració financera ":title"',
// roles // roles
'administration_role_owner' => 'Owner', 'administration_role_owner' => 'Propietari',
'administration_role_ro' => 'Read-only', 'administration_role_ro' => 'Només de lectura',
'administration_role_mng_trx' => 'Manage transactions', 'administration_role_mng_trx' => 'Gestionar transaccions',
'administration_role_mng_meta' => 'Manage classification and meta-data', 'administration_role_mng_meta' => 'Gestionar classificació i meta-dades',
'administration_role_mng_budgets' => 'Manage budgets', 'administration_role_mng_budgets' => 'Gestionar pressupostos',
'administration_role_mng_piggies' => 'Manage piggy banks', 'administration_role_mng_piggies' => 'Administra guardioles',
'administration_role_mng_subscriptions' => 'Manage subscriptions', 'administration_role_mng_subscriptions' => 'Gestionar subscripcions',
'administration_role_mng_rules' => 'Manage rules', 'administration_role_mng_rules' => 'Gestionar normes',
'administration_role_mng_recurring' => 'Manage recurring transactions ', 'administration_role_mng_recurring' => 'Gestionar transaccions recurrents ',
'administration_role_mng_webhooks' => 'Manage webhooks', 'administration_role_mng_webhooks' => 'Gestionar Webhooks',
'administration_role_mng_currencies' => 'Manage currencies', 'administration_role_mng_currencies' => 'Gestionar divises',
'administration_role_view_reports' => 'View reports', 'administration_role_view_reports' => 'Veure informes',
'administration_role_full' => 'Full access', 'administration_role_full' => 'Accés total',
// profile: // profile:
'purge_data_title' => 'Purgar dades de Firefly III', 'purge_data_title' => 'Purgar dades de Firefly III',
@@ -2144,6 +2144,7 @@ return [
'logout' => 'Tanca la sessió', 'logout' => 'Tanca la sessió',
'logout_other_sessions' => 'Tanca les altres sessions', 'logout_other_sessions' => 'Tanca les altres sessions',
'toggleNavigation' => 'Alternar navegació', 'toggleNavigation' => 'Alternar navegació',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Cerca...', 'searchPlaceholder' => 'Cerca...',
'version' => 'Versió', 'version' => 'Versió',
'dashboard' => 'Panell de control', 'dashboard' => 'Panell de control',

View File

@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'La selecció és invàlida.', 'invalid_selection' => 'La selecció és invàlida.',
'belongs_user' => 'Aquest valor està enllaçat a un objecte que sembla que no existeix.', 'belongs_user' => 'Aquest valor està enllaçat a un objecte que sembla que no existeix.',
'belongs_user_or_user_group' => 'Aquest valor està enllaçat a un objecte que sembla no existir a la teva administració financera actual.', 'belongs_user_or_user_group' => 'Aquest valor està enllaçat a un objecte que sembla no existir a la teva administració financera actual.',
'no_access_group' => 'The user has no access to this user group.', 'no_access_group' => 'L\'usuari no té accés a aquest grup d\'usuaris.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.', 'no_accepted_roles_defined' => 'No s\'ha definit cap rol d\'accés per a aquest endpoint, accés denegat.',
'at_least_one_transaction' => 'Necessites almenys una transacció.', 'at_least_one_transaction' => 'Necessites almenys una transacció.',
'recurring_transaction_id' => 'Necessites almenys una transacció.', 'recurring_transaction_id' => 'Necessites almenys una transacció.',
'need_id_to_match' => 'Has d\'enviar aquesta entrada amb un ID perquè l\'API sigui capaç de comparar-lo.', 'need_id_to_match' => 'Has d\'enviar aquesta entrada amb un ID perquè l\'API sigui capaç de comparar-lo.',
@@ -302,7 +302,7 @@ return [
// no access to administration: // no access to administration:
'no_access_user_group' => 'No tens accés a aquesta administració.', 'no_access_user_group' => 'No tens accés a aquesta administració.',
'administration_owner_rename' => 'You can\'t rename your standard administration.', 'administration_owner_rename' => 'No pots canviar el nom de la teva administració estàndard.',
]; ];
/* /*

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Odhlásit se', 'logout' => 'Odhlásit se',
'logout_other_sessions' => 'Logout all other sessions', 'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Vyp/zap. navigaci', 'toggleNavigation' => 'Vyp/zap. navigaci',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Hledat…', 'searchPlaceholder' => 'Hledat…',
'version' => 'Verze', 'version' => 'Verze',
'dashboard' => 'Přehled', 'dashboard' => 'Přehled',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Logout', 'logout' => 'Logout',
'logout_other_sessions' => 'Logout all other sessions', 'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Toggle navigation', 'toggleNavigation' => 'Toggle navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Search...', 'searchPlaceholder' => 'Search...',
'version' => 'Version', 'version' => 'Version',
'dashboard' => 'Dashboard', 'dashboard' => 'Dashboard',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Abmelden', 'logout' => 'Abmelden',
'logout_other_sessions' => 'Alle anderen Sitzungen abmelden', 'logout_other_sessions' => 'Alle anderen Sitzungen abmelden',
'toggleNavigation' => 'Navigation umschalten', 'toggleNavigation' => 'Navigation umschalten',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Suchen...', 'searchPlaceholder' => 'Suchen...',
'version' => 'Version', 'version' => 'Version',
'dashboard' => 'Übersicht', 'dashboard' => 'Übersicht',

View File

@@ -68,7 +68,7 @@ return [
'invalid_selection' => 'Ihre Auswahl ist ungültig.', 'invalid_selection' => 'Ihre Auswahl ist ungültig.',
'belongs_user' => 'Dieser Wert verweist auf ein Objekt, das offenbar nicht existiert.', 'belongs_user' => 'Dieser Wert verweist auf ein Objekt, das offenbar nicht existiert.',
'belongs_user_or_user_group' => 'Dieser Wert verweist auf ein Objekt, das in Ihrer aktuellen Finanzverwaltung offenbar nicht existiert.', 'belongs_user_or_user_group' => 'Dieser Wert verweist auf ein Objekt, das in Ihrer aktuellen Finanzverwaltung offenbar nicht existiert.',
'no_access_group' => 'The user has no access to this user group.', 'no_access_group' => 'Der Benutzer hat keinen Zugriff auf diese Benutzergruppe.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.', 'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.',
'at_least_one_transaction' => 'Sie brauchen mindestens eine Transaktion.', 'at_least_one_transaction' => 'Sie brauchen mindestens eine Transaktion.',
'recurring_transaction_id' => 'Sie benötigen mindestens eine Buchung.', 'recurring_transaction_id' => 'Sie benötigen mindestens eine Buchung.',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Αποσύνδεση', 'logout' => 'Αποσύνδεση',
'logout_other_sessions' => 'Αποσυνδέσετε όλες τις άλλες συνεδρίες', 'logout_other_sessions' => 'Αποσυνδέσετε όλες τις άλλες συνεδρίες',
'toggleNavigation' => 'Εναλλαγή περιήγησης', 'toggleNavigation' => 'Εναλλαγή περιήγησης',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Αναζήτηση...', 'searchPlaceholder' => 'Αναζήτηση...',
'version' => 'Έκδοση', 'version' => 'Έκδοση',
'dashboard' => 'Επισκόπηση', 'dashboard' => 'Επισκόπηση',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Logout', 'logout' => 'Logout',
'logout_other_sessions' => 'Logout all other sessions', 'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Toggle navigation', 'toggleNavigation' => 'Toggle navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Search...', 'searchPlaceholder' => 'Search...',
'version' => 'Version', 'version' => 'Version',
'dashboard' => 'Dashboard', 'dashboard' => 'Dashboard',

View File

@@ -2090,6 +2090,7 @@ return [
'logout' => 'Logout', 'logout' => 'Logout',
'logout_other_sessions' => 'Logout all other sessions', 'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Toggle navigation', 'toggleNavigation' => 'Toggle navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Search...', 'searchPlaceholder' => 'Search...',
'version' => 'Version', 'version' => 'Version',
'dashboard' => 'Dashboard', 'dashboard' => 'Dashboard',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Cerrar sesión', 'logout' => 'Cerrar sesión',
'logout_other_sessions' => 'Desconectar todas las demás sesiones', 'logout_other_sessions' => 'Desconectar todas las demás sesiones',
'toggleNavigation' => 'Activar navegación', 'toggleNavigation' => 'Activar navegación',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Buscar...', 'searchPlaceholder' => 'Buscar...',
'version' => 'Versión', 'version' => 'Versión',
'dashboard' => 'Panel de control', 'dashboard' => 'Panel de control',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Kirjaudu ulos', 'logout' => 'Kirjaudu ulos',
'logout_other_sessions' => 'Kirjaudu ulos kaikista muista istunnoista', 'logout_other_sessions' => 'Kirjaudu ulos kaikista muista istunnoista',
'toggleNavigation' => 'Vaihda navigointia', 'toggleNavigation' => 'Vaihda navigointia',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Hae ...', 'searchPlaceholder' => 'Hae ...',
'version' => 'Versio', 'version' => 'Versio',
'dashboard' => 'Etusivu', 'dashboard' => 'Etusivu',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Se déconnecter', 'logout' => 'Se déconnecter',
'logout_other_sessions' => 'Déconnecter toutes les autres sessions', 'logout_other_sessions' => 'Déconnecter toutes les autres sessions',
'toggleNavigation' => 'Activer navigation', 'toggleNavigation' => 'Activer navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Rechercher...', 'searchPlaceholder' => 'Rechercher...',
'version' => 'Version', 'version' => 'Version',
'dashboard' => 'Tableau de bord', 'dashboard' => 'Tableau de bord',

View File

@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'Votre sélection est invalide.', 'invalid_selection' => 'Votre sélection est invalide.',
'belongs_user' => 'Cette valeur est liée à un objet qui ne semble pas exister.', 'belongs_user' => 'Cette valeur est liée à un objet qui ne semble pas exister.',
'belongs_user_or_user_group' => 'Cette valeur est liée à un objet qui ne semble pas exister dans votre administration financière actuelle.', 'belongs_user_or_user_group' => 'Cette valeur est liée à un objet qui ne semble pas exister dans votre administration financière actuelle.',
'no_access_group' => 'The user has no access to this user group.', 'no_access_group' => 'L\'utilisateur n\'a pas accès à ce groupe d\'utilisateurs.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.', 'no_accepted_roles_defined' => 'Aucun rôle d\'accès n\'a été défini pour ce point d\'accès, accès refusé.',
'at_least_one_transaction' => 'Besoin d\'au moins une opération.', 'at_least_one_transaction' => 'Besoin d\'au moins une opération.',
'recurring_transaction_id' => 'Au moins une opération est nécessaire.', 'recurring_transaction_id' => 'Au moins une opération est nécessaire.',
'need_id_to_match' => 'Vous devez saisir cette entrée avec un identifiant pour que l\'API puisse la faire correspondre.', 'need_id_to_match' => 'Vous devez saisir cette entrée avec un identifiant pour que l\'API puisse la faire correspondre.',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Kijelentkezés', 'logout' => 'Kijelentkezés',
'logout_other_sessions' => 'Minden más munkamenet kijelentkeztetése', 'logout_other_sessions' => 'Minden más munkamenet kijelentkeztetése',
'toggleNavigation' => 'Navigációs mód átkapcsolása', 'toggleNavigation' => 'Navigációs mód átkapcsolása',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Keresés...', 'searchPlaceholder' => 'Keresés...',
'version' => 'Verzió', 'version' => 'Verzió',
'dashboard' => 'Műszerfal', 'dashboard' => 'Műszerfal',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Keluar', 'logout' => 'Keluar',
'logout_other_sessions' => 'Logout all other sessions', 'logout_other_sessions' => 'Logout all other sessions',
'toggleNavigation' => 'Toggle navigation', 'toggleNavigation' => 'Toggle navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Pencarian...', 'searchPlaceholder' => 'Pencarian...',
'version' => 'Versi', 'version' => 'Versi',
'dashboard' => 'Dasbor', 'dashboard' => 'Dasbor',

View File

@@ -64,7 +64,7 @@ return [
// 'date_time' => '%B %e, %Y, @ %T', // 'date_time' => '%B %e, %Y, @ %T',
'date_time_js' => 'D MMMM YYYY, HH:mm:ss', 'date_time_js' => 'D MMMM YYYY, HH:mm:ss',
'date_time_fns' => 'do MMMM yyyy @ HH:mm:ss', 'date_time_fns' => 'do MMMM yyyy @ HH:mm:ss',
'date_time_fns_short' => 'MMMM do, yyyy @ HH:mm', 'date_time_fns_short' => 'do MMMM yyyy @ HH:mm',
// 'specific_day' => '%e %B %Y', // 'specific_day' => '%e %B %Y',
'specific_day_js' => 'D MMMM YYYY', 'specific_day_js' => 'D MMMM YYYY',

View File

@@ -42,7 +42,7 @@ return [
'fatal_error' => 'Si è verificato un errore fatale. Controlla i file di login "storage/Los" o usa "Docker Los f [container]" per vedere cosa sta succedendo.', 'fatal_error' => 'Si è verificato un errore fatale. Controlla i file di login "storage/Los" o usa "Docker Los f [container]" per vedere cosa sta succedendo.',
'maintenance_mode' => 'Firefox III è in modalità di manutenzione.', 'maintenance_mode' => 'Firefox III è in modalità di manutenzione.',
'be_right_back' => 'Torno subito!', 'be_right_back' => 'Torno subito!',
'check_back' => 'Firefly III is down for some necessary maintenance. Please check back in a second. If you happen to see this message on the demo site, just wait a few minutes. The database is reset every few hours.', 'check_back' => 'Firefly III non è disponibile per via di una manutenzione necessaria. Per favore riprova tra qualche istante. Se ti capita di vedere questo messaggio sul sito demo, attendi qualche minuto. Il database viene reimpostato ogni poche ore.',
'error_occurred' => 'Oops! Si è verificato un errore.', 'error_occurred' => 'Oops! Si è verificato un errore.',
'db_error_occurred' => 'Oops! Si è verificato un errore del database.', 'db_error_occurred' => 'Oops! Si è verificato un errore del database.',
'error_not_recoverable' => 'Sfortunatamente questo errore non è riparabile :(. Firefly III è rotto. L\'errore è:', 'error_not_recoverable' => 'Sfortunatamente questo errore non è riparabile :(. Firefly III è rotto. L\'errore è:',

View File

@@ -896,9 +896,9 @@ return [
'rule_trigger_budget_is' => 'Il budget è ":trigger_value"', 'rule_trigger_budget_is' => 'Il budget è ":trigger_value"',
'rule_trigger_tag_is_choice' => 'Qualsiasi tag è..', 'rule_trigger_tag_is_choice' => 'Qualsiasi tag è..',
'rule_trigger_tag_is' => 'Qualsiasi tag è ":trigger_value"', 'rule_trigger_tag_is' => 'Qualsiasi tag è ":trigger_value"',
'rule_trigger_tag_contains_choice' => 'Any tag contains..', 'rule_trigger_tag_contains_choice' => 'Qualsiasi tag contiene..',
'rule_trigger_tag_contains' => 'Any tag contains ":trigger_value"', 'rule_trigger_tag_contains' => 'Qualsiasi tag contiene ":trigger_value"',
'rule_trigger_tag_ends_choice' => 'Any tag ends with..', 'rule_trigger_tag_ends_choice' => 'Qualsiasi tag finisce con..',
'rule_trigger_tag_ends' => 'Any tag ends with ":trigger_value"', 'rule_trigger_tag_ends' => 'Any tag ends with ":trigger_value"',
'rule_trigger_tag_starts_choice' => 'Any tag starts with..', 'rule_trigger_tag_starts_choice' => 'Any tag starts with..',
'rule_trigger_tag_starts' => 'Any tag starts with ":trigger_value"', 'rule_trigger_tag_starts' => 'Any tag starts with ":trigger_value"',
@@ -1434,10 +1434,10 @@ return [
'administrations_page_edit_sub_title' => 'Edit financial administration ":title"', 'administrations_page_edit_sub_title' => 'Edit financial administration ":title"',
// roles // roles
'administration_role_owner' => 'Owner', 'administration_role_owner' => 'Proprietario',
'administration_role_ro' => 'Read-only', 'administration_role_ro' => 'Sola lettura',
'administration_role_mng_trx' => 'Manage transactions', 'administration_role_mng_trx' => 'Gestisci le transazioni',
'administration_role_mng_meta' => 'Manage classification and meta-data', 'administration_role_mng_meta' => 'Gestisci classificazione e meta-dati',
'administration_role_mng_budgets' => 'Manage budgets', 'administration_role_mng_budgets' => 'Manage budgets',
'administration_role_mng_piggies' => 'Manage piggy banks', 'administration_role_mng_piggies' => 'Manage piggy banks',
'administration_role_mng_subscriptions' => 'Manage subscriptions', 'administration_role_mng_subscriptions' => 'Manage subscriptions',
@@ -2017,7 +2017,7 @@ return [
'deleted_transfer' => 'Trasferimento ":description" eliminato correttamente', 'deleted_transfer' => 'Trasferimento ":description" eliminato correttamente',
'deleted_reconciliation' => 'Transazione di riconciliazione ":description" elimina con successo', 'deleted_reconciliation' => 'Transazione di riconciliazione ":description" elimina con successo',
'stored_journal' => 'Nuova transazione ":description" creata correttamente', 'stored_journal' => 'Nuova transazione ":description" creata correttamente',
'stored_journal_js' => 'Successfully created new transaction "{{description}}"', 'stored_journal_js' => 'Nuova transazione "{{description}} " creata con successo',
'stored_journal_no_descr' => 'Hai creato con successo la nuova transazione', 'stored_journal_no_descr' => 'Hai creato con successo la nuova transazione',
'updated_journal_no_descr' => 'Transazione aggiornata con successo', 'updated_journal_no_descr' => 'Transazione aggiornata con successo',
'select_transactions' => 'Seleziona transazioni', 'select_transactions' => 'Seleziona transazioni',
@@ -2144,6 +2144,7 @@ return [
'logout' => 'Esci', 'logout' => 'Esci',
'logout_other_sessions' => 'Esci da tutte le altre sessioni', 'logout_other_sessions' => 'Esci da tutte le altre sessioni',
'toggleNavigation' => 'Attiva / disattiva la navigazione', 'toggleNavigation' => 'Attiva / disattiva la navigazione',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Cerca...', 'searchPlaceholder' => 'Cerca...',
'version' => 'Versione', 'version' => 'Versione',
'dashboard' => 'Cruscotto', 'dashboard' => 'Cruscotto',
@@ -2325,7 +2326,7 @@ return [
'description' => 'Descrizione', 'description' => 'Descrizione',
'sum_of_period' => 'Somma del periodo', 'sum_of_period' => 'Somma del periodo',
'average_in_period' => 'Media nel periodo', 'average_in_period' => 'Media nel periodo',
'no_account_role' => '(no role)', 'no_account_role' => '(nessun ruolo)',
'account_role_defaultAsset' => 'Conto attività predefinito', 'account_role_defaultAsset' => 'Conto attività predefinito',
'account_role_sharedAsset' => 'Conto attività condiviso', 'account_role_sharedAsset' => 'Conto attività condiviso',
'account_role_savingAsset' => 'Conto risparmio', 'account_role_savingAsset' => 'Conto risparmio',
@@ -2490,7 +2491,7 @@ return [
'block_code_bounced' => 'Messaggi email respinti', 'block_code_bounced' => 'Messaggi email respinti',
'block_code_expired' => 'Conto demo scaduto', 'block_code_expired' => 'Conto demo scaduto',
'no_block_code' => 'Nessun motivo per bloccare o non bloccare un utente', 'no_block_code' => 'Nessun motivo per bloccare o non bloccare un utente',
'demo_user_export' => 'The demo user cannot export data', 'demo_user_export' => 'L\'utente demo non può esportare dati',
'block_code_email_changed' => 'L\'utente non ha ancora confermato il nuovo indirizzo emails', 'block_code_email_changed' => 'L\'utente non ha ancora confermato il nuovo indirizzo emails',
'admin_update_email' => 'Contrariamente alla pagina del profilo, l\'utente NON riceverà alcuna notifica al proprio indirizzo email!', 'admin_update_email' => 'Contrariamente alla pagina del profilo, l\'utente NON riceverà alcuna notifica al proprio indirizzo email!',
'update_user' => 'Aggiorna utente', 'update_user' => 'Aggiorna utente',

View File

@@ -70,5 +70,5 @@ return [
'cannot_find_budget' => 'Firefly III non riesce a trovare il budget ":name"', 'cannot_find_budget' => 'Firefly III non riesce a trovare il budget ":name"',
'cannot_find_category' => 'Firefly III non riesce a trovare la categoria ":name"', 'cannot_find_category' => 'Firefly III non riesce a trovare la categoria ":name"',
'cannot_set_budget' => 'Firefly III non può impostare il budget ":name" a una transazione di tipo ":type"', 'cannot_set_budget' => 'Firefly III non può impostare il budget ":name" a una transazione di tipo ":type"',
'journal_invalid_amount' => 'Firefly III can\'t set amount ":amount" because it is not a valid number.', 'journal_invalid_amount' => 'Firefly III non può impostare l\'importo ":amount" perché non è un numero valido.',
]; ];

View File

@@ -55,11 +55,11 @@ return [
'reconciled_forbidden_field' => 'Questa transazione è già riconciliata, non è possibile modificare il campo ":field"', 'reconciled_forbidden_field' => 'Questa transazione è già riconciliata, non è possibile modificare il campo ":field"',
'deleted_user' => 'A causa dei vincoli di sicurezza, non è possibile registrarsi utilizzando questo indirizzo email.', 'deleted_user' => 'A causa dei vincoli di sicurezza, non è possibile registrarsi utilizzando questo indirizzo email.',
'rule_trigger_value' => 'Questo valore non è valido per il trigger selezionato.', 'rule_trigger_value' => 'Questo valore non è valido per il trigger selezionato.',
'rule_action_expression' => 'Invalid expression. :error', 'rule_action_expression' => 'Espressione non valida. :error',
'rule_action_value' => 'Questo valore non è valido per l\'azione selezionata.', 'rule_action_value' => 'Questo valore non è valido per l\'azione selezionata.',
'file_already_attached' => 'Il file caricato ":name" è già associato a questo oggetto.', 'file_already_attached' => 'Il file caricato ":name" è già associato a questo oggetto.',
'file_attached' => 'File caricato con successo ":name".', 'file_attached' => 'File caricato con successo ":name".',
'file_zero' => 'The file is zero bytes in size.', 'file_zero' => 'Il file ha dimensione zero.',
'must_exist' => 'L\'ID nel campo :attribute non esiste nel database.', 'must_exist' => 'L\'ID nel campo :attribute non esiste nel database.',
'all_accounts_equal' => 'Tutti i conti in questo campo devono essere uguali.', 'all_accounts_equal' => 'Tutti i conti in questo campo devono essere uguali.',
'group_title_mandatory' => 'Il titolo del gruppo è obbligatorio quando ci sono più di una transazione.', 'group_title_mandatory' => 'Il titolo del gruppo è obbligatorio quando ci sono più di una transazione.',
@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'La tua selezione non è valida.', 'invalid_selection' => 'La tua selezione non è valida.',
'belongs_user' => 'Questo valore è collegato a un oggetto che non sembra esistere.', 'belongs_user' => 'Questo valore è collegato a un oggetto che non sembra esistere.',
'belongs_user_or_user_group' => 'Questo valore è collegato a un oggetto che non sembra esistere nella tua attuale amministrazione finanziaria.', 'belongs_user_or_user_group' => 'Questo valore è collegato a un oggetto che non sembra esistere nella tua attuale amministrazione finanziaria.',
'no_access_group' => 'The user has no access to this user group.', 'no_access_group' => 'L\'utente non ha accesso a questo gruppo.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.', 'no_accepted_roles_defined' => 'Nessun ruolo di accesso è stato definito per questo endpoint, accesso negato.',
'at_least_one_transaction' => 'Hai bisogno di almeno una transazione.', 'at_least_one_transaction' => 'Hai bisogno di almeno una transazione.',
'recurring_transaction_id' => 'Hai bisogno di almeno una transazione.', 'recurring_transaction_id' => 'Hai bisogno di almeno una transazione.',
'need_id_to_match' => 'È necessario inviare questa voce con un ID affinché l\'API sia in grado di abbinarla.', 'need_id_to_match' => 'È necessario inviare questa voce con un ID affinché l\'API sia in grado di abbinarla.',
@@ -199,7 +199,7 @@ return [
* *
*/ */
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password', 'secure_password' => 'Questa non è una password sicura. Per favore riprova. Per ulteriori informazioni, visita https://bit.ly/FF3-password',
'valid_recurrence_rep_type' => 'Il tipo di ripetizione della transazione ricorrente non è valido.', 'valid_recurrence_rep_type' => 'Il tipo di ripetizione della transazione ricorrente non è valido.',
'valid_recurrence_rep_moment' => 'Il momento di ripetizione per questo tipo di ripetizione non è valido.', 'valid_recurrence_rep_moment' => 'Il momento di ripetizione per questo tipo di ripetizione non è valido.',
'invalid_account_info' => 'Informazione sul conto non valida.', 'invalid_account_info' => 'Informazione sul conto non valida.',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'ログアウト', 'logout' => 'ログアウト',
'logout_other_sessions' => 'すべてのセッションからログアウト', 'logout_other_sessions' => 'すべてのセッションからログアウト',
'toggleNavigation' => 'ナビゲーションを切り替え', 'toggleNavigation' => 'ナビゲーションを切り替え',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => '検索...', 'searchPlaceholder' => '検索...',
'version' => 'バージョン', 'version' => 'バージョン',
'dashboard' => 'ダッシュボード', 'dashboard' => 'ダッシュボード',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => '로그아웃', 'logout' => '로그아웃',
'logout_other_sessions' => '다른 모든 세션 로그아웃', 'logout_other_sessions' => '다른 모든 세션 로그아웃',
'toggleNavigation' => '토글 내비게이션', 'toggleNavigation' => '토글 내비게이션',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => '검색...', 'searchPlaceholder' => '검색...',
'version' => '버전', 'version' => '버전',
'dashboard' => '대시보드', 'dashboard' => '대시보드',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Logg ut', 'logout' => 'Logg ut',
'logout_other_sessions' => 'Logg ut alle andre økter', 'logout_other_sessions' => 'Logg ut alle andre økter',
'toggleNavigation' => 'Vis/Skjul navigation', 'toggleNavigation' => 'Vis/Skjul navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Søk...', 'searchPlaceholder' => 'Søk...',
'version' => 'Versjon', 'version' => 'Versjon',
'dashboard' => 'Startskjerm', 'dashboard' => 'Startskjerm',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Uitloggen', 'logout' => 'Uitloggen',
'logout_other_sessions' => 'Alle andere sessies afmelden', 'logout_other_sessions' => 'Alle andere sessies afmelden',
'toggleNavigation' => 'Navigatie aan of uit', 'toggleNavigation' => 'Navigatie aan of uit',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Zoeken...', 'searchPlaceholder' => 'Zoeken...',
'version' => 'Versie', 'version' => 'Versie',
'dashboard' => 'Dashboard', 'dashboard' => 'Dashboard',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Logg ut', 'logout' => 'Logg ut',
'logout_other_sessions' => 'Logg ut alle andre økter', 'logout_other_sessions' => 'Logg ut alle andre økter',
'toggleNavigation' => 'Vis/Skjul navigation', 'toggleNavigation' => 'Vis/Skjul navigation',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Søk...', 'searchPlaceholder' => 'Søk...',
'version' => 'Versjon', 'version' => 'Versjon',
'dashboard' => 'Startskjerm', 'dashboard' => 'Startskjerm',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Wyloguj', 'logout' => 'Wyloguj',
'logout_other_sessions' => 'Wyloguj z pozostałych sesji', 'logout_other_sessions' => 'Wyloguj z pozostałych sesji',
'toggleNavigation' => 'Przełącz nawigację', 'toggleNavigation' => 'Przełącz nawigację',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Szukaj...', 'searchPlaceholder' => 'Szukaj...',
'version' => 'Wersja', 'version' => 'Wersja',
'dashboard' => 'Kokpit', 'dashboard' => 'Kokpit',

View File

@@ -64,7 +64,7 @@ return [
// 'date_time' => '%B %e, %Y, @ %T', // 'date_time' => '%B %e, %Y, @ %T',
'date_time_js' => 'DD [de] MMMM [de] YYYY, [às] HH:mm:ss', 'date_time_js' => 'DD [de] MMMM [de] YYYY, [às] HH:mm:ss',
'date_time_fns' => 'dd \'de\' MMMM \'de\' yyyy, \'às\' HH:mm:ss', 'date_time_fns' => 'dd \'de\' MMMM \'de\' yyyy, \'às\' HH:mm:ss',
'date_time_fns_short' => 'MMMM do, yyyy @ HH:mm', 'date_time_fns_short' => 'dd/MMM/yyyy HH:mm',
// 'specific_day' => '%e %B %Y', // 'specific_day' => '%e %B %Y',
'specific_day_js' => 'DD [de] MMMM [de] YYYY', 'specific_day_js' => 'DD [de] MMMM [de] YYYY',

View File

@@ -42,7 +42,7 @@ return [
'fatal_error' => 'Houve um erro fatal. Por favor, verifique os arquivos de log em "storage/logs" ou use "docker logs -f [container]" para ver o que está acontecendo.', 'fatal_error' => 'Houve um erro fatal. Por favor, verifique os arquivos de log em "storage/logs" ou use "docker logs -f [container]" para ver o que está acontecendo.',
'maintenance_mode' => 'Firefly III está em modo de manutenção.', 'maintenance_mode' => 'Firefly III está em modo de manutenção.',
'be_right_back' => 'Volta logo!', 'be_right_back' => 'Volta logo!',
'check_back' => 'Firefly III is down for some necessary maintenance. Please check back in a second. If you happen to see this message on the demo site, just wait a few minutes. The database is reset every few hours.', 'check_back' => 'Firefly III está desligado para algumas manutenções necessárias. Volte em um segundo. Se acontecer de você ver esta mensagem no site de demonstração, espere alguns minutos. O banco de dados é reiniciado a cada algumas horas.',
'error_occurred' => 'Ops! Aconteceu um erro.', 'error_occurred' => 'Ops! Aconteceu um erro.',
'db_error_occurred' => 'Ops! Ocorreu um erro no banco de dados.', 'db_error_occurred' => 'Ops! Ocorreu um erro no banco de dados.',
'error_not_recoverable' => 'Infelizmente este erro não é recuperável :(. Firefly III quebrou. O erro é:', 'error_not_recoverable' => 'Infelizmente este erro não é recuperável :(. Firefly III quebrou. O erro é:',

View File

@@ -113,7 +113,7 @@ return [
'two_factor_forgot' => 'Esqueci minha autenticação em duas etapas.', 'two_factor_forgot' => 'Esqueci minha autenticação em duas etapas.',
'two_factor_lost_header' => 'Perdeu sua autenticação em duas etapas?', 'two_factor_lost_header' => 'Perdeu sua autenticação em duas etapas?',
'two_factor_lost_intro' => 'Se você perdeu seus códigos de backup também, você tem azar. Isso não é algo que você pode corrigir a partir da interface da web. Você tem duas escolhas.', 'two_factor_lost_intro' => 'Se você perdeu seus códigos de backup também, você tem azar. Isso não é algo que você pode corrigir a partir da interface da web. Você tem duas escolhas.',
'two_factor_lost_fix_self' => 'If you run your own instance of Firefly III, read <a href="https://docs.firefly-iii.org/references/faq/firefly-iii/using/#i-lost-my-2fa-token-generator-or-2fa-has-stopped-working">this entry in the FAQ</a> for instructions.', 'two_factor_lost_fix_self' => 'Se você roda sua própria instância do Firefly III, leia <a href="https://docs.firefly-iii.org/references/faq/firefly-iii/using/#i-lost-my-2fa-token-generator-or-2fa-has-stopped-working>esta seção no FAQ</a> para instruções.',
'two_factor_lost_fix_owner' => 'Caso contrário, entre em contato com o proprietário do site, <a href="mailto::site_owner">:site_owner</a>, e peça que redefina sua autenticação de duas etapas.', 'two_factor_lost_fix_owner' => 'Caso contrário, entre em contato com o proprietário do site, <a href="mailto::site_owner">:site_owner</a>, e peça que redefina sua autenticação de duas etapas.',
'mfa_backup_code' => 'Você usou um código de backup para acessar o Firefly III. Não pode ser usado novamente, então cruze-o na sua lista.', 'mfa_backup_code' => 'Você usou um código de backup para acessar o Firefly III. Não pode ser usado novamente, então cruze-o na sua lista.',
'pref_two_factor_new_backup_codes' => 'Obter novos códigos de backup', 'pref_two_factor_new_backup_codes' => 'Obter novos códigos de backup',
@@ -317,8 +317,8 @@ return [
'update_new_version_alert' => 'Uma nova versão do Firefly lll está disponível. Você está utilizando a versão :your_version, e a nova é a :new_version, que foi lançada no dia :date.', 'update_new_version_alert' => 'Uma nova versão do Firefly lll está disponível. Você está utilizando a versão :your_version, e a nova é a :new_version, que foi lançada no dia :date.',
'update_version_beta' => 'Esta versão é uma versão BETA. Você pode encontrar problemas.', 'update_version_beta' => 'Esta versão é uma versão BETA. Você pode encontrar problemas.',
'update_version_alpha' => 'Esta versão é uma versão ALPHA. Você pode encontrar problemas.', 'update_version_alpha' => 'Esta versão é uma versão ALPHA. Você pode encontrar problemas.',
'update_current_dev_older' => 'You are running development release ":version", which is older than the latest release :new_version. Please update!', 'update_current_dev_older' => 'Você está executando a versão de desenvolvimento ":version", que é mais antiga que o último lançamento :new_version. Por favor, atualize!',
'update_current_dev_newer' => 'You are running development release ":version", which is newer than the latest release :new_version.', 'update_current_dev_newer' => 'Você está executando a versão de desenvolvimento ":version", que é mais recente que o último lançamento :new_version.',
'update_current_version_alert' => 'Você está utilizando a versão :version, que é a última disponível.', 'update_current_version_alert' => 'Você está utilizando a versão :version, que é a última disponível.',
'update_newer_version_alert' => 'Você está utilizando a versão :your_version, que é mais nova do que a mais recente :new_version.', 'update_newer_version_alert' => 'Você está utilizando a versão :your_version, que é mais nova do que a mais recente :new_version.',
'update_check_error' => 'Ocorreu um erro durante a verificação de atualizações: :error', 'update_check_error' => 'Ocorreu um erro durante a verificação de atualizações: :error',
@@ -896,12 +896,12 @@ return [
'rule_trigger_budget_is' => 'O orçamento é ":trigger_value"', 'rule_trigger_budget_is' => 'O orçamento é ":trigger_value"',
'rule_trigger_tag_is_choice' => 'Qualquer tag é..', 'rule_trigger_tag_is_choice' => 'Qualquer tag é..',
'rule_trigger_tag_is' => 'Qualquer tag é ":trigger_value"', 'rule_trigger_tag_is' => 'Qualquer tag é ":trigger_value"',
'rule_trigger_tag_contains_choice' => 'Any tag contains..', 'rule_trigger_tag_contains_choice' => 'Qualquer tag contém..',
'rule_trigger_tag_contains' => 'Any tag contains ":trigger_value"', 'rule_trigger_tag_contains' => 'Qualquer tag contém ":trigger_value"',
'rule_trigger_tag_ends_choice' => 'Any tag ends with..', 'rule_trigger_tag_ends_choice' => 'Qualquer tag termina com..',
'rule_trigger_tag_ends' => 'Any tag ends with ":trigger_value"', 'rule_trigger_tag_ends' => 'Qualquer tag termina com ":trigger_value"',
'rule_trigger_tag_starts_choice' => 'Any tag starts with..', 'rule_trigger_tag_starts_choice' => 'Qualquer tag começa com..',
'rule_trigger_tag_starts' => 'Any tag starts with ":trigger_value"', 'rule_trigger_tag_starts' => 'Qualquer tag começa com ":trigger_value"',
'rule_trigger_currency_is_choice' => 'A moeda da transação é..', 'rule_trigger_currency_is_choice' => 'A moeda da transação é..',
'rule_trigger_currency_is' => 'A moeda da transação é ":trigger_value"', 'rule_trigger_currency_is' => 'A moeda da transação é ":trigger_value"',
'rule_trigger_foreign_currency_is_choice' => 'A moeda estrangeira da transação é...', 'rule_trigger_foreign_currency_is_choice' => 'A moeda estrangeira da transação é...',
@@ -1203,7 +1203,7 @@ return [
'rule_trigger_not_exists' => 'Transação não existe', 'rule_trigger_not_exists' => 'Transação não existe',
'rule_trigger_not_has_attachments' => 'A transação não tem anexos', 'rule_trigger_not_has_attachments' => 'A transação não tem anexos',
'rule_trigger_not_has_any_category' => 'A transação não tem categoria', 'rule_trigger_not_has_any_category' => 'A transação não tem categoria',
'rule_trigger_not_has_any_budget' => 'Transaction has no budget', 'rule_trigger_not_has_any_budget' => 'A transação não tem orçamento',
'rule_trigger_not_has_any_bill' => 'A transação não tem nenhuma fatura', 'rule_trigger_not_has_any_bill' => 'A transação não tem nenhuma fatura',
'rule_trigger_not_has_any_tag' => 'A transação não tem tags', 'rule_trigger_not_has_any_tag' => 'A transação não tem tags',
'rule_trigger_not_any_notes' => 'A transação não tem notas', 'rule_trigger_not_any_notes' => 'A transação não tem notas',
@@ -1286,8 +1286,8 @@ return [
'rule_action_append_notes_to_descr' => 'Adicionar notas à descrição', 'rule_action_append_notes_to_descr' => 'Adicionar notas à descrição',
'rule_action_move_descr_to_notes' => 'Substituir notas por descrição', 'rule_action_move_descr_to_notes' => 'Substituir notas por descrição',
'rule_action_move_notes_to_descr' => 'Substituir descrição por notas', 'rule_action_move_notes_to_descr' => 'Substituir descrição por notas',
'rule_action_set_amount_choice' => 'Set amount to ..', 'rule_action_set_amount_choice' => 'Definir valor para ..',
'rule_action_set_amount' => 'Set amount to ":action_value"', 'rule_action_set_amount' => 'Definir valor para ":action_value"',
'rule_action_set_destination_to_cash_choice' => 'Definir a conta destino para (dinheiro)', 'rule_action_set_destination_to_cash_choice' => 'Definir a conta destino para (dinheiro)',
'rule_action_set_source_to_cash_choice' => 'Definir a conta de ativo para (dinheiro)', 'rule_action_set_source_to_cash_choice' => 'Definir a conta de ativo para (dinheiro)',
'rulegroup_for_bills_title' => 'Grupo de regras para faturas', 'rulegroup_for_bills_title' => 'Grupo de regras para faturas',
@@ -1419,34 +1419,34 @@ return [
// Financial administrations // Financial administrations
'administration_index' => 'Administração financeira', 'administration_index' => 'Administração financeira',
'administrations_index_menu' => 'Administração(ões) financeira(s)', 'administrations_index_menu' => 'Administração(ões) financeira(s)',
'administrations_breadcrumb' => 'Financial administrations', 'administrations_breadcrumb' => 'Administrações financeira',
'administrations_page_title' => 'Financial administrations', 'administrations_page_title' => 'Administrações financeiras',
'administrations_page_sub_title' => 'Overview', 'administrations_page_sub_title' => 'Visão Geral',
'create_administration' => 'Create new administration', 'create_administration' => 'Criar nova administração',
'administration_owner' => 'Administration owner: {{email}}', 'administration_owner' => 'Proprietário da administração: {{email}}',
'administration_you' => 'Your role: {{role}}', 'administration_you' => 'Sua função: {{role}}',
'other_users_in_admin' => 'Other users in this administration', 'other_users_in_admin' => 'Outros usuários nesta administração',
'administrations_create_breadcrumb' => 'Create new financial administration', 'administrations_create_breadcrumb' => 'Criar nova administração financeira',
'administrations_page_create_sub_title' => 'Create new financial administration', 'administrations_page_create_sub_title' => 'Criar nova administração financeira',
'basic_administration_information' => 'Basic administration information', 'basic_administration_information' => 'Informações básicas da administração',
'new_administration_created' => 'New financial administration "{{title}}" has been created', 'new_administration_created' => 'Nova administração financeira "{{title}}" foi criada',
'edit_administration_breadcrumb' => 'Edit financial administration ":title"', 'edit_administration_breadcrumb' => 'Editar administração financeira ":title"',
'administrations_page_edit_sub_title' => 'Edit financial administration ":title"', 'administrations_page_edit_sub_title' => 'Editar administração financeira ":title"',
// roles // roles
'administration_role_owner' => 'Owner', 'administration_role_owner' => 'Proprietário',
'administration_role_ro' => 'Read-only', 'administration_role_ro' => 'Somente leitura',
'administration_role_mng_trx' => 'Manage transactions', 'administration_role_mng_trx' => 'Gerenciar transações',
'administration_role_mng_meta' => 'Manage classification and meta-data', 'administration_role_mng_meta' => 'Gerenciar classificação e metadados',
'administration_role_mng_budgets' => 'Manage budgets', 'administration_role_mng_budgets' => 'Gerenciar orçamentos',
'administration_role_mng_piggies' => 'Manage piggy banks', 'administration_role_mng_piggies' => 'Gerenciar cofrinhos',
'administration_role_mng_subscriptions' => 'Manage subscriptions', 'administration_role_mng_subscriptions' => 'Gerenciar assinaturas',
'administration_role_mng_rules' => 'Manage rules', 'administration_role_mng_rules' => 'Gerenciar regras',
'administration_role_mng_recurring' => 'Manage recurring transactions ', 'administration_role_mng_recurring' => 'Gerenciar transações recorrentes ',
'administration_role_mng_webhooks' => 'Manage webhooks', 'administration_role_mng_webhooks' => 'Gerenciar webhooks',
'administration_role_mng_currencies' => 'Manage currencies', 'administration_role_mng_currencies' => 'Gerenciar moedas',
'administration_role_view_reports' => 'View reports', 'administration_role_view_reports' => 'Ver relatórios',
'administration_role_full' => 'Full access', 'administration_role_full' => 'Acesso completo',
// profile: // profile:
'purge_data_title' => 'Expurgar dados do Firefly III', 'purge_data_title' => 'Expurgar dados do Firefly III',
@@ -1616,8 +1616,8 @@ return [
'submission_options' => 'Opções de envio', 'submission_options' => 'Opções de envio',
'apply_rules_checkbox' => 'Aplicar regras', 'apply_rules_checkbox' => 'Aplicar regras',
'fire_webhooks_checkbox' => 'Acionar webhooks', 'fire_webhooks_checkbox' => 'Acionar webhooks',
'select_source_account' => 'Please select or type a valid source account name', 'select_source_account' => 'Por favor, selecione ou digite um nome de conta de origem válido',
'select_dest_account' => 'Please select or type a valid destination account name', 'select_dest_account' => 'Por favor, selecione ou digite um nome de conta de destino válido',
// convert stuff: // convert stuff:
'convert_is_already_type_Withdrawal' => 'Esta transação já é uma saída', 'convert_is_already_type_Withdrawal' => 'Esta transação já é uma saída',
@@ -2017,7 +2017,7 @@ return [
'deleted_transfer' => 'Transferência ":description" excluída com sucesso', 'deleted_transfer' => 'Transferência ":description" excluída com sucesso',
'deleted_reconciliation' => 'Transação de reconciliação ":description" excluída com sucesso', 'deleted_reconciliation' => 'Transação de reconciliação ":description" excluída com sucesso',
'stored_journal' => 'Transação ":description" incluída com sucesso', 'stored_journal' => 'Transação ":description" incluída com sucesso',
'stored_journal_js' => 'Successfully created new transaction "{{description}}"', 'stored_journal_js' => 'Transação "{{description}}" criada com sucesso',
'stored_journal_no_descr' => 'Transação criada com sucesso', 'stored_journal_no_descr' => 'Transação criada com sucesso',
'updated_journal_no_descr' => 'Transação atualizada com sucesso', 'updated_journal_no_descr' => 'Transação atualizada com sucesso',
'select_transactions' => 'Selecione as transações', 'select_transactions' => 'Selecione as transações',
@@ -2144,6 +2144,7 @@ return [
'logout' => 'Desconectar', 'logout' => 'Desconectar',
'logout_other_sessions' => 'Sair de todas as outras sessões', 'logout_other_sessions' => 'Sair de todas as outras sessões',
'toggleNavigation' => 'Alternar navegação', 'toggleNavigation' => 'Alternar navegação',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Pesquisar...', 'searchPlaceholder' => 'Pesquisar...',
'version' => 'Versão', 'version' => 'Versão',
'dashboard' => 'Painel de Controle', 'dashboard' => 'Painel de Controle',
@@ -2325,7 +2326,7 @@ return [
'description' => 'Descrição', 'description' => 'Descrição',
'sum_of_period' => 'Soma de período', 'sum_of_period' => 'Soma de período',
'average_in_period' => 'Média do período', 'average_in_period' => 'Média do período',
'no_account_role' => '(no role)', 'no_account_role' => '(sem função)',
'account_role_defaultAsset' => 'Conta padrão', 'account_role_defaultAsset' => 'Conta padrão',
'account_role_sharedAsset' => 'Contas de ativos compartilhadas', 'account_role_sharedAsset' => 'Contas de ativos compartilhadas',
'account_role_savingAsset' => 'Conta poupança', 'account_role_savingAsset' => 'Conta poupança',
@@ -2490,7 +2491,7 @@ return [
'block_code_bounced' => 'Mensagem(s) de email devolvidas', 'block_code_bounced' => 'Mensagem(s) de email devolvidas',
'block_code_expired' => 'Conta de demonstração expirada', 'block_code_expired' => 'Conta de demonstração expirada',
'no_block_code' => 'Nenhuma razão para o bloqueio ou o usuário não está bloqueado', 'no_block_code' => 'Nenhuma razão para o bloqueio ou o usuário não está bloqueado',
'demo_user_export' => 'The demo user cannot export data', 'demo_user_export' => 'O usuário de demonstração não pode exportar dados',
'block_code_email_changed' => 'O usuário ainda não confirmou o novo endereço de e-mail', 'block_code_email_changed' => 'O usuário ainda não confirmou o novo endereço de e-mail',
'admin_update_email' => 'Ao contrário da página de perfil, o usuário NÃO será notificado de que seu endereço de e-mail mudou!', 'admin_update_email' => 'Ao contrário da página de perfil, o usuário NÃO será notificado de que seu endereço de e-mail mudou!',
'update_user' => 'Atualizar usuário', 'update_user' => 'Atualizar usuário',
@@ -2598,9 +2599,9 @@ return [
'store_as_new' => 'Armazene como uma nova transação em vez de atualizar.', 'store_as_new' => 'Armazene como uma nova transação em vez de atualizar.',
'reset_after' => 'Limpar o formulário após o envio', 'reset_after' => 'Limpar o formulário após o envio',
'errors_submission' => 'Algo deu errado com seu envio. Por favor, verifique os erros abaixo.', 'errors_submission' => 'Algo deu errado com seu envio. Por favor, verifique os erros abaixo.',
'errors_submission_v2' => 'There was something wrong with your submission. Please check out the errors below: {{errorMessage}}', 'errors_submission_v2' => 'Algo deu errado com seu envio. Por favor, verifique os erros abaixo: {{errorMessage}}',
'transaction_expand_split' => 'Exibir divisão', 'transaction_expand_split' => 'Exibir divisão',
'transaction_remove_split' => 'Remove split', 'transaction_remove_split' => 'Remover divisão',
'transaction_collapse_split' => 'Esconder divisão', 'transaction_collapse_split' => 'Esconder divisão',
// object groups // object groups
@@ -2800,7 +2801,7 @@ return [
'ale_action_add_to_piggy' => 'Cofrinho', 'ale_action_add_to_piggy' => 'Cofrinho',
'ale_action_remove_from_piggy' => 'Cofrinho', 'ale_action_remove_from_piggy' => 'Cofrinho',
'ale_action_add_tag' => 'Tag adicionada', 'ale_action_add_tag' => 'Tag adicionada',
'ale_action_update_amount' => 'Updated amount', 'ale_action_update_amount' => 'Valor atualizado',
// dashboard // dashboard
'enable_auto_convert' => 'Habilitar conversão de moeda', 'enable_auto_convert' => 'Habilitar conversão de moeda',

View File

@@ -70,5 +70,5 @@ return [
'cannot_find_budget' => 'O Firefly III não pode encontrar o orçamento ":name"', 'cannot_find_budget' => 'O Firefly III não pode encontrar o orçamento ":name"',
'cannot_find_category' => 'O Firefly III não pode encontrar a categoria ":name"', 'cannot_find_category' => 'O Firefly III não pode encontrar a categoria ":name"',
'cannot_set_budget' => 'O Firefly III não pode definir o orçamento ":name" à transação de tipo ":type"', 'cannot_set_budget' => 'O Firefly III não pode definir o orçamento ":name" à transação de tipo ":type"',
'journal_invalid_amount' => 'Firefly III can\'t set amount ":amount" because it is not a valid number.', 'journal_invalid_amount' => 'Firefly III não pode definir o valor ":amount" porque não é um número válido.',
]; ];

View File

@@ -55,11 +55,11 @@ return [
'reconciled_forbidden_field' => 'Esta transação já está reconciliada, você não pode mudar o campo ":field"', 'reconciled_forbidden_field' => 'Esta transação já está reconciliada, você não pode mudar o campo ":field"',
'deleted_user' => 'Devido a restrições de segurança, você não pode se registrar usando este endereço de e-mail.', 'deleted_user' => 'Devido a restrições de segurança, você não pode se registrar usando este endereço de e-mail.',
'rule_trigger_value' => 'Este valor é inválido para o disparo selecionado.', 'rule_trigger_value' => 'Este valor é inválido para o disparo selecionado.',
'rule_action_expression' => 'Invalid expression. :error', 'rule_action_expression' => 'Expressão inválida. :error',
'rule_action_value' => 'Este valor é inválido para a ação selecionada.', 'rule_action_value' => 'Este valor é inválido para a ação selecionada.',
'file_already_attached' => 'Arquivo ":name" carregado já está anexado para este objeto.', 'file_already_attached' => 'Arquivo ":name" carregado já está anexado para este objeto.',
'file_attached' => 'Arquivo carregado com sucesso ":name".', 'file_attached' => 'Arquivo carregado com sucesso ":name".',
'file_zero' => 'The file is zero bytes in size.', 'file_zero' => 'O arquivo tem zero byte de tamanho.',
'must_exist' => 'O ID no campo :attribute não existe no banco de dados.', 'must_exist' => 'O ID no campo :attribute não existe no banco de dados.',
'all_accounts_equal' => 'Todas as contas neste campo devem ser iguais.', 'all_accounts_equal' => 'Todas as contas neste campo devem ser iguais.',
'group_title_mandatory' => 'Um título de grupo é obrigatório quando existe mais de uma transação.', 'group_title_mandatory' => 'Um título de grupo é obrigatório quando existe mais de uma transação.',
@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'Sua seleção é inválida.', 'invalid_selection' => 'Sua seleção é inválida.',
'belongs_user' => 'Este valor está vinculado a um objeto que aparentemente não existe.', 'belongs_user' => 'Este valor está vinculado a um objeto que aparentemente não existe.',
'belongs_user_or_user_group' => 'Este valor está ligado a um objeto que aparentemente não existe na sua administração financeira atual.', 'belongs_user_or_user_group' => 'Este valor está ligado a um objeto que aparentemente não existe na sua administração financeira atual.',
'no_access_group' => 'The user has no access to this user group.', 'no_access_group' => 'O usuário não tem acesso a este grupo de usuários.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.', 'no_accepted_roles_defined' => 'Nenhuma função de acesso foi definida para esta rota, acesso negado.',
'at_least_one_transaction' => 'Precisa de ao menos uma transação.', 'at_least_one_transaction' => 'Precisa de ao menos uma transação.',
'recurring_transaction_id' => 'Precisa de ao menos uma transação.', 'recurring_transaction_id' => 'Precisa de ao menos uma transação.',
'need_id_to_match' => 'Você precisa enviar esta entrada com um ID para a API poder identificá-la.', 'need_id_to_match' => 'Você precisa enviar esta entrada com um ID para a API poder identificá-la.',
@@ -199,7 +199,7 @@ return [
* *
*/ */
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password', 'secure_password' => 'Esta não é uma senha segura. Por favor, tente novamente. Para mais informações, visite https://bit.ly/FF3-password',
'valid_recurrence_rep_type' => 'Tipo de repetição inválido para transações recorrentes.', 'valid_recurrence_rep_type' => 'Tipo de repetição inválido para transações recorrentes.',
'valid_recurrence_rep_moment' => 'Momento de repetição inválido para esse tipo de repetição.', 'valid_recurrence_rep_moment' => 'Momento de repetição inválido para esse tipo de repetição.',
'invalid_account_info' => 'Informação de conta inválida.', 'invalid_account_info' => 'Informação de conta inválida.',
@@ -302,7 +302,7 @@ return [
// no access to administration: // no access to administration:
'no_access_user_group' => 'Você não direitos de acesso suficientes para esta administração.', 'no_access_user_group' => 'Você não direitos de acesso suficientes para esta administração.',
'administration_owner_rename' => 'You can\'t rename your standard administration.', 'administration_owner_rename' => 'Você não pode renomear sua administração padrão.',
]; ];
/* /*

View File

@@ -64,7 +64,7 @@ return [
// 'date_time' => '%B %e, %Y, @ %T', // 'date_time' => '%B %e, %Y, @ %T',
'date_time_js' => 'DD [de] MMMM [de] YYYY, @ HH:mm:ss', 'date_time_js' => 'DD [de] MMMM [de] YYYY, @ HH:mm:ss',
'date_time_fns' => 'DO [de] MMMM YYYY, @ HH:mm:ss', 'date_time_fns' => 'DO [de] MMMM YYYY, @ HH:mm:ss',
'date_time_fns_short' => 'MMMM do, yyyy @ HH:mm', 'date_time_fns_short' => 'do MMMM yyyy @ HH:mm',
// 'specific_day' => '%e %B %Y', // 'specific_day' => '%e %B %Y',
'specific_day_js' => 'D MMMM YYYY', 'specific_day_js' => 'D MMMM YYYY',

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Terminar Sessão', 'logout' => 'Terminar Sessão',
'logout_other_sessions' => 'Terminar todas as outras sessões', 'logout_other_sessions' => 'Terminar todas as outras sessões',
'toggleNavigation' => 'Mostrar/esconder navegação', 'toggleNavigation' => 'Mostrar/esconder navegação',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Pesquisar...', 'searchPlaceholder' => 'Pesquisar...',
'version' => 'Versão', 'version' => 'Versão',
'dashboard' => 'Painel de controlo', 'dashboard' => 'Painel de controlo',

View File

@@ -55,11 +55,11 @@ return [
'reconciled_forbidden_field' => 'Esta transação já está reconciliada, não pode alterar o ":field"', 'reconciled_forbidden_field' => 'Esta transação já está reconciliada, não pode alterar o ":field"',
'deleted_user' => 'Devido a motivos de segurança, não se pode registar com este email.', 'deleted_user' => 'Devido a motivos de segurança, não se pode registar com este email.',
'rule_trigger_value' => 'Este valor é inválido para o gatilho selecionado.', 'rule_trigger_value' => 'Este valor é inválido para o gatilho selecionado.',
'rule_action_expression' => 'Invalid expression. :error', 'rule_action_expression' => 'Expressão inválida. :error',
'rule_action_value' => 'Este valor é inválido para a ação selecionada.', 'rule_action_value' => 'Este valor é inválido para a ação selecionada.',
'file_already_attached' => 'O ficheiro ":name" carregado já está anexado a este objeto.', 'file_already_attached' => 'O ficheiro ":name" carregado já está anexado a este objeto.',
'file_attached' => 'Ficheiro carregado com sucesso ":name".', 'file_attached' => 'Ficheiro carregado com sucesso ":name".',
'file_zero' => 'The file is zero bytes in size.', 'file_zero' => 'O tamanho do ficheiro é nulo.',
'must_exist' => 'O ID no campo :attribute não existe na base de dados.', 'must_exist' => 'O ID no campo :attribute não existe na base de dados.',
'all_accounts_equal' => 'Todas as contas neste campo têm de ser iguais.', 'all_accounts_equal' => 'Todas as contas neste campo têm de ser iguais.',
'group_title_mandatory' => 'Um título de grupo é obrigatório quando existe mais de uma transação.', 'group_title_mandatory' => 'Um título de grupo é obrigatório quando existe mais de uma transação.',
@@ -68,8 +68,8 @@ return [
'invalid_selection' => 'A sua seleção é invalida.', 'invalid_selection' => 'A sua seleção é invalida.',
'belongs_user' => 'Esse valor está ligado a um objeto que parece não existir.', 'belongs_user' => 'Esse valor está ligado a um objeto que parece não existir.',
'belongs_user_or_user_group' => 'Esse valor está ligado a um objeto que parece não existir na sua administração financeira atual.', 'belongs_user_or_user_group' => 'Esse valor está ligado a um objeto que parece não existir na sua administração financeira atual.',
'no_access_group' => 'The user has no access to this user group.', 'no_access_group' => 'O utilizador não tem acesso a este grupo.',
'no_accepted_roles_defined' => 'No access roles have been defined for this endpoint, access denied.', 'no_accepted_roles_defined' => 'Nenhum acesso foi definido para este endpoint, acesso recusado.',
'at_least_one_transaction' => 'Necessita pelo menos de uma transação.', 'at_least_one_transaction' => 'Necessita pelo menos de uma transação.',
'recurring_transaction_id' => 'Precisa de pelo menos uma transação.', 'recurring_transaction_id' => 'Precisa de pelo menos uma transação.',
'need_id_to_match' => 'Precisa de enviar esta entrada com um ID para corresponder com a API.', 'need_id_to_match' => 'Precisa de enviar esta entrada com um ID para corresponder com a API.',
@@ -199,7 +199,7 @@ return [
* *
*/ */
'secure_password' => 'This is not a secure password. Please try again. For more information, visit https://bit.ly/FF3-password', 'secure_password' => 'Palavra-passe não é segura. Por favor, tente novamente. Para mais informações visite https://bit.ly/FF3-password',
'valid_recurrence_rep_type' => 'Tipo de repetição inválido para transações recorrentes.', 'valid_recurrence_rep_type' => 'Tipo de repetição inválido para transações recorrentes.',
'valid_recurrence_rep_moment' => 'Momento inválido para este tipo de repetição.', 'valid_recurrence_rep_moment' => 'Momento inválido para este tipo de repetição.',
'invalid_account_info' => 'Informação de conta inválida.', 'invalid_account_info' => 'Informação de conta inválida.',
@@ -302,7 +302,7 @@ return [
// no access to administration: // no access to administration:
'no_access_user_group' => 'Não tem as permissões de acesso necessárias para esta administração.', 'no_access_user_group' => 'Não tem as permissões de acesso necessárias para esta administração.',
'administration_owner_rename' => 'You can\'t rename your standard administration.', 'administration_owner_rename' => 'Não pode modificar o nome da sua administração padrão.',
]; ];
/* /*

View File

@@ -2144,6 +2144,7 @@ return [
'logout' => 'Ieșire', 'logout' => 'Ieșire',
'logout_other_sessions' => 'Deconectează toate celelalte sesiuni', 'logout_other_sessions' => 'Deconectează toate celelalte sesiuni',
'toggleNavigation' => 'Navigare', 'toggleNavigation' => 'Navigare',
'toggle_dropdown' => 'Toggle dropdown',
'searchPlaceholder' => 'Cautare...', 'searchPlaceholder' => 'Cautare...',
'version' => 'Versiunea', 'version' => 'Versiunea',
'dashboard' => 'Panou de control', 'dashboard' => 'Panou de control',

Some files were not shown because too many files have changed in this diff Show More