Skip to content

Conversation

@Boy132
Copy link
Member

@Boy132 Boy132 commented Sep 9, 2025

See commit history for all changes.

Notable changes:

  • Fix totp migration by not migrating the old secret - this means 2fa will be disabled for all users and they have to set it up again!

@Boy132 Boy132 self-assigned this Sep 9, 2025
@coderabbitai
Copy link

coderabbitai bot commented Sep 9, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Redirect query key for server power actions changed from activeTab to tab. ScheduleSupport added: a new ScheduleStatus enum and a computed nullable enum status on Schedule; UI and translations updated to use it. The TOTP migration no longer migrates per-user data. Many hintIcon+hintIconTooltip pairs consolidated to hintIcon(icon, tooltip); several labels hidden and minor UI/API fixes applied.

Changes

Cohort / File(s) Summary
Servers list page
app/Filament/App/Resources/Servers/Pages/ListServers.php
powerAction redirect param changed from activeTabtab. Visibility closures for power actions updated from bitwise & to logical &&. Notifications, cache invalidation, and exception handling unchanged.
Schedule model & admin UI
app/Models/Schedule.php, app/Enums/ScheduleStatus.php, app/Filament/Server/Resources/Schedules/ScheduleResource.php, app/Filament/Server/Resources/Schedules/Pages/ViewSchedule.php, lang/en/server/schedule.php
Added ScheduleStatus enum and computed status() Attribute on Schedule. Filament forms/tables/views switched to enum-backed status (enum config, badge, color, label); closures updated to accept ?Schedule. Translations moved under schedule_status.
Migrations — MFA/TOTP
database/migrations/2025_07_22_091435_update_users_totp.php
Removed per-user data migration that copied TOTP secrets into new MFA columns; migration now only adds new MFA columns and drops legacy TOTP columns without populating existing user fields.
hintIcon / tooltip consolidation
Multiple files (examples: app/Filament/..., app/Livewire/..., app/Filament/Admin/..., app/Filament/Components/...)
Replaced paired ->hintIcon(...); ->hintIconTooltip(...) with single ->hintIcon(icon, tooltip) calls; dynamic tooltips moved into closures where needed. No business-logic changes.
Label visibility / minor UI tweaks
Examples: app/Filament/Admin/Resources/Servers/ServerResource.php, app/Filament/Server/Pages/Settings.php, app/Filament/Server/Resources/Files/Pages/ListFiles.php, app/Filament/Server/Resources/Users/UserResource.php, app/Filament/Components/Actions/ImportEggAction.php, app/Livewire/Installer/...
Replaced ->label('') with ->hiddenLabel() and similar visibility tweaks; ListFiles pagination options/defaults updated; some placeholders removed; TextArea → Textarea corrected.
Server resource — edit/create
app/Filament/Admin/Resources/Servers/Pages/EditServer.php, app/Filament/Admin/Resources/Servers/Pages/CreateServer.php
Consolidated hintIcon tooltips; renamed data key keepOldVariableskeep_old_variables; redirect tab identifiers updated to ...::data::tab; fixed modalheadingmodalHeading.
Nodes & related pages
app/Filament/Admin/Resources/Nodes/...
Consolidated hintIcon tooltips and normalized redirect/tab parameter values; some hintIcon usages now pass tooltip as second argument.
Installer / Livewire steps
app/Livewire/Installer/...
Merged hintIcon and hintIconTooltip into hintIcon(icon, tooltip) across Environment, Database, Cache, Queue, Session steps; closures used for dynamic tooltips.
Form & API fixes
app/Filament/Server/Resources/Backups/BackupResource.php, app/Filament/Components/Forms/Fields/StartupVariable.php, app/Filament/Components/Actions/ImportEggAction.php, app/Filament/Admin/Resources/DatabaseHosts/..., app/Http/Controllers/Auth/OAuthController.php, app/Models/ActivityLog.php
Fixed component class name (TextAreaTextarea); StartupVariable::fromRecord closures accept ?ServerVariable; helperText casing normalized; OAuth redirect tab → oauth::data::tab; ActivityLog::actor() now calls withoutGlobalScopes() when resolving the actor.
Translations & composer
lang/en/server/schedule.php, lang/en/admin/databasehost.php, composer.json
Moved schedule labels under schedule_status; removed select_placeholder for databasehost; removed doctrine/dbal from composer require.
Frontend JS refactors
public/js/filament/forms/components/select.js, public/js/filament/tables/components/columns/select.js, public/js/filament/forms/components/slider.js
Internal renames and parameter-destructuring changes in select modules (some default export parameter aliases changed); slider file only formatting change. These are refactors of internal identifiers and prop mappings.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Browser
  participant ListServersPage
  participant ServerService
  Note right of ListServersPage #DDEEF8: User triggers server power action
  Browser->>ListServersPage: request power action
  ListServersPage->>ServerService: perform action (start/restart/stop/kill)
  ServerService-->>ListServersPage: success / exception
  alt success
    ListServersPage->>Browser: redirect to /servers?tab=...
  else error
    ListServersPage->>Browser: show error notification
  end
