107 direct toLocaleString/DateString/TimeString calls followed the
browser's locale (or a hard-coded en-US/en-GB) instead of the language
the panel is set to, and built a formatter per call. They now go
through utils/intl (formatDate/Time/DateTime/Number), keeping each
site's components via parts. A missing date now renders the fallback
dash instead of "Invalid Date". Ratchet ceiling 115 -> 4.
Each list page restyled DataTable on top of the shared look: fourteen
re-skin classes, filled grey headers, padded cards inside padded pages
and nth-child column widths (which put Docker's Name column 300px in
once the checkbox column existed). The table wrap is now the only
frame, the header is unfilled, column widths come from the column
definition, and raw tables and ui Table uses render through DataTable.
scripts/check-tables.mjs holds it in lint.
Page bodies drop the 1400px reading column (and the per-page caps on
Domains, Deployments, Dashboard, detail pages and Recipes) for one
20px gutter everywhere; Settings caps only its form column. The top
bar gets the sidebar's surface and edge so the chrome reads apart from
the canvas, and the bulk-selection pill clears the status bar.
Also removes decorative chrome: gradient letter avatars and tinted
stat icons become neutral, Domains rows lose the icon tile and the
"Registrar -" sub-line, and destructive row actions are quiet ghost
buttons that turn red on hover (.btn-ghost.is-danger).
1,250 strings across 223 files, edited at their inline English
defaults (en.json regenerated, keys unchanged):
- sentence case for buttons, titles, labels, tabs and nav (827),
with an allowlist of product names and acronyms
- every em dash rewritten (184); "successfully", neutral "!" and
short-toast periods dropped; helper sentences end with a period
- "Are you sure?" confirms now state the consequence; "Danger Zone",
"no going back", "to get started" and "You're all set" gone
- straight quotes, "…", "time zone", unit spacing, "and" for "&"
- Confirm/Cancel and four other hardcoded labels wrapped in t()
scripts/copy-rewrite.mjs applies a {key: English} map at every call
site; the glossary pass reuses it.
en.json drops from 8107 to 6624 keys: repeated UI copy (Cancel x95,
Status x67, Refresh x54, ...) now lives under common.actions /
common.labels / common.loading, and extractor-era suffix duplicates
(refresh2, status3) within a component collapse onto one key.
Trailing ... defaults are normalized to the ellipsis character.
Translations are preserved: all 16 locales were re-keyed, carrying
existing per-component translations onto their new common.* keys
(majority vote where sources disagreed), and stale keys were pruned.
Verified: npm run lint (0 errors), node --test (140 pass), vite build.
edit
Mass conversion of ~8,000 English literals across 320+ files to
t('app.<file>.<key>', 'English default') calls, plus hand-conversion of
the 43 literals the codemod refused (concatenated toasts, module-level
helpers, class components) using bare t() from i18n/t or restructured
{{placeholder}} keys. Marketplace unsigned-release dialog now translates
the Install/Update verb inside the placeholder.
ESLint: 0 errors. Literal checker: 0 remaining.
statusKind()/statusVariant()/statusDotClass()/statusLabel() drive both
Pill kinds and Badge variants from ONE table; ~40 per-page maps across
35+ files migrate to it. Scoped overrides stay in the same file:
serviceStatusKind (running IS the healthy steady state for services/
units/previews -> green), processStateVariant, alertStatusKind,
envActionKind, impactTone. Unifications: run-shaped 'running' is cyan
everywhere (Git.jsx's amber gone), QueueDetail/QueueOperations' invalid
blue/yellow kinds fixed, severity tones (critical/high/medium/low)
agree across security surfaces. Ratchet: npm run check:status fails on
new local maps outside ds/status.js (frozen allowlist for domain maps
and D4-territory hex/css-class renderers). Lint + build green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Docker's four remaining tabs (Compose, Images, Volumes, Networks) drop their raw
<table className="docker-table"> markup and bespoke toolbars for the shape
ContainersTab already used. Each gets a distinct viewPageKey AND urlScope, since
one route now mounts five tables and a shared scope has them writing each other's
?view=. Views were chosen from what the payload actually carries rather than what
would read well: Volumes has no "Unused" view because neither transport reports a
reference count, and a Networks "Containers" column was dropped because the agent
sends the count and the local service does not — a column that is permanently
blank on half your hosts is the exact failure this round exists to stop.
Terminal stops hand-rolling two surfaces that already had converged twins in the
repo, imported by nothing but the Style Guide: Processes renders ProcessTable,
and Services renders serverdetail/ServicesTab, taught to serve the local host as
well as a paired agent. This was mostly deletion.
Databases: the explorer's tables move onto the shared chrome, losing three raw
search inputs, two page-level row counts and their segmented rows.
Deployments: the fake table (a header row over <button> rows) becomes a real one,
and the target-server <select> becomes the Target column's own menu.
Templates keeps its card grid — a catalog is a legitimate place for tiles — but
loses the row count, filter-chip row and sort control the shared chrome replaces.
FTP and WorkspaceDetail get chrome on tables that had none.
components/SearchFilterBar.jsx is deleted: a complete competing search/filter/sort
bar with zero importers, confirmed not on the SDK export list.
Fixes for regressions the verification pass caught, before they shipped:
- Terminal > Processes swapped the whole table out on every `loading` tick. It
auto-refreshes on a timer, so the chrome, active view, column rules, sort and
scroll position were being unmounted and rebuilt every few seconds. Only the
first load swaps now.
- The Databases backups pane returned its empty state INSTEAD of the chrome, so
a tab with no backups had no Refresh — exactly when you want one, because a
backup that just finished is why the list looks empty.
- Every open table tab kept its chrome mounted while sharing one urlScope, so
four open tables fought over ?dbstruct.view=. Scoped per tab. The process list
is namespaced per ENGINE too: `state` reads p.command on MySQL and p.state on
PostgreSQL, so one namespace let a MySQL view apply itself to Postgres and
match nothing.
- The Images size column disagreed with itself: the rule value was base-1000 MB
while the cell rendered base-1024, so "Size is over 400 MB" matched a row whose
own cell read "392.9 MB".
- Deployments' server filter used to reach the whole history through ?server_id=;
as a column rule it only reaches what was fetched. The window is explicit now —
a full page offers Load more instead of quietly filtering a truncated list.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Queue messages/operations, delivery log, process table, env-history and
docker containers migrated. The containers tab's select+button sort UI is
deleted in favor of native header sorting (running-first default kept) with
controlled menus; FilterDrawer pairings untouched.
Per docs/plans/FRONTEND_UX_TAILWIND_CLEANUP_PLAN.md §8.5. React 18's automatic
JSX runtime makes 'import React' unnecessary; removed it from the 142 files
eslint flagged as 'React defined but never used' (named imports like useState
preserved). Driven by an eslint --format json pass so only flagged files were
touched.
Lint warnings: 1603 -> 1461 (0 errors). Verified: npm run build passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add dev toggle for IPC auth and fix CORS Authorization header; introduce SERVERKIT_IPC_NO_AUTH to skip bearer checks in dev and log a warning. Frontend: wide UI refactor — convert Sheet-based modals to Dialogs, restyle ConfirmDialog, update Badge and Button variants (sizes, rounded tokens, data attributes), improve Tabs overflow trigger handling, and add ARIA labels for process action buttons. Docker page: unify/normalize ports formatting for multiple agent shapes and render safely. ServerDetail: add Alerts tab, load and manage security alerts (acknowledge/resolve), and restructure overview into KPI tiles, info rows, and SystemStatusCard. Replace several ad-hoc modals in Cron/Cloudflared with Dialog + Select forms and tidy Settings/agent sections. Also add UI_REPORT.md to .gitignore.
Introduce Cloudflare Tunnel management end-to-end.
Highlights:
- Add agent/internal/cloudflared package (Manager interface, Linux impl, non-Linux stub) to shell out to cloudflared and detect auth via cert.pem.
- Wire cloudflared Manager into the agent and register cloudflared:* handlers for status/list/create/route/delete.
- Extend protocol.Capabilities and agent payloads with runtimes detection and a cloudflared capability; implement runtime version probes.
- Add backend API endpoints and RemoteCloudflaredService that forward cloudflared actions to agents; update agent registry to store runtimes.
- Frontend: new CloudflaredTab UI, API client methods for remote cloudflared operations, styles, and UX tweaks (plus minor component/class refinements in LogViewer, ProcessTable, FileManager, StyleGuide, terminal styles).
Purpose: allow the panel to manage Cloudflare named tunnels by delegating commands to the agent's cloudflared CLI, while surfacing binary/auth state (install vs authenticated) and detected language runtimes.
Agent: factor run logic into agentMainLoop and detect SCM launch; add Windows service dispatcher (service_windows.go) and POSIX stub (service_other.go) to properly handle SCM lifecycle and avoid Windows SCM error 1053. Frontend: add a set of presentational components (DangerZone, InfoList/InfoItem, JournalControls, LogViewer, MetricRow/MetricItem, ProcessTable, ProgressBar, ServiceCard, StatCard) and wire them into multiple pages and security tabs, replacing many ad-hoc info-list blocks. Also add a route for style-guide/:tab and update AgentFleet to use the new StatCard/StatsGrid layout. These changes improve service reliability on Windows and DRY up UI layouts with reusable components.