* feat: add developer-mode startup and stack hydration timing
Instrument boot-to-list and detail hydration with commit-aligned milestones, truthful request stages, and destination/gateway debug duration logs so performance work is guided by measurements.
* fix: redact stack names and complete hydration request stages
Stop logging stack identifiers in containers debug timing, and record state_dispatch (plus detail fetch spans) so copied reports match the advertised stage breakdown.
Remove the MonitorService 6-hour version-check cooldown so node_update_available
fires when the shared version cache observes a published release, matching the
Fleet update button. Dedup and publish-pending gating still prevent spam.
* feat: add Admiral Hardened Build channel and business assurance surfaces
Introduce Studio Saelix entitlement-backed Hardened Build switching, a
single-flight image operation coordinator, Recovery Vault naming, Admiral
Account settings, and typed Fleet update failures while preserving Community
custom-repo and targetless pull-current updates.
* fix: harden image-op paths and clear CI CodeQL/pilot flake
Validate operation IDs before filesystem use, use hostname checks in Fleet
fetch mocks, sanitize registry probe logs, and swallow expected TCP teardown
errors in the pilot reverse-route post-handshake test.
* fix: sanitize image-op docker config write and probe logs
Allowlist-copy registry host keys and base64 auth before writing the
temp DOCKER_CONFIG, and log registry probe failures with a fixed message
so CodeQL no longer flags network-to-file and log-injection mediums.
* fix: address Admiral Hardened Build audit blockers
Expose imageChannel so hardened Fleet peers still POST for typed rejection, claim community updates before 202, terminalize helper failures, gate Hardened on paid, and align support/docs/e2e wording.
* fix: terminalize image ops on helper survival and aborted claims
* fix: prevent recreating persist from overwriting helper-exit failure
* test: assert helper-exit failure lands before recreating persist
* fix: keep current pointer when acknowledging a stale image operation
The AGPLv3 relicensing change left a duplicated url mapping key under
info.license, which breaks YAML parsing for any Mintlify docs preview
on any branch (error duplicated mapping key).
Release publish runs leave steps.release.outputs.pr empty, so fromJSON crashed
even when the credit step was gated off. Credit external issue openers with an
inline thanks suffix on logical changelog bullets instead of a Thanks section.
Keep fatal API lookup logs status-only.
* docs: align README and overview docs with current AGPLv3 tier model
Community is now described as the complete free product, with a single
consolidated Admiral section replacing scattered per-bullet tags that had
drifted out of sync with the actual gates (security scanning, private
registries, and most of RBAC/audit moved to Community over time). Remove
promotion of Sencho Mesh, Fleet Secrets, and Host Console, which are no
longer discoverable by default. Align the Fleet Secrets, Host Console, and
Sencho Mesh sections in the features overview with the limited-availability
framing already used elsewhere on that page.
Refresh every README screenshot to the current UI and add new captures for
Security, Blueprints, Scheduled Operations, and Compose Doctor.
The introductory tier-framing sentence and docs navigation placement for the
now-hidden surfaces are intentionally left for a later, dedicated pass once
the Admiral positioning work settles.
* docs: restructure README around the open-source Community product
Drop "What Sencho is not (yet)", fold its known-limitations pointer into
the Documentation section. Rewrite Telemetry and data handling to drop the
Admiral license-validation detail, since this file is the open-source
entry point and Admiral customers work from their own agreements. Move
the Admiral section to just before Documentation, community, and license
so the README leads with the Community product throughout.
Gate Routing, Secrets, Host Console, and Mesh dashboard/settings surfaces on the existing useExperimental readiness flag so immature operator surfaces stay out of the default UI while paid and admin backend gates remain unchanged.
* docs: relicense Sencho to AGPLv3 and reframe Community positioning
Replace BSL with AGPLv3 for the public Community product, update contributor
and licensing copy for Community-focused contributions, and surface source
and license links in Settings About.
* docs: clarify CLA scope and Community contribution framing
* fix(ui): split About link constants and harden AboutSection test selectors
* fix(ui): lower-overhead Reduced effects path for constrained GPUs
Disable backdrop-filter glass and solidify chrome fills when data-effects is reduced (Calm default), with Appearance warning and docs for constrained rendering devices. Related to #1614.
* test(ui): harden Reduced effects glass e2e and docs wording
Parse Color Level 4 slash alpha so opacity asserts are not vacuously true, cover dialog/toast/overlay both ways with stable data-sn hooks, and soften troubleshooting copy that overstated the unmeasured diagnosis.
* docs(ui): lead constrained-GPU guidance with Reduced Motion
Rename the troubleshooting section to neutral GPU framing, point Appearance and docs at Reduced Motion first, and show the callout whenever Motion is off so Calm or Reduced effects alone do not hide the validated workaround.
The Timeline lane marker lacked shrink-0, so inside the fixed 80px label
column the widest labels flex-shrank their color dot to zero width. The
Maintenance and Lifecycle dots collapsed and rendered as no dot at all,
while the shorter labels kept theirs. Add shrink-0 so every lane dot
renders at a consistent size.
Maintenance was the only label wide enough to fill the 80px column on its
own, which is what left its dot no room. Rename it to Upkeep so all five
labels fit and align. A registry test now pins each lane's key, order,
and label, and asserts every lane carries a color, so a future rewrite of
the action registry cannot silently rename a lane or drop a dot color.
Replace the desktop 8-column table with card-like mobile rows on phones,
following the ImagesTab pattern. Each row shows a 44px checkbox for compare
selection, a severity dot, truncated image ref with trigger and timestamp
meta, count tags (total vulns + fixable, at most 2), and a chevron.
Secret/config-only scans use the FINDINGS dot and suppress the clean tag,
matching the getSeverityKey classification from severityStyles.
Extract a shared HistoryStateMessage component to deduplicate the
loading/error/empty state blocks between the mobile and desktop branches.
* fix: polish stack health table, security card heights, and scanner-gate copy
- Remove state dot column from Stack Health rows; state still signaled
via row tinting and sparkline color
- Reposition Update available badge adjacent to stack name and track
the theme accent (--brand) instead of static fuchsia
- Equalize Top exploit-risk findings and Severity x exploitability
card heights via h-full in a stretching grid
- Add resolution prop to CapabilityGate so scanner-gated tabs show
"Install a scanner from the Scanner setup tab." instead of the
misleading "Upgrade the node" message
* fix: scope Resources scroll area to table contents only
- Remove bg-background from the outer wrapper so search/filter bars
no longer sit on a dark strip
- Replace outer ScrollArea with a plain div so search and filter
controls stay fixed while only table rows scroll
- Add ScrollArea (max-h-[62vh]) inside each table card for Images,
Volumes, and Networks tabs
* fix: remove static bg-background from Security table scroll areas
Images and History tab tables used bg-background on their ScrollArea,
forcing a near-black fill that didn't adapt to the theme. Removing it
lets the parent card's bg-card show through, matching the Resources
table pattern that correctly respects DIM, OLED, and Light modes.
* fix: collapsible search icon and transparent Combobox across Resources and Security
- Replace always-visible search inputs on Resources tabs (Images,
Volumes, Networks) and Security Images (desktop + mobile) with
Fleet-style collapsible search: an icon button that expands to
a full input on click, collapses on blur when empty
- Add [&>button]:!bg-background to Security Images severity
Combobox, matching Fleet's transparent dropdown design
* fix: remove redundant orange badge from Unmanaged tab label
The count was shown twice: once as inline text in the tab and again
as an orange bg-warning pill badge. The inline text remains; the
duplicate badge is removed.
* fix: outline buttons invisible in Light mode
- Changed outline variant border from border-input to border so it
uses --card-border, which maintains a visible 0.035 lightness gap
from --background in Light mode (was 0.005, essentially invisible)
- Boosted Light-mode --button-inner-glow from a 4% white inset to
a 10% inset plus a subtle drop shadow for the physical-key feel
* fix: bump table cell horizontal padding from 8px to density-aware token
Changed TableHead and TableCell px-2 (8px) to px-[var(--density-row-x)]
which resolves to 20px comfortable / 16px compact. Matches the density
system used by StackHealthTable and gives every shadcn-based table
proper breathing room on both edges.
* fix: expand collapsible search before typing in ImagesTab test
The test was written for the old always-visible search input. Now that
the search bar collapses to an icon, click it first to expand before
interacting with the input.
* fix: reorder Settings Infrastructure to Nodes, Stacks, Fleet
Move the Stacks section directly below Nodes so the Infrastructure
sidebar reads Nodes, Stacks, Fleet. Pure array-element relocation in
the settings registry; the sidebar renders in array order.
* fix: simplify pilot enroll command and add Step 2 copy button
Step 2 of the pilot-agent enrollment modal now shows "docker compose up
-d" instead of the redundant "-f compose.yaml" form, since Step 1
already has the operator save the file as the default compose.yaml. Add
an inline copy button next to the command so it can be copied without
selecting the text by hand.
* fix: stack Fleet/Security tab heading actions on mobile
The shared FleetTabHeading kept its title and action buttons on one row
at every width, so on phones the Security Suppressions heading and its
Export VEX / Add suppression buttons were crammed together. Stack the
heading and actions vertically below the md breakpoint and restore the
original row layout at md and up, so desktop is unchanged.
* feat: add node selector to mobile Home masthead
The mobile Home page showed the active node as static text, so switching
nodes was only possible from the Stacks page. Render the same compact
NodeSwitcher in the Home masthead kicker slot, giving a second place to
view and switch the active node with the identical popover and Manage
nodes action.
* feat(security): add triage status and OpenVEX justification parity
Share triage options across SuppressionsPanel and the scan-sheet suppress dialog, require justification for not_affected and false_positive, and document the fields.
* fix(security): use design-system Select for triage dropdowns
Replace native selects so OpenVEX justification options use themed popover content instead of unreadable OS option lists in dark mode.
* fix(security): keep triage justification Select controlled
Pass an empty string instead of undefined so Radix Select does not flip between uncontrolled and controlled when the placeholder is shown.
* feat(resources): show multi-stack usedByStacks on images
Classify images with a deduped sorted stack reverse index, surface chips in the Images table and inspect sheet, and clear node-bound sheet selection on active-node change.
* feat(registries): add exact-ID tag browser with non-401 failures
Add GET /api/registries/:id/tags using credentials for that registry row only, map upstream auth failures to 424, and surface a Registry tags section on the image inspect sheet.
* fix(registries): distinguish unreachable hosts from auth failures
Map auth transport errors to REGISTRY_UPSTREAM (502), surface registry list-load failures in the tag panel, document Used by and Registry tags, and add parser coverage.
* fix(registries): drop unused RegistryTagsPanel __test export
The non-component export tripped react-refresh/only-export-components and failed Frontend lint in CI.
Classify images with a deduped sorted stack reverse index, surface chips in the Images table and inspect sheet, and clear node-bound sheet selection on active-node change.
* feat(resources): bind prune to fingerprinted itemized plans
* fix(resources): repair prune plan volume usage and preview list
Source volume RefCount from docker df, keep preview rows from flex-shrinking, tighten managed image attribution and becomesFree, and stop audit summaries from claiming success on rejected prunes.
* feat(scheduler): include node identifier in remote proxy error messages
Remote lifecycle proxy errors from postToRemoteStack,
executeUpdateRemote, postToRemoteContainer, and getRemoteContainers
now include a stable node label (name and numeric id) so a hub
operator reading run history can correlate failures to a node without
cross-referencing the task table.
The prefix matches the existing containerNotFoundMessage pattern in
the same class. Transport-level failures (DNS, ECONNREFUSED, timeout)
also receive the node label. A startsWith guard prevents double-
prefixing within the same method. The restart fan-out catch relies
on the inner postToRemoteStack error for node context so the label
appears exactly once.
* fix(scheduler): pilot-aware remote proxy no-target error context
Use formatNoTargetError for null proxy targets so pilot tunnel disconnects
are not misdiagnosed as missing credentials. Standardize the failure prefix
to Remote node name/id, share require/rethrow helpers, and cover pilot
no-target plus remote container action failures in tests.
* feat: add compose discovery for setup preflight and sidebar empty state
Expose read-only compose discovery via GET /api/stacks/discovery and setup
diagnostics. Replace the blank sidebar with path-aware discovery and move
adopt into a dedicated dialog with a three-tab Create Stack flow.
* test: assert post-setup handoff via sessionStorage read-back
The Setup preflight test spied on Storage.prototype.setItem to check the
post-setup adopt handoff. When the jsdom storage probe fails and the test
harness swaps in its in-memory storage stub (which does not extend Storage),
that stub's setItem never touches Storage.prototype, so the spy records zero
calls and the assertion fails even though the component wrote the value.
Read the value back with sessionStorage.getItem instead, matching how every
other storage test in the suite asserts. This is robust to both the native
jsdom storage and the in-memory fallback.
* fix(setup): surface compose discovery as a preflight check row
Drop the Setup discovery banner and non-working Review button. Show
counts as a pass row in EnvironmentChecks (Setup only) and keep
Enter Sencho as the handoff that opens adopt when candidates exist.
* test(setup): cover zero-count discovery row omission
* fix(stacks): widen adopt scan to any yaml and rename into place
Homelab layouts often use nginx.yml or plex.yml. Surface those for
adopt (except overrides), rename to compose.yaml on move so stacks
register, and reset the confirm UI when a move fails.
Non-admin users no longer see Update buttons in Fleet View; the UI shows
read-only "Available" badges instead. The accordion describing a 403-click
path was orphaned by the frontend role-gating that shipped in an earlier PR.
The Note above the troubleshooting section already states the admin-role
requirement in plain language.
* feat: open compose editor in edit mode with one click
Remove the desktop double edit gate so Anatomy "Edit compose" and empty-stack
create land in an immediately editable workspace. Close discards both compose
and env buffers; deferred loads keep startInComposeEdit through unsaved confirm.
* docs: align compose editor close behavior and Edit compose labels
Update stack-management and editor docs for one-click edit mode.
Close discards unsaved compose/env edits. Anatomy shortcuts use Edit compose.
* fix(e2e): update routing test to use anatomy-edit-compose-btn test id
The compose editor env tab routing test was written against the old
'edit' button name. The single-compose-edit-gate branch renamed that
button to 'Edit compose' with test id 'anatomy-edit-compose-btn'.
Update the selector to match.
* feat: add confirmed Take down stack action with optional volume removal
Expose Take down in the stack header and sidebar with a confirmation dialog
that runs compose down while keeping the stack definition on disk. Optional
volume removal is gated by node capability and stack:deploy permission, with
remote gateway preflight before proxying removeVolumes requests.
Closes#1582
* fix: reset take-down volume checkbox when dialog closes
* test: align getStackMenuVisibility assertions with showTakeDown key
getStackMenuVisibility now returns a fifth lifecycle flag, showTakeDown,
but three exhaustive toEqual assertions still listed only the prior four
keys and failed. Add the expected showTakeDown value to each: true for
the partial and exited running-stack cases, false for the self stack.
* test: cover Take down visibility for running non-self stacks
The getStackMenuVisibility assertions exercised the partial and exited
branches and the self-stack guard, but not the raw === 'running' literal
that drives showTakeDown for a normal running stack. Add a case so a
regression dropping 'running' from that check is caught.
* fix: drop Take down from header overflow and wire activity shortcut
Remove duplicate Take down from More actions.
Keep inline button when running, sidebar menu, and Cmd+ArrowDown.
Record stack_taken_down in activity on successful POST /down.
Sidebar opens /stacks/:name (anatomy). Monaco uses /compose|/env|/files.
Refresh of a detail URL no longer opens the editor, and editor deep links
keep a hydration shell instead of flashing the dashboard.
Gate stack resolution until the active node matches a pending remote deep link.
Return env inventory from loadFileForRoute so empty stacks settle env tab routes.
Reject backslashes in buildPath env query tokens.
Update docs.json logo paths from PNG to SVG, matching the frontend
convention (sencho-logo-dark.svg / sencho-logo-light.svg). Remove old
PNG assets from docs/images/logo/.
* fix(routing): basename env URLs and defer writes during node hydration
Encode only env file basenames in ?env= and omit the default file.
Resolve legacy absolute-path bookmarks on load.
Block history writes until the active node matches a cold-loaded remote deep link.
* fix(routing): restore env deep links after stack load hydrates file list
Defer env selection until envFiles is populated after loadFileForRoute.
Apply default env when the URL omits ?env= (Back/popstate).
Document env URL rules and legacy basename resolution in deep-links.mdx.
* feat: add routable browser URLs for stacks and shell views
Sync in-memory navigation to the address bar via a History API hook so
deep links, refresh, Back/Forward, and bookmarks work across nodes,
views, stack editor tabs, and mobile surfaces. Gate role/tier URL
normalization on permissions and license readiness, preserve URLs on
metadata fetch failure, and surface retryable stack-list errors without
rewriting pending stack paths.
* fix: preserve deep-link views on cold load and refresh
Stop the node-switch effect from resetting to dashboard on initial mount.
Defer URL writer settlement until hydrated activeView matches the route.
Adds E2E coverage for shell cold loads, stack refresh, and compose env tab.
* fix: keep mobile dashboard on list surface so sidebar renders
On mobile, the URL sync hook was routing /nodes/<slug>/dashboard to the
content surface, hiding the stack list sidebar. This prevented the
data-stacks-loaded sentinel from appearing, causing sidebar truncation
E2E tests to time out after reload on a mobile viewport.
Mobile dashboard now stays on the list surface; other non-editor views
still render on the content surface.
* fix: complete mobile URL routing follow-ups for stack deep links
Restore mobile /dashboard vs /stacks, list surface always writes /stacks.
Hydrate pendingDetailStack, freeze compose failures with routeDetailError,
and add unit plus E2E coverage.
* fix: hydrate shell views from URL and sync in-app navigation
Bootstrap activeView and tab state from the pathname on cold load.
Settle route phase when state already matches, normalize unknown segments,
and open Monaco editor tabs from stack deep links via applyEditorRouteState.
* fix: prevent mobile stack deep links from hanging on cold load
The resolvePendingStack effect did not re-fire when the pending stack ref
was populated during URL hydration, because the urlHydratingStack state
set in the same callback was not listed in the effect's dependency array.
Adding it causes the effect to retry once hydration has committed.
A resolvingRef mutex prevents concurrent invocations. When the target file
is already loaded, route state is applied directly without calling
loadFileForRoute, which avoids unmounting the editor (and hiding the
recovery chip) if a background refresh triggers route resolution during
a deploy operation.
* test: adapt stack, deploy, and sidebar e2e specs to routable stack URLs
* ci: raise E2E Playwright job timeout to 20 minutes
Historical net_rx_mb/net_tx_mb values are MB/s rates, not cumulative bytes.
Replace delta bucketing with per-bucket aggregate averaging converted to
bytes/s so the NETWORK sparkline matches the live headline units.
Compare runtimeResourceName against the project-prefixed default instead
of the compose key so networks like tailscale: { name: tailscale } are
not mis-resolved as network_tailscale in Drift, Fleet summary, and preflight.
Fixes#1581
* fix: repin semver compose tags during fleet self-update
Fleet updates failed when docker-compose.yml pinned a semver tag because recreate reused the on-disk pin. Pull the target image first, rewrite semver pins via the update helper, and block digest or unresolved pins with fast 409s.
* fix: update OFFLINE_META shape in capability and node-registry meta tests
Closes#1580. The Command Center header showed the first container's
image directly above stack-wide Start/Stop/Update controls, which implied
those buttons targeted one image. Remove the header image/digest row;
per-container ImageSourceMenu on each row remains.
* fix: increase masthead rail shimmer visibility
Bumped shimmer highlight opacity from 25% to 50% and reduced
animation duration from 11s to 5s, matching the login page
AuthCanvas shimmer precedent (via-white/60 at 4.5s).
* fix: reduce masthead rail opacity to match login page pattern
Changed all MastheadRail background classes from 100% to 70% opacity
(bg-brand → bg-brand/70, etc.) so the shimmer highlight reads as a surface
reflection rather than a detached floating bar. Matches the AuthCanvas
login card precedent.
* fix: improve masthead rail glow visibility
Replaced the invisible inset box-shadow glow (10px blur inside a 3px
element) with a white overlay that pulses opacity 0.15-0.55 over 4s.
Sped up glow animation from 5.5s to 4s for a more noticeable breath.
* fix: replace cursor-follow tooltip with standard Radix tooltip in sidebar rows
Replaced the Cursor/CursorFollow animate-ui primitives in StackRow
with the standard Radix Tooltip/TooltipTrigger/TooltipContent already
used throughout the app. The custom cursor dot that followed the mouse
is gone; tooltips now appear as static popovers on hover/touch.
* fix: wrap tooltip icon triggers in span for Radix compatibility
TooltipTrigger asChild requires a native element to forward props.
Lucide icon components did not reliably receive data-state and event
handlers, so tooltips on the check-failed and git-pending indicators
did not open. Wrapped each icon in a span.
* fix: rename Notification Routing to Routing in settings sidebar
* fix: replace Timeline/All tasks buttons with SegmentedControl
The two loose Button elements had indistinguishable selected/unselected
states (secondary vs ghost). Replaced with the SegmentedControl component
already used elsewhere on the same page, which has a clear active
highlight indicator.
* fix: standardize Blueprint empty state headings to font-heading
Replaced manual font-serif [font-style:var(--heading-style)] with the
font-heading class on the main heading and three step titles so the
Deployments empty state follows the same heading convention as the
rest of the app and respects the Calm/Signature theme toggle.
* fix: remove custom tooltip styling, use standard TooltipContent defaults
The RowTooltip wrapped its label in a font-mono text-stat-value span
instead of using the TooltipContent base styling (text-xs
text-popover-foreground) like every other tooltip in the app.
* Revert "fix: remove custom tooltip styling, use standard TooltipContent defaults"
This reverts commit 209fbd2742.
* fix: standardize all tooltips to match sidebar RowTooltip design
Wrapped every TooltipContent child in a font-mono text-xs
tabular-nums text-stat-value span so all tooltips across the app
share a consistent look. Previously some used plain text, others
used <p> elements with different fonts and sizes.
* Revert "fix: standardize all tooltips to match sidebar RowTooltip design"
This reverts commit 9e1d97d39e.
* fix: bake standard tooltip styling into TooltipContent component
Added font-mono tabular-nums text-stat-value directly to the
TooltipContent base styles so every tooltip in the app inherits
the same look without per-instance wrappers. Removed the now-
redundant span from StackRow's RowTooltip.
* fix: replace custom tooltip with shadcn/ui Radix tooltip
Replaced the glass/blur-styled tooltip with the standard shadcn/ui
pattern: bg-foreground/text-background, arrow pointer, proper
slide/fade animations, and w-fit max-w-xs sizing. This gives all
tooltips a consistent dark-solid look across the entire app.
* fix: apply glass/blur design to shadcn tooltip component
Replaced the solid bg-foreground/text-background style with the app's
glass design: bg-popover, border-glass-border, backdrop-blur, and
text-popover-foreground. Kept the shadcn structure (Portal, Arrow,
slide/fade animations).
* fix: replace native title tooltips with Radix tooltips on Fleet toolbar
Converted Refresh, Export Dossier, Search, Sort direction, Node Update,
and Manage Nodes buttons from native HTML title attributes to the shared
Radix Tooltip component so they match the app-wide glass tooltip design.
* fix: replace native title tooltip on Fleet Snapshots upload button
* fix: replace native title tooltips with Radix tooltips on Resources page
Converted all actionable button tooltips (Open stack, Inspect image,
Scan, Browse volume, and delete buttons) plus the SenchoBadge
informational tooltip. Wrapped disabled protected-resource delete
buttons in span triggers so tooltips fire on disabled elements.
* fix: replace native title tooltips with Radix tooltips on Security page
Converted scanner info icon, exploitability n/a badge, and scan
image button from native HTML title attributes to the shared Radix
Tooltip component.
* fix: replace native title tooltips with Radix tooltips on Schedules and Settings pages
Converted Run now, Execution history, Edit, Delete buttons on Schedules;
Download/Delete on Cloud Backup; Send test/Edit/Delete on Notification
Routing; Reset 2FA on Users; and Edit/Remove suppression on
Suppressions panel. Skipped SettingsSection/Modal title props which
are React component props, not native HTML attributes.
* feat: add copy button to execution history details column
Replaced the plain truncated Details cell with a flex layout containing
a copy button. Users can now copy the full error/output text instead
of relying on the native title tooltip to read long messages.
* fix: change tab highlight from neutral to brand color
Replaced bg-glass-highlight with bg-brand/20 on all TabsHighlight
instances and updated TabsTrigger active state to text-brand,
matching the SegmentedControl selected style. Works on both
dark and light themes.
* fix: restructure Resources page tabs to match Fleet/Security pattern
Moved tab band out of the outer card into a standalone full-width
element. Replaced custom FilterToggle with Fleet-style Button
toggles. Added search inputs per tab. Wrapped each resource table
in a card container matching the Security Images table design.
* fix: match Resources tab font size to Fleet and Security
Removed explicit text-xs from Resources TabsTrigger elements so they
use the default text-sm, matching Fleet and Security tab typography.
* fix: restore missing closing bracket on TabsTrigger tag
* fix: add aria-labels to schedule action buttons, update test selectors
Replaced native title attributes with aria-labels on Run now,
Execution history, Edit, and Delete buttons so the Radix tooltip
conversion does not break test selectors that relied on title.
Updated tests from findByTitle to findByRole.
* fix: add fingerprint-based dismiss to post-deploy scan banner
Created useScanBannerDismiss hook following the usePreflightDismiss
pattern. The banner now persists dismissal in localStorage keyed to a
fingerprint of scan status + attemptedAt. Dismissal survives page
reloads for the same scan outcome, and the banner automatically
reappears when a new scan runs or the status changes.
* fix: update Configuration Status card labels and add new rows
Notifications section: renamed Notification agents to Channels,
Notification routing to Routing, added Mute Rules row linking to
notification-suppression settings.
Security section: added Trivy installed Yes/No row, renamed
Vulnerability scanning to Scan policies.
Backend: added trivyInstalled and suppressionRules fields to
the /dashboard/configuration payload.
* fix: style Trivy row as badge and link to Security scanner setup
* fix: remove Mute button from stack anatomy panel header
* Revert "fix: remove Mute button from stack anatomy panel header"
This reverts commit 16843a81b5.
* fix: remove Mute button from stack anatomy panel header
* fix: remove unused stackMuteActions imports and props from StackAnatomyPanel
The removal of the ActivityMuteKebab rendering left orphaned imports
and props that cause TS6133 errors under strict mode. Clean up the
imports, prop type, destructuring, and caller prop passes.
* fix: refine anatomy tab sizing and add pulsing scroll chevron
Changed anatomy tabs from 12px fixed height to 11px with py-1
padding, matching the Fleet tab approach. Bumped Files/Edit buttons
from 10px to xs for better visibility. Added subtle animate-pulse
to the right scroll chevron to hint at overflow tabs, gated behind
the Reduced effects appearance setting.
* fix: link reclaim hero number to heading style
* fix: replace native title tooltips with Radix tooltips on stack detail page
Converted Expand/Collapse logs, Stats unavailable, Copy service URL,
Dismiss findings, Likely secret badge, Move up/down, and Remove
buttons from native HTML title attributes to the shared Radix
glass tooltip component.
* fix: replace native title tooltip on image source link button
* fix: add tooltips to container logs and bash session buttons
* fix: add tooltip to download logs button
* fix: add tooltip to copy digest button
* fix: replace cursor-follow tooltip with Radix tooltip on severity badge
* fix: add tooltips to density toggle buttons
* feat: add expand button to multi-container health panel
Added an expand/collapse toggle next to the density controls that
expands the containers panel to fill the column and hides the logs
section. The expand and logs-expand are mutually exclusive. Only
appears for stacks with more than one container.
* fix: reduce Structured/Raw terminal toggle font to 10px
* fix: set compact density as default for multi-container stacks
* fix: change Feedback to Open New Issue with GitHub issues link
* fix: replace ExternalLink with GitHub icon for Open New Issue menu item
* fix: restore ExternalLink import needed by other menu items
* fix: default host threshold alerts to off for new installations
* fix: resolve CI typecheck and test failures
Broaden MenuRowProps.icon type to accept custom SVG components alongside
lucide icons, fixing TS2741 on GitHubIcon import.
Update host_alerts_enabled seed test assertion to match the new opt-in
default of off (0).
* fix: update ContainersHealth tests for compact default density
Adjust three tests to reflect the new default of compact mode:
- Rename 'detailed mode is the default' to 'compact mode is the default'
- Update sparkline visibility checks to switch to detailed first
- Rename remount test and verify reset to compact (new default)
* feat: block self-stack lifecycle ops with UI and preflight guardrails
Refuse update, deploy, down, stop, and delete when the stack matches Sencho's compose project.
Return 409 self_stack_protected. Expose isSelf on /statuses and disable guarded UI actions.
Add SelfStackProtectedDialog and self-managed-stack preflight warning.
Closes#1564
* fix: add missing stackSelfFlags mock to useSidebarContextMenu test
The production hook now reads stackListState.stackSelfFlags[file], but the
test mock did not include it, causing 6 tests to fail with TypeError:
Cannot read properties of undefined (reading 'web.yml').
* fix: harden self-stack protection during startup
Add a global environment preflight warning when Sencho is managed inside COMPOSE_DIR.
Align status decoration and route guards on Docker label fallback detection.
Block rollback and service-level stop on the protected self stack.
* fix: add self_stack_location to diagnostics-route expected check IDs
Drift compared raw compose YAML to runtime, so ${VAR:-default} image
expressions false-positive as image-mismatch. Source the declared side
from docker compose config instead, matching deploy-time resolution.
Fixes#1572
* feat: move core Blueprint orchestration to Community tier
Blueprints CRUD, reconciliation, and drift modes are now available on
Community. Pin remains Admiral-only via Federation placement controls.
* test: update NodeCard cordon tests for Admiral-only tier gate
Cordon now requires both isPaid and node:manage permission, matching the
backend requirePaid + requirePermission guard. Three tests still used
isPaid:false but expected the menu to be visible.