Loading
sequenceDiagram
  autonumber
  participant AdminUI
  participant ScheduleResource
  Note right of ScheduleResource #F6F0F8: Resolve enum-backed schedule status for UI
  AdminUI->>ScheduleResource: formatStateUsing(?Schedule $schedule)
  alt $schedule is null
    ScheduleResource-->>AdminUI: return default ('new' / inactive)
  else $schedule exists
    ScheduleResource-->>AdminUI: return $schedule->status->value (inactive/processing/active)
  end
Loading

Possibly related PRs

Pre-merge checks

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.42% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title "Collection of smaller v4 fixes" is accurate in that the PR aggregates many minor v4 changes, but it is generic and does not call out the most important user‑facing change in the diff (the TOTP migration removal that disables existing 2FA). Because it fails to surface that primary impact, the title is too vague for reviewers who need to quickly understand the main intent. Please make the title more specific by calling out the notable TOTP change and that this is an assortment of v4 fixes; for example, "Disable TOTP migration (requires users to reconfigure 2FA) and assorted v4 fixes." If you prefer a short title, add a one‑line summary at the top of the PR body that highlights the TOTP impact and any other high‑impact changes so reviewers can see the intent at a glance.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed The PR description references the commit history and explicitly highlights the notable TOTP migration change and its user impact (existing 2FA will be disabled), which directly relates to the changes in the diff, so it satisfies the lenient description check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

@Boy132 Boy132 linked an issue Sep 9, 2025 that may be closed by this pull request
@Boy132 Boy132 changed the title Small v4 fixes Collection of smaller v4 fixes Sep 9, 2025
coderabbitai[bot]

This comment was marked as outdated.

Co-authored-by: notCharles <charles@pelican.dev>
@Boy132 Boy132 linked an issue Sep 9, 2025 that may be closed by this pull request
Boy132 and others added 2 commits September 9, 2025 14:33
coderabbitai[bot]

This comment was marked as outdated.

@Boy132 Boy132 linked an issue Sep 10, 2025 that may be closed by this pull request
3 tasks
coderabbitai[bot]

This comment was marked as outdated.

@rmartinoscar rmartinoscar linked an issue Sep 10, 2025 that may be closed by this pull request
3 tasks
coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

@Boy132 Boy132 marked this pull request as draft September 11, 2025 12:05
@Boy132 Boy132 linked an issue Sep 12, 2025 that may be closed by this pull request
3 tasks
@Boy132 Boy132 marked this pull request as ready for review September 15, 2025 16:00
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/Filament/Pages/Auth/EditProfile.php (1)

545-559: Bug: console_graph_period not unset; may hit mass-assignment/unknown column on save

You add console_graph_period to customization but don’t unset it from $data. Also, persist proper types when saving.

Apply this diff:

-        $customization = [
-            'console_font' => $data['console_font'],
-            'console_font_size' => $data['console_font_size'],
-            'console_rows' => $data['console_rows'],
-            'console_graph_period' => $data['console_graph_period'],
-            'dashboard_layout' => $data['dashboard_layout'],
-            'top_navigation' => $data['top_navigation'],
-        ];
+        $customization = [
+            'console_font' => (string) $data['console_font'],
+            'console_font_size' => (int) $data['console_font_size'],
+            'console_rows' => (int) $data['console_rows'],
+            'console_graph_period' => (int) $data['console_graph_period'],
+            'dashboard_layout' => (string) $data['dashboard_layout'],
+            'top_navigation' => (bool) $data['top_navigation'],
+        ];
@@
-        unset($data['console_font'],$data['console_font_size'], $data['console_rows'], $data['dashboard_layout'], $data['top_navigation']);
+        unset(
+            $data['console_font'],
+            $data['console_font_size'],
+            $data['console_rows'],
+            $data['console_graph_period'],
+            $data['dashboard_layout'],
+            $data['top_navigation'],
+        );
♻️ Duplicate comments (1)
app/Filament/Server/Resources/Files/Pages/ListFiles.php (1)

