mirror of
https://github.com/pelican-dev/panel.git
synced 2026-02-24 11:20:41 +03:00
Compare commits
16 Commits
lance/enco
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e35ce1e79d | ||
|
|
42c127c004 | ||
|
|
593f209142 | ||
|
|
9bf5b2cf0a | ||
|
|
f76e864a30 | ||
|
|
01cfa31ee1 | ||
|
|
dead664e4d | ||
|
|
1bbbcd0e25 | ||
|
|
677d2f742c | ||
|
|
650fb16d2d | ||
|
|
58814ea782 | ||
|
|
0918ed308b | ||
|
|
85d5f2ec3f | ||
|
|
810f237547 | ||
|
|
8f191890a1 | ||
|
|
160e0e54f5 |
@@ -69,8 +69,7 @@ RUN apk add --no-cache \
|
||||
zip unzip 7zip bzip2-dev yarn git
|
||||
|
||||
# Copy composer binary for runtime plugin dependency management
|
||||
COPY --from=composer /usr/local/bin/composer /usr/local/bin/composer
|
||||
|
||||
COPY --from=composer /usr/local/bin/composer /usr/local/bin/composer
|
||||
COPY --chown=root:www-data --chmod=770 --from=composerbuild /build .
|
||||
COPY --chown=root:www-data --chmod=770 --from=yarnbuild /build/public ./public
|
||||
|
||||
|
||||
@@ -74,8 +74,7 @@ RUN apk add --no-cache \
|
||||
zip unzip 7zip bzip2-dev yarn git
|
||||
|
||||
# Copy composer binary for runtime plugin dependency management
|
||||
COPY --from=composer /usr/local/bin/composer /usr/local/bin/composer
|
||||
|
||||
COPY --from=composer /usr/local/bin/composer /usr/local/bin/composer
|
||||
COPY --chown=root:www-data --chmod=770 --from=composerbuild /build .
|
||||
COPY --chown=root:www-data --chmod=770 --from=yarnbuild /build/public ./public
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Services\Eggs\Sharing\EggExporterService;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use JsonException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class CheckEggUpdatesCommand extends Command
|
||||
@@ -22,14 +21,12 @@ class CheckEggUpdatesCommand extends Command
|
||||
try {
|
||||
$this->check($egg, $exporterService);
|
||||
} catch (Exception $exception) {
|
||||
$this->error("{$egg->name}: Error ({$exception->getMessage()})");
|
||||
$this->error("$egg->name: Error ({$exception->getMessage()})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
/** @throws Exception */
|
||||
private function check(Egg $egg, EggExporterService $exporterService): void
|
||||
{
|
||||
if (is_null($egg->update_url)) {
|
||||
@@ -45,7 +42,13 @@ class CheckEggUpdatesCommand extends Command
|
||||
? Yaml::parse($exporterService->handle($egg->id, EggFormat::YAML))
|
||||
: json_decode($exporterService->handle($egg->id, EggFormat::JSON), true);
|
||||
|
||||
$remote = Http::timeout(5)->connectTimeout(1)->get($egg->update_url)->throw()->body();
|
||||
$remote = Http::timeout(5)->connectTimeout(1)->get($egg->update_url);
|
||||
|
||||
if ($remote->failed()) {
|
||||
throw new Exception("HTTP request returned status code {$remote->status()}");
|
||||
}
|
||||
|
||||
$remote = $remote->body();
|
||||
$remote = $isYaml ? Yaml::parse($remote) : json_decode($remote, true);
|
||||
|
||||
unset($local['exported_at'], $remote['exported_at']);
|
||||
|
||||
@@ -16,7 +16,7 @@ class DisablePluginCommand extends Command
|
||||
{
|
||||
$id = $this->argument('id') ?? $this->choice('Plugin', Plugin::pluck('name', 'id')->toArray());
|
||||
|
||||
$plugin = Plugin::find($id);
|
||||
$plugin = Plugin::find(str($id)->lower()->toString());
|
||||
|
||||
if (!$plugin) {
|
||||
$this->error('Plugin does not exist!');
|
||||
|
||||
@@ -18,7 +18,7 @@ class InstallPluginCommand extends Command
|
||||
{
|
||||
$id = $this->argument('id') ?? $this->choice('Plugin', Plugin::pluck('name', 'id')->toArray());
|
||||
|
||||
$plugin = Plugin::find($id);
|
||||
$plugin = Plugin::find(str($id)->lower()->toString());
|
||||
|
||||
if (!$plugin) {
|
||||
$this->error('Plugin does not exist!');
|
||||
|
||||
@@ -18,7 +18,7 @@ class UninstallPluginCommand extends Command
|
||||
{
|
||||
$id = $this->argument('id') ?? $this->choice('Plugin', Plugin::pluck('name', 'id')->toArray());
|
||||
|
||||
$plugin = Plugin::find($id);
|
||||
$plugin = Plugin::find(str($id)->lower()->toString());
|
||||
|
||||
if (!$plugin) {
|
||||
$this->error('Plugin does not exist!');
|
||||
|
||||
@@ -17,7 +17,7 @@ class UpdatePluginCommand extends Command
|
||||
{
|
||||
$id = $this->argument('id') ?? $this->choice('Plugin', Plugin::pluck('name', 'id')->toArray());
|
||||
|
||||
$plugin = Plugin::find($id);
|
||||
$plugin = Plugin::find(str($id)->lower()->toString());
|
||||
|
||||
if (!$plugin) {
|
||||
$this->error('Plugin does not exist!');
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use App\Exceptions\Solutions\ManifestDoesNotExistSolution;
|
||||
use Exception;
|
||||
use Spatie\Ignition\Contracts\ProvidesSolution;
|
||||
use Spatie\Ignition\Contracts\Solution;
|
||||
|
||||
class ManifestDoesNotExistException extends Exception implements ProvidesSolution
|
||||
{
|
||||
public function getSolution(): Solution
|
||||
{
|
||||
return new ManifestDoesNotExistSolution();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions\Solutions;
|
||||
|
||||
use Spatie\Ignition\Contracts\Solution;
|
||||
|
||||
class ManifestDoesNotExistSolution implements Solution
|
||||
{
|
||||
public function getSolutionTitle(): string
|
||||
{
|
||||
return "The manifest.json file hasn't been generated yet";
|
||||
}
|
||||
|
||||
public function getSolutionDescription(): string
|
||||
{
|
||||
return 'Run yarn run build:production to build the frontend first.';
|
||||
}
|
||||
|
||||
public function getDocumentationLinks(): array
|
||||
{
|
||||
return [
|
||||
'Docs' => 'https://github.com/pelican/panel/blob/master/package.json',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ class DatabaseHostResource extends Resource
|
||||
->toolbarActions([
|
||||
CreateAction::make(),
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
DeleteBulkAction::make('exclude_bulk_delete'),
|
||||
]),
|
||||
])
|
||||
->emptyStateIcon(TablerIcon::Database)
|
||||
|
||||
@@ -175,7 +175,8 @@ class CreateEgg extends CreateRecord
|
||||
->addActionLabel(trans('admin/egg.add_new_variable'))
|
||||
->grid()
|
||||
->relationship('variables')
|
||||
->reorderable()->orderColumn()
|
||||
->orderColumn()
|
||||
->reorderAction(fn (Action $action) => $action->hiddenLabel()->tooltip(fn () => $action->getLabel()))
|
||||
->collapsible()->collapsed()
|
||||
->columnSpan(2)
|
||||
->defaultItems(0)
|
||||
|
||||
@@ -333,9 +333,9 @@ class EditEgg extends EditRecord
|
||||
->hiddenLabel()
|
||||
->grid()
|
||||
->relationship('variables')
|
||||
->reorderable()
|
||||
->collapsible()->collapsed()
|
||||
->orderColumn()
|
||||
->reorderAction(fn (Action $action) => $action->hiddenLabel()->tooltip(fn () => $action->getLabel()))
|
||||
->collapsible()->collapsed()
|
||||
->addActionLabel(trans('admin/egg.add_new_variable'))
|
||||
->itemLabel(fn (array $state) => $state['name'])
|
||||
->mutateRelationshipDataBeforeCreateUsing(function (array $data): array {
|
||||
@@ -485,18 +485,20 @@ class EditEgg extends EditRecord
|
||||
],
|
||||
]);
|
||||
|
||||
$normalizedExtension = match ($extension) {
|
||||
'svg+xml', 'svg' => 'svg',
|
||||
'jpeg', 'jpg' => 'jpg',
|
||||
'png' => 'png',
|
||||
'webp' => 'webp',
|
||||
default => throw new Exception(trans('admin/egg.import.unknown_extension')),
|
||||
};
|
||||
|
||||
$data = @file_get_contents($imageUrl, false, $context, 0, 1048576); // 1024KB
|
||||
|
||||
if (empty($data)) {
|
||||
throw new Exception(trans('admin/egg.import.invalid_url'));
|
||||
}
|
||||
|
||||
$normalizedExtension = match ($extension) {
|
||||
'svg+xml' => 'svg',
|
||||
'jpeg' => 'jpg',
|
||||
default => $extension,
|
||||
};
|
||||
|
||||
Storage::disk('public')->put(Egg::ICON_STORAGE_PATH . "/$egg->uuid.$normalizedExtension", $data);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ class ListEggs extends ListRecords
|
||||
->multiple(),
|
||||
CreateAction::make(),
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make()
|
||||
DeleteBulkAction::make('exclude_bulk_delete')
|
||||
->before(function (Collection &$records) {
|
||||
$eggsWithServers = $records->filter(fn (Egg $egg) => $egg->servers_count > 0);
|
||||
|
||||
@@ -106,7 +106,7 @@ class ListEggs extends ListRecords
|
||||
$this->halt();
|
||||
}
|
||||
}),
|
||||
UpdateEggBulkAction::make()
|
||||
UpdateEggBulkAction::make('exclude_bulk_update')
|
||||
->before(function (Collection &$records) {
|
||||
$eggsWithoutUpdateUrl = $records->filter(fn (Egg $egg) => $egg->update_url === null);
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class MountResource extends Resource
|
||||
->toolbarActions([
|
||||
CreateAction::make(),
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
DeleteBulkAction::make('exclude_bulk_delete'),
|
||||
]),
|
||||
])
|
||||
->emptyStateIcon(TablerIcon::LayersLinked)
|
||||
|
||||
@@ -103,6 +103,7 @@ class AllocationsRelationManager extends RelationManager
|
||||
->live()
|
||||
->hintAction(
|
||||
Action::make('hint_refresh')
|
||||
->hiddenLabel()
|
||||
->icon(TablerIcon::Refresh)
|
||||
->tooltip(trans('admin/node.refresh'))
|
||||
->action(function () {
|
||||
|
||||
@@ -202,7 +202,7 @@ class PluginResource extends Resource
|
||||
->icon(TablerIcon::Trash)
|
||||
->color('danger')
|
||||
->requiresConfirmation()
|
||||
->visible(fn (Plugin $plugin) => $plugin->status === PluginStatus::NotInstalled)
|
||||
->visible(fn (Plugin $plugin) => $plugin->status === PluginStatus::NotInstalled || $plugin->status === PluginStatus::Errored)
|
||||
->action(function (Plugin $plugin, $livewire, PluginService $pluginService) {
|
||||
$pluginService->deletePlugin($plugin);
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ class RoleResource extends Resource
|
||||
->toolbarActions([
|
||||
CreateAction::make(),
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
DeleteBulkAction::make('exclude_bulk_delete'),
|
||||
]),
|
||||
])
|
||||
->checkIfRecordIsSelectableUsing(fn (Role $role) => !$role->isRootAdmin() && $role->users_count <= 0);
|
||||
|
||||
@@ -121,6 +121,7 @@ class EditServer extends EditRecord
|
||||
->columnSpan(2)
|
||||
->alignJustify(),
|
||||
Action::make('uploadIcon')
|
||||
->hiddenLabel()
|
||||
->icon(TablerIcon::PhotoUp)
|
||||
->tooltip(trans('admin/server.import_image'))
|
||||
->modal()
|
||||
@@ -320,7 +321,7 @@ class EditServer extends EditRecord
|
||||
try {
|
||||
$logs = $serverRepository->setServer($server)->getInstallLogs();
|
||||
|
||||
return convert_to_utf8($logs);
|
||||
return mb_convert_encoding($logs, 'UTF-8', ['UTF-8', 'UTF-16', 'ISO-8859-1', 'ASCII']);
|
||||
} catch (ConnectionException) {
|
||||
Notification::make()
|
||||
->title(trans('admin/server.notifications.error_connecting', ['node' => $server->node->name]))
|
||||
@@ -1126,7 +1127,7 @@ class EditServer extends EditRecord
|
||||
->hidden(fn () => $canForceDelete)
|
||||
->authorize(fn (Server $server) => user()?->can('delete server', $server))
|
||||
->icon(TablerIcon::Trash),
|
||||
Action::make('ForceDelete')
|
||||
Action::make('exclude_force_delete')
|
||||
->color('danger')
|
||||
->label(trans('filament-actions::force-delete.single.label'))
|
||||
->modalHeading(trans('filament-actions::force-delete.single.modal.heading', ['label' => $this->getRecordTitle()]))
|
||||
@@ -1218,18 +1219,20 @@ class EditServer extends EditRecord
|
||||
],
|
||||
]);
|
||||
|
||||
$normalizedExtension = match ($extension) {
|
||||
'svg+xml', 'svg' => 'svg',
|
||||
'jpeg', 'jpg' => 'jpg',
|
||||
'png' => 'png',
|
||||
'webp' => 'webp',
|
||||
default => throw new Exception(trans('admin/egg.import.unknown_extension')),
|
||||
};
|
||||
|
||||
$data = @file_get_contents($imageUrl, false, $context, 0, 262144); //256KB
|
||||
|
||||
if (empty($data)) {
|
||||
throw new \Exception(trans('admin/egg.import.invalid_url'));
|
||||
throw new Exception(trans('admin/egg.import.invalid_url'));
|
||||
}
|
||||
|
||||
$normalizedExtension = match ($extension) {
|
||||
'svg+xml' => 'svg',
|
||||
'jpeg' => 'jpg',
|
||||
default => $extension,
|
||||
};
|
||||
|
||||
Storage::disk('public')->put(Server::ICON_STORAGE_PATH . "/$server->uuid.$normalizedExtension", $data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ class WebhookResource extends Resource
|
||||
->toolbarActions([
|
||||
CreateAction::make(),
|
||||
BulkActionGroup::make([
|
||||
DeleteBulkAction::make(),
|
||||
DeleteBulkAction::make('exclude_bulk_delete'),
|
||||
]),
|
||||
])
|
||||
->emptyStateIcon(TablerIcon::Webhook)
|
||||
|
||||
@@ -16,13 +16,15 @@ class RotateDatabasePasswordAction extends Action
|
||||
{
|
||||
public static function getDefaultName(): ?string
|
||||
{
|
||||
return 'hint_rotate';
|
||||
return 'exclude_hint_rotate';
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->hiddenLabel();
|
||||
|
||||
$this->tooltip(trans('admin/databasehost.rotate'));
|
||||
|
||||
$this->icon(TablerIcon::Refresh);
|
||||
|
||||
@@ -426,13 +426,13 @@ class EditProfile extends BaseEditProfile
|
||||
->label(trans('profile.tabs.activity'))
|
||||
->icon(TablerIcon::History)
|
||||
->schema([
|
||||
Repeater::make('activity')
|
||||
->hiddenLabel()
|
||||
Repeater::make('activity') // TODO: move to a table
|
||||
->label(trans('profile.activity_info'))
|
||||
->inlineLabel(false)
|
||||
->deletable(false)
|
||||
->addable(false)
|
||||
->relationship(null, function (Builder $query) {
|
||||
$query->orderBy('timestamp', 'desc');
|
||||
$query->orderBy('timestamp', 'desc')->limit(50);
|
||||
})
|
||||
->schema([
|
||||
TextEntry::make('log')
|
||||
|
||||
@@ -462,18 +462,20 @@ class Settings extends ServerFormPage
|
||||
],
|
||||
]);
|
||||
|
||||
$normalizedExtension = match ($extension) {
|
||||
'svg+xml', 'svg' => 'svg',
|
||||
'jpeg', 'jpg' => 'jpg',
|
||||
'png' => 'png',
|
||||
'webp' => 'webp',
|
||||
default => throw new Exception(trans('admin/egg.import.unknown_extension')),
|
||||
};
|
||||
|
||||
$data = @file_get_contents($imageUrl, false, $context, 0, 262144); //256KB
|
||||
|
||||
if (empty($data)) {
|
||||
throw new \Exception(trans('admin/egg.import.invalid_url'));
|
||||
throw new Exception(trans('admin/egg.import.invalid_url'));
|
||||
}
|
||||
|
||||
$normalizedExtension = match ($extension) {
|
||||
'svg+xml' => 'svg',
|
||||
'jpeg' => 'jpg',
|
||||
default => $extension,
|
||||
};
|
||||
|
||||
Storage::disk('public')->put(Server::ICON_STORAGE_PATH . "/$server->uuid.$normalizedExtension", $data);
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class BackupResource extends Resource
|
||||
/** @var Server $server */
|
||||
$server = Filament::getTenant();
|
||||
|
||||
return $server->backup_limit;
|
||||
return $server->backup_limit ?? 0;
|
||||
}
|
||||
|
||||
public static function defaultForm(Schema $schema): Schema
|
||||
|
||||
@@ -62,7 +62,7 @@ class DatabaseResource extends Resource
|
||||
/** @var Server $server */
|
||||
$server = Filament::getTenant();
|
||||
|
||||
return $server->database_limit;
|
||||
return $server->database_limit ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -149,7 +149,7 @@ class EditFiles extends Page
|
||||
try {
|
||||
$contents = $this->getDaemonFileRepository()->getContent($this->path, config('panel.files.max_edit_size'));
|
||||
|
||||
return convert_to_utf8($contents);
|
||||
return mb_convert_encoding($contents, 'UTF-8', ['UTF-8', 'UTF-16', 'ISO-8859-1', 'ASCII']);
|
||||
} catch (FileSizeTooLargeException) {
|
||||
AlertBanner::make('file_too_large')
|
||||
->title(trans('server/file.alerts.file_too_large.title', ['name' => basename($this->path)]))
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Facades\Activity;
|
||||
use App\Models\Schedule;
|
||||
use App\Models\Task;
|
||||
use Exception;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\EditAction;
|
||||
@@ -73,6 +74,7 @@ class TasksRelationManager extends RelationManager
|
||||
return $table
|
||||
->reorderable('sequence_id')
|
||||
->defaultSort('sequence_id')
|
||||
->reorderRecordsTriggerAction(fn (Action $action, bool $isReordering) => $action->hiddenLabel()->tooltip(fn () => $action->getLabel()))
|
||||
->columns([
|
||||
TextColumn::make('action')
|
||||
->label(trans('server/schedule.tasks.actions.title'))
|
||||
|
||||
@@ -97,8 +97,7 @@ class ScheduleResource extends Resource
|
||||
->formatStateUsing(fn (?Schedule $schedule) => $schedule?->status->value ?? 'new')
|
||||
->options(fn (?Schedule $schedule) => [$schedule?->status->value ?? 'new' => $schedule?->status->getLabel() ?? 'New'])
|
||||
->visibleOn('view'),
|
||||
Section::make('Cron')
|
||||
->label(trans('server/schedule.cron'))
|
||||
Section::make(trans('server/schedule.cron'))
|
||||
->description(function (Get $get) {
|
||||
try {
|
||||
$nextRun = Utilities::getScheduleNextRunDate($get('cron_minute'), $get('cron_hour'), $get('cron_day_of_month'), $get('cron_month'), $get('cron_day_of_week'))->timezone(user()->timezone ?? 'UTC');
|
||||
@@ -110,22 +109,22 @@ class ScheduleResource extends Resource
|
||||
})
|
||||
->schema([
|
||||
Actions::make([
|
||||
CronPresetAction::make('hourly')
|
||||
CronPresetAction::make('exclude_hourly')
|
||||
->label(trans('server/schedule.time.hourly'))
|
||||
->cron('0', '*', '*', '*', '*'),
|
||||
CronPresetAction::make('daily')
|
||||
CronPresetAction::make('exclude_daily')
|
||||
->label(trans('server/schedule.time.daily'))
|
||||
->cron('0', '0', '*', '*', '*'),
|
||||
CronPresetAction::make('weekly_monday')
|
||||
CronPresetAction::make('exclude_weekly_monday')
|
||||
->label(trans('server/schedule.time.weekly_mon'))
|
||||
->cron('0', '0', '*', '*', '1'),
|
||||
CronPresetAction::make('weekly_sunday')
|
||||
CronPresetAction::make('exclude_weekly_sunday')
|
||||
->label(trans('server/schedule.time.weekly_sun'))
|
||||
->cron('0', '0', '*', '*', '0'),
|
||||
CronPresetAction::make('monthly')
|
||||
CronPresetAction::make('exclude_monthly')
|
||||
->label(trans('server/schedule.time.monthly'))
|
||||
->cron('0', '0', '1', '*', '*'),
|
||||
CronPresetAction::make('every_x_minutes')
|
||||
CronPresetAction::make('exclude_every_x_minutes')
|
||||
->label(trans('server/schedule.time.every_min'))
|
||||
->color(fn (Get $get) => str($get('cron_minute'))->startsWith('*/')
|
||||
&& $get('cron_hour') == '*'
|
||||
@@ -148,7 +147,7 @@ class ScheduleResource extends Resource
|
||||
$set('cron_month', '*');
|
||||
$set('cron_day_of_week', '*');
|
||||
}),
|
||||
CronPresetAction::make('every_x_hours')
|
||||
CronPresetAction::make('exclude_every_x_hours')
|
||||
->color(fn (Get $get) => $get('cron_minute') == '0'
|
||||
&& str($get('cron_hour'))->startsWith('*/')
|
||||
&& $get('cron_day_of_month') == '*'
|
||||
@@ -170,7 +169,7 @@ class ScheduleResource extends Resource
|
||||
$set('cron_month', '*');
|
||||
$set('cron_day_of_week', '*');
|
||||
}),
|
||||
CronPresetAction::make('every_x_days')
|
||||
CronPresetAction::make('exclude_every_x_days')
|
||||
->color(fn (Get $get) => $get('cron_minute') == '0'
|
||||
&& $get('cron_hour') == '0'
|
||||
&& str($get('cron_day_of_month'))->startsWith('*/')
|
||||
@@ -192,7 +191,7 @@ class ScheduleResource extends Resource
|
||||
$set('cron_month', '*');
|
||||
$set('cron_day_of_week', '*');
|
||||
}),
|
||||
CronPresetAction::make('every_x_months')
|
||||
CronPresetAction::make('exclude_every_x_months')
|
||||
->color(fn (Get $get) => $get('cron_minute') == '0'
|
||||
&& $get('cron_hour') == '0'
|
||||
&& $get('cron_day_of_month') == '1'
|
||||
@@ -214,7 +213,7 @@ class ScheduleResource extends Resource
|
||||
$set('cron_month', '*/' . $data['x']);
|
||||
$set('cron_day_of_week', '*');
|
||||
}),
|
||||
CronPresetAction::make('every_x_day_of_week')
|
||||
CronPresetAction::make('exclude_every_x_day_of_week')
|
||||
->color(fn (Get $get) => $get('cron_minute') == '0'
|
||||
&& $get('cron_hour') == '0'
|
||||
&& $get('cron_day_of_month') == '*'
|
||||
|
||||
@@ -167,7 +167,7 @@ class SubuserResource extends Resource
|
||||
])
|
||||
->formatStateUsing(fn (Subuser $subuser) => $subuser->user->email),
|
||||
Actions::make([
|
||||
Action::make('assignAll')
|
||||
Action::make('exclude_assignAll')
|
||||
->label(trans('server/user.assign_all'))
|
||||
->action(function (Set $set) use ($permissionsArray) {
|
||||
$permissions = $permissionsArray;
|
||||
@@ -244,7 +244,7 @@ class SubuserResource extends Resource
|
||||
])
|
||||
->required(),
|
||||
Actions::make([
|
||||
Action::make('assignAll')
|
||||
Action::make('exclude_assignAll')
|
||||
->label(trans('server/user.assign_all'))
|
||||
->action(function (Set $set, Get $get) use ($permissionsArray) {
|
||||
$permissions = $permissionsArray;
|
||||
|
||||
@@ -77,7 +77,7 @@ class FileController extends ClientApiController
|
||||
->property('file', $request->get('file'))
|
||||
->log();
|
||||
|
||||
return new Response(convert_to_utf8($response), Response::HTTP_OK, ['Content-Type' => 'text/plain; charset=utf-8']);
|
||||
return new Response($response, Response::HTTP_OK, ['Content-Type' => 'text/plain']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@ use Filament\Notifications\Concerns\HasStatus;
|
||||
use Filament\Notifications\Concerns\HasTitle;
|
||||
use Filament\Support\Components\ViewComponent;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Livewire\Livewire;
|
||||
|
||||
final class AlertBanner extends ViewComponent implements Arrayable
|
||||
{
|
||||
@@ -83,7 +84,13 @@ final class AlertBanner extends ViewComponent implements Arrayable
|
||||
|
||||
public function send(): AlertBanner
|
||||
{
|
||||
session()->push('alert-banners', $this->toArray());
|
||||
$data = $this->toArray();
|
||||
|
||||
if (Livewire::isLivewireRequest()) {
|
||||
$data['from_livewire'] = true;
|
||||
}
|
||||
|
||||
session()->push('alert-banners', $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
15
app/Livewire/AlertBannerCollection.php
Normal file
15
app/Livewire/AlertBannerCollection.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Filament\Notifications\Collection;
|
||||
|
||||
class AlertBannerCollection extends Collection
|
||||
{
|
||||
public static function fromLivewire($value): static
|
||||
{
|
||||
return (new static($value))->transform(
|
||||
fn (array $alertBanner): AlertBanner => AlertBanner::fromArray($alertBanner),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,35 @@
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Filament\Notifications\Collection;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Component;
|
||||
|
||||
class AlertBannerContainer extends Component
|
||||
{
|
||||
public Collection $alertBanners;
|
||||
public AlertBannerCollection $alertBanners;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->alertBanners = new Collection();
|
||||
$this->pullFromSession();
|
||||
$this->alertBanners = new AlertBannerCollection();
|
||||
|
||||
foreach (session()->pull('alert-banners', []) as $alertBanner) {
|
||||
// Alerts created during Livewire requests should have been consumed by the event handler on the same page.
|
||||
if (!empty($alertBanner['from_livewire'])) {
|
||||
// If they weren't, then discard them instead of showing on the wrong page.
|
||||
continue;
|
||||
}
|
||||
|
||||
$alertBanner = AlertBanner::fromArray($alertBanner);
|
||||
$this->alertBanners->put($alertBanner->getId(), $alertBanner);
|
||||
}
|
||||
}
|
||||
|
||||
#[On('alertBannerSent')]
|
||||
public function pullFromSession(): void
|
||||
{
|
||||
foreach (session()->pull('alert-banners', []) as $alertBanner) {
|
||||
unset($alertBanner['from_livewire']);
|
||||
$alertBanner = AlertBanner::fromArray($alertBanner);
|
||||
$this->alertBanners->put($alertBanner->getId(), $alertBanner);
|
||||
}
|
||||
|
||||
@@ -109,13 +109,11 @@ class Plugin extends Model implements HasPluginSettings
|
||||
continue;
|
||||
}
|
||||
|
||||
$plugin = Str::lower($plugin);
|
||||
|
||||
try {
|
||||
$data = File::json($path, JSON_THROW_ON_ERROR);
|
||||
$data['id'] = Str::lower($data['id']);
|
||||
|
||||
if ($data['id'] !== $plugin) {
|
||||
if ($data['id'] !== Str::lower($plugin)) {
|
||||
throw new PluginIdMismatchException("Plugin id mismatch for folder name ($plugin) and id in plugin.json ({$data['id']})!");
|
||||
}
|
||||
|
||||
@@ -161,7 +159,7 @@ class Plugin extends Model implements HasPluginSettings
|
||||
|
||||
if (!$exception instanceof JsonException) {
|
||||
$plugins[] = [
|
||||
'id' => $data['id'] ?? Str::uuid(),
|
||||
'id' => $exception instanceof PluginIdMismatchException ? $plugin : ($data['id'] ?? Str::uuid()),
|
||||
'name' => $data['name'] ?? Str::headline($plugin),
|
||||
'author' => $data['author'] ?? 'Unknown',
|
||||
'version' => $data['version'] ?? '0.0.0',
|
||||
|
||||
@@ -34,7 +34,7 @@ use Illuminate\Support\ServiceProvider;
|
||||
use Livewire\Component;
|
||||
use Livewire\Livewire;
|
||||
|
||||
use function Livewire\on;
|
||||
use function Livewire\before;
|
||||
use function Livewire\store;
|
||||
|
||||
class FilamentServiceProvider extends ServiceProvider
|
||||
@@ -74,7 +74,7 @@ class FilamentServiceProvider extends ServiceProvider
|
||||
fn () => Blade::render("@vite(['resources/js/app.js'])"),
|
||||
);
|
||||
|
||||
on('dehydrate', function (Component $component) {
|
||||
before('dehydrate', function (Component $component) {
|
||||
if (!Livewire::isLivewireRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class PluginService
|
||||
/** @var ClassLoader $classLoader */
|
||||
$classLoader = File::getRequire(base_path('vendor/autoload.php'));
|
||||
|
||||
$plugins = Plugin::query()->orderBy('load_order')->get();
|
||||
$plugins = Plugin::orderBy('load_order')->get();
|
||||
foreach ($plugins as $plugin) {
|
||||
try {
|
||||
// Filter out plugins that are not compatible with the current panel version
|
||||
@@ -138,7 +138,7 @@ class PluginService
|
||||
return;
|
||||
}
|
||||
|
||||
$plugins = Plugin::query()->orderBy('load_order')->get();
|
||||
$plugins = Plugin::orderBy('load_order')->get();
|
||||
foreach ($plugins as $plugin) {
|
||||
try {
|
||||
if (!$plugin->shouldLoad($panel->getId())) {
|
||||
@@ -172,7 +172,7 @@ class PluginService
|
||||
{
|
||||
$newPackages ??= [];
|
||||
|
||||
$plugins = Plugin::query()->orderBy('load_order')->get();
|
||||
$plugins = Plugin::orderBy('load_order')->get();
|
||||
foreach ($plugins as $plugin) {
|
||||
if (!$plugin->composer_packages) {
|
||||
continue;
|
||||
@@ -434,7 +434,7 @@ class PluginService
|
||||
/** @param array<string, mixed> $data */
|
||||
private function setMetaData(string|Plugin $plugin, array $data): void
|
||||
{
|
||||
$path = plugin_path($plugin instanceof Plugin ? $plugin->id : $plugin, 'plugin.json');
|
||||
$path = plugin_path($plugin->id, 'plugin.json');
|
||||
|
||||
if (File::exists($path)) {
|
||||
$pluginData = File::json($path, JSON_THROW_ON_ERROR);
|
||||
@@ -443,7 +443,6 @@ class PluginService
|
||||
|
||||
File::put($path, json_encode($pluginData, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
$plugin = $plugin instanceof Plugin ? $plugin : Plugin::findOrFail($plugin);
|
||||
$plugin->update($metaData);
|
||||
}
|
||||
}
|
||||
@@ -464,6 +463,8 @@ class PluginService
|
||||
public function updateLoadOrder(array $order): void
|
||||
{
|
||||
foreach ($order as $i => $plugin) {
|
||||
$plugin = Plugin::firstOrFail(str($plugin)->lower()->toString());
|
||||
|
||||
$this->setMetaData($plugin, [
|
||||
'load_order' => $i,
|
||||
]);
|
||||
@@ -472,7 +473,7 @@ class PluginService
|
||||
|
||||
public function hasThemePluginEnabled(): bool
|
||||
{
|
||||
$plugins = Plugin::query()->orderBy('load_order')->get();
|
||||
$plugins = Plugin::orderBy('load_order')->get();
|
||||
foreach ($plugins as $plugin) {
|
||||
if ($plugin->isTheme() && $plugin->status === PluginStatus::Enabled) {
|
||||
return true;
|
||||
@@ -487,7 +488,7 @@ class PluginService
|
||||
{
|
||||
$languages = [];
|
||||
|
||||
$plugins = Plugin::query()->orderBy('load_order')->get();
|
||||
$plugins = Plugin::orderBy('load_order')->get();
|
||||
foreach ($plugins as $plugin) {
|
||||
if ($plugin->status !== PluginStatus::Enabled || !$plugin->isLanguage()) {
|
||||
continue;
|
||||
@@ -504,7 +505,7 @@ class PluginService
|
||||
return config('panel.plugin.dev_mode', false);
|
||||
}
|
||||
|
||||
private function handlePluginException(string|Plugin $plugin, Exception $exception): void
|
||||
private function handlePluginException(Plugin $plugin, Exception $exception): void
|
||||
{
|
||||
if ($this->isDevModeActive()) {
|
||||
throw ($exception);
|
||||
|
||||
@@ -130,27 +130,6 @@ if (!function_exists('encode_path')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('convert_to_utf8')) {
|
||||
/**
|
||||
* Convert a string to UTF-8 from an unknown encoding
|
||||
*/
|
||||
function convert_to_utf8(string $contents): string
|
||||
{
|
||||
// Valid UTF-8 passes through unchanged
|
||||
if (mb_check_encoding($contents, 'UTF-8')) {
|
||||
return $contents;
|
||||
}
|
||||
|
||||
// Only detect UTF-16 by BOM instead of mb_check_encoding('UTF-16') which can cause false positives
|
||||
if (str_starts_with($contents, "\xFF\xFE") || str_starts_with($contents, "\xFE\xFF")) {
|
||||
return mb_convert_encoding($contents, 'UTF-8', 'UTF-16');
|
||||
}
|
||||
|
||||
// ISO-8859-1 serves as a universal fallback since any byte sequence is valid in it
|
||||
return mb_convert_encoding($contents, 'UTF-8', 'ISO-8859-1');
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('user')) {
|
||||
function user(): ?App\Models\User
|
||||
{
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
"calebporzio/sushi": "^2.5",
|
||||
"dedoc/scramble": "^0.13",
|
||||
"filament/filament": "^4.5",
|
||||
"gboquizosanchez/filament-log-viewer": "^2.1",
|
||||
"gboquizosanchez/filament-log-viewer": "^2.2",
|
||||
"guzzlehttp/guzzle": "^7.10",
|
||||
"laravel/framework": "^12.51",
|
||||
"laravel/framework": "^12.52",
|
||||
"laravel/helpers": "^1.8",
|
||||
"laravel/sanctum": "^4.2",
|
||||
"laravel/sanctum": "^4.3",
|
||||
"laravel/socialite": "^5.24",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"laravel/ui": "^4.6",
|
||||
@@ -34,7 +34,7 @@
|
||||
"socialiteproviders/steam": "^4.3",
|
||||
"spatie/laravel-data": "^4.19",
|
||||
"spatie/laravel-fractal": "^6.3",
|
||||
"spatie/laravel-health": "^1.34",
|
||||
"spatie/laravel-health": "^1.37",
|
||||
"spatie/laravel-permission": "^6.24",
|
||||
"spatie/laravel-query-builder": "^6.4",
|
||||
"spatie/temporary-directory": "^2.3",
|
||||
@@ -55,8 +55,7 @@
|
||||
"nunomaduro/collision": "^8.6",
|
||||
"pestphp/pest": "^3.7",
|
||||
"pestphp/pest-plugin-faker": "^3.0",
|
||||
"pestphp/pest-plugin-livewire": "^3.0",
|
||||
"spatie/laravel-ignition": "^2.9"
|
||||
"pestphp/pest-plugin-livewire": "^3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
|
||||
543
composer.lock
generated
543
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "784a5e04d3c28e0dba289d45a239075e",
|
||||
"content-hash": "f6d587063490fa0aeb46b8f05dd30a22",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
@@ -128,16 +128,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.369.31",
|
||||
"version": "3.369.36",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "c7bf53dfb09bea3ebfd19b89213625aa134dcc71"
|
||||
"reference": "2a69e7df5e03be9e08f9f73fb6a8cc9dd63b59c0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c7bf53dfb09bea3ebfd19b89213625aa134dcc71",
|
||||
"reference": "c7bf53dfb09bea3ebfd19b89213625aa134dcc71",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2a69e7df5e03be9e08f9f73fb6a8cc9dd63b59c0",
|
||||
"reference": "2a69e7df5e03be9e08f9f73fb6a8cc9dd63b59c0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -219,9 +219,9 @@
|
||||
"support": {
|
||||
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.369.31"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.369.36"
|
||||
},
|
||||
"time": "2026-02-10T19:13:30+00:00"
|
||||
"time": "2026-02-17T19:45:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "blade-ui-kit/blade-heroicons",
|
||||
@@ -822,16 +822,16 @@
|
||||
},
|
||||
{
|
||||
"name": "dedoc/scramble",
|
||||
"version": "v0.13.12",
|
||||
"version": "v0.13.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dedoc/scramble.git",
|
||||
"reference": "1788ab68ae51ae2fce34e16add1387ee1ac5d88b"
|
||||
"reference": "8f0c1bba364e4916f3f2ff23b7f4ca002e586b75"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dedoc/scramble/zipball/1788ab68ae51ae2fce34e16add1387ee1ac5d88b",
|
||||
"reference": "1788ab68ae51ae2fce34e16add1387ee1ac5d88b",
|
||||
"url": "https://api.github.com/repos/dedoc/scramble/zipball/8f0c1bba364e4916f3f2ff23b7f4ca002e586b75",
|
||||
"reference": "8f0c1bba364e4916f3f2ff23b7f4ca002e586b75",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -890,7 +890,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/dedoc/scramble/issues",
|
||||
"source": "https://github.com/dedoc/scramble/tree/v0.13.12"
|
||||
"source": "https://github.com/dedoc/scramble/tree/v0.13.14"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -898,7 +898,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-05T07:47:09+00:00"
|
||||
"time": "2026-02-15T13:14:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dflydev/dot-access-data",
|
||||
@@ -2544,16 +2544,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v12.51.0",
|
||||
"version": "v12.52.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16"
|
||||
"reference": "d5511fa74f4608dbb99864198b1954042aa8d5a7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/ce4de3feb211e47c4f959d309ccf8a2733b1bc16",
|
||||
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/d5511fa74f4608dbb99864198b1954042aa8d5a7",
|
||||
"reference": "d5511fa74f4608dbb99864198b1954042aa8d5a7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2762,7 +2762,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2026-02-10T18:20:19+00:00"
|
||||
"time": "2026-02-17T17:07:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/helpers",
|
||||
@@ -4877,16 +4877,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v4.1.2",
|
||||
"version": "v4.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5"
|
||||
"reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
|
||||
"reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe",
|
||||
"reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4898,8 +4898,10 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"jetbrains/phpstorm-attributes": "^1.2",
|
||||
"nette/phpstan-rules": "^1.0",
|
||||
"nette/tester": "^2.5",
|
||||
"phpstan/phpstan": "^2.0@stable",
|
||||
"phpstan/extension-installer": "^1.4@stable",
|
||||
"phpstan/phpstan": "^2.1@stable",
|
||||
"tracy/tracy": "^2.9"
|
||||
},
|
||||
"suggest": {
|
||||
@@ -4960,9 +4962,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.2"
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.3"
|
||||
},
|
||||
"time": "2026-02-03T17:21:09+00:00"
|
||||
"time": "2026-02-13T03:05:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
@@ -5024,31 +5026,31 @@
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/termwind",
|
||||
"version": "v2.3.3",
|
||||
"version": "v2.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nunomaduro/termwind.git",
|
||||
"reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017"
|
||||
"reference": "712a31b768f5daea284c2169a7d227031001b9a8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017",
|
||||
"reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017",
|
||||
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8",
|
||||
"reference": "712a31b768f5daea284c2169a7d227031001b9a8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": "^8.2",
|
||||
"symfony/console": "^7.3.6"
|
||||
"symfony/console": "^7.4.4 || ^8.0.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/console": "^11.46.1",
|
||||
"laravel/pint": "^1.25.1",
|
||||
"illuminate/console": "^11.47.0",
|
||||
"laravel/pint": "^1.27.1",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3",
|
||||
"pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2",
|
||||
"phpstan/phpstan": "^1.12.32",
|
||||
"phpstan/phpstan-strict-rules": "^1.6.2",
|
||||
"symfony/var-dumper": "^7.3.5",
|
||||
"symfony/var-dumper": "^7.3.5 || ^8.0.4",
|
||||
"thecodingmachine/phpstan-strict-rules": "^1.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -5080,7 +5082,7 @@
|
||||
"email": "enunomaduro@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Its like Tailwind CSS, but for the console.",
|
||||
"description": "It's like Tailwind CSS, but for the console.",
|
||||
"keywords": [
|
||||
"cli",
|
||||
"console",
|
||||
@@ -5091,7 +5093,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nunomaduro/termwind/issues",
|
||||
"source": "https://github.com/nunomaduro/termwind/tree/v2.3.3"
|
||||
"source": "https://github.com/nunomaduro/termwind/tree/v2.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5107,7 +5109,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-20T02:34:59+00:00"
|
||||
"time": "2026-02-16T23:10:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "openspout/openspout",
|
||||
@@ -6526,16 +6528,16 @@
|
||||
},
|
||||
{
|
||||
"name": "psy/psysh",
|
||||
"version": "v0.12.19",
|
||||
"version": "v0.12.20",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bobthecow/psysh.git",
|
||||
"reference": "a4f766e5c5b6773d8399711019bb7d90875a50ee"
|
||||
"reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/a4f766e5c5b6773d8399711019bb7d90875a50ee",
|
||||
"reference": "a4f766e5c5b6773d8399711019bb7d90875a50ee",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/19678eb6b952a03b8a1d96ecee9edba518bb0373",
|
||||
"reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6599,9 +6601,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bobthecow/psysh/issues",
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.19"
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.20"
|
||||
},
|
||||
"time": "2026-01-30T17:33:13+00:00"
|
||||
"time": "2026-02-11T15:05:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
@@ -7657,16 +7659,16 @@
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-health",
|
||||
"version": "1.36.0",
|
||||
"version": "1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-health.git",
|
||||
"reference": "e2a84e886cb38ab0a53f136e4554c64e0480e634"
|
||||
"reference": "2d3a68ae2f855d3997a85deb819898a4b7720d49"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-health/zipball/e2a84e886cb38ab0a53f136e4554c64e0480e634",
|
||||
"reference": "e2a84e886cb38ab0a53f136e4554c64e0480e634",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-health/zipball/2d3a68ae2f855d3997a85deb819898a4b7720d49",
|
||||
"reference": "2d3a68ae2f855d3997a85deb819898a4b7720d49",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7738,7 +7740,7 @@
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/spatie/laravel-health/tree/1.36.0"
|
||||
"source": "https://github.com/spatie/laravel-health/tree/1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7746,7 +7748,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-09T15:38:27+00:00"
|
||||
"time": "2026-02-12T16:31:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-package-tools",
|
||||
@@ -12744,39 +12746,36 @@
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/collision",
|
||||
"version": "v8.8.3",
|
||||
"version": "v8.9.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nunomaduro/collision.git",
|
||||
"reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4"
|
||||
"reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/1dc9e88d105699d0fee8bb18890f41b274f6b4c4",
|
||||
"reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4",
|
||||
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/a1ed3fa530fd60bc515f9303e8520fcb7d4bd935",
|
||||
"reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"filp/whoops": "^2.18.1",
|
||||
"nunomaduro/termwind": "^2.3.1",
|
||||
"filp/whoops": "^2.18.4",
|
||||
"nunomaduro/termwind": "^2.4.0",
|
||||
"php": "^8.2.0",
|
||||
"symfony/console": "^7.3.0"
|
||||
"symfony/console": "^7.4.4 || ^8.0.4"
|
||||
},
|
||||
"conflict": {
|
||||
"laravel/framework": "<11.44.2 || >=13.0.0",
|
||||
"phpunit/phpunit": "<11.5.15 || >=13.0.0"
|
||||
"laravel/framework": "<11.48.0 || >=14.0.0",
|
||||
"phpunit/phpunit": "<11.5.50 || >=14.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"brianium/paratest": "^7.8.3",
|
||||
"larastan/larastan": "^3.4.2",
|
||||
"laravel/framework": "^11.44.2 || ^12.18",
|
||||
"laravel/pint": "^1.22.1",
|
||||
"laravel/sail": "^1.43.1",
|
||||
"laravel/sanctum": "^4.1.1",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"orchestra/testbench-core": "^9.12.0 || ^10.4",
|
||||
"pestphp/pest": "^3.8.2 || ^4.0.0",
|
||||
"sebastian/environment": "^7.2.1 || ^8.0"
|
||||
"brianium/paratest": "^7.8.5",
|
||||
"larastan/larastan": "^3.9.2",
|
||||
"laravel/framework": "^11.48.0 || ^12.52.0",
|
||||
"laravel/pint": "^1.27.1",
|
||||
"orchestra/testbench-core": "^9.12.0 || ^10.9.0",
|
||||
"pestphp/pest": "^3.8.5 || ^4.4.1 || ^5.0.0",
|
||||
"sebastian/environment": "^7.2.1 || ^8.0.3 || ^9.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -12839,7 +12838,7 @@
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-20T02:55:25+00:00"
|
||||
"time": "2026-02-17T17:33:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pestphp/pest",
|
||||
@@ -13416,11 +13415,11 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.38",
|
||||
"version": "2.1.39",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/dfaf1f530e1663aa167bc3e52197adb221582629",
|
||||
"reference": "dfaf1f530e1663aa167bc3e52197adb221582629",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224",
|
||||
"reference": "c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -13465,7 +13464,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-30T17:12:46+00:00"
|
||||
"time": "2026-02-11T14:48:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@@ -14909,388 +14908,6 @@
|
||||
],
|
||||
"time": "2024-10-09T05:16:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/backtrace",
|
||||
"version": "1.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/backtrace.git",
|
||||
"reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/backtrace/zipball/8c0f16a59ae35ec8c62d85c3c17585158f430110",
|
||||
"reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-json": "*",
|
||||
"laravel/serializable-closure": "^1.3 || ^2.0",
|
||||
"phpunit/phpunit": "^9.3 || ^11.4.3",
|
||||
"spatie/phpunit-snapshot-assertions": "^4.2 || ^5.1.6",
|
||||
"symfony/var-dumper": "^5.1 || ^6.0 || ^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\Backtrace\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Freek Van de Herten",
|
||||
"email": "freek@spatie.be",
|
||||
"homepage": "https://spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A better backtrace",
|
||||
"homepage": "https://github.com/spatie/backtrace",
|
||||
"keywords": [
|
||||
"Backtrace",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/backtrace/issues",
|
||||
"source": "https://github.com/spatie/backtrace/tree/1.8.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/spatie",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://spatie.be/open-source/support-us",
|
||||
"type": "other"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-26T08:22:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/error-solutions",
|
||||
"version": "1.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/error-solutions.git",
|
||||
"reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/error-solutions/zipball/e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
|
||||
"reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/broadcasting": "^10.0|^11.0|^12.0",
|
||||
"illuminate/cache": "^10.0|^11.0|^12.0",
|
||||
"illuminate/support": "^10.0|^11.0|^12.0",
|
||||
"livewire/livewire": "^2.11|^3.5.20",
|
||||
"openai-php/client": "^0.10.1",
|
||||
"orchestra/testbench": "8.22.3|^9.0|^10.0",
|
||||
"pestphp/pest": "^2.20|^3.0",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"psr/simple-cache": "^3.0",
|
||||
"psr/simple-cache-implementation": "^3.0",
|
||||
"spatie/ray": "^1.28",
|
||||
"symfony/cache": "^5.4|^6.0|^7.0",
|
||||
"symfony/process": "^5.4|^6.0|^7.0",
|
||||
"vlucas/phpdotenv": "^5.5"
|
||||
},
|
||||
"suggest": {
|
||||
"openai-php/client": "Require get solutions from OpenAI",
|
||||
"simple-cache-implementation": "To cache solutions from OpenAI"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\Ignition\\": "legacy/ignition",
|
||||
"Spatie\\ErrorSolutions\\": "src",
|
||||
"Spatie\\LaravelIgnition\\": "legacy/laravel-ignition"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ruben Van Assche",
|
||||
"email": "ruben@spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "This is my package error-solutions",
|
||||
"homepage": "https://github.com/spatie/error-solutions",
|
||||
"keywords": [
|
||||
"error-solutions",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/error-solutions/issues",
|
||||
"source": "https://github.com/spatie/error-solutions/tree/1.1.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-14T12:29:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/flare-client-php",
|
||||
"version": "1.10.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/flare-client-php.git",
|
||||
"reference": "bf1716eb98bd689451b071548ae9e70738dce62f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/flare-client-php/zipball/bf1716eb98bd689451b071548ae9e70738dce62f",
|
||||
"reference": "bf1716eb98bd689451b071548ae9e70738dce62f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/pipeline": "^8.0|^9.0|^10.0|^11.0|^12.0",
|
||||
"php": "^8.0",
|
||||
"spatie/backtrace": "^1.6.1",
|
||||
"symfony/http-foundation": "^5.2|^6.0|^7.0",
|
||||
"symfony/mime": "^5.2|^6.0|^7.0",
|
||||
"symfony/process": "^5.2|^6.0|^7.0",
|
||||
"symfony/var-dumper": "^5.2|^6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dms/phpunit-arraysubset-asserts": "^0.5.0",
|
||||
"pestphp/pest": "^1.20|^2.0",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"spatie/pest-plugin-snapshots": "^1.0|^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Spatie\\FlareClient\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Send PHP errors to Flare",
|
||||
"homepage": "https://github.com/spatie/flare-client-php",
|
||||
"keywords": [
|
||||
"exception",
|
||||
"flare",
|
||||
"reporting",
|
||||
"spatie"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/flare-client-php/issues",
|
||||
"source": "https://github.com/spatie/flare-client-php/tree/1.10.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-14T13:42:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/ignition",
|
||||
"version": "1.15.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/ignition.git",
|
||||
"reference": "31f314153020aee5af3537e507fef892ffbf8c85"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/ignition/zipball/31f314153020aee5af3537e507fef892ffbf8c85",
|
||||
"reference": "31f314153020aee5af3537e507fef892ffbf8c85",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": "^8.0",
|
||||
"spatie/error-solutions": "^1.0",
|
||||
"spatie/flare-client-php": "^1.7",
|
||||
"symfony/console": "^5.4|^6.0|^7.0",
|
||||
"symfony/var-dumper": "^5.4|^6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"illuminate/cache": "^9.52|^10.0|^11.0|^12.0",
|
||||
"mockery/mockery": "^1.4",
|
||||
"pestphp/pest": "^1.20|^2.0",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"psr/simple-cache-implementation": "*",
|
||||
"symfony/cache": "^5.4|^6.0|^7.0",
|
||||
"symfony/process": "^5.4|^6.0|^7.0",
|
||||
"vlucas/phpdotenv": "^5.5"
|
||||
},
|
||||
"suggest": {
|
||||
"openai-php/client": "Require get solutions from OpenAI",
|
||||
"simple-cache-implementation": "To cache solutions from OpenAI"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.5.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spatie\\Ignition\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Spatie",
|
||||
"email": "info@spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A beautiful error page for PHP applications.",
|
||||
"homepage": "https://flareapp.io/ignition",
|
||||
"keywords": [
|
||||
"error",
|
||||
"flare",
|
||||
"laravel",
|
||||
"page"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://flareapp.io/docs/ignition-for-laravel/introduction",
|
||||
"forum": "https://twitter.com/flareappio",
|
||||
"issues": "https://github.com/spatie/ignition/issues",
|
||||
"source": "https://github.com/spatie/ignition"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-21T14:31:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-ignition",
|
||||
"version": "2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-ignition.git",
|
||||
"reference": "2abefdcca6074a9155f90b4ccb3345af8889d5f5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/2abefdcca6074a9155f90b4ccb3345af8889d5f5",
|
||||
"reference": "2abefdcca6074a9155f90b4ccb3345af8889d5f5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"illuminate/support": "^11.0|^12.0",
|
||||
"nesbot/carbon": "^2.72|^3.0",
|
||||
"php": "^8.2",
|
||||
"spatie/ignition": "^1.15.1",
|
||||
"symfony/console": "^7.4|^8.0",
|
||||
"symfony/var-dumper": "^7.4|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"livewire/livewire": "^3.7.0|^4.0",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"openai-php/client": "^0.10.3",
|
||||
"orchestra/testbench": "^v9.16.0|^10.6",
|
||||
"pestphp/pest": "^3.7|^4.0",
|
||||
"phpstan/extension-installer": "^1.4.3",
|
||||
"phpstan/phpstan-deprecation-rules": "^2.0.3",
|
||||
"phpstan/phpstan-phpunit": "^2.0.8",
|
||||
"vlucas/phpdotenv": "^5.6.2"
|
||||
},
|
||||
"suggest": {
|
||||
"openai-php/client": "Require get solutions from OpenAI",
|
||||
"psr/simple-cache-implementation": "Needed to cache solutions from OpenAI"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"Flare": "Spatie\\LaravelIgnition\\Facades\\Flare"
|
||||
},
|
||||
"providers": [
|
||||
"Spatie\\LaravelIgnition\\IgnitionServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Spatie\\LaravelIgnition\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Spatie",
|
||||
"email": "info@spatie.be",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A beautiful error page for Laravel applications.",
|
||||
"homepage": "https://flareapp.io/ignition",
|
||||
"keywords": [
|
||||
"error",
|
||||
"flare",
|
||||
"laravel",
|
||||
"page"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://flareapp.io/docs/ignition-for-laravel/introduction",
|
||||
"forum": "https://twitter.com/flareappio",
|
||||
"issues": "https://github.com/spatie/laravel-ignition/issues",
|
||||
"source": "https://github.com/spatie/laravel-ignition"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/spatie",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-20T13:16:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "staabm/side-effects-detector",
|
||||
"version": "1.0.5",
|
||||
@@ -15345,23 +14962,23 @@
|
||||
},
|
||||
{
|
||||
"name": "ta-tikoma/phpunit-architecture-test",
|
||||
"version": "0.8.6",
|
||||
"version": "0.8.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ta-tikoma/phpunit-architecture-test.git",
|
||||
"reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e"
|
||||
"reference": "1248f3f506ca9641d4f68cebcd538fa489754db8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/ad48430b92901fd7d003fdaf2d7b139f96c0906e",
|
||||
"reference": "ad48430b92901fd7d003fdaf2d7b139f96c0906e",
|
||||
"url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/1248f3f506ca9641d4f68cebcd538fa489754db8",
|
||||
"reference": "1248f3f506ca9641d4f68cebcd538fa489754db8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.18.0 || ^5.0.0",
|
||||
"php": "^8.1.0",
|
||||
"phpdocumentor/reflection-docblock": "^5.3.0 || ^6.0.0",
|
||||
"phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0",
|
||||
"phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0 || ^13.0.0",
|
||||
"symfony/finder": "^6.4.0 || ^7.0.0 || ^8.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -15398,9 +15015,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues",
|
||||
"source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.6"
|
||||
"source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.7"
|
||||
},
|
||||
"time": "2026-01-30T07:16:00+00:00"
|
||||
"time": "2026-02-17T17:25:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
@@ -15470,5 +15087,5 @@
|
||||
"platform-overrides": {
|
||||
"php": "8.2"
|
||||
},
|
||||
"plugin-api-version": "2.9.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
@@ -8,29 +8,35 @@ return new class extends Migration
|
||||
{
|
||||
$mappings = [
|
||||
// Forge Minecraft
|
||||
'ed072427-f209-4603-875c-f540c6dd5a65' => [
|
||||
'new_uuid' => 'd6018085-eecc-42bf-bf8c-51ea45a69ace',
|
||||
'd6018085-eecc-42bf-bf8c-51ea45a69ace' => [
|
||||
'new_uuid' => 'ed072427-f209-4603-875c-f540c6dd5a65',
|
||||
'new_update_url' => 'https://raw.githubusercontent.com/pelican-eggs/minecraft/refs/heads/main/java/forge/egg-forge-minecraft.yaml',
|
||||
],
|
||||
|
||||
// Paper
|
||||
'5da37ef6-58da-4169-90a6-e683e1721247' => [
|
||||
'new_uuid' => '150956be-4164-4086-9057-631ae95505e9',
|
||||
'150956be-4164-4086-9057-631ae95505e9' => [
|
||||
'new_uuid' => '5da37ef6-58da-4169-90a6-e683e1721247',
|
||||
'new_update_url' => 'https://raw.githubusercontent.com/pelican-eggs/minecraft/refs/heads/main/java/paper/egg-paper.yaml',
|
||||
],
|
||||
|
||||
// Garrys Mod
|
||||
'60ef81d4-30a2-4d98-ab64-f59c69e2f915' => [
|
||||
'new_uuid' => 'c0b2f96a-f753-4d82-a73e-6e5be2bbadd5',
|
||||
'c0b2f96a-f753-4d82-a73e-6e5be2bbadd5' => [
|
||||
'new_uuid' => '60ef81d4-30a2-4d98-ab64-f59c69e2f915',
|
||||
'new_update_url' => 'https://raw.githubusercontent.com/pelican-eggs/games-steamcmd/refs/heads/main/gmod/egg-garrys-mod.yaml',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($mappings as $oldUuid => $newData) {
|
||||
DB::table('eggs')->where('uuid', $oldUuid)->update([
|
||||
'uuid' => $newData['new_uuid'],
|
||||
'update_url' => $newData['new_update_url'],
|
||||
]);
|
||||
if (DB::table('eggs')->where('uuid', $newData['new_uuid'])->exists()) {
|
||||
DB::table('eggs')->where('uuid', $newData['new_uuid'])->update([
|
||||
'update_url' => $newData['new_update_url'],
|
||||
]);
|
||||
} else {
|
||||
DB::table('eggs')->where('uuid', $oldUuid)->update([
|
||||
'uuid' => $newData['new_uuid'],
|
||||
'update_url' => $newData['new_update_url'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
{$CADDY_STRICT_PROXIES}
|
||||
}
|
||||
admin off
|
||||
{$PARSED_AUTO_HTTPS}
|
||||
{$PARSED_LE_EMAIL}
|
||||
{$CADDY_AUTO_HTTPS}
|
||||
{$CADDY_LE_EMAIL}
|
||||
}
|
||||
|
||||
{$PARSED_APP_URL} {
|
||||
{$CADDY_APP_URL} {
|
||||
root * /var/www/html/public
|
||||
encode gzip
|
||||
|
||||
|
||||
@@ -1,34 +1,48 @@
|
||||
#!/bin/ash -e
|
||||
# shellcheck shell=dash
|
||||
|
||||
# check for .env file or symlink and generate app keys if missing
|
||||
if [ -f /var/www/html/.env ]; then
|
||||
echo "external vars exist."
|
||||
if [ -f /pelican-data/.env ]; then
|
||||
echo ".env vars exist."
|
||||
# load specific env vars from .env used in the entrypoint and they are not already set
|
||||
for VAR in "APP_KEY" "APP_INSTALLED" "DB_CONNECTION" "DB_HOST" "DB_PORT"; do if ! (printenv | grep -q ${VAR}); then export $(grep ${VAR} .env | grep -ve "^#"); fi; done
|
||||
for VAR in "APP_KEY" "APP_INSTALLED" "DB_CONNECTION" "DB_HOST" "DB_PORT"; do
|
||||
echo "checking for ${VAR}"
|
||||
## skip if it looks like it might try to execute code
|
||||
if (grep "${VAR}" .env | grep -qE "\$\(|=\`|\$#"); then echo "var in .env may be executable or a comment, skipping"; continue; fi
|
||||
# if the variable is in .env then set it
|
||||
if (grep -q "${VAR}" .env); then
|
||||
echo "loading ${VAR} from .env"
|
||||
export "$(grep "${VAR}" .env | sed 's/"//g')"
|
||||
continue
|
||||
fi
|
||||
## variable wasn't loaded or in the env to set
|
||||
echo "didn't find variable to set"
|
||||
done
|
||||
else
|
||||
echo "external vars don't exist."
|
||||
echo ".env vars don't exist."
|
||||
# webroot .env is symlinked to this path
|
||||
touch /pelican-data/.env
|
||||
|
||||
# manually generate a key because key generate --force fails
|
||||
if [ -z ${APP_KEY} ]; then
|
||||
echo -e "Generating key."
|
||||
if [ -z "${APP_KEY}" ]; then
|
||||
echo "No key set, Generating key."
|
||||
APP_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
|
||||
echo -e "Generated app key: $APP_KEY"
|
||||
echo -e "APP_KEY=$APP_KEY" > /pelican-data/.env
|
||||
echo "APP_KEY=$APP_KEY" > /pelican-data/.env
|
||||
echo "Generated app key written to .env file"
|
||||
else
|
||||
echo -e "APP_KEY exists in environment, using that."
|
||||
echo -e "APP_KEY=$APP_KEY" > /pelican-data/.env
|
||||
echo "APP_KEY exists in environment, using that."
|
||||
echo "APP_KEY=$APP_KEY" > /pelican-data/.env
|
||||
fi
|
||||
|
||||
# enable installer
|
||||
echo -e "APP_INSTALLED=false" >> /pelican-data/.env
|
||||
echo "APP_INSTALLED=false" >> /pelican-data/.env
|
||||
fi
|
||||
|
||||
# create directories for volumes
|
||||
mkdir -p /pelican-data/database /pelican-data/storage/avatars /pelican-data/storage/fonts /pelican-data/storage/icons /pelican-data/plugins /var/www/html/storage/logs/supervisord 2>/dev/null
|
||||
|
||||
# if the app is installed then we need to run migrations on start. New installs will run migrations when you run the installer.
|
||||
if [ "${APP_INSTALLED}" == "true" ]; then
|
||||
if [ "${APP_INSTALLED}" = "true" ]; then
|
||||
#if the db is anything but sqlite wait until it's accepting connections
|
||||
if [ "${DB_CONNECTION}" != "sqlite" ]; then
|
||||
# check for DB up before starting the panel
|
||||
@@ -39,36 +53,44 @@ if [ "${APP_INSTALLED}" == "true" ]; then
|
||||
# wait for 1 seconds before check again
|
||||
sleep 1
|
||||
done
|
||||
else
|
||||
echo "using sqlite database"
|
||||
fi
|
||||
|
||||
# run migration
|
||||
php artisan migrate --force
|
||||
fi
|
||||
|
||||
echo -e "Optimizing Filament"
|
||||
echo "Optimizing Filament"
|
||||
php artisan filament:optimize
|
||||
|
||||
# default to caddy not starting
|
||||
export SUPERVISORD_CADDY=false
|
||||
export PARSED_APP_URL=${APP_URL}
|
||||
export CADDY_APP_URL="${APP_URL}"
|
||||
|
||||
# checking if app url is using https
|
||||
if echo "${APP_URL}" | grep -qE '^https://'; then
|
||||
# checking if app url is https
|
||||
if (echo "${APP_URL}" | grep -qE '^https://'); then
|
||||
# check lets encrypt email was set without a proxy
|
||||
if [ -z "${LE_EMAIL}" ] && [ "${BEHIND_PROXY}" != "true" ]; then
|
||||
echo "when app url is https a lets encrypt email must be set when not behind a proxy"
|
||||
exit 1
|
||||
fi
|
||||
echo "https domain found setting email var"
|
||||
export PARSED_LE_EMAIL="email ${LE_EMAIL}"
|
||||
export CADDY_LE_EMAIL="email ${LE_EMAIL}"
|
||||
fi
|
||||
|
||||
# when running behind a proxy
|
||||
if [ "${BEHIND_PROXY}" == "true" ]; then
|
||||
if [ "${BEHIND_PROXY}" = "true" ]; then
|
||||
echo "running behind proxy"
|
||||
echo "listening on port 80 internally"
|
||||
export PARSED_LE_EMAIL=""
|
||||
export PARSED_APP_URL=":80"
|
||||
export PARSED_AUTO_HTTPS="auto_https off"
|
||||
export ASSET_URL=${APP_URL}
|
||||
export CADDY_LE_EMAIL=""
|
||||
export CADDY_APP_URL=":80"
|
||||
export CADDY_AUTO_HTTPS="auto_https off"
|
||||
export ASSET_URL="${APP_URL}"
|
||||
fi
|
||||
|
||||
# disable caddy if SKIP_CADDY is set
|
||||
if [ "${SKIP_CADDY:-}" == "true" ]; then
|
||||
if [ "${SKIP_CADDY:-}" = "true" ]; then
|
||||
echo "Starting PHP-FPM only"
|
||||
else
|
||||
echo "Starting PHP-FPM and Caddy"
|
||||
@@ -76,8 +98,9 @@ else
|
||||
export SUPERVISORD_CADDY=true
|
||||
|
||||
# handle trusted proxies for caddy when variable has data
|
||||
if [ ! -z ${TRUSTED_PROXIES} ]; then
|
||||
export CADDY_TRUSTED_PROXIES=$(echo "trusted_proxies static ${TRUSTED_PROXIES}" | sed 's/,/ /g')
|
||||
if [ -n "${TRUSTED_PROXIES:-}" ]; then
|
||||
FORMATTED_PROXIES=$(echo "trusted_proxies static ${TRUSTED_PROXIES}" | sed 's/,/ /g')
|
||||
export CADDY_TRUSTED_PROXIES="${FORMATTED_PROXIES}"
|
||||
export CADDY_STRICT_PROXIES="trusted_proxies_strict"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -31,6 +31,7 @@ return [
|
||||
'no_local_ip' => 'Local IP Addresses are not allowed',
|
||||
'unsupported_format' => 'Unsupported Format. Supported Formats: :formats',
|
||||
'invalid_url' => 'The provided URL is invalid',
|
||||
'unknown_extension' => 'Unknown image extension',
|
||||
'image_deleted' => 'Image Deleted',
|
||||
'no_image' => 'No Image Provided',
|
||||
'image_updated' => 'Image Updated',
|
||||
|
||||
@@ -69,4 +69,5 @@ return [
|
||||
'no_oauth' => 'No Accounts Linked',
|
||||
'no_api_keys' => 'No API Keys',
|
||||
'no_ssh_keys' => 'No SSH Keys',
|
||||
'activity_info' => 'Showing last 50 activity logs',
|
||||
];
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,120 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Unit\Helpers;
|
||||
|
||||
use App\Tests\TestCase;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
|
||||
class ConvertToUtf8Test extends TestCase
|
||||
{
|
||||
#[DataProvider('helperDataProvider')]
|
||||
public function test_helper(string $input, string $expected): void
|
||||
{
|
||||
$result = convert_to_utf8($input);
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Every output must be valid UTF-8, regardless of input encoding.
|
||||
*/
|
||||
#[DataProvider('helperDataProvider')]
|
||||
public function test_output_is_valid_utf8(string $input): void
|
||||
{
|
||||
$result = convert_to_utf8($input);
|
||||
$this->assertTrue(mb_check_encoding($result, 'UTF-8'), 'Output is not valid UTF-8: ' . bin2hex($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Running convert_to_utf8 twice must produce the same result as once.
|
||||
*/
|
||||
#[DataProvider('helperDataProvider')]
|
||||
public function test_idempotent(string $input): void
|
||||
{
|
||||
$once = convert_to_utf8($input);
|
||||
$twice = convert_to_utf8($once);
|
||||
$this->assertSame($once, $twice, 'Double conversion changed the output (double-encoding bug): ' . bin2hex($once) . ' → ' . bin2hex($twice));
|
||||
}
|
||||
|
||||
public static function helperDataProvider(): array
|
||||
{
|
||||
return [
|
||||
// UTF-8 passthrough - must never be re-encoded
|
||||
'ascii string' => ['hello world', 'hello world'],
|
||||
'empty string' => ['', ''],
|
||||
'utf8 accented cafe' => ["caf\xC3\xA9", "caf\xC3\xA9"],
|
||||
'utf8 emoji' => ["\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80"],
|
||||
'utf8 cjk characters' => ["\xE4\xB8\xAD\xE6\x96\x87", "\xE4\xB8\xAD\xE6\x96\x87"],
|
||||
'utf8 cyrillic' => ["\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82", "\xD0\x9F\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"], // Привет
|
||||
'utf8 bom preserved' => ["\xEF\xBB\xBFhello", "\xEF\xBB\xBFhello"],
|
||||
'utf8 null byte' => ["a\x00b", "a\x00b"],
|
||||
|
||||
// Issue #2187 - small caps were double-encoded breaking Monaco display
|
||||
'utf8 small caps phrase (issue #2187)' => [
|
||||
"\xE1\xB4\x9B\xCA\x9C\xC9\xAA\xEA\x9C\xB1 \xC9\xAA\xEA\x9C\xB1 \xE1\xB4\x80\xC9\xB4 \xE1\xB4\x87x\xE1\xB4\x80\xE1\xB4\x8D\xE1\xB4\x98\xCA\x9F\xE1\xB4\x87",
|
||||
"\xE1\xB4\x9B\xCA\x9C\xC9\xAA\xEA\x9C\xB1 \xC9\xAA\xEA\x9C\xB1 \xE1\xB4\x80\xC9\xB4 \xE1\xB4\x87x\xE1\xB4\x80\xE1\xB4\x8D\xE1\xB4\x98\xCA\x9F\xE1\xB4\x87",
|
||||
],
|
||||
|
||||
// Minecraft § color codes - extremely common in game server files
|
||||
'utf8 minecraft section sign' => ["\xC2\xA7aGreen \xC2\xA7cRed", "\xC2\xA7aGreen \xC2\xA7cRed"],
|
||||
'iso-8859-1 minecraft section sign' => ["\xA7aGreen", "\xC2\xA7aGreen"],
|
||||
|
||||
// PR #2199 double-encoding regression - UTF-8 é (\xC3\xA9) must NOT become \xC3\x83\xC2\xA9
|
||||
'no double encoding of utf8 e-acute' => ["\xC3\xA9", "\xC3\xA9"],
|
||||
'no double encoding of utf8 multi-byte' => ["\xC3\xBC\xC3\xA4\xC3\xB6", "\xC3\xBC\xC3\xA4\xC3\xB6"], // üäö
|
||||
|
||||
// Issue #1606 - ISO-8859-1 files couldn't be edited
|
||||
'iso-8859-1 cafe (issue #1606)' => ["caf\xE9", "caf\xC3\xA9"],
|
||||
'iso-8859-1 german umlauts' => ["\xFC\xE4\xF6", "\xC3\xBC\xC3\xA4\xC3\xB6"], // üäö
|
||||
'iso-8859-1 full range latin' => ["\xE0\xE8\xEC\xF2\xF9", "\xC3\xA0\xC3\xA8\xC3\xAC\xC3\xB2\xC3\xB9"], // àèìòù
|
||||
'iso-8859-1 single high byte 0xFF' => ["\xFF", "\xC3\xBF"], // ÿ
|
||||
'iso-8859-1 copyright symbol' => ["\xA9 2026", "\xC2\xA9 2026"], // ©
|
||||
|
||||
// PR #1896 - UTF-16LE files from Windows
|
||||
'utf16le with bom' => ["\xFF\xFEh\x00i\x00", 'hi'],
|
||||
'utf16be with bom' => ["\xFE\xFF\x00h\x00i", 'hi'],
|
||||
'utf16le with bom and accents' => ["\xFF\xFE" . "c\x00a\x00f\x00\xE9\x00", "caf\xC3\xA9"],
|
||||
'utf16le with bom multiline' => ["\xFF\xFE" . "l\x00i\x00n\x00e\x001\x00\x0A\x00l\x00i\x00n\x00e\x002\x00", "line1\nline2"],
|
||||
'utf16le bom only no content' => ["\xFF\xFE", ''],
|
||||
'utf16be bom only no content' => ["\xFE\xFF", ''],
|
||||
|
||||
// PR #1991 - Windows-1252 smart quotes fall through to ISO-8859-1 fallback.
|
||||
// Bytes 0x80-0x9F are C1 control chars in ISO-8859-1 but printable in Windows-1252.
|
||||
// The result is valid UTF-8 (C1 control codepoints), not the "smart" characters,
|
||||
// but this is acceptable... it doesn't crash and the output is valid UTF-8.
|
||||
'windows-1252 smart quotes via iso-8859-1 fallback' => [
|
||||
"\x93Hello\x94",
|
||||
"\xC2\x93Hello\xC2\x94",
|
||||
],
|
||||
'windows-1252 em dash via iso-8859-1 fallback' => [
|
||||
"word\x97word",
|
||||
"word\xC2\x97word",
|
||||
],
|
||||
|
||||
// Truncated UTF-8: max_edit_size can cut a file mid-character.
|
||||
// \xC3 starts a 2-byte sequence but has no continuation byte → invalid UTF-8 → ISO-8859-1 fallback
|
||||
'truncated utf8 2-byte sequence' => ["hello\xC3", 'helloÃ'],
|
||||
'truncated utf8 3-byte sequence' => ["hello\xE2\x80", "helloâ\xC2\x80"],
|
||||
'truncated utf8 4-byte sequence' => ["hello\xF0\x9F\x98", "helloð\xC2\x9F\xC2\x98"],
|
||||
|
||||
// Lone continuation bytes - invalid UTF-8, falls to ISO-8859-1
|
||||
'lone continuation byte 0x80' => ["\x80", "\xC2\x80"],
|
||||
'lone continuation bytes' => ["\x80\x81\x82", "\xC2\x80\xC2\x81\xC2\x82"],
|
||||
|
||||
// UTF-16 without BOM - by design falls to ISO-8859-1, not detected as UTF-16.
|
||||
// This produces garbled output, but it's safe (valid UTF-8) and avoids false positives.
|
||||
'utf16le without bom falls to iso-8859-1' => ["h\x00i\x00", "h\x00i\x00"],
|
||||
|
||||
// Game server config file content (real-world)
|
||||
'ascii config with equals and brackets' => [
|
||||
"[server]\nname=My Server\nport=25565",
|
||||
"[server]\nname=My Server\nport=25565",
|
||||
],
|
||||
'yaml config with utf8' => [
|
||||
"motd: \"Willkommen \xC3\xBC\"\nmax-players: 20",
|
||||
"motd: \"Willkommen \xC3\xBC\"\nmax-players: 20",
|
||||
],
|
||||
'windows line endings' => ["line1\r\nline2\r\n", "line1\r\nline2\r\n"],
|
||||
'tab separated values' => ["key\tvalue\nfoo\tbar", "key\tvalue\nfoo\tbar"],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user