diff --git a/app/Helpers/Functions/helpers.php b/app/Helpers/Functions/helpers.php
index 1e7e1dbf87..46ffe93e2c 100644
--- a/app/Helpers/Functions/helpers.php
+++ b/app/Helpers/Functions/helpers.php
@@ -30,8 +30,10 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\AppConfiguration;
use FireflyIII\Support\Facades\Steam;
+use FireflyIII\Support\Search\OperatorQuerySearch;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
use function Safe\mb_ord;
use function Safe\preg_match;
use function Safe\preg_replace_callback;
@@ -53,6 +55,22 @@ if (!function_exists('env_default_when_empty')) {
}
}
+if(!function_exists('parseMarkdown')) {
+ function parseMarkdown(string $string): string {
+ $converter = new GithubFlavoredMarkdownConverter(['allow_unsafe_links' => false, 'max_nesting_level' => 5, 'html_input' => 'escape']);
+
+ return (string) $converter->convert($string);
+ }
+}
+
+if(!function_exists('getRootSearchOperator')) {
+ function getRootSearchOperator(string $operator): string {
+ $result = OperatorQuerySearch::getRootOperator($operator);
+
+ return str_replace('-', 'not_', $result);
+ }
+}
+
if(!function_exists('getAppConfiguration')) {
function getAppConfiguration(string $name, mixed $default = null): mixed {
try {
diff --git a/app/Support/Http/Controllers/PeriodOverview.php b/app/Support/Http/Controllers/PeriodOverview.php
index d0cd6f7c03..9fe656b6af 100644
--- a/app/Support/Http/Controllers/PeriodOverview.php
+++ b/app/Support/Http/Controllers/PeriodOverview.php
@@ -155,6 +155,7 @@ trait PeriodOverview
'revenue' => 'earned',
'transfer' => 'transferred',
'transfers' => 'transferred',
+ 'all' => 'all',
];
if (!array_key_exists($type, $setTypes)) {
throw new FireflyException(sprintf('[c] Cannot deal with type "%s"', $type));
diff --git a/config/firefly.php b/config/firefly.php
index ce28ff1124..832c56aaf9 100644
--- a/config/firefly.php
+++ b/config/firefly.php
@@ -390,6 +390,7 @@ return [
AccountTypeEnum::MORTGAGE->value => AccountTypeEnum::MORTGAGE->value,
],
'transactionTypesByType' => [
+ 'all' => ['Withdrawal','Deposit','Transfer'],
'expenses' => ['Withdrawal'],
'withdrawal' => ['Withdrawal'],
'revenue' => ['Deposit'],
diff --git a/resources/assets/v3/js/pages/rules/index.js b/resources/assets/v3/js/pages/rules/index.js
new file mode 100644
index 0000000000..217ae6c5fb
--- /dev/null
+++ b/resources/assets/v3/js/pages/rules/index.js
@@ -0,0 +1,61 @@
+/*
+ * dashboard.js
+ * Copyright (c) 2026 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 .
+ */
+
+// CSS
+import '../../boot/bootstrap.js';
+import sidebar from '../../pages/shared/sidebar.js';
+import dates from '../shared/dates.js';
+
+let index = function () {
+ return {
+ foo2: 'bar2',
+ init() {
+ console.log('init op index xxx');
+ }
+ }
+};
+
+
+const comps = {
+ index,
+ sidebar,
+ dates
+};
+
+function loadPage(comps) {
+ console.log('loadPage');
+ Object.keys(comps).forEach(comp => {
+ let data = comps[comp]();
+ Alpine.data(comp, () => data);
+ console.log(comp);
+ });
+ Alpine.start();
+}
+
+// wait for load until bootstrapped event is received.
+document.addEventListener('firefly-iii-bootstrapped', () => {
+ console.log('Loaded through event listener.');
+ loadPage(comps);
+});
+// or is bootstrapped before event is triggered.
+if (window.bootstrapped) {
+ console.log('Loaded through window variable.');
+ loadPage(comps);
+}
diff --git a/resources/assets/v3/vite.config.js b/resources/assets/v3/vite.config.js
index 124b5f60e1..e387aa6430 100644
--- a/resources/assets/v3/vite.config.js
+++ b/resources/assets/v3/vite.config.js
@@ -53,6 +53,9 @@ export default defineConfig(({command, mode, isSsrBuild, isPreview}) => {
// budgets
'js/pages/budgets/index.js',
+ // rules
+ 'js/pages/rules/index.js',
+
// subscriptions
'js/pages/subscriptions/index.js',
diff --git a/resources/views/accounts/index.blade.php b/resources/views/accounts/index.blade.php
index 90f05c75f6..b6d2d6ea37 100644
--- a/resources/views/accounts/index.blade.php
+++ b/resources/views/accounts/index.blade.php
@@ -37,9 +37,10 @@
@endif
@if(0 === count($accounts) && 1 === $page)
- TODO TODO TODO TODO
- {% include 'partials.empty' with {objectType: objectType, type: 'accounts',route: route('accounts.create', [objectType])} %}
-
+ @php
+ $shownDemo = true
+ @endphp
+
@if($inactiveCount > 0)
diff --git a/resources/views/components/lists/periods.blade.php b/resources/views/components/lists/periods.blade.php
index b188f2056b..703f4f285f 100644
--- a/resources/views/components/lists/periods.blade.php
+++ b/resources/views/components/lists/periods.blade.php
@@ -14,7 +14,7 @@
@endif
@if(array_key_exists('spent', $period))
@foreach($period['spent'] as $spent)
- @if($spent['amount'] !== 0)
+ @if(is_array($spent) && $spent['amount'] !== 0)
| {{ __('firefly.spent') }} |
@@ -45,7 +45,7 @@
@endforeach
@endif
@foreach($period['transferred'] ?? [] as $entry)
- @if($entry['amount'] !== 0)
+ @if(is_array($entry) && $entry['amount'] !== 0)
|
| {{ __('firefly.transferred') }} |
@@ -58,7 +58,7 @@
@endforeach
@foreach($period['transferred_away'] ?? [] as $entry)
- @if($entry['amount'] !== 0)
+ @if(is_array($entry) && $entry['amount'] !== 0)
|
| {{ __('firefly.transferred_away') }} |
diff --git a/resources/views/components/lists/piggy-banks.blade.php b/resources/views/components/lists/piggy-banks.blade.php
index 2d92587d7b..b820a28bcb 100644
--- a/resources/views/components/lists/piggy-banks.blade.php
+++ b/resources/views/components/lists/piggy-banks.blade.php
@@ -1,6 +1,6 @@
@foreach($piggyBanks as $objectGroupOrder => $objectGroup)
{{ $objectGroup['object_group_title'] }}
-
+
| |
diff --git a/resources/views/components/lists/subscriptions.blade.php b/resources/views/components/lists/subscriptions.blade.php
index 43b01ec86c..dc0818cde8 100644
--- a/resources/views/components/lists/subscriptions.blade.php
+++ b/resources/views/components/lists/subscriptions.blade.php
@@ -1,7 +1,7 @@
@foreach($bills as $objectGroupOrder => $objectGroup)
{{ $objectGroup['object_group_title'] }}
-
+
@endforeach
-Totals
@if(count($totals) > 0)
+Totals
+
@foreach($totals as $sum)
diff --git a/resources/views/rules/index.blade.php b/resources/views/rules/index.blade.php
new file mode 100644
index 0000000000..816a4e4f14
--- /dev/null
+++ b/resources/views/rules/index.blade.php
@@ -0,0 +1,210 @@
+@extends('layout.v3.session')
+@section('content')
+
+@if(1 === count($ruleGroups) && 0 === $ruleGroups[0]->count())
+@php
+$shownDemo = true
+@endphp
+
+@endif
+@foreach($ruleGroups as $ruleGroup)
+
+
+
+
+
+
+ {{ $ruleGroup->description }}
+
+
+ {{ __('firefly.new_rule') }}
+
+
+ @if($ruleGroup->rules->count() > 0)
+
+
+
+ | |
+ |
+ |
+ {{ __('firefly.rule_name') }} |
+ {{ __('firefly.rule_triggers') }} |
+ {{ __('firefly.rule_actions') }} |
+
+
+
+ @foreach($ruleGroup->rules as $rule)
+
+ |
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+ @if($rule->active)
+ {{ $rule->title }}
+ @else
+ {{ $rule->title }} ({{ strtolower(__('firefly.inactive')) }})
+ @endif
+ @if($rule->stop_processing)
+
+ @endif
+ @if('' !== $rule->description)
+ {{ parseMarkdown($rule->description) }}
+ @endif
+ (@if($rule->strict){{ __('firefly.rule_is_strict') }}@else{{ __('firefly.rule_is_not_strict') }}@endif​)
+ |
+
+ @if($rule->ruleTriggers->count() > 0)
+
+ @foreach($rule->ruleTriggers as $trigger)
+ @if('user_action' === $trigger->trigger_type)
+ - active)
+ class="text-muted"
+ @endif
+ data-id="{{ $trigger->id }}">
+ {{ trans(('firefly.rule_trigger_' . getRootSearchOperator($trigger->trigger_type)), ['trigger_value' => $trigger->trigger_value]) }}
+ @if($trigger->stop_processing)
+
+ @endif
+
+ @endif
+ @endforeach
+
+
+ - {{ __('firefly.show_triggers') }}
+
+ @endif
+ |
+
+ @if($rule->ruleActions->count() > 0)
+
+ @foreach($rule->ruleActions as $action)
+ - active)
+ class="text-muted"
+ @endif
+ data-id="{{ $action->id }}">{{ trans(('firefly.rule_action_' . $action->action_type), ['action_value' => $action->action_value]) }}
+ @if($action->stop_processing)
+
+ @endif
+
+ @endforeach
+
+
+ - {{ __('firefly.show_actions') }}
+
+ @endif
+ |
+
+ @endforeach
+
+
+ @else
+
+ {{ __('firefly.no_rules_in_group') }}
+
+ @endif
+
+
+ {{ __('firefly.new_rule') }}
+
+
+
+
+
+@endforeach
+
+ {% include 'rules.partials.test-trigger-modal' %}
+
+
+
+@endsection
+@section('scripts')
+ @vite(['js/pages/rules/index.js'])
+
+
+
+@endsection
diff --git a/resources/views/rules/index.twig b/resources/views/rules/old-index.twig
similarity index 100%
rename from resources/views/rules/index.twig
rename to resources/views/rules/old-index.twig
|