86-95: deferLoading is ineffective here — move File::get into ->query and cache with once()

$files = File::get(...) runs eagerly, so IO still happens before the table defers. Cache the call per request while truly deferring the fetch.

-        $files = File::get($server, $this->path);
...
-            ->query(fn () => $files->orderByDesc('is_directory'))
+            ->query(fn () => once(fn () => File::get($server, $this->path))->orderByDesc('is_directory'))
🧹 Nitpick comments (8)
app/Filament/Pages/Auth/Login.php (1)

37-40: Guard against undefined property access when hiding captcha.

If userUndertakingMultiFactorAuthentication isn’t always defined, this can emit notices in PHP 8.2+. Add a property_exists check.

Apply:

-            $components[] = $captchaComponent
-                ->hidden(fn () => filled($this->userUndertakingMultiFactorAuthentication));
+            $components[] = $captchaComponent
+                ->hidden(fn () => property_exists($this, 'userUndertakingMultiFactorAuthentication')
+                    && filled($this->userUndertakingMultiFactorAuthentication));
app/Filament/Pages/Auth/EditProfile.php (1)

149-156: Avatar on public disk—add limits

Storing on disk('public') is fine. Add a size cap to prevent large uploads.

Apply this diff:

-                                    ->acceptedFileTypes(['image/png'])
+                                    ->acceptedFileTypes(['image/png'])
                                     ->directory('avatars')
                                     ->disk('public')
+                                    ->maxSize(1024) // 1 MB

Also verify storage:link is in deploy steps so /storage/avatars/{id}.png resolves publicly.

public/js/filament/forms/components/select.js (3)

1-1: Clear active descendant on close to avoid stale a11y reference

closeDropdown() removes selection classes but keeps aria-activedescendant on the listbox. Clear it on close.

 closeDropdown(){
   this.dropdown.style.display="none",
   this.selectButton.setAttribute("aria-expanded","false"),
   this.isOpen=!1,
+  this.dropdown.removeAttribute("aria-activedescendant"),
   this.resizeListener&&(window.removeEventListener("resize",this.resizeListener),this.resizeListener=null),
   ...
 }

1-1: Value type mismatch can prevent selection highlight

Comparisons use strict equality between data-value (string) and state (may be number), e.g., e[s].getAttribute("data-value")===this.state. Normalize to string when comparing to avoid missed highlights/selection.

Example adjustments in the relevant spots:

