Compare commits

..

26 Commits

Author SHA1 Message Date
github-actions[bot]
c8c4816fe8 Merge pull request #11948 from firefly-iii/release-1773486711
🤖 Automatically merge the PR into the develop branch.
2026-03-14 12:12:01 +01:00
JC5
aa57252b11 🤖 Auto commit for release 'develop' on 2026-03-14 2026-03-14 12:11:52 +01:00
James Cole
58e4c26a87 Fix call to budget repos. 2026-03-14 12:05:45 +01:00
github-actions[bot]
ac323f11c4 Merge pull request #11946 from firefly-iii/release-1773474241
🤖 Automatically merge the PR into the develop branch.
2026-03-14 08:44:10 +01:00
JC5
a907f9b2f7 🤖 Auto commit for release 'develop' on 2026-03-14 2026-03-14 08:44:01 +01:00
James Cole
8abd2a6604 Add text about AI reports. 2026-03-14 08:36:39 +01:00
James Cole
0780390ff6 Update changelog. 2026-03-14 07:46:47 +01:00
James Cole
b9d1ed28a5 Update dev mode settings. 2026-03-14 07:31:16 +01:00
James Cole
b8ebcdf1a8 Remove CSS, only chartJS remains 2026-03-14 06:40:23 +01:00
James Cole
ac8dbbff6c Remove CSS and unused files. 2026-03-14 06:25:11 +01:00
James Cole
fea89c5231 Remove and replace inline styles. 2026-03-14 06:16:53 +01:00
James Cole
654f2ee489 Remove inline CSS 2026-03-14 06:02:40 +01:00
James Cole
5c18624cf9 Fix https://github.com/firefly-iii/firefly-iii/issues/11944 2026-03-14 05:37:30 +01:00
James Cole
27ba8e842a Remove CSS 2026-03-13 20:47:42 +01:00
James Cole
e504ee204a Remove styles. 2026-03-13 20:44:51 +01:00
James Cole
a3a332643c Replace styles with classes. 2026-03-13 20:35:39 +01:00
James Cole
464a89f305 Remove lots of style attributes. 2026-03-13 20:22:50 +01:00
James Cole
062c2323e3 Clean up and expand css styles. 2026-03-13 19:49:56 +01:00
James Cole
a37f995872 Can be returned directly. 2026-03-13 17:36:03 +01:00
James Cole
a5b6315cb8 Clean up transaction link code. 2026-03-13 17:35:39 +01:00
github-actions[bot]
ff568653c8 Merge pull request #11940 from firefly-iii/release-1773385883
🤖 Automatically merge the PR into the develop branch.
2026-03-13 08:11:30 +01:00
JC5
21447a9b2f 🤖 Auto commit for release 'develop' on 2026-03-13 2026-03-13 08:11:23 +01:00
James Cole
238bfc819e Catch a null pointer. 2026-03-13 08:05:04 +01:00
James Cole
3fab4668fc Move copyright. 2026-03-13 04:14:46 +01:00
James Cole
190050d6cf Rate limit mail message. 2026-03-13 04:12:32 +01:00
James Cole
45d623e0c1 Fix some linting issues 2026-03-13 04:05:38 +01:00
173 changed files with 1147 additions and 705 deletions

25
.github/security.md vendored
View File

@@ -3,13 +3,12 @@
Firefly III is an application to manage your personal finances. As such, the developer has adopted this security
disclosure and response policy to ensure that critical issues are responsibly handled.
## Supported Versions
## Supported versions
Only the latest Firefly III release is maintained. Applicable fixes, including security fixes, will not backported to
older release branches. Please refer to [releases.md](https://github.com/firefly-iii/firefly-iii/blob/main/releases.md)
for details.
older release branches. Please refer to [releases.md](https://github.com/firefly-iii/firefly-iii/blob/main/releases.md) for details.
## Reporting a Vulnerability - Private Disclosure Process
## Reporting a vulnerability - private disclosure process
Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be
reported to Firefly III privately, to minimize attacks against current users of Firefly III before they are fixed.
@@ -28,7 +27,7 @@ within 3 business days, including a detailed plan to investigate the issue and a
the meantime. Do not report non-security-impacting bugs through this channel.
Use [GitHub issues](https://github.com/firefly-iii/firefly-iii/issues/new/choose) instead.
### Proposed Email Content
### Proposed email content
Provide a descriptive subject line and in the body of the email include the following information:
@@ -47,7 +46,7 @@ Provide a descriptive subject line and in the body of the email include the foll
* When you know of or suspect a potential vulnerability on another project that is used by Firefly III. For example
Firefly III has a dependency on Docker, MySQL, etc.
## Patch, Release, and Disclosure
## Patch, release, and disclosure
The Firefly III developer will respond to vulnerability reports as follows:
@@ -75,7 +74,7 @@ The Firefly III developer will respond to vulnerability reports as follows:
8. Once the fix is confirmed, the developer will patch the vulnerability in the next patch or minor release. Upon
release of the patched version of Firefly III, we will follow the **Public Disclosure Process**.
### Public Disclosure Process
### Public disclosure process
The developer publishes a public [advisory](https://github.com/firefly-iii/firefly-iii/security/advisories) to the
Firefly III community via GitHub. In most cases, additional communication via Mastodon, Gitter and other channels will
@@ -97,6 +96,18 @@ III to provide a hardened Firefly III environment. We will not act on any securi
safe defaults. Over time, we will work towards improved safe-by-default configuration, taking into account backwards
compatibility.
## Security scanning through automated means
There is some additional guidance for security vulnerabilities or suspected security vulnerabilities that have been
found with the full or partial support of AI coding agents, large language models and other code-scanning tools. Many of
such reports the developer of Firefly III receives are not applicable. This takes time away from responding to
actual security vulnerabilities or suspected security vulnerabilities. If you use automated means to find these in
the Firefly III code base, please take care to:
1. Manually validate the results before you submit a report,
2. explain how the vulnerability can actually be abused by a nefarious third party, and
3. try to limit the verbosity of your report.
## Credits
This security policy is based on [Harbor](https://github.com/goharbor/harbor)'s security policy.

View File

@@ -185,6 +185,8 @@ final class DestroyController extends Controller
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$budgetRepository->destroyAll();
$abRepository->cleanup();
}
private function destroyCategories(): void

View File

@@ -1,10 +1,8 @@
<?php
declare(strict_types=1);
/*
* TriggerController.php
* Copyright (c) 2025 james@firefly-iii.org
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,6 +20,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\Models\Recurrence;
use FireflyIII\Api\V1\Controllers\Controller;

View File

@@ -98,7 +98,7 @@ final class TriggerController extends Controller
$enrichment->setUser($rule->user);
$transactions = $enrichment->enrich($transactions);
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($transactions, $count, 31_337, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rules.test', [$rule->id]).$this->buildParams());
// resulting list is presented as JSON thing.

View File

@@ -105,7 +105,7 @@ final class TriggerController extends Controller
$enrichment->setUser($group->user);
$transactions = $enrichment->enrich($transactions);
$paginator = new LengthAwarePaginator($transactions, $count, 31337, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($transactions, $count, 31_337, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rule-groups.test', [$group->id]).$this->buildParams());
// resulting list is presented as JSON thing.

View File

@@ -32,6 +32,7 @@ use FireflyIII\Support\Facades\Preferences;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
/**
* Class DestroyController
@@ -71,6 +72,12 @@ final class DestroyController extends Controller
if (false === $linkType->editable) {
throw new FireflyException('200020: Link type cannot be changed.');
}
if (false === auth()->user()->hasRole('owner')) {
Log::channel('audit')->warning('Non-owner user tries to delete a link type.');
response()->json([], 401);
}
$this->repository->destroy($linkType);
Preferences::mark();

View File

@@ -81,6 +81,7 @@ final class BasicController extends Controller
$this->accountRepository->setUser($user);
$this->abRepository->setUser($user);
$this->opsRepository->setUser($user);
$this->abRepository->cleanup();
return $next($request);
});

View File

@@ -1,7 +1,5 @@
<?php
declare(strict_types=1);
/*
* BatchController.php
* Copyright (c) 2026 james@firefly-iii.org
@@ -22,6 +20,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers\System;
use FireflyIII\Api\V1\Controllers\Controller;

View File

@@ -1,10 +1,8 @@
<?php
declare(strict_types=1);
/*
* AutocompleteApiRequest.php
* Copyright (c) 2025 james@firefly-iii.org
* Copyright (c) 2026 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
@@ -22,6 +20,8 @@ declare(strict_types=1);
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests\Autocomplete;
use FireflyIII\Api\V1\Requests\AggregateFormRequest;

View File

@@ -45,7 +45,7 @@ class StoreRequest extends FormRequest
public function getAll(): array
{
$active = true;
$order = 31337;
$order = 31_337;
if (null !== $this->get('active')) {
$active = $this->boolean('active');
}

View File

@@ -29,6 +29,8 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
use FireflyIII\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
@@ -92,6 +94,18 @@ class RemovesLinksToDeletedObjects extends Command
if (count($deletedCategories) > 0) {
$this->cleanupCategories($deletedCategories);
}
// count and clean up available budgets in currencies with no budget limits.
// this is not entirely the place for it but OK.
/** @var AvailableBudgetRepositoryInterface $repository */
$repository = app(AvailableBudgetRepositoryInterface::class);
/** @var User $user */
foreach (User::get() as $user) {
$repository->setUser($user);
$repository->cleanup();
}
$this->friendlyNeutral('Validated links to deleted objects.');
}

View File

@@ -75,7 +75,10 @@ class RollbacksSingleMigration extends Command
}
if ($res) {
DB::table('migrations')->where('id', (int) $entry->id)->delete();
DB::table('migrations')
->where('id', (int) $entry->id)
->delete()
;
$this->friendlyInfo(sprintf('Database migration #%d ("%s") is deleted.', $entry->id, $entry->migration));
$this->friendlyLine('');
$this->friendlyLine('Try running "php artisan migrate" now.');

View File

@@ -0,0 +1,79 @@
<?php
/*
* SendTestEmail.php
* 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 <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use FireflyIII\Events\Test\OwnerTestsNotificationChannel;
use FireflyIII\Notifications\Notifiables\OwnerNotifiable;
use FireflyIII\Support\Facades\FireflyConfig;
use Illuminate\Console\Command;
class SendTestEmail extends Command
{
use ShowsFriendlyMessages;
use VerifiesAccessToken;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'firefly-iii:send-test-email
{--user=1 : The user ID.}
{--token= : The user\'s access token.}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Send test email';
/**
* Execute the console command.
*/
public function handle(): int
{
$user = $this->getUser();
if (!$user->hasRole('owner')) {
$this->friendlyError((string) trans('firefly.must_be_owner'));
return Command::FAILURE;
}
/** @var int $lastNotification */
$lastNotification = FireflyConfig::get('last_test_notification', 123)->data;
if ((time() - $lastNotification) < 120) {
$this->friendlyError((string) trans('firefly.test_rate_limited'));
return Command::FAILURE;
}
$owner = new OwnerNotifiable();
event(new OwnerTestsNotificationChannel('email', $owner));
FireflyConfig::set('last_test_notification', time());
return Command::SUCCESS;
}
}

View File

@@ -107,7 +107,10 @@ class RepairsPostgresSequences extends Command
$this->friendlyLine(sprintf('Checking the next id sequence for table "%s".', $tableToCheck));
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
$nextId = DB::table($tableToCheck)
->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))
->first()
;
if (null === $nextId) {
$this->friendlyInfo(sprintf('nextval is NULL for table "%s", go to next table.', $tableToCheck));
@@ -117,7 +120,10 @@ class RepairsPostgresSequences extends Command
if ($nextId->nextval < $highestId->max) {
DB::select(sprintf('SELECT setval(\'%s_id_seq\', %d)', $tableToCheck, $highestId->max));
$highestId = DB::table($tableToCheck)->select(DB::raw('MAX(id)'))->first();
$nextId = DB::table($tableToCheck)->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))->first();
$nextId = DB::table($tableToCheck)
->select(DB::raw(sprintf('nextval(\'%s_id_seq\')', $tableToCheck)))
->first()
;
if ($nextId->nextval > $highestId->max) {
$this->friendlyInfo(sprintf('Table "%s" autoincrement corrected.', $tableToCheck));
}

View File

@@ -219,7 +219,7 @@ class AccountFactory
'user_group_id' => $this->user->user_group_id,
'account_type_id' => $type->id,
'name' => $data['name'],
'order' => 25000,
'order' => 25_000,
'virtual_balance' => $virtualBalance,
'active' => $active,
'iban' => $data['iban'],

View File

@@ -159,7 +159,7 @@ class PiggyBankFactory
}
// no amount set, use previous amount
$toBeLinked[$account->id] = ['current_amount' => $toBeLinked[$account->id]['current_amount']];
$toBeLinked[$account->id] = ['current_amount' => $toBeLinked[$account->id]['current_amount'] ?? '0'];
Log::debug(sprintf('[b] Will link account #%d with amount %s', $account->id, $toBeLinked[$account->id]['current_amount']));
// create event:
@@ -246,7 +246,7 @@ class PiggyBankFactory
$piggyBankData['target_date_tz'] = $piggyBankData['target_date']?->format('e');
$piggyBankData['account_id'] = null;
$piggyBankData['transaction_currency_id'] = $this->getCurrency($data)->id;
$piggyBankData['order'] = 131337;
$piggyBankData['order'] = 131_337;
try {
/** @var PiggyBank $piggyBank */

View File

@@ -124,8 +124,16 @@ final class NotificationController extends Controller
return redirect(route('settings.notification.index'));
}
$all = $request->all();
$channel = $all['test_submit'] ?? '';
/** @var int $lastNotification */
$lastNotification = FireflyConfig::get('last_test_notification', 123)->data;
if ((time() - $lastNotification) < 120) {
session()->flash('error', (string) trans('firefly.test_rate_limited'));
return redirect(route('settings.notification.index'));
}
$all = $request->all();
$channel = $all['test_submit'] ?? '';
switch ($channel) {
default:
@@ -142,6 +150,7 @@ final class NotificationController extends Controller
event(new OwnerTestsNotificationChannel($channel, $owner));
session()->flash('success', (string) trans('firefly.notification_test_executed', ['channel' => $channel]));
}
FireflyConfig::set('last_test_notification', time());
return redirect(route('settings.notification.index'));
}

View File

@@ -33,7 +33,6 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\User;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

View File

@@ -31,7 +31,6 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\Support\Http\Controllers\CreateStuff;
use FireflyIII\User;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\RedirectResponse;

View File

@@ -172,7 +172,7 @@ final class BudgetLimitController extends Controller
// return empty array:
return response()->json([]);
}
if ((int) $amount > 268435456) { // intentional cast to integer
if ((int) $amount > 268_435_456) { // intentional cast to integer
$amount = '268435456';
}
if (-1 === bccomp($amount, '0')) {
@@ -232,7 +232,7 @@ final class BudgetLimitController extends Controller
if ('' === $amount) {
$amount = '0';
}
if ((int) $amount > 268435456) { // 268 million, intentional integer
if ((int) $amount > 268_435_456) { // 268 million, intentional integer
$amount = '268435456';
}
// sanity check on amount:
@@ -254,8 +254,8 @@ final class BudgetLimitController extends Controller
$amount = bcmul($amount, '-1');
}
$notes = (string) $request->get('notes');
if (strlen($notes) > 32768) {
$notes = substr($notes, 0, 32768);
if (strlen($notes) > 32_768) {
$notes = substr($notes, 0, 32_768);
}
$limit = $this->blRepository->update($budgetLimit, ['amount' => $amount, 'notes' => $notes]);

View File

@@ -160,7 +160,7 @@ final class DebugController extends Controller
}
if ('' !== $logContent) {
// last few lines
$logContent = 'Truncated from this point <----|'.substr($logContent, -16384);
$logContent = 'Truncated from this point <----|'.substr($logContent, -16_384);
}
return view('debug', ['table' => $table, 'now' => $now, 'logContent' => $logContent]);

View File

@@ -60,6 +60,7 @@ final class BudgetController extends Controller
$this->abRepository = app(AvailableBudgetRepositoryInterface::class);
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
$this->repository->cleanupBudgets();
$this->abRepository->cleanup();
return $next($request);
});

View File