- if(e[s].getAttribute("data-value")===this.state){
+ if(String(e[s].getAttribute("data-value"))===String(this.state)){

- if(this.state.includes(e[s].getAttribute("data-value"))){
+ if(this.state.map(String).includes(String(e[s].getAttribute("data-value")))){

Please confirm whether state can be numeric in your usage; if yes, the normalization prevents subtle UI desyncs.


1-1: i18n: hardcoded “Search” aria-label

this.searchInput.setAttribute("aria-label","Search") is hardcoded English. Prefer using a prop (e.g., searchAriaLabel) or reuse searchPrompt (sans ellipsis) for localization.

- this.searchInput.setAttribute("aria-label","Search"),
+ this.searchInput.setAttribute("aria-label",(this.searchAriaLabel ?? (this.searchPrompt || "")).toString().replace(/\u2026|\.\.\.$/,"")),
public/js/filament/tables/components/columns/select.js (3)

1-1: Clear active descendant on close to avoid stale a11y reference

Mirror the aria-activedescendant cleanup in closeDropdown() here as well.

 closeDropdown(){
   this.dropdown.style.display="none",
   this.selectButton.setAttribute("aria-expanded","false"),
   this.isOpen=!1,
+  this.dropdown.removeAttribute("aria-activedescendant"),
   ...
 }

1-1: Value type mismatch can prevent selection highlight

Normalize comparisons between data-value and state to strings in this build too (same rationale and snippets as the forms component).


1-1: i18n: hardcoded “Search” aria-label

Replace the hardcoded "Search" with a localized prop or reuse searchPrompt consistently as an accessible label.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ec0055 and 4508567.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • app/Filament/Admin/Resources/Nodes/RelationManagers/AllocationsRelationManager.php (1 hunks)
  • app/Filament/Pages/Auth/EditProfile.php (8 hunks)
  • app/Filament/Pages/Auth/Login.php (2 hunks)
  • app/Filament/Server/Resources/Files/Pages/ListFiles.php (3 hunks)
  • app/Providers/AppServiceProvider.php (1 hunks)
  • public/js/filament/filament/app.js (1 hunks)
  • public/js/filament/forms/components/select.js (1 hunks)
  • public/js/filament/forms/components/slider.js (1 hunks)
  • public/js/filament/tables/components/columns/select.js (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • public/js/filament/forms/components/slider.js
  • public/js/filament/filament/app.js
🧰 Additional context used
🧬 Code graph analysis (3)
app/Filament/Pages/Auth/Login.php (8)
app/Extensions/OAuth/OAuthSchemaInterface.php (1)
  • getHexColor (32-32)
app/Extensions/OAuth/Schemas/OAuthSchema.php (1)
  • getHexColor (112-115)
app/Extensions/OAuth/Schemas/AuthentikSchema.php (1)
  • getHexColor (59-62)
app/Extensions/OAuth/Schemas/CommonSchema.php (1)
  • getHexColor (35-38)
app/Extensions/OAuth/Schemas/DiscordSchema.php (1)
  • getHexColor (50-53)
app/Extensions/OAuth/Schemas/GithubSchema.php (1)
  • getHexColor (50-53)
app/Extensions/OAuth/Schemas/GitlabSchema.php (1)
  • getHexColor (61-64)
app/Extensions/OAuth/Schemas/SteamSchema.php (1)
  • getHexColor (67-70)
app/Filament/Server/Resources/Files/Pages/ListFiles.php (1)
app/Services/Activity/ActivityLogService.php (1)
  • property (109-117)
app/Filament/Pages/Auth/EditProfile.php (8)
app/Extensions/OAuth/OAuthSchemaInterface.php (1)
  • getHexColor (32-32)
app/Extensions/OAuth/Schemas/AuthentikSchema.php (1)
  • getHexColor (59-62)
app/Extensions/OAuth/Schemas/CommonSchema.php (1)
  • getHexColor (35-38)
app/Extensions/OAuth/Schemas/DiscordSchema.php (1)
  • getHexColor (50-53)
app/Extensions/OAuth/Schemas/GithubSchema.php (1)
  • getHexColor (50-53)
app/Extensions/OAuth/Schemas/GitlabSchema.php (1)
  • getHexColor (61-64)
app/Extensions/OAuth/Schemas/SteamSchema.php (1)
  • getHexColor (67-70)
app/Models/User.php (1)
  • getCustomization (323-329)
🔇 Additional comments (11)
app/Filament/Admin/Resources/Nodes/RelationManagers/AllocationsRelationManager.php (1)

45-45: Pagination options should be ints — good fix

Switching to integer page sizes aligns with Filament expectations.

app/Filament/Server/Resources/Files/Pages/ListFiles.php (2)

337-337: Label hidden for delete — consistent with UI tweaks

Matches the pattern used elsewhere in the PR.


436-438: Activity “new_file” property now uses the resolved path — good

Using $path avoids double-joining and keeps analytics consistent.

Confirm downstream consumers expect the key to be file (not path) for “server:file.write”.

app/Filament/Pages/Auth/Login.php (1)

79-84: Null‑safety for OAuth button color — set color only when hex provided.

getHexColor() can be null; calling Color::hex(null) will error. Construct the Action, then call ->color(...) only if a hex string exists.

File: app/Filament/Pages/Auth/Login.php — lines ~79–84

-            $actions[] = Action::make("oauth_$id")
-                ->label($schema->getName())
-                ->icon($schema->getIcon())
-                ->color(Color::hex($schema->getHexColor()))
-                ->url(route('auth.oauth.redirect', ['driver' => $id], false));
+            $action = Action::make("oauth_$id")
+                ->label($schema->getName())
+                ->icon($schema->getIcon())
+                ->url(route('auth.oauth.redirect', ['driver' => $id], false));
+            if ($hex = $schema->getHexColor()) {
+                $action->color(Color::hex($hex));
+            }
+            $actions[] = $action;

Verification scripts returned no files in the sandbox; confirm in-repo and apply the patch.

app/Providers/AppServiceProvider.php (1)

107-115: Confirm 'blurple' shade usage & Color::hex behavior

rg reported "No files were searched" — I couldn't verify whether any shade-specific classes (e.g., blurple-500) exist or whether Color::hex('#5865F2') generates a full shade palette in your Filament version.

  • Action: Search the repo for shade-specific uses and paste results, e.g. run locally:
    git grep -nE 'blurple(-[0-9]{2,3})?' || rg --hidden --no-ignore -n -e '\bblurple-(50|100|200|300|400|500|600|700|800|900|950)\b' -e '\bblurple\b'
  • Action: Confirm your Filament version and whether Color::hex produces multi‑shade tokens (check Filament docs or inspect FilamentColor::register output).

File: app/Providers/AppServiceProvider.php (lines 107–115).

app/Filament/Pages/Auth/EditProfile.php (6)

181-181: Verify translation keys exist

Ensure profile.link and profile.unlink exist and include the {name} placeholder to avoid runtime “missing translation” strings.


237-237: Confirm tab query values

Double-check that api-keys::data::tab and ssh-keys::data::tab match the actual persisted tab key Filament expects. If unsure, set explicit IDs on the tabs (e.g., ->id('api-keys') / ->id('ssh-keys')) and use those.

Also applies to: 320-320


428-432: BooleanStateCast mapping—verify behavior

Options are 1/0 while you cast to bool via new BooleanStateCast(false, true). Confirm this maps selected values to true/false as intended and that persistence round-trips correctly.


506-506: hintIcon tooltip usage looks good

Migration to the new two-argument signature is correct here.


566-571: Good: coercing types on fill

Casting numeric and boolean preferences on fill is correct. Paired with the save-side casting in the earlier comment.


30-30: Import OK

BooleanStateCast import aligns with its usage below.

Comment on lines +181 to 184
->label(trans('profile.' . ($unlink ? 'unlink' : 'link'), ['name' => $name]))
->icon($unlink ? 'tabler-unlink' : 'tabler-link')
->color(Color::generateV3Palette($schema->getHexColor()))
->color(Color::hex($schema->getHexColor()))
->action(function (UserUpdateService $updateService) use ($id, $name, $unlink) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Null-safe OAuth action color

OAuthSchemaInterface::getHexColor() is nullable; Color::hex(null) will fail for schemas that don’t define a color.

Apply this diff:

-                                        ->color(Color::hex($schema->getHexColor()))
+                                        ->color(fn () => Color::hex($schema->getHexColor() ?? '#64748B'))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
->label(trans('profile.' . ($unlink ? 'unlink' : 'link'), ['name' => $name]))
->icon($unlink ? 'tabler-unlink' : 'tabler-link')
->color(Color::generateV3Palette($schema->getHexColor()))
->color(Color::hex($schema->getHexColor()))
->action(function (UserUpdateService $updateService) use ($id, $name, $unlink) {
->label(trans('profile.' . ($unlink ? 'unlink' : 'link'), ['name' => $name]))
->icon($unlink ? 'tabler-unlink' : 'tabler-link')
->color(fn () => Color::hex($schema->getHexColor() ?? '#64748B'))
->action(function (UserUpdateService $updateService) use ($id, $name, $unlink) {
🤖 Prompt for AI Agents
In app/Filament/Pages/Auth/EditProfile.php around lines 181 to 184,
Color::hex($schema->getHexColor()) can receive null because
OAuthSchemaInterface::getHexColor() is nullable; change the code to handle null
safely by using a fallback or conditional: if getHexColor() returns a string use
Color::hex(...) otherwise pass a sensible default color or omit the color call
so no exception is thrown. Ensure the fix uses the schema hex only when non-null
(e.g. null-coalesce to a default hex or wrap the Color::hex call in a
conditional) so null values don’t cause failures.

@Boy132 Boy132 merged commit d5d50d4 into main Sep 15, 2025
25 checks passed
@Boy132 Boy132 deleted the boy132/v4-fixes branch September 15, 2025 21:28
@github-actions github-actions bot locked and limited conversation to collaborators Sep 15, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.