@@ -26,13 +26,11 @@ namespace FireflyIII\Http\Middleware;
use Closure;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Exceptions\Handler;
use FireflyIII\User;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Factory as Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use League\OAuth2\Server\Exception\OAuthServerException;
/**
* Class Authenticate
@@ -100,7 +98,6 @@ class Authenticate
throw new FireflyException('This point is generally unreachable.');
//
// exit('five');
// foreach ($guards as $guard) {
// exit('six');

View File

@@ -205,7 +205,12 @@ class InterestingMessage
// send message about newly created transaction group.
/** @var null|TransactionGroup $group */
$group = auth()->user()->transactionGroups()->with(['transactionJournals', 'transactionJournals.transactionType'])->find((int) $transactionGroupId);
$group = auth()
->user()
->transactionGroups()
->with(['transactionJournals', 'transactionJournals.transactionType'])
->find((int) $transactionGroupId)
;
if (null === $group) {
return;

View File

@@ -58,8 +58,10 @@ class SecureHeaders
"default-src 'none'",
"object-src 'none'",
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s'", $nonce),
"style-src 'unsafe-inline' 'self'",
// sprintf("style-src 'self' 'nonce-%1s'", $nonce), // safe variant
"style-src 'self' 'unsafe-eval'", // unsafe variant
"base-uri 'self'",
"form-action 'self'",
"font-src 'self' data:",
sprintf("connect-src 'self' %s", $trackingScriptSrc),
sprintf("img-src 'self' data: 'nonce-%1s' ", $nonce),
@@ -71,9 +73,11 @@ class SecureHeaders
$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/",
sprintf("script-src 'unsafe-eval' 'strict-dynamic' 'nonce-%1s'", $nonce),
// sprintf("style-src 'self' 'nonce-%1s' https://10.0.0.15:5173/", $nonce), // safe variant
"style-src 'self' 'unsafe-inline' https://10.0.0.15:5173/", // unsafe variant
"base-uri 'self'",
"form-action '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),
@@ -89,7 +93,7 @@ class SecureHeaders
$customUrl = $logoutUrl;
}
if (null !== $route && 'oauth/authorize' !== $route->uri) {
if ('' !== $customUrl && null !== $route && 'oauth/authorize' !== $route->uri) {
$csp[] = sprintf("form-action 'self' %s", $customUrl);
}

View File

@@ -68,7 +68,7 @@ class ChecksForNewVersion implements ShouldQueue
$now = Carbon::now()->getTimestamp();
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800) {
if ($diff < 604_800) {
Log::debug(sprintf('Checked for updates less than a week ago (on %s).', Carbon::createFromTimestamp($lastCheckTime->data)->format('Y-m-d H:i:s')));
return;
@@ -121,7 +121,7 @@ class ChecksForNewVersion implements ShouldQueue
$now = Carbon::now()->getTimestamp();
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Last warning time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < (604800 * 4)) {
if ($diff < (604_800 * 4)) {
Log::debug(sprintf(
'Warned about updates less than four weeks ago (on %s).',
Carbon::createFromTimestamp($lastCheckTime->data)->format('Y-m-d H:i:s')

View File

@@ -73,7 +73,11 @@ class Preference extends Model
// try again with ID, but this time don't care about the preferred user_group_id
if (null === $preference) {
$preference = $user->preferences()->where('id', (int) $value)->first();
$preference = $user
->preferences()
->where('id', (int) $value)
->first()
;
}
if (null !== $preference) {
/** @var Preference $preference */

View File

@@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;
use Override;
/**

View File

@@ -69,6 +69,21 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
}
$exists[$key] = true;
}
// grab budget limit currencies.
$currencies = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->where('budgets.user_id', $this->user->id)
->distinct()
->get(['budget_limits.transaction_currency_id'])
->pluck('transaction_currency_id')
->toArray()
;
// delete available budgets without these currencies.
$this->user
->availableBudgets()
->whereNotIn('transaction_currency_id', $currencies)
->delete()
;
}
/**

View File

@@ -256,8 +256,14 @@ class BudgetRepository implements BudgetRepositoryInterface, UserGroupInterface
foreach ($budgets as $budget) {
DB::table('budget_transaction')->where('budget_id', $budget->id)->delete();
DB::table('budget_transaction_journal')->where('budget_id', $budget->id)->delete();
RecurrenceTransactionMeta::where('name', 'budget_id')->where('value', (string) $budget->id)->delete();
RuleAction::where('action_type', 'set_budget')->where('action_value', (string) $budget->id)->delete();
RecurrenceTransactionMeta::where('name', 'budget_id')
->where('value', (string) $budget->id)
->delete()
;
RuleAction::where('action_type', 'set_budget')
->where('action_value', (string) $budget->id)
->delete()
;
$budget->delete();
}
Log::channel('audit')->info('Delete all budgets through destroyAll');

View File

@@ -86,7 +86,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
}
// is being used in accounts:
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((string) $currency->id))->count();
$meta = AccountMeta::where('name', 'currency_id')
->where('data', json_encode((string) $currency->id))
->count()
;
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));
@@ -94,7 +97,10 @@ class CurrencyRepository implements CurrencyRepositoryInterface, UserGroupInterf
}
// second search using integer check.
$meta = AccountMeta::where('name', 'currency_id')->where('data', json_encode((int) $currency->id))->count();
$meta = AccountMeta::where('name', 'currency_id')
->where('data', json_encode((int) $currency->id))
->count()
;
if ($meta > 0) {
Log::info(sprintf('Used in %d accounts as currency_id, return true. ', $meta));

View File

@@ -116,8 +116,15 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface, UserGroupInterf
$links = $linkType->transactionJournalLinks()->get(['source_id', 'destination_id']);
$sources = $links->pluck('source_id')->toArray();
$destinations = $links->pluck('destination_id')->toArray();
$joined = array_unique(array_merge($sources, $destinations));
return array_unique(array_merge($sources, $destinations));
return $this->user
->transactionJournals()
->whereIn('id', $joined)
->get(['transaction_journals.id'])
->pluck('id')
->toArray()
;
}
/**

View File

@@ -327,7 +327,7 @@ class RuleRepository implements RuleRepositoryInterface, UserGroupInterface
$rule->userGroup()->associate($this->user->userGroup);
$rule->rule_group_id = $ruleGroup->id;
$rule->order = 31337;
$rule->order = 31_337;
$rule->active = array_key_exists('active', $data) ? $data['active'] : true;
$rule->strict = array_key_exists('strict', $data) ? $data['strict'] : false;
$rule->stop_processing = array_key_exists('stop_processing', $data) ? $data['stop_processing'] : false;

View File

@@ -382,7 +382,7 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface, UserGroupInte
'user_group_id' => $this->user->user_group_id,
'title' => $data['title'],
'description' => $data['description'],
'order' => 31337,
'order' => 31_337,
'active' => array_key_exists('active', $data) ? $data['active'] : true,
]);
$newRuleGroup->save();

View File

@@ -41,7 +41,10 @@ class UserGroupAccount implements BinderInterface
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$account = Account::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
$account = Account::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $account) {
return $account;
}

View File

@@ -41,7 +41,10 @@ class UserGroupBill implements BinderInterface
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$currency = Bill::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
$currency = Bill::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $currency) {
return $currency;
}

View File

@@ -38,7 +38,10 @@ class UserGroupExchangeRate implements BinderInterface
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$rate = CurrencyExchangeRate::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
$rate = CurrencyExchangeRate::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $rate) {
return $rate;
}

View File

@@ -38,7 +38,10 @@ class UserGroupTransaction implements BinderInterface
if (auth()->check()) {
/** @var User $user */
$user = auth()->user();
$group = TransactionGroup::where('id', (int) $value)->where('user_group_id', $user->user_group_id)->first();
$group = TransactionGroup::where('id', (int) $value)
->where('user_group_id', $user->user_group_id)
->first()
;
if (null !== $group) {
return $group;
}

View File

@@ -35,7 +35,7 @@ abstract class AbstractCronjob
public bool $jobFired = false;
public bool $jobSucceeded = false;
public ?string $message = null;
public int $timeBetweenRuns = 43200;
public int $timeBetweenRuns = 43_200;
protected Carbon $date;
protected bool $force = false;

View File

@@ -47,7 +47,7 @@ class AutoBudgetCronjob extends AbstractCronjob
Log::info('Auto budget cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
if ($lastTime > 0 && $diff <= 43_200) {
Log::info(sprintf('It has been %s since the auto budget cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The auto budget cron-job will not fire now.');
@@ -58,7 +58,7 @@ class AutoBudgetCronjob extends AbstractCronjob
Log::info('Execution of the auto budget cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
if ($lastTime > 0 && $diff > 43_200) {
Log::info(sprintf('It has been %s since the auto budget cron-job has fired. It will fire now!', $diffForHumans));
}

View File

@@ -54,7 +54,7 @@ class BillWarningCronjob extends AbstractCronjob
Log::info('The bill notification cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
if ($lastTime > 0 && $diff <= 43_200) {
Log::info(sprintf('It has been %s since the bill notification cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The cron-job will not fire now.');
@@ -69,7 +69,7 @@ class BillWarningCronjob extends AbstractCronjob
Log::info('Execution of the bill notification cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
if ($lastTime > 0 && $diff > 43_200) {
Log::info(sprintf('It has been %s since the bill notification cron-job has fired. It will fire now!', $diffForHumans));
}

View File

@@ -47,7 +47,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
Log::info('Exchange rates cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
if ($lastTime > 0 && $diff <= 43_200) {
Log::info(sprintf('It has been %s since the exchange rates cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The exchange rates cron-job will not fire now.');
@@ -59,7 +59,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
Log::info('Execution of the exchange rates cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
if ($lastTime > 0 && $diff > 43_200) {
Log::info(sprintf('It has been %s since the exchange rates cron-job has fired. It will fire now!', $diffForHumans));
}

View File

@@ -54,7 +54,7 @@ class RecurringCronjob extends AbstractCronjob
Log::info('Recurring transactions cron-job has never fired before.');
}
// less than half a day ago:
if ($lastTime > 0 && $diff <= 43200) {
if ($lastTime > 0 && $diff <= 43_200) {
Log::info(sprintf('It has been "%s" since the recurring transactions cron-job has fired.', $diffForHumans));
if (false === $this->force) {
Log::info('The cron-job will not fire now.');
@@ -68,7 +68,7 @@ class RecurringCronjob extends AbstractCronjob
Log::info('Execution of the recurring transaction cron-job has been FORCED.');
}
if ($lastTime > 0 && $diff > 43200) {
if ($lastTime > 0 && $diff > 43_200) {
Log::info(sprintf('It has been "%s" since the recurring transactions cron-job has fired. It will fire now!', $diffForHumans));
}

View File

@@ -60,7 +60,7 @@ class UpdateCheckCronjob extends AbstractCronjob
$now = Carbon::now()->getTimestamp();
$diff = $now - $lastCheckTime->data;
Log::debug(sprintf('Last check time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
if ($diff < 604800 && false === $this->force) {
if ($diff < 604_800 && false === $this->force) {
// get stuff from job:
$this->jobFired = false;
$this->jobErrored = false;

View File

@@ -221,7 +221,7 @@ trait GetConfigurationData
return;
}
if (($now - $lastTime) > 129600) {
if (($now - $lastTime) > 129_600) {
request()->session()->flash('warning', trans('firefly.recurring_cron_long_ago'));
}
}

View File

@@ -111,6 +111,7 @@ class AvailableBudgetCalculator
$viewRange = Preferences::getForUser($this->user, 'viewRange', '1M')->data;
$viewRange = !is_string($viewRange) ? '1M' : $viewRange;
$this->viewRange = $this->correctViewRange($viewRange);
$this->abRepository->cleanup();
}
private function correctViewRange(string $viewRange): string

View File

@@ -48,7 +48,10 @@ class AppendNotes implements ActionInterface
public function actOnArray(array $journal): bool
{
$this->refreshNotes($journal);
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])->where('noteable_type', TransactionJournal::class)->first(['notes.*']);
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])
->where('noteable_type', TransactionJournal::class)
->first(['notes.*'])
;
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];

View File

@@ -44,7 +44,10 @@ class PrependNotes implements ActionInterface
public function actOnArray(array $journal): bool
{
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])->where('noteable_type', TransactionJournal::class)->first(['notes.*']);
$dbNote = Note::where('noteable_id', (int) $journal['transaction_journal_id'])
->where('noteable_type', TransactionJournal::class)
->first(['notes.*'])
;
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable_id = (int) $journal['transaction_journal_id'];

View File

@@ -255,7 +255,7 @@ class SearchRuleEngine implements RuleEngineInterface
$searchEngine = app(SearchInterface::class);
$searchEngine->setUser($this->user);
$searchEngine->setPage(1);
$searchEngine->setLimit(31337);
$searchEngine->setLimit(31_337);
foreach ($searchArray as $type => $value) {
$searchEngine->parseQuery(sprintf('%s:%s', $type, $value));
@@ -345,7 +345,7 @@ class SearchRuleEngine implements RuleEngineInterface
$searchEngine = app(SearchInterface::class);
$searchEngine->setUser($this->user);
$searchEngine->setPage(1);
$searchEngine->setLimit(31337);
$searchEngine->setLimit(31_337);
$searchEngine->setDate($date);
Log::debug('Search array', $searchArray);

View File

@@ -72,7 +72,7 @@ trait ValidatesAutoBudgetRequest
$validator->errors()->add('auto_budget_amount', (string) trans('validation.require_currency_info'));
}
// too big amount
if ((int) $amount > 268435456) {
if ((int) $amount > 268_435_456) {
$validator->errors()->add('auto_budget_amount', (string) trans('validation.amount_required_for_auto_budget'));
}
}

View File

@@ -355,7 +355,11 @@ trait RecurrenceValidation
}
if (array_key_exists('id', $transaction)) { // don't matter if $idsMandatory
Log::debug('Array has ID.');
$idCount = $recurrence->recurrenceTransactions()->where('recurrences_transactions.id', (int) $transaction['id'])->count();
$idCount = $recurrence
->recurrenceTransactions()
->where('recurrences_transactions.id', (int) $transaction['id'])
->count()
;
if (0 === $idCount) {
Log::debug('ID does not exist or no match. Count another unmatched ID.');
++$unmatchedIds;

View File

@@ -3,33 +3,34 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## x.x.x - 20xx-xx-xx
## 6.5.5 - 2026-03-15
<!-- summary: If you can read this I forgot to update the summary! -->
<!-- summary: This release takes note of some security issues, and fixes interesting bugs. -->
### Added
- Initial release.
- Add the ability for Fosstodon posts to read a summary of the changelog.
### Changed
- Initial release.
### Deprecated
- Initial release.
### Removed
- Initial release.
- Lots of code cleanup and small quality issues fixed.
### Fixed
- Initial release.
- [Discussion 11879](https://github.com/orgs/firefly-iii/discussions/11879) (Searching for accounts should include inactive accounts?) started by @b-ryan
- [Issue 11916](https://github.com/firefly-iii/firefly-iii/issues/11916) (Balance is not recalculated when multiple transactions are selected and then deleted) reported by @elp3dr0
- [Discussion 11936](https://github.com/orgs/firefly-iii/discussions/11936) (Links in emails don't link to correct domain) started by @SamLMB
- [Issue 11944](https://github.com/firefly-iii/firefly-iii/issues/11944) (Stale available_budgets rows prevent disabling a currency after switching default) reported by @k-leveller
### Security
- Enum thing in rule engine, reported by basically all users with preview access to the new Claude code security scanner
> [!NOTE]
> A lot of people have access to the new Claude model that has enhanced code scanning capabilities. Many new issues are being reported through (semi-)automated means. I will update the security policy to reflect this. The following security related issues no longer need reporting:
- It is possible to point webhooks to private or internal IPs.
- You can see all transaction link types. If you are an owner, you can also delete them.
- `unsafe-inline` is allowed for CSS, which means you can overrule the layout if you manage to get CSS on the page.
- You can make the rule engine print internal enums.
### API

View File

@@ -78,8 +78,8 @@ return [
'running_balance_column' => (bool)envDefaultWhenEmpty(env('USE_RUNNING_BALANCE'), true), // this is only the default value, is not used.
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2026-03-13',
'build_time' => 1773370359,
'version' => 'develop/2026-03-14',
'build_time' => 1773486518,
'api_version' => '2.1.0', // field is no longer used.
'db_version' => 28, // field is no longer used.

View File

@@ -22,6 +22,267 @@
.no-margin-pagination {padding-bottom:0;padding-top:0;}
.no-margin-pagination ul.pagination {margin:0 !important;}
/* date range */
.date-range-holder {color:#fff;padding: 15px;display: block;line-height: 20px;}
.dropdown-holder {cursor:default;color:#fff;padding: 15px;display: block;line-height: 20px;}
/** new classes because of CSP */
.wide-chart {width:100%;height:400px;}
.low-chart {width:100%;height:200px;}
.medium-chart {width:100%;height:250px;}
.center-chart {width:100%;margin:0 auto;}
.map-size {width:100%;height:300px;}
/* install box border */
.install-box-border {border:1px #ddd solid;}
.install-box-title {font-family: monospace;font-size:16pt;}
/* some borders and lines */
.top-light-border {border-top:1px #aaa solid;}
.top-dark-border {border-top:1px #777 solid;}
.bottom-light-border {border-bottom:1px #aaa solid;}
/* misc */
.calendar-display {max-width: 400px;margin: 0 auto;}
.empty-high-block {height:400px;}
.fw-normal {font-weight: normal;}
.position-relative {position: relative;}
.pointer {cursor:pointer;}
.big-line {line-height:1.7em;}
.bold-label {font-weight: normal;font-size:0.9em;}
/** tables **/
th.five {width:5%;}
th.ten {width:10%;}
th.fifteen td.fifteen {width:15%;}
td.twenty th.twenty {width:25%;}
td.onetwenty {width:120px;}
td.quarter th.quarter {width:25%;}
td.thirty th.thirty {width:30%;}
td.third th.third {width:33%;}
td.forty th.forty {width:40%;}
td.half th.half {width:50%;}
td.sixty-six th.sixty-six {width:66%;}
td.twenty-px {width:20px;}
td.forty-px {width:40px;}
td.sixty-px {width:60px;}
td.hundred-px {width:100px;}
/** width for progress bar **/
.width-0 {width:0;}
.width-1 {width:1%;}
.width-2 {width:2%;}
.width-3 {width:3%;}
.width-4 {width:4%;}
.width-5 {width:5%;}
.width-6 {width:6%;}
.width-7 {width:7%;}
.width-8 {width:8%;}
.width-9 {width:9%;}
.width-10 {width:10%;}
.width-11 {width:11%;}
.width-12 {width:12%;}
.width-13 {width:13%;}
.width-14 {width:14%;}
.width-15 {width:15%;}
.width-16 {width:16%;}
.width-17 {width:17%;}
.width-18 {width:18%;}
.width-19 {width:19%;}
.width-20 {width:20%;}
.width-21 {width:21%;}
.width-22 {width:22%;}
.width-23 {width:23%;}
.width-24 {width:24%;}
.width-25 {width:25%;}
.width-26 {width:26%;}
.width-27 {width:27%;}
.width-28 {width:28%;}
.width-29 {width:29%;}
.width-30 {width:30%;}
.width-31 {width:31%;}
.width-32 {width:32%;}
.width-33 {width:33%;}
.width-34 {width:34%;}
.width-35 {width:35%;}
.width-36 {width:36%;}
.width-37 {width:37%;}
.width-38 {width:38%;}
.width-39 {width:39%;}
.width-40 {width:40%;}
.width-41 {width:41%;}
.width-42 {width:42%;}
.width-43 {width:43%;}
.width-44 {width:44%;}
.width-45 {width:45%;}
.width-46 {width:46%;}
.width-47 {width:47%;}
.width-48 {width:48%;}
.width-49 {width:49%;}
.width-50 {width:50%;}
.width-51 {width:51%;}
.width-52 {width:52%;}
.width-53 {width:53%;}
.width-54 {width:54%;}
.width-55 {width:55%;}
.width-56 {width:56%;}
.width-57 {width:57%;}
.width-58 {width:58%;}
.width-59 {width:59%;}
.width-60 {width:60%;}
.width-61 {width:61%;}
.width-62 {width:62%;}
.width-63 {width:63%;}
.width-64 {width:64%;}
.width-65 {width:65%;}
.width-66 {width:66%;}
.width-67 {width:67%;}
.width-68 {width:68%;}
.width-69 {width:69%;}
.width-70 {width:70%;}
.width-71 {width:71%;}
.width-72 {width:72%;}
.width-73 {width:73%;}
.width-74 {width:74%;}
.width-75 {width:75%;}
.width-76 {width:76%;}
.width-77 {width:77%;}
.width-78 {width:78%;}
.width-79 {width:79%;}
.width-80 {width:80%;}
.width-81 {width:81%;}
.width-82 {width:82%;}
.width-83 {width:83%;}
.width-84 {width:84%;}
.width-85 {width:85%;}
.width-86 {width:86%;}
.width-87 {width:87%;}
.width-88 {width:88%;}
.width-89 {width:89%;}
.width-90 {width:90%;}
.width-91 {width:91%;}
.width-92 {width:92%;}
.width-93 {width:93%;}
.width-94 {width:94%;}
.width-95 {width:95%;}
.width-96 {width:96%;}
.width-97 {width:97%;}
.width-98 {width:98%;}
.width-99 {width:99%;}
.width-100 {width:100%;}
/* spacing and padding */
.m-0 { margin:0!important; }
.m-1 { margin:.25rem!important; }
.m-2 { margin:.5rem !important; }
.m-3 { margin:1rem !important; }
.m-4 { margin:1.5rem !important; }
.m-5 { margin:3rem!important; }
.mt-0 { margin-top:0!important; }
.mr-0 { margin-right:0!important; }
.mb-0 { margin-bottom:0!important; }
.ml-0 { margin-left:0!important; }
.mx-0 { margin-left:0 !important;margin-right:0!important; }
.my-0 { margin-top:0 !important;margin-bottom:0!important; }
.mt-1 { margin-top:.25rem!important; }
.mr-1 { margin-right:.25rem!important; }
.mb-1 { margin-bottom:.25rem!important; }
.ml-1 { margin-left:.25rem!important; }
.mx-1 { margin-left:.25rem!important;margin-right:.25rem!important; }
.my-1 { margin-top:.25rem!important;margin-bottom:.25rem!important; }
.mt-2 { margin-top:.5rem!important; }
.mr-2 { margin-right:.5rem!important; }
.mb-2 { margin-bottom:.5rem!important; }
.ml-2 { margin-left:.5rem!important; }
.mx-2 { margin-right:.5rem!important;margin-left:.5rem!important; }
.my-2 { margin-top:.5rem!important;margin-bottom:.5rem!important; }
.mt-3 { margin-top:1rem!important; }
.mr-3 { margin-right:1rem!important; }
.mb-3 { margin-bottom:1rem!important; }
.ml-3 { margin-left:1rem!important; }
.mx-3 { margin-right:1rem!important;margin-left:1rem!important; }
.my-3 { margin-bottom:1rem!important;margin-top:1rem!important; }
.mt-4 { margin-top:1.5rem!important; }
.mr-4 { margin-right:1.5rem!important; }
.mb-4 { margin-bottom:1.5rem!important; }
.ml-4 { margin-left:1.5rem!important; }
.mx-4 { margin-right:1.5rem!important;margin-left:1.5rem!important; }
.my-4 { margin-top:1.5rem!important;margin-bottom:1.5rem!important; }
.mt-5 { margin-top:3rem!important; }
.mr-5 { margin-right:3rem!important; }
.mb-5 { margin-bottom:3rem!important; }
.ml-5 { margin-left:3rem!important; }
.mx-5 { margin-right:3rem!important;margin-left:3rem!important; }
.my-5 { margin-top:3rem!important;margin-bottom:3rem!important; }
.mt-auto { margin-top:auto!important; }
.mr-auto { margin-right:auto!important; }
.mb-auto { margin-bottom:auto!important; }
.ml-auto { margin-left:auto!important; }
.mx-auto { margin-right:auto!important;margin-left:auto!important; }
.my-auto { margin-bottom:auto!important;margin-top:auto!important; }
.p-0 { padding:0!important; }
.p-1 { padding:.25rem!important; }
.p-2 { padding:.5rem!important; }
.p-3 { padding:1rem!important; }
.p-4 { padding:1.5rem!important; }
.p-5 { padding:3rem!important; }
.pt-0 { padding-top:0!important; }
.pr-0 { padding-right:0!important; }
.pb-0 { padding-bottom:0!important; }
.pl-0 { padding-left:0!important; }
.px-0 { padding-left:0!important;padding-right:0!important; }
.py-0 { padding-top:0!important;padding-bottom:0!important; }
.pt-1 { padding-top:.25rem!important; }
.pr-1 { padding-right:.25rem!important; }
.pb-1 { padding-bottom:.25rem!important; }
.pl-1 { padding-left:.25rem!important; }
.px-1 { padding-left:.25rem!important;padding-right:.25rem!important; }
.py-1 { padding-top:.25rem!important;padding-bottom:.25rem!important; }
.pt-2 { padding-top:.5rem!important; }
.pr-2 { padding-right:.5rem!important; }
.pb-2 { padding-bottom:.5rem!important; }
.pl-2 { padding-left:.5rem!important; }
.px-2 { padding-right:.5rem!important;padding-left:.5rem!important; }
.py-2 { padding-top:.5rem!important;padding-bottom:.5rem!important; }
.pt-3 { padding-top:1rem!important; }
.pr-3 { padding-right:1rem!important; }
.pb-3 { padding-bottom:1rem!important; }
.pl-3 { padding-left:1rem!important; }
.py-3 { padding-bottom:1rem!important;padding-top:1rem!important; }
.px-3 { padding-right:1rem!important;padding-left:1rem!important; }
.pt-4 { padding-top:1.5rem!important; }
.pr-4 { padding-right:1.5rem!important; }
.pb-4 { padding-bottom:1.5rem!important; }
.pl-4 { padding-left:1.5rem!important; }
.px-4 { padding-right:1.5rem!important;padding-left:1.5rem!important; }
.py-4 { padding-top:1.5rem!important;padding-bottom:1.5rem!important; }
.pt-5 { padding-top:3rem!important; }
.pr-5 { padding-right:3rem!important; }
.pb-5 { padding-bottom:3rem!important; }
.pl-5 { padding-left:3rem!important; }
.px-5 { padding-right:3rem!important;padding-left:3rem!important; }
.py-5 { padding-top:3rem!important;padding-bottom:3rem!important; }
/* TODO find out where this is used. */
input.ti-new-tag-input {
font-size: 14px !important;

View File

@@ -25,6 +25,10 @@ $(function () {
lineChart('chart/piggy-bank/' + piggyBankID, 'piggy-bank-history');
}
$('.confirm-history-delete').click(function() {
return confirm(confirmText);
});
// on submit of logout button:
$('.reset-link').click(function(e) {
console.log('here we are');

View File

@@ -22,4 +22,7 @@
$(function () {
"use strict";
$('.confirm-tag-delete').on('click', function() {
return confirm(confirmText);
});
});

View File

@@ -197,6 +197,7 @@ return [
'journals_in_period_for_category' => 'All transactions for category :name between :start and :end',
'journals_in_period_for_tag' => 'All transactions for tag :tag between :start and :end',
'not_available_demo_user' => 'The feature you try to access is not available to demo users.',
'test_rate_limited' => 'Please wait a moment before trying again',
'exchange_rate_instructions' => 'Asset account "@name" only accepts transactions in @primary_currency. If you wish to use @foreign_currency instead, make sure that the amount in @primary_currency is known as well:',
'transfer_exchange_rate_instructions' => 'Source asset account "@source_name" only accepts transactions in @source_currency. Destination asset account "@dest_name" only accepts transactions in @dest_currency. You must provide the transferred amount correctly in both currencies.',
'transaction_data' => 'Transaction data',
@@ -1526,6 +1527,7 @@ return [
'administration_role_mng_currencies' => 'Manage currencies',
'administration_role_view_reports' => 'View reports',
'administration_role_full' => 'Full access',
'must_be_owner' => 'You must be system owner to do this',
// mfa
'enable_mfa' => 'Enable multi-factor authentication',

View File

@@ -26,12 +26,10 @@
</div>
<div class="box-body no-padding">
<div style="padding:8px;">
<div class="m-1">
<a href="{{ route('accounts.create', objectType) }}" class="btn btn-success"><span class="fa fa-plus fa-fw"></span> {{ ('make_new_' ~ objectType ~ '_account')|_ }}</a>
</div>
{% include 'list.accounts' %}
</div>
<div class="box-footer">

View File

@@ -16,22 +16,22 @@
<table class="table table-hover">
<thead>
<tr>
<th colspan="2" style="width:50%;">{{ 'start_balance'|_ }}</th>
<th colspan="2" class="half">{{ 'start_balance'|_ }}</th>
<th colspan="2">{{ 'end_balance'|_ }}</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width:25%;">
<td class="quarter">
{{ 'date'|_ }}
</td>
<td style="width:25%;">
<td class="quarter">
{{ 'balance'|_ }}
</td>
<td style="width:25%;">
<td class="quarter">
{{ 'date'|_ }}
</td>
<td style="width:25%;">
<td class="quarter">
{{ 'balance'|_ }}
</td>
</tr>
@@ -72,16 +72,16 @@
<div class="update_balance_instruction">
{{ 'update_balance_dates_instruction'|_ }}
</div>
<div class="select_transactions_instruction" style="display:none;">
<div class="select_transactions_instruction hidden">
{{ 'select_transactions_instruction'|_ }}
</div>
<div class="date_change_warning text-danger" style="display:none;">
<div class="date_change_warning text-danger hidden">
{{ 'date_change_instruction'|_ }}
</div>
</td>
<td>
<a href="#" class="btn btn-default start_reconcile">{{ 'start_reconcile'|_ }}</a>
<a href="#" class="btn btn-default change_date_button" style="display: none;">{{ 'update_selection'|_ }}</a>
<a href="#" class="btn btn-default change_date_button hidden">{{ 'update_selection'|_ }}</a>
</td>
</tr>
</tfoot>

View File

@@ -8,7 +8,7 @@
</h4>
</div>
<form style="display: inline;" class="form-horizontal" id="income" action="{{ route }}" method="POST">
<form class="form-horizontal inline" id="income" action="{{ route }}" method="POST">
<div class="modal-body">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<input type="hidden" name="start" value="{{ start.format('Y-m-d') }}"/>

View File

@@ -43,7 +43,7 @@
</td>
</tr>
<tr>
<td style="width:30%;">{{ trans('list.date') }}</td>
<td class="thirty">{{ trans('list.date') }}</td>
<td>{{ journal.date.isoFormat(monthAndDayFormat) }}</td>
</tr>
</tbody>
@@ -81,7 +81,7 @@
<td>
{% for tag in journal.tags %}
<h4 style="display: inline;"><a class="label label-success" href="{{ route('tags.show',tag) }}">
<h4 class="inline"><a class="label label-success" href="{{ route('tags.show',tag) }}">
{% if tag.tag_mode == 'nothing' %}
<span class="fa fa-fw fa-tag"></span>
{% endif %}

View File

@@ -3,7 +3,7 @@
<tr class="ignore">
<th class="hidden-xs" colspan="2">&nbsp;</th>
<th>{{ trans('list.description') }}</th>
<th style="text-align:right;">{{ trans('list.amount') }}</th>
<th class="text-right">{{ trans('list.amount') }}</th>
<th class="hidden-xs hidden-sm hidden-md">{{ trans('list.reconcile') }}</th>
<th class="hidden-xs hidden-sm">{{ trans('list.date') }}</th>
<th class="hidden-xs hidden-sm hidden-md">{{ trans('list.from') }}</th>
@@ -100,8 +100,8 @@
{{ journal.description }}</a>
</td>
<td style="text-align: right;">
<span style="margin-right:5px;">
<td class="text-right">
<span class="mr-1">
{{ formatAmountBySymbol(journal.amount, journal.currency_symbol, journal.currency_decimal_places) }}
{% if null != journal.foreign_amount %}
({{ formatAmountBySymbol(journal.foreign_amount, journal.foreign_currency_symbol, journal.foreign_currency_decimal_places) }})

View File

@@ -39,7 +39,7 @@
</div>
<div class="box-body">
<div>
<canvas id="overview-chart" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="overview-chart" class="wide-chart" height="400" width="100%"></canvas>
</div>
</div>
</div>
@@ -81,8 +81,8 @@
<h3 class="box-title">{{ 'expenses_by_category'|_ }}</h3>
</div>
<div class="box-body">
<div style="width:100%;margin:0 auto;">
<canvas id="account-cat-out" style="width:100%;height:250px;" height="250"></canvas>
<div class="center-chart">
<canvas id="account-cat-out" class="medium-chart" height="250"></canvas>
</div>
</div>
</div>
@@ -93,8 +93,8 @@
<h3 class="box-title">{{ 'expenses_by_budget'|_ }}</h3>
</div>
<div class="box-body">
<div style="width:100%;margin:0 auto;">
<canvas id="account-budget-out" style="width:100%;height:250px;" height="250"></canvas>
<div class="center-chart">
<canvas id="account-budget-out" class="medium-chart" height="250"></canvas>
</div>
</div>
</div>
@@ -105,8 +105,8 @@
<h3 class="box-title">{{ 'income_by_category'|_ }}</h3>
</div>
<div class="box-body">
<div style="width:100%;margin:0 auto;">
<canvas id="account-cat-in" style="width:100%;height:250px;" height="250"></canvas>
<div class="center-chart">
<canvas id="account-cat-in" class="medium-chart" height="250"></canvas>
</div>
</div>
</div>
@@ -122,7 +122,7 @@
<h3 class="box-title">{{ 'location'|_ }}</h3>
</div>
<div class="box-body">
<div id="location_map" style="width:100%;height:300px;"></div>
<div id="location_map" class="map-size"></div>
</div>
</div>
</div>

View File

@@ -23,7 +23,7 @@
</div>
</div>
<div class="box-body no-padding">
<div style="padding:8px;">
<div class="m-1">
<a class="btn btn-success" href="{{ route('subscriptions.create') }}"><span class="fa fa-plus fa-fw"></span> {{ 'create_new_bill'|_ }}</a>
</div>
{% include 'list/bills' %}

View File

@@ -42,7 +42,7 @@
</tr>
<tr>
<td style="width:50%;">{{ 'bill_is_active'|_ }}</td>
<td class="half">{{ 'bill_is_active'|_ }}</td>
<td>
{% if object.data.active %}
<span class="fa fa-check fa-fw" title="{{ 'active'|_ }}"></span> {{ 'yes'|_ }}
@@ -162,7 +162,7 @@
<h3 class="box-title">{{ 'chart'|_ }}</h3>
</div>
<div class="box-body">
<canvas id="bill-overview" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="bill-overview" class="wide-chart" height="400" width="100%"></canvas>
</div>
</div>
</div>

View File

@@ -9,7 +9,7 @@
</h4>
</div>
<form style="display: inline;" id="income" action="{{ route('budget-limits.store') }}" method="POST">
<form class="inline" id="income" action="{{ route('budget-limits.store') }}" method="POST">
<div class="modal-body">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<input type="hidden" name="start" value="{{ start.format('Y-m-d') }}"/>

View File

@@ -8,7 +8,7 @@
</h4>
</div>
<form style="display: inline;" action="{{ route('budget-limits.update', [budgetLimit.id]) }}" method="POST">
<form class="inline" action="{{ route('budget-limits.update', [budgetLimit.id]) }}" method="POST">
<div class="modal-body">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
<input type="hidden" name="redirect" value="true"/>

View File

@@ -24,7 +24,7 @@
</select>
</div>
<div class="col-lg-8 col-md-4 col-sm-12 col-xs-12 text-center">
<div class="btn btn-group btn-group-lg" style="padding-top:0;">
<div class="btn btn-group btn-group-lg pt-0">
<a href="{{ route('budgets.index', [prevLoop[0].start.format('Y-m-d'), prevLoop[0].end.format('Y-m-d')]) }}"
class="btn btn-default" title="{{ prevLoop[0].title }}">&larr;</a>
<a title="{{ start.isoFormat(monthAndDayFormat) }} - {{ end.isoFormat(monthAndDayFormat) }}"
@@ -71,7 +71,7 @@
</small>
</div>
{# info about the amount spent #}
<div class="col-lg-9 col-md-9 col-sm-9 col-xs-9" style="text-align:right;margin-bottom:3px;">
<div class="col-lg-9 col-md-9 col-sm-9 col-xs-9 text-right mb-1">
<small class="available_bar"
data-id="0">{{ trans('firefly.available_between', {start: start.isoFormat(monthAndDayFormat), end: end.isoFormat(monthAndDayFormat) }) }}
:
@@ -123,7 +123,7 @@
</small>
</div>
{# info about the amount spent #}
<div class="col-lg-9 col-md-9 col-sm-9 col-xs-9" style="text-align:right;margin-bottom:3px;">
<div class="col-lg-9 col-md-9 col-sm-9 col-xs-9 text-right mb-1">
<small class="available_bar"
data-id="{{ budget.id }}">{{ trans('firefly.available_between', {start: budget.start_date.isoFormat(monthAndDayFormat), end: budget.end_date.isoFormat(monthAndDayFormat) }) }}
:
@@ -146,17 +146,17 @@
{# red: the exact amount of the available budget, if more has budgeted. #}
<div class="progress-bar progress-bar-danger" data-id="{{ budget.id }}" role="progressbar" aria-valuenow="10"
aria-valuemin="0"
aria-valuemax="100" style="width: 0;"></div>
aria-valuemax="100"></div>
{# orange: overbudgeted amount #}
<div class="progress-bar progress-bar-warning" data-id="{{ budget.id }}" role="progressbar" aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100" style="width: 0;"></div>
aria-valuemax="100"></div>
{# budgeted amount if enough or les #}
<div class="progress-bar progress-bar-info" data-id="{{ budget.id }}" role="progressbar" aria-valuenow="0"
aria-valuemin="0"
aria-valuemax="100" style="width: 0;"></div>
aria-valuemax="100"></div>
</div>
</div>
</div>
@@ -179,12 +179,9 @@
<div class="progress spent_bar" data-id="{{ budget.id }}" data-budgeted="{{ budget.budgeted }}"
data-spent="{{ budget.spent }}">
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="0" aria-valuemin="0"
aria-valuemax="100"
style="width: 0;"></div>
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"
style="width: 0;"></div>
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"
style="width: 0;"></div>
aria-valuemax="100"></div>
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
@@ -207,15 +204,15 @@
<h3 class="box-title">{{ 'budgets'|_ }}</h3>
</div>
<div class="box-body no-padding">
<div style="padding:8px;">
<div class="m-1">
<a href="{{ route('budgets.create') }}" class="btn btn-success"><span class="fa fa-plus fa-fw"></span> {{ 'createBudget'|_ }}</a>
</div>
<table class="table table-bordered sortable-table table-striped sortable" id="budgetList">
<thead>
<tr>
<th class="hidden-sm hidden-xs" style="width:10%;">&nbsp;</th>
<th class="hidden-sm hidden-xs ten">&nbsp;</th>
<th>{{ 'budget'|_ }}</th>
<th style="width:25%;">{{ 'budgeted'|_ }}</th>
<th class="quarter">{{ 'budgeted'|_ }}</th>
<th class="hidden-sm hidden-xs">{{ 'spent'|_ }} ({{ 'per_day'|_|lower }})</th>
<th>{{ 'left'|_ }} ({{ 'per_day'|_|lower }})</th>
</tr>
@@ -276,8 +273,8 @@
---
{% endif %}
</div>
<span class="text-danger budget_warning" data-id="{{ budget.id }}" data-budgetLimit="{{ budgetLimit.id }}"
style="display:none;"></span>
<span class="hidden text-danger budget_warning" data-id="{{ budget.id }}" data-budgetLimit="{{ budgetLimit.id }}"
></span>
{% endif %}
{% if budget.budgeted|length > 0 %}
{% for budgetLimit in budget.budgeted %}
@@ -313,8 +310,8 @@
{% endif %}
</div>
</div>
<span class="text-danger budget_warning" data-id="{{ budget.id }}" data-budgetLimit="{{ budgetLimit.id }}"
style="display:none;"></span>
<span class="hidden text-danger budget_warning" data-id="{{ budget.id }}" data-budgetLimit="{{ budgetLimit.id }}"
></span>
{% endfor %}
{% endif %}
{% if budget.budgeted|length < currencies.count() %}
@@ -323,11 +320,11 @@
</a>
{% endif %}
</td>
<td class="hidden-sm hidden-xs spent" data-id="{{ budget.id }}" style="text-align:right;">
<td class="hidden-sm hidden-xs spent text-right" data-id="{{ budget.id }}">
{% include('budgets.partials.amount-spent') %}
</td>
{# this cell displays the amount left in the budget, per budget limit. #}
<td class="left" data-id="{{ budget.id }}" style="text-align: right;">
<td class="left" data-id="{{ budget.id }}" class="text-right">
{% include('budgets.partials.amount-left') %}
</td>
</tr>

View File

@@ -27,7 +27,7 @@
</div>
</div>
<div class="box-body">
<canvas id="budgetOverview" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="budgetOverview" class="wide-chart" height="400" width="100%"></canvas>
</div>
{% if budgetLimit %}
<div class="box-footer">
@@ -60,8 +60,8 @@
<h3 class="box-title">{{ 'expenses_by_category'|_ }}</h3>
</div>
<div class="box-body">
<div style="width:100%;margin:0 auto;">
<canvas id="budget-cat-out" style="width:100%;height:250px;" height="250"></canvas>
<div class="center-chart">
<canvas id="budget-cat-out" class="medium-chart" height="250"></canvas>
</div>
</div>
{% if budgetLimit %}
@@ -79,8 +79,8 @@
<h3 class="box-title">{{ 'expenses_by_asset_account'|_ }}</h3>
</div>
<div class="box-body">
<div style="width:100%;margin:0 auto;">
<canvas id="budget-asset-out" style="width:100%;height:250px;" height="250"></canvas>
<div class="center-chart">
<canvas id="budget-asset-out" class="medium-chart" height="250"></canvas>
</div>
</div>
{% if budgetLimit %}
@@ -98,8 +98,8 @@
<h3 class="box-title">{{ 'expenses_by_expense_account'|_ }}</h3>
</div>
<div class="box-body">
<div style="width:100%;margin:0 auto;">
<canvas id="budget-expense-out" style="width:100%;height:250px;" height="250"></canvas>
<div class="center-chart">
<canvas id="budget-expense-out" class="medium-chart" height="250"></canvas>
</div>
</div>
{% if budgetLimit %}
@@ -155,7 +155,7 @@
<div class="box-body no-padding">
<table class="table table-hover">
<tr>
<td style="width:33%;">{{ 'amount'|_ }}</td>
<td class="third">{{ 'amount'|_ }}</td>
<td>
{{ formatAmountBySymbol(limit.amount, limit.transactionCurrency.symbol, limit.transactionCurrency.decimal_places) }}
{% if convertToPrimary and null != limit.native_amount %}
@@ -164,7 +164,7 @@
</td>
</tr>
<tr>
<td style="width:33%;">{{ 'spent'|_ }}</td>
<td class="third">{{ 'spent'|_ }}</td>
<td>
{% if convertToPrimary %}
{{ formatAmountBySymbol(limit.spent, limit.transactionCurrency.symbol, limit.transactionCurrency.decimal_places) }}
@@ -176,7 +176,7 @@
{% endif %}
</td>
</tr>
{% if limit.spent > 0 %}
{% if 0 != bccomp('0', limit.spent) %}
<tr>
<td colspan="2">
{% set overspent = limit.amount + limit.spent < 0 %}
@@ -184,18 +184,18 @@
{% if overspent %}
{% set pct = (limit.spent != 0 ? (limit.amount / (limit.spent*-1))*100 : 0) %} {# must have -1 here #}
<div class="progress progress-striped">
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="{{ pct|round }}"
<div class="progress-bar progress-bar-warning width-{{ pct|round }}" role="progressbar" aria-valuenow="{{ pct|round }}"
aria-valuemin="0"
aria-valuemax="100" style="width: {{ pct|round }}%;"></div>
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="{{ (100-pct)|round }}"
aria-valuemin="0" aria-valuemax="100" style="width: {{ (100-pct)|round }}%;"></div>
aria-valuemax="100"></div>
<div class="progress-bar progress-bar-danger width-{{ 100-pct|round }}" role="progressbar" aria-valuenow="{{ (100-pct)|round }}"
aria-valuemin="0" aria-valuemax="100"></div>
</div>
{% else %}
{% set pct = (limit.amount != 0 ? (((limit.spent*-1) / limit.amount)*100) : 0) %} {# must have -1 here #}
<div class="progress progress-striped">
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{ pct|round }}"
<div class="progress-bar progress-bar-success width-{{ pct|round }}" role="progressbar" aria-valuenow="{{ pct|round }}"
aria-valuemin="0"
aria-valuemax="100" style="width: {{ pct|round }}%;"></div>
aria-valuemax="100"></div>
</div>
{% endif %}
</td>

View File

@@ -22,7 +22,7 @@
</div>
<div class="box-body no-padding">
<div style="padding:8px;">
<div class="m-1">
<a class="btn btn-success" href="{{ route('categories.create') }}"><span class="fa fa-plus fa-fw"></span> {{ 'new_category'|_ }}</a>
</div>
{% include 'list/categories' %}

View File

@@ -16,7 +16,7 @@
</h3>
</div>
<div class="box-body">
<canvas id="specific-period" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="specific-period" class="wide-chart" height="400" width="100%"></canvas>
</div>
</div>
</div>
@@ -28,7 +28,7 @@
</h3>
</div>
<div class="box-body">
<canvas id="category-everything" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="category-everything" class="wide-chart" height="400" width="100%"></canvas>
</div>
</div>
</div>
@@ -43,7 +43,7 @@
</h3>
</div>
<div class="box-body">
<canvas id="category-everything" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="category-everything" class="wide-chart" height="400" width="100%"></canvas>
</div>
</div>
</div>

View File

@@ -19,7 +19,7 @@
{{ 'currencies_switch_default'|_ }}
</p>
{% if currencies|length > 0 %}
<div style="padding-left:8px;">
<div class="m-1">
{{ currencies.links('pagination.bootstrap-4')|raw }}
</div>
<table class="table table-hover">
@@ -81,7 +81,7 @@
{% endfor %}
</tbody>
</table>
<div style="padding-left:8px;">
<div class="m-1">
{{ currencies.links('pagination.bootstrap-4')|raw }}
</div>
{% endif %}

View File

@@ -3,16 +3,21 @@
<head>
<title>{{ trans('firefly.debug_page') }}</title>
</head>
<style nonce="{{ JS_NONCE }}">
p.default-text {font-family:Arial, Arial, Helvetica, sans-serif;font-size:12pt;width:600px;}
p.warn-text {font-family:Arial, Arial, Helvetica, sans-serif;font-size:12pt;width:600px;color:#a00;}
textarea {font-family:Menlo, Monaco, Consolas, monospace;font-size:8pt;}
</style>
<body>
<p style="font-family:Arial, Arial, Helvetica, sans-serif;font-size:12pt;width:600px;">
<p class="default-text">
{{ trans('firefly.debug_submit_instructions')|raw }}
</p>
<p style="font-family:Arial, Arial, Helvetica, sans-serif;font-size:12pt;width:600px;">
<p class="default-text">
<strong>{{ trans('firefly.debug_pretty_table') }}</strong>
</p>
<textarea rows="30" cols="100" name="debug_info" id="debug_info"
style="font-family:Menlo, Monaco, Consolas, monospace;font-size:8pt;">
<label for="debug_info"></label>
<textarea rows="30" cols="100" name="debug_info" id="debug_info">
Debug information generated at {{ now }} for Firefly III version **{% if not FF_IS_DEVELOP %}v{% endif %}{{ FF_VERSION }}**.
{{ table|escape('html') }}
@@ -25,21 +30,21 @@ Debug information generated at {{ now }} for Firefly III version **{% if not FF_
textArea.value = text;
</script>
<p style="font-family:Arial, Arial, Helvetica, sans-serif;font-size:12pt;width:600px;color:#a00;">
<p class=default-text">
<a href="{{ route('index') }}">{{ trans('firefly.back_to_index') }}</a>
</p>
<p style="font-family:Arial, Arial, Helvetica, sans-serif;font-size:12pt;width:600px;color:#a00;">
<p class="warn-text">
{{ trans('firefly.debug_additional_data')|raw }}
</p>
<textarea rows="30" cols="100" name="log_info" style="font-family:Menlo, Monaco, Consolas, monospace;font-size:7pt;">
<textarea rows="30" cols="100" name="log_info">
```
{{ logContent }}
```
</textarea>
<p style="font-family:Arial, Arial, Helvetica, sans-serif;font-size:12pt;width:600px;color:#a00;">
<p class=default-text">
<a href="{{ route('index') }}">{{ trans('firefly.back_to_index') }}</a>
</p>

View File

@@ -52,7 +52,7 @@
<h4>
{{ trans('errors.stacktrace') }}
</h4>
<div style="font-family: monospace;font-size:11px;">
<div class="monospace">
{!! nl2br($exception->getTraceAsString()) !!}
</div>
</div>

View File

@@ -52,7 +52,7 @@
<h4>
{{ trans('errors.stacktrace') }}
</h4>
<div style="font-family: monospace;font-size:11px;">
<div class="monospace">
{!! nl2br($exception->getTraceAsString()) !!}
</div>
</div>

View File

@@ -66,7 +66,7 @@
<h4>
{{ trans('errors.stacktrace') }}
</h4>
<div style="font-family: monospace;font-size:11px;">
<div class="monospace">
{!! nl2br($exception->getTraceAsString()) !!}
</div>
</div>

View File

@@ -5,7 +5,7 @@
{% for groupName, accounts in grouped %}
<strong>{{ groupName }}</strong><br/>
{% for id, account in accounts %}
<div class="checkbox" style="margin-left:2em;">
<div class="checkbox ml-4">
<label>
{% if account in selected or (selected|length == 0 and options.select_all == true) %}
{{ Html.checkbox(name~'[]',true, id).id(id) }}

View File

@@ -14,7 +14,7 @@
title="{{ 'yourAccounts'|_ }}">{{ 'yourAccounts'|_ }}</a></h3>
</div>
<div class="box-body">
<canvas id="accounts-chart" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="accounts-chart" class="wide-chart" height="400" width="100%"></canvas>
</div>
<div class="box-footer">
<a href="{{ route('accounts.index',['asset']) }}" class="btn btn-default button-sm"><span
@@ -29,7 +29,7 @@
title="{{ 'budgetsAndSpending'|_ }}">{{ 'budgetsAndSpending'|_ }}</a></h3>
</div>
<div class="box-body">
<canvas id="budgets-chart" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="budgets-chart" class="wide-chart" height="400" width="100%"></canvas>
</div>
<div class="box-footer">
<a href="{{ route('budgets.index') }}" class="btn btn-default button-sm">
@@ -46,7 +46,7 @@
</div>
<div class="box-body">
<canvas id="categories-chart" style="width:100%;height:400px;" height="400" width="100%"></canvas>
<canvas id="categories-chart" class="wide-chart" height="400" width="100%"></canvas>
</div>
<div class="box-footer">
<a href="{{ route('categories.index') }}" class="btn btn-default button-sm">
@@ -137,8 +137,8 @@
</div>
<div class="box-body">
<div style="width:100%;margin:0 auto;">
<canvas id="bills-chart" style="width:100%;height:200px;" height="200"></canvas>
<div class="center-chart">
<canvas id="bills-chart" class="low-chart" height="200"></canvas>
</div>
</div>
<div class="box-footer">
@@ -164,7 +164,7 @@
</h3>
</div>
<div class="box-body">
<canvas id="expense-accounts-chart" style="width:100%;height:400px;" height="400"
<canvas id="expense-accounts-chart" class="wide-chart" height="400"
width="100%"></canvas>
</div>
<div class="box-footer">
@@ -180,7 +180,7 @@
</div>
<div class="box-body">
<canvas id="revenue-accounts-chart" style="width:100%;height:400px;" height="400"
<canvas id="revenue-accounts-chart" class="wide-chart" height="400"
width="100%"></canvas>
</div>
<div class="box-footer">

View File

@@ -1,26 +0,0 @@
{% extends "./layout/install" %}
{% block content %}
<div class="card mb-2">
<div class="card-body login-card-body">
<p class="login-box-msg">Please wait...</p>
<div class="row">
<div class="col-lg-12">
<div id="status-box" style="border:1px #ddd solid;padding:5px;">
<span class="fa fa-spin fa-spinner"></span> Waiting to start...
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script type="text/javascript" nonce="{{ JS_NONCE }}">
var token = '{{ csrf_token() }}';
var index = 0;
var runCommandUrl = '{{ route('installer.runCommand') }}';
var homeUrl = '{{ route('flush') }}';
</script>
<script type="text/javascript" src="v1/js/ff/install/Xindex.js" nonce="{{ JS_NONCE }}"></script>
{% endblock %}

View File

@@ -83,7 +83,7 @@
<p>The upgrade and installation is ongoing. Please track its progress through the box below.</p>
<div class="row">
<div class="col-lg-12">
<div id="status-box" style="border:1px #ddd solid;padding:5px;">
<div id="status-box p-3 install-box-border">
<span class="fa fa-spin fa-spinner"></span> Waiting to start...
</div>
</div>

View File

@@ -7,8 +7,7 @@
{% for entry in info %}
<strong>{{ entry.name }}</strong><br/>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="{{ entry.percentage }}" aria-valuemin="0" aria-valuemax="100"
style="width: {{ entry.percentage }}%;">
<div class="progress-bar width-{{ entry.percentage|round }}" role="progressbar" aria-valuenow="{{ entry.percentage }}" aria-valuemin="0" aria-valuemax="100">
{% if entry.percentage >=20 %}
{% if convertToPrimary and 0 != avg.pc_amount %}
{{ formatAmountBySymbol(entry.pc_amount, entry.primary_currency_symbol, entry.primary_currency_decimal_places, false) }}

View File

@@ -131,13 +131,13 @@
</li>
<li>
<span style="color:#fff;padding: 15px;display: block;line-height: 20px;">
<span class="date-range-holder">
<span id="daterange"></span>
</span>
</li>
<li class="dropdown user user-menu">
<span style="cursor:default;color:#fff;padding: 15px;display: block;line-height: 20px;">
<span class="dropdown-holder">
<span class="hidden-xs">{{ Auth.user.email }}</span>
</span>
</li>
@@ -290,10 +290,10 @@
</script>
<noscript><p><img
src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1"
style="border:0;" alt=""/></p></noscript>
class="no-border" alt=""/></p></noscript>
{% endif %}
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="hidden">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
</form>

View File

@@ -84,7 +84,7 @@
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" style="border:0;" alt=""/></p></noscript>
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" class="no-border" alt=""/></p></noscript>
{% endif %}
</body>

View File

@@ -98,7 +98,7 @@
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" style="border:0;" alt=""/></p></noscript>
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" class="no-border" alt=""/></p></noscript>
{% endif %}
</body>

View File

@@ -26,7 +26,7 @@
<div class="login-box">
<div class="login-logo">
<strong>Firefly</strong>III<br/>
<span style="font-family: monospace;font-size:16pt;">installation and upgrade</span>
<span class="install-box-title">installation and upgrade</span>
</div>
{% block content %}{% endblock %}
</div>
@@ -57,7 +57,7 @@
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" style="border:0;" alt=""/></p></noscript>
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" class="no-border" alt=""/></p></noscript>
{% endif %}
</body>

View File

@@ -63,6 +63,9 @@
</script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@vite(['src/sass/app.scss'])
<style nonce="{{ $JS_NONCE ?? '' }}">
.monospace {font-family: monospace;font-size:11px;}
</style>
</head>
<body class="container bg-body-secondary">

View File

@@ -1,4 +1,4 @@
<div style="padding-left:8px;">
<div class="ml-1">
{{ accounts.links('pagination.bootstrap-4')|raw }}
</div>
<table class="table table-responsive table-hover" id="sortable-table">
@@ -16,10 +16,10 @@
{% endif %}
<th class="hidden-sm hidden-xs">{{ trans('form.account_number') }}</th>
{% if objectType != 'liabilities' %}
<th style="text-align: right;">{{ trans('list.currentBalance') }}</th>
<th class="text-right">{{ trans('list.currentBalance') }}</th>
{% endif %}
{% if objectType == 'liabilities' %}
<th style="text-align: right;">
<th class="text-right">
{{ trans('firefly.left_in_debt') }}
</th>
{% endif %}
@@ -28,7 +28,7 @@
{% if objectType != 'liabilities' %}
<th class="hidden-sm hidden-xs hidden-md">{{ trans('list.lastActivity') }}</th>
{% endif %}
<th style="width:15%;"
<th class="fifteen"
class="hidden-sm hidden-xs hidden-md">{{ trans('list.balanceDiff') }}</th>
<th class="hidden-sm hidden-xs">&nbsp;</th>
</tr>
@@ -64,8 +64,8 @@
{% endif %}
<td class="hidden-sm hidden-xs">{{ account.iban }}{% if account.iban == '' %}{{ accountGetMetaField(account, 'account_number') }}{% endif %}</td>
{% if objectType != 'liabilities' %}
<td style="text-align: right;">
<span style="margin-right:5px;">
<td class="text-right">
<span class="mr-2">
{% for key, balance in account.endBalances %}
<span title="{{ key }}">
{% if 'balance' == key %}
@@ -85,7 +85,7 @@
</td>
{% endif %}
{% if objectType == 'liabilities' %}
<td style="text-align: right;">
<td class="text-right">
{% if '-' != account.current_debt %}
<span class="text-info money-transfer">
{{ formatAmountBySymbol(account.current_debt, account.currency.symbol, account.currency.decimal_places, false) }}
@@ -113,8 +113,8 @@
</td>
{% endif %}
{% endif %}
<td class="hidden-sm hidden-xs hidden-md" style="text-align: right;">
<span style="margin-right:5px;">
<td class="text-right hidden-sm hidden-xs hidden-md">
<span class="mr-1">
{% for key, balance in account.differences %}
<span title="{{ key }}">
{% if 'balance' == key or 'pc_balance' == key %}
@@ -145,6 +145,6 @@
{% endfor %}
</tbody>
</table>
<div style="padding-left:8px;">
<div class="pl-3">
{{ accounts.links('pagination.bootstrap-4')|raw }}
</div>

View File

@@ -7,7 +7,7 @@
<tbody>
{% for logEntry in logEntries %}
<tr>
<th style="width:20%;" scope="row">
<th class="twenty" scope="row">
{# link to object: #}
{% if 'FireflyIII\\Models\\Rule' == logEntry.changer_type %}
<a href="{{ route('rules.edit', [logEntry.changer_id] ) }}">
@@ -18,7 +18,7 @@
{{ logEntry.changer_type|replace({"FireflyIII\\Models\\": ""})|replace({"FireflyIII\\": ""}) }} #{{ logEntry.changer_id }}
</a>
</th>
<td style="width:30%;" title="{{ logEntry.created_at.isoFormat(dateTimeFormat) }}">
<td class="thirty" title="{{ logEntry.created_at.isoFormat(dateTimeFormat) }}">
{{ trans('firefly.ale_action_'~logEntry.action) }}
</td>
<td>

View File

@@ -1,7 +1,7 @@
<table class="table table-responsive table-hover">
{% for attachment in attachments %}
<tr>
<td style="width:120px;">
<td class="onetwenty">
<div class="btn-group btn-group-xs">
<a href="{{ route('attachments.edit', attachment.id) }}" class="btn btn-default"><span
class="fa fa-pencil"></span></a>

View File

@@ -1,4 +1,4 @@
<div style="padding-left:8px;">
<div class="pl-2">
{{ paginator.links('pagination.bootstrap-4')|raw }}
</div>
<table class="table table-responsive table-hover" id="bill-sortable">
@@ -8,7 +8,7 @@
<th class="hidden-sm hidden-xs">&nbsp;</th>
<th>{{ trans('list.name') }}</th>
<th class="hidden-sm hidden-md hidden-xs">{{ trans('list.linked_to_rules') }}</th>
<th style="text-align: right;">{{ trans('list.matchingAmount') }}</th>
<th class="text-right">{{ trans('list.matchingAmount') }}</th>
<th class="hidden-sm hidden-xs">{{ trans('list.paid_current_period') }}</th>
<th class="hidden-sm hidden-xs">{{ trans('list.next_expected_match') }}</th>
<th class="hidden-sm hidden-xs">{{ trans('list.repeat_freq') }}</th>
@@ -62,10 +62,8 @@
</ul>
{% endif %}
</td>
<td style="text-align: right;">
<span style="margin-right:5px;"
title="{{ formatAmountBySymbol(entry.amount_min, entry.currency_symbol, entry.currency_decimal_places, false)|escape }} -- {{ formatAmountBySymbol(entry.amount_max, entry.currency_symbol, entry.currency_decimal_places, false)|escape }}"
>
<td class="text-right">
<span class="mr-2" title="{{ formatAmountBySymbol(entry.amount_min, entry.currency_symbol, entry.currency_decimal_places, false)|escape }} -- {{ formatAmountBySymbol(entry.amount_max, entry.currency_symbol, entry.currency_decimal_places, false)|escape }}">
~ {{ formatAmountBySymbol((entry.amount_max + entry.amount_min)/2, entry.currency_symbol, entry.currency_decimal_places) }}
{% if '0' != entry.pc_amount_max and null != entry.pc_amount_max %}
@@ -178,10 +176,10 @@
<tr>
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- handle -->
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- buttons -->
<td colspan="2" style="text-align: right;"> <!-- title -->
<td colspan="2" class="text-right"> <!-- title -->
<small>{{ 'sum'|_ }} ({{ sum.currency_name }}) ({{ 'active_exp_bills_only'|_ }})</small>
</td>
<td style="text-align: right;"> <!-- amount -->
<td class="text-right"> <!-- amount -->
{{ formatAmountBySymbol(sum.avg, sum.currency_symbol, sum.currency_decimal_places) }}
</td>
<td>&nbsp;</td> <!-- paid in period -->
@@ -193,10 +191,10 @@
<tr>
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- handle -->
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- buttons -->
<td colspan="2" style="text-align: right;"> <!-- title -->
<td colspan="2" class="text-right"> <!-- title -->
<small>{{ 'sum'|_ }} ({{ sum.currency_name }}) ({{ 'left_to_pay_active_bills'|_ }})</small>
</td>
<td style="text-align: right;"> <!-- amount -->
<td class="text-right"> <!-- amount -->
{{ formatAmountBySymbol(sum.total_left_to_pay, sum.currency_symbol, sum.currency_decimal_places) }}
</td>
<td>&nbsp;</td> <!-- paid in period -->
@@ -208,11 +206,11 @@
<tr>
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- handle -->
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- buttons -->
<td colspan="2" style="text-align: right;"> <!-- title -->
<td colspan="2" class="text-right"> <!-- title -->
<small>{{ ('per_period_sum_'~sum.period)|_ }} ({{ sum.currency_name }})
({{ 'active_bills_only'|_ }})</small>
</td>
<td style="text-align: right;"> <!-- amount -->
<td class="text-right"> <!-- amount -->
{{ formatAmountBySymbol(sum.per_period, sum.currency_symbol, sum.currency_decimal_places) }}
</td>
<td>&nbsp;</td> <!-- paid in period -->
@@ -227,17 +225,17 @@
{% if totals|length > 0 %}
<tfoot>
<tr>
<td colspan="8" style="border-top:1px #777 solid;"></td>
<td colspan="8" class="top-dark-border"></td>
</tr>
{% for sum in totals %}
{% if '0' != sum.avg %}
<tr>
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- handle -->
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- buttons -->
<td colspan="2" style="text-align: right;"> <!-- title -->
<td colspan="2" class="text-right"> <!-- title -->
<small>{{ 'sum'|_ }} ({{ sum.currency_name }}) ({{ 'active_exp_bills_only_total'|_ }})</small>
</td>
<td style="text-align: right;"> <!-- amount -->
<td class="text-right"> <!-- amount -->
{{ formatAmountBySymbol(sum.avg, sum.currency_symbol, sum.currency_decimal_places) }}
</td>
<td>&nbsp;</td> <!-- paid in period -->
@@ -249,11 +247,11 @@
<tr>
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- handle -->
<td class="hidden-sm hidden-xs">&nbsp;</td> <!-- buttons -->
<td colspan="2" style="text-align: right;"> <!-- title -->
<td colspan="2" class="text-right"> <!-- title -->
<small>{{ ('per_period_sum_'~sum.period)|_ }} ({{ sum.currency_name }})
({{ 'active_bills_only_total'|_ }})</small>
</td>
<td style="text-align: right;"> <!-- amount -->
<td class="text-right"> <!-- amount -->
{{ formatAmountBySymbol(sum.per_period, sum.currency_symbol, sum.currency_decimal_places) }}
</td>
<td>&nbsp;</td> <!-- paid in period -->
@@ -266,6 +264,6 @@
{% endif %}
</table>
<div style="padding-left:8px;">
<div class="pl-2">
{{ paginator.links('pagination.bootstrap-4')|raw }}
</div>

View File

@@ -1,4 +1,4 @@
<div style="padding-left:8px;">
<div class="pl-3">
{{ categories.links('pagination.bootstrap-4')|raw }}
</div>
<table class="table table-hover sortable">
@@ -42,6 +42,6 @@
{% endfor %}
</tbody>
</table>
<div style="padding-left:8px;">
<div class="pl-3">
{{ categories.links('pagination.bootstrap-4')|raw }}
</div>

View File

@@ -8,10 +8,10 @@
{% endif %}
<td colspan="1" class="hidden-xs">
<!-- Single button -->
<div class="btn-group btn-group-xs action-menu pull-right" style="display: none;">
<div class="btn-group btn-group-xs action-menu pull-right hidden">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
{{ 'actions'|_ }} <span class="caret"></span>
{{ 'actions'|_ }}<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="#" class="mass-edit"><span class="fa fa-fw fa-pencil"></span>
@@ -52,14 +52,14 @@
<tbody>
{% for group in groups %}
{% if group.count > 1 %}
<tr style="border-top:1px #aaa solid;">
<td colspan="2" style="border-top:1px #aaa solid;">
<tr class="top-light-border">
<td colspan="2" class="top-light-border">
<small><strong>
<a href="{{ route('transactions.show', [group.id]) }}"
title="{{ group.title }}">{{ group.title }}</a>
</strong></small>
</td>
<td colspan="1" style="text-align:right;border-top:1px #aaa solid;">
<td colspan="1" class="text-right top-light-border">
{% for sum in group.sums %}
{% if group.transaction_type == 'Deposit' %}
{{ formatAmountBySymbol(sum.amount*-1, sum.currency_symbol, sum.currency_decimal_places) }}
@@ -87,11 +87,11 @@
</td>
<!-- column to span accounts + extra fields -->
{% if showCategory or showBudget %}
<td style="border-top:1px #aaa solid;" colspan="3">&nbsp;</td>
<td class="top-light-border" colspan="3">&nbsp;</td>
{% else %}
<td style="border-top:1px #aaa solid;" colspan="2">&nbsp;</td>
<td class="top-light-border" colspan="2">&nbsp;</td>
{% endif %}
<td style="border-top:1px #aaa solid;" colspan="2" class="hidden-xs">
<td class="top-light-border hidden-xs" colspan="2">
<div class="btn-group btn-group-xs pull-right">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
@@ -108,17 +108,17 @@
</ul>
</div>
</td>
<td style="border-top:1px #aaa solid;" class="hidden-xs">&nbsp;</td>
<td class="top-light-border hidden-xs">&nbsp;</td>
</tr>
{% endif %}
{% for index, transaction in group.transactions %}
{% set style="" %}
{% set className="" %}
{% if group.transactions|length == loop.index and group.count > 1 %}
{% set style="border-bottom:1px #aaa solid;" %}
{% set className="bottom-light-border" %}
{% endif %}
<tr data-date="{{ transaction.date.format('Y-m-d') }}" data-count="{{ group.count }}"
data-id="{{ group.id }}">
<td style=" {{ style|raw }}" class="hidden-xs">
<td class="hidden-xs {{ className }}">
{% if transaction.transaction_type_type == 'Withdrawal' %}
<span class="fa fa-long-arrow-left fa-fw"
title="{{ trans('firefly.Withdrawal') }}"></span>
@@ -147,7 +147,7 @@
{% endif %}
</td>
<td style=" {{ style|raw }}">
<td class="{{ className }}">
{% if transaction.reconciled %}
<span class="fa fa-check"></span>
{% endif %}
@@ -162,7 +162,7 @@
</a>
{% endif %}
</td>
<td style="{{ style|raw }};text-align:right">
<td class="{{ className }} text-right">
{# deposit #}
{% if transaction.transaction_type_type == 'Deposit' %}
@@ -275,7 +275,7 @@
{% endif %}
</td>
{% if (fireflyiiiconfig('use_running_balance', true)) %}
<td style="{{ style|raw }};text-align:right">
<td class=" {{ className }} text-right">
{# RUNNING BALANCE #}
{% if (null == transaction.balance_dirty or false == transaction.balance_dirty) and null != transaction.destination_balance_after and null != transaction.source_balance_after %}
{% if transaction.transaction_type_type == 'Deposit' %}
@@ -335,10 +335,10 @@
{% endif %}
</td>
{% endif %}
<td style=" {{ style|raw }}">
<td class="{{ className }}">
{{ transaction.date.isoFormat(monthAndDayFormat) }}
</td>
<td style=" {{ style|raw }}">
<td class="{{ className }}">
{% if 'Cash account' == transaction.source_account_type %}
<span class="text-success">({{ 'cash'|_ }})</span>
{% else %}
@@ -346,7 +346,7 @@
title="{{ transaction.source_account_iban|default(transaction.source_account_name) }}">{{ transaction.source_account_name }}</a>
{% endif %}
</td>
<td style=" {{ style|raw }}">
<td class="{{ className }}">
{% if 'Cash account' == transaction.destination_account_type %}
<span class="text-success">({{ 'cash'|_ }})</span>
{% else %}
@@ -355,7 +355,7 @@
{% endif %}
</td>
{% if showCategory %}
<td style=" {{ style|raw }}" class="hidden-xs">
<td class="hidden-xs {{ className }}">
{% if transaction.category_id %}
<a href="{{ route('categories.show', [transaction.category_id]) }}"
title="{{ transaction.category_name }}">{{ transaction.category_name }}</a>
@@ -363,7 +363,7 @@
</td>
{% endif %}
{% if showBudget %}
<td style=" {{ style|raw }}" class="hidden-xs">
<td class="hidden-xs {{ className }}">
{% if transaction.budget_id %}
<a href="{{ route('budgets.show', [transaction.budget_id]) }}"
title="{{ transaction.budget_name }}">{{ transaction.budget_name }}</a>
@@ -372,7 +372,7 @@
{% endif %}
{% if group.count == 1 %}
<td style=" {{ style|raw }};" class="hidden-xs">
<td class="hidden-xs {{ className }}">
<div class="btn-group btn-group-xs pull-right">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
@@ -400,11 +400,11 @@
{% endif %}
{% if group.count != 1 %}
<td style=" {{ style|raw }};" class="hidden-xs">
<td class="hidden-xs {{ className }}">
&nbsp;
</td>
{% endif %}
<td style="{{ style|raw }}" class="hidden-xs">
<td class="hidden-xs {{ className }}">
{% if transaction.transaction_type_type != 'Reconciliation' and transaction.transaction_type_type != 'Opening balance' and transaction.transaction_type_type != 'Liability credit' %}
<div class="pull-right">
<input id="list_{{ transaction.transaction_journal_id }}"
@@ -424,7 +424,7 @@
<td colspan="8">
<div class="pull-right">
<!-- Single button -->
<div class="btn-group action-menu btn-group-xs pull-right" style="display:none;">
<div class="btn-group action-menu btn-group-xs pull-right hidden">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
{{ 'actions'|_ }} <span class="caret"></span>

View File

@@ -8,15 +8,15 @@
<table class="table table-hover">
{% if period.total_transactions > 0 %}
<tr>
<td style="width:33%;">{{ 'transactions'|_ }}</td>
<td style="text-align: right;">{{ period.total_transactions }}</td>
<td class="third">{{ 'transactions'|_ }}</td>
<td class="text-right">{{ period.total_transactions }}</td>
</tr>
{% endif %}
{% for entry in period.spent %}
{% if entry.amount != 0 %}
<tr>
<td style="width:33%;">{{ 'spent'|_ }}</td>
<td style="text-align: right;">
<td class="third">{{ 'spent'|_ }}</td>
<td class="text-right">
<span title="{{ entry.count }}">
{{ formatAmountBySymbol(entry.amount, entry.currency_symbol, entry.currency_decimal_places) }}
</span>
@@ -28,8 +28,8 @@
{% for entry in period.earned %}
{% if entry.amount != 0 %}
<tr>
<td style="width:33%;">{{ 'earned'|_ }}</td>
<td style="text-align: right;">
<td class="third">{{ 'earned'|_ }}</td>
<td class="text-right">
<span title="{{ entry.count }}">
{% if entry.amount < 0 %}
{{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }}
@@ -45,8 +45,8 @@
{% for entry in period.transferred %}
{% if entry.amount != 0 %}
<tr>
<td style="width:33%;">{{ 'transferred'|_ }}</td>
<td style="text-align: right;">
<td class="third">{{ 'transferred'|_ }}</td>
<td class="text-right">
<span title="{{ entry.count }}">
{{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }}
</span>
@@ -58,8 +58,8 @@
{% for entry in period.transferred_away %}
{% if entry.amount != 0 %}
<tr>
<td style="width:33%;">{{ 'transferred_away'|_ }}</td>
<td style="text-align: right;">
<td class="third">{{ 'transferred_away'|_ }}</td>
<td class="text-right">
<span title="{{ entry.count }}">
{% if entry.amount < 0 %}
{{ formatAmountBySymbol(entry.amount, entry.currency_symbol, entry.currency_decimal_places) }}
@@ -75,8 +75,8 @@
{% for entry in period.transferred_in %}
{% if entry.amount != 0 %}
<tr>
<td style="width:33%;">{{ 'transferred_in'|_ }}</td>
<td style="text-align: right;">
<td class="third">{{ 'transferred_in'|_ }}</td>
<td class="text-right">
<span title="{{ entry.count }}">
{% if entry.amount < 0 %}
{{ formatAmountBySymbol(entry.amount*-1, entry.currency_symbol, entry.currency_decimal_places) }}

View File

@@ -22,7 +22,7 @@
{% endif %}
</td>
<td style="text-align: right;">
<td class="text-right">
{% if event.amount < 0 %}
<span class="text-danger money-negative">{{ trans('firefly.removed_amount', {amount: formatAmountBySymbol(event.amount,event.piggyBank.transactionCurrency.symbol, event.piggyBank.transactionCurrency.decimal_places, false)})|raw }}</span>
{% else %}

View File

@@ -3,11 +3,11 @@
<tr>
<th colspan="2">&nbsp;</th>
<th>{{ 'piggy_bank'|_ }}</th>
<th style="text-align: right;">{{ 'saved_so_far'|_ }}</th>
<th class="text-right">{{ 'saved_so_far'|_ }}</th>
<th colspan="3" class="hidden-sm hidden-xs">&nbsp;</th>
<th style="text-align: right;" class="hidden-sm hidden-xs">{{ 'target_amount'|_ }}</th>
<th style="text-align: right;" class="hidden-sm hidden-xs">{{ 'left_to_save'|_ }}</th>
<th style="text-align: right;" class="hidden-sm hidden-xs">{{ 'suggested_savings_per_month'|_ }}</th>
<th class="text-right hidden-sm hidden-xs">{{ 'target_amount'|_ }}</th>
<th class="text-right hidden-sm hidden-xs">{{ 'left_to_save'|_ }}</th>
<th class="text-right hidden-sm hidden-xs">{{ 'suggested_savings_per_month'|_ }}</th>
</tr>
</thead>
@@ -29,11 +29,11 @@
<a href="{{ route('piggy-banks.add-money-mobile', piggy.id) }}" class="btn btn-default btn-xs"><span class="fa fa-plus"></span></a>
</div>
</td>
<td style="width:60px;" class="hidden-sm hidden-xs">
<td class="hidden-sm hidden-xs sixty-px">
<span class="fa fa-fw fa-bars piggy-handle"></span>
<span class="loadSpin"></span>
</td>
<td style="width:100px;" class="hidden-sm hidden-xs">
<td class="hidden-sm hidden-xs hundred-px">
<div class="btn-group btn-group-xs">
<a href="{{ route('piggy-banks.edit', piggy.id) }}" class="btn btn-default btn-xs"><span class="fa fa-pencil fa-fw"></span></a>
<a href="{{ route('piggy-banks.delete', piggy.id) }}" class="btn btn-danger btn-xs"><span class="fa fa-trash fa-fw"></span></a>
@@ -45,15 +45,15 @@
<span class="fa fa-fw fa-paperclip"></span>
{% endif %}
</td>
<td style="text-align: right;" class="piggySaved">
<span title="Saved so far" style="text-align:right;">
<td class="text-right piggySaved">
<span title="Saved so far" class="text-right">
{{ formatAmountBySymbol(piggy.current_amount,piggy.currency_symbol,piggy.currency_decimal_places) }}
{% if convertToPrimary and piggy.currency_id != primaryCurrency.id and null != piggy.pc_current_amount %}
({{ formatAmountBySymbol(piggy.pc_current_amount,primaryCurrency.symbol,primaryCurrency.decimal_places) }})
{% endif %}
</span>
</td>
<td class="hidden-sm hidden-xs" style="text-align:right;width:40px;">
<td class="hidden-sm hidden-xs text-right forty-px">
{% if piggy.current_amount > 0 %}
<a href="{{ route('piggy-banks.remove-money', piggy.id) }}" class="btn btn-default btn-xs removeMoney" data-id="{{ piggy.id }}">
<span data-id="{{ piggy.id }}" class="fa fa-minus"></span></a>
@@ -62,17 +62,16 @@
<td class="hidden-sm hidden-xs piggyBar">
{% if null != piggy.percentage %}
<div class="progress progress" style="margin-bottom:0;">
<div class="progress progress mb-0">
<div
{% if piggy.percentage == 100 %}
class="progress-bar progress-bar-success"
class="progress-bar progress-bar-success width-{{ max(30, piggy.percentage)|round }}"
{% elseif piggy.percentage == 0 %}
class="progress-bar progress-bar-warning"
class="progress-bar progress-bar-warning width-{{ max(30, piggy.percentage)|round }}"
{% else %}
class="progress-bar progress-bar-info"
class="progress-bar progress-bar-info width-{{ max(30, piggy.percentage)|round }}"
{% endif %}
role="progressbar" aria-valuenow="{{ piggy.percentage }}" aria-valuemin="0" aria-valuemax="100"
style="min-width: 30px;width: {{ piggy.percentage }}%;">
role="progressbar" aria-valuenow="{{ piggy.percentage }}" aria-valuemin="0" aria-valuemax="100">
{{ piggy.percentage }}%
</div>
</div>
@@ -80,14 +79,14 @@
</td>
<td class="hidden-sm hidden-xs" style="width:40px;">
<td class="hidden-sm hidden-xs forty-px">
{% if piggy.left_to_save > 0 or null == piggy.left_to_save %}
<a href="{{ route('piggy-banks.add-money', piggy.id) }}" class="btn btn-default btn-xs addMoney" data-id="{{ piggy.id }}">
<span data-id="{{ piggy.id }}" class="fa fa-plus"></span></a>
{% endif %}
</td>
<td class="hidden-sm hidden-xs" style="text-align:right;">
<td class="hidden-sm hidden-xs text-right">
{% if null != piggy.target_amount and 0 != piggy.target_amount %}
<span title="{{ 'target_amount'|_ }}">{{ formatAmountBySymbol(piggy.target_amount,piggy.currency_symbol,piggy.currency_decimal_places) }}</span>
{% if convertToPrimary and piggy.currency_id != primaryCurrency.id and null != piggy.pc_target_amount %}
@@ -95,7 +94,7 @@
{% endif %}
{% endif %}
</td>
<td class="hidden-sm hidden-xs" style="text-align:right;">
<td class="hidden-sm hidden-xs text-right">
{% if piggy.left_to_save > 0 %}
<span title="{{ 'left_to_save'|_ }}">{{ formatAmountBySymbol(piggy.left_to_save,piggy.currency_symbol,piggy.currency_decimal_places) }}</span>
{% if convertToPrimary and piggy.currency_id != primaryCurrency.id and null != piggy.pc_left_to_save %}
@@ -103,7 +102,7 @@
{% endif %}
{% endif %}
</td>
<td class="hidden-sm hidden-xs" style="text-align:right;">
<td class="hidden-sm hidden-xs text-right">
{% if piggy.target_date and piggy.save_per_month %}
{{ formatAmountBySymbol(piggy.save_per_month, piggy.currency_symbol, piggy.currency_decimal_places) }}
{% if convertToPrimary and piggy.currency_id != primaryCurrency.id and null != piggy.pc_save_per_month %}
@@ -119,7 +118,7 @@
<td class="hidden-sm hidden-xs">&nbsp;</td> {# handle #}
<td class="hidden-sm hidden-xs">&nbsp;</td> {# buttons #}
<td>&nbsp;</td>
<td style="text-align: right;">
<td class="text-right">
{% for sum in objectGroup.sums %}
{{ formatAmountBySymbol(sum.saved, sum.currency_symbol, sum.currency_decimal_places) }}<br />
{% endfor %}
@@ -127,17 +126,17 @@
<td class="hidden-sm hidden-xs">&nbsp;</td> {# remove money #}
<td class="hidden-sm hidden-xs">&nbsp;</td> {# progress#}
<td class="hidden-sm hidden-xs">&nbsp;</td> {# add money #}
<td class="hidden-sm hidden-xs" style="text-align: right;">
<td class="text-right hidden-sm hidden-xs">
{% for sum in objectGroup.sums %}
{{ formatAmountBySymbol(sum.target, sum.currency_symbol, sum.currency_decimal_places) }}<br />
{% endfor %}
</td>
<td class="hidden-sm hidden-xs" style="text-align: right;">
<td class="text-right hidden-sm hidden-xs">
{% for sum in objectGroup.sums %}
{{ formatAmountBySymbol(sum.left_to_save, sum.currency_symbol, sum.currency_decimal_places) }}<br />
{% endfor %}
</td>
<td class="hidden-sm hidden-xs" style="text-align: right;">
<td class="text-right hidden-sm hidden-xs">
{% for sum in objectGroup.sums %}
{{ formatAmountBySymbol(sum.save_per_month, sum.currency_symbol, sum.currency_decimal_places) }}<br />
{% endfor %}

View File

@@ -10,7 +10,7 @@
<span class="info-box-number" id="box-balance-sums"></span>
<div class="progress" id="box-balance-progress">
<div class="progress-bar" style="width: 0%"></div>
<div class="progress-bar"></div>
</div>
<span class="progress-description">
<span id="box-balance-list" ></span>
@@ -29,7 +29,7 @@
<span class="info-box-number" id="box-bills-unpaid"></span>
<div class="progress">
<div class="progress-bar" style="width: 0%"></div>
<div class="progress-bar"></div>
</div>
<span class="progress-description">
{{ 'paid'|_ }}:
@@ -48,7 +48,7 @@
<span class="info-box-number" id="box-left-to-spend"></span>
<div class="progress">
<div class="progress-bar" style="width: 0%"></div>
<div class="progress-bar"></div>
</div>
<span class="progress-description">
{{ 'per_day'|_ }}:
@@ -69,7 +69,7 @@
<span class="info-box-number" id="box-net-worth"></span>
<div class="progress">
<div class="progress-bar" style="width: 0%"></div>
<div class="progress-bar"></div>
</div>
<span class="progress-description"></span>
</div>

View File

@@ -13,7 +13,7 @@
{{ ('no_'~type~'_imperative_'~objectType)|_ }}
</p>
<p style="text-align: center;">
<p class="text-center">
<a class="btn btn-lg btn-success" href="{{ route }}">{{ ('no_'~type~'_create_'~objectType)|_ }}</a>
</p>
</div>

View File

@@ -1 +0,0 @@
<h1 style="color:red;">REPLACE ME</h1>

View File

@@ -1 +0,0 @@
<h1 style="color:red;">REPLACE ME</h1>

View File

@@ -6,7 +6,7 @@
<h4 class="modal-title">{{ trans('firefly.add_money_to_piggy_title', {name: piggyBank.name}) }}</h4>
</div>
{% if total > 0 %}
<form style="display: inline;" id="add" action="{{ route('piggy-banks.add', piggyBank.id) }}" method="POST">
<form class="inline" id="add" action="{{ route('piggy-banks.add', piggyBank.id) }}" method="POST">
<div class="modal-body">
<input type="hidden" name="_token" value="{{ csrf_token() }}"/>
{% for account in accounts %}

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