diff --git a/backend/src/__tests__/settings-routes.test.ts b/backend/src/__tests__/settings-routes.test.ts index 83c11dc6..ba6a3eb4 100644 --- a/backend/src/__tests__/settings-routes.test.ts +++ b/backend/src/__tests__/settings-routes.test.ts @@ -663,19 +663,19 @@ describe('Paid-only setting keys (audit_retention_days)', () => { }); describe('reclaim_hero setting', () => { - it('is allowlisted and seeds to "1" (banner on by default)', async () => { + it('is allowlisted and seeds to "0" (banner off by default)', async () => { const res = await request(app).get('/api/settings').set('Cookie', adminCookie); expect(res.status).toBe(200); - expect(res.body.reclaim_hero).toBe('1'); + expect(res.body.reclaim_hero).toBe('0'); }); it('accepts a well-formed write and rejects a non-enum value', async () => { const ok = await request(app) .patch('/api/settings') .set('Cookie', adminCookie) - .send({ reclaim_hero: '0' }); + .send({ reclaim_hero: '1' }); expect(ok.status).toBe(200); - expect(DatabaseService.getInstance().getGlobalSettings().reclaim_hero).toBe('0'); + expect(DatabaseService.getInstance().getGlobalSettings().reclaim_hero).toBe('1'); const bad = await request(app) .patch('/api/settings') @@ -683,9 +683,9 @@ describe('reclaim_hero setting', () => { .send({ reclaim_hero: 'banana' }); expect(bad.status).toBe(400); expect(bad.body.error).toBe('Validation failed'); - expect(DatabaseService.getInstance().getGlobalSettings().reclaim_hero).toBe('0'); + expect(DatabaseService.getInstance().getGlobalSettings().reclaim_hero).toBe('1'); // Reset for any later reads of the shared test DB. - DatabaseService.getInstance().updateGlobalSetting('reclaim_hero', '1'); + DatabaseService.getInstance().updateGlobalSetting('reclaim_hero', '0'); }); }); diff --git a/backend/src/services/DatabaseService.ts b/backend/src/services/DatabaseService.ts index fe868ee7..a1032014 100644 --- a/backend/src/services/DatabaseService.ts +++ b/backend/src/services/DatabaseService.ts @@ -2012,7 +2012,7 @@ export class DatabaseService { stmt.run('cve_intel_enabled', '1'); stmt.run('mesh_auto_recreate', '0'); stmt.run('prune_on_update', '1'); - stmt.run('reclaim_hero', '1'); + stmt.run('reclaim_hero', '0'); stmt.run('health_gate_enabled', '1'); stmt.run('health_gate_window_seconds', '90'); stmt.run('image_update_check_interval_minutes', '120'); diff --git a/docs/features/alerts-notifications.mdx b/docs/features/alerts-notifications.mdx index 97043bb4..4cd08e0e 100644 --- a/docs/features/alerts-notifications.mdx +++ b/docs/features/alerts-notifications.mdx @@ -7,14 +7,14 @@ description: Threshold and event alerts for your fleet, dispatched to Discord, S Sencho watches each node it manages for container crashes, host pressure, scheduled-task results, and update availability, then surfaces every signal in two places: the in-app notification bell at the top of the shell and an external channel you configure. This page covers everything from configuring channels to writing stack and service threshold rules, routing alerts to dedicated channels with routing rules, and tuning retention. - Settings · Notifications · Channels panel with NODE Local in the header, a Delivery retries row showing Extra attempts 0 and a Save retries button, Discord Slack Webhook and Apprise tabs with Apprise selected, Enabled off, an empty Apprise endpoint placeholder, and Test beside Save. + Settings · Notifications · Channels panel with NODE Local in the header, Discord Slack Webhook and Apprise tabs with Apprise selected, Enabled off, an empty Apprise endpoint placeholder, Test beside Save, and a Delivery retries section below showing Extra attempts 0 and a Save retries button. ## Notification channels Open **Settings · Notifications · Channels** to configure Discord, Slack, custom webhook, and Apprise channels. Each channel is per-node, so switching the active node via the node picker reloads the panel against that node's stored settings. The masthead carries a `CHANNELS` stat showing how many of the four slots are enabled. -Above the channel tabs, **Delivery retries** sets how many extra in-process attempts (0 to 3) Sencho makes after a transient delivery failure on that node. The default is `0` (single-shot). Extra attempts wait a fixed one second between tries. Admin role is required to change the value. +Below the channel tabs, **Delivery retries** sets how many extra in-process attempts (0 to 3) Sencho makes after a transient delivery failure on that node. The default is `0` (single-shot). Extra attempts wait a fixed one second between tries. Admin role is required to change the value. Each Discord, Slack, and Webhook tab carries an **Enabled** toggle, a **Webhook URL** input (HTTPS only), and **Test** / **Save**. The Apprise tab uses an **Apprise endpoint** instead: keyed `/notify/{key}` shows optional **Tags**; stateless `/notify` shows **Destination URLs**. The kicker on each tab toggles between `enabled` and `off` so you can see at a glance which slots are wired up. diff --git a/docs/features/appearance.mdx b/docs/features/appearance.mdx index f66047e6..31fc1ab0 100644 --- a/docs/features/appearance.mdx +++ b/docs/features/appearance.mdx @@ -97,10 +97,10 @@ The **Navigation** group chooses how the desktop top bar presents page destinati - **Navigation style** - **Smart bar** (recommended default): keeps a short set of primary destinations visible and moves the rest into a grouped **More** menu. - - **Classic bar**: shows the full horizontal destination strip. - - **Compact launcher**: puts destinations in a left-side launcher menu and optionally pins up to five **quick links** on the bar. + - **Classic bar**: shows the full horizontal destination strip. Choosing Classic shows a callout that Classic bar will be removed soon; the preference is kept until then. + - **Compact launcher**: puts destinations in a left-side launcher menu and optionally pins up to seven **quick links** on the bar. - **Top navigation labels** (Classic and Smart): shows text beside top navigation icons. Turn it off for an icon-only bar; destinations stay reachable by tooltip, accessible name, and the command palette. Phone layout always keeps labels. With labels off, **Top navigation alignment** places the icon-only bar left or centered. -- **Quick links** (Compact launcher): labeled pins after the launcher, with a trailing **+** that opens reachable unpinned destinations. Right-click a pin and choose Remove, or manage the full list under Appearance. Up to five pins; recommended defaults start you with four. +- **Quick links** (Compact launcher): labeled pins after the launcher, with a trailing **+** that opens reachable unpinned destinations. Right-click a pin and choose Remove, or manage the full list under Appearance. Up to seven pins; recommended defaults start you with four. Deploy-progress behavior and the diff-preview-before-save step are stack workflow preferences, so they live in **Settings → Infrastructure → Stacks**, not here. diff --git a/docs/features/deep-links.mdx b/docs/features/deep-links.mdx index 5e1ec9e1..7b6bd2d5 100644 --- a/docs/features/deep-links.mdx +++ b/docs/features/deep-links.mdx @@ -95,7 +95,7 @@ On a phone, `/nodes/local/stacks//files` opens the compose editor instead Some in-app state is intentionally not encoded: -- **Stack Anatomy sub-tabs** (Anatomy, Activity, Dossier, Drift, Environment, and the rest) stay in memory only. Refresh returns you to the default Anatomy tab for that stack. A [Networking](/features/networking) finding's action can open a stack directly on its Doctor, Dossier, or Drift tab; this is in-app navigation, not a separate URL, so the same refresh behavior applies. +- **Stack Anatomy sub-tabs** (Anatomy, Activity, Doctor, Drift, Dossier, Environment, and the rest) stay in memory only. Refresh returns you to the default Anatomy tab for that stack. A [Networking](/features/networking) finding's action can open a stack directly on its Doctor, Dossier, or Drift tab; this is in-app navigation, not a separate URL, so the same refresh behavior applies. ## Tips diff --git a/docs/features/editor.mdx b/docs/features/editor.mdx index a975023f..0f1260a7 100644 --- a/docs/features/editor.mdx +++ b/docs/features/editor.mdx @@ -79,21 +79,21 @@ Stacks with more than one container gain a summary strip above the container lis The right column shows the **Anatomy panel** by default: a read-only summary of the compose file alongside a scrollable tab row for other stack views. - Anatomy panel header strip showing the Anatomy, Activity, Dossier, Drift, Environment, Networking, Doctor, and Storage tab row with Files and Edit compose shortcuts on the right + Anatomy panel header strip showing the Anatomy, Activity, Doctor, Drift, Dossier, Environment, Networking, and Storage tab row with Files and Edit compose shortcuts on the right -The tab row always shows four tabs: **Anatomy**, **Activity**, **Dossier**, and **Drift**. Four more tabs appear when the active node advertises the matching capability. +The tab row always shows four tabs: **Anatomy**, **Activity**, **Drift**, and **Dossier**. When Compose Doctor is available on the node, **Doctor** sits between Activity and Drift. Four more capability-gated tabs appear when the active node advertises them. | Tab | Always present? | What it shows | |-----|----------------|--------------| | **Anatomy** | Yes | Read-only compose file summary. | | **Activity** | Yes | Operational event timeline for this stack. See [Stack Activity](/features/stack-activity). | -| **Dossier** | Yes | Exportable Markdown of the anatomy combined with operator notes. See [Stack Dossier](/features/stack-dossier). | +| **Doctor** | When `compose-doctor` capability is present | Preflight check results grouped by severity. The tab gains a red dot for blocker findings and an amber dot for high-risk findings. See [Compose Doctor](/features/compose-doctor). | | **Drift** | Yes | Live comparison of the declared compose against the running containers. See [Stack Drift](/features/stack-drift). | +| **Dossier** | Yes | Exportable Markdown of the anatomy combined with operator notes. See [Stack Dossier](/features/stack-dossier). | | **Environment** | When `env-inventory` capability is present | Variable inventory across all env files, with status for each variable. See [Environment Guardrails](/features/environment-guardrails). | | **Compose Labels** | When `container-label-inventory` capability is present | Declared Compose labels vs runtime container labels per service. See [Docker Label Audit](/features/docker-label-audit). | | **Networking** | When `compose-networking` capability is present | Port exposure summary per service with intent classification. See [Compose Networking](/features/compose-networking). | -| **Doctor** | When `compose-doctor` capability is present | Preflight check results grouped by severity. The tab gains a red dot for blocker findings and an amber dot for high-risk findings. See [Compose Doctor](/features/compose-doctor). | | **Storage** | When `compose-storage` capability is present | Mount inventory with portability assessment and snapshot coverage. See [Compose Storage](/features/compose-storage). | The **Files** shortcut and the **Edit compose** button sit at the right end of the strip and stay available regardless of which tab is active. diff --git a/docs/features/overview.mdx b/docs/features/overview.mdx index 681c3f68..bb42b92d 100644 --- a/docs/features/overview.mdx +++ b/docs/features/overview.mdx @@ -13,7 +13,7 @@ Sencho is a self-hosted cockpit for Docker Compose. The catalog below groups Sen ## Core workflow - A stack open in the editor: the action toolbar, the container card with CPU and memory sparklines, the live log stream, and the right-hand panel on the Networking tab showing exposure intent, network memberships, published ports, and a runtime drift check. The full tab strip (Anatomy, Activity, Dossier, Drift, Environment, Networking, Doctor, Storage) is visible across the top of the panel. + A stack open in the editor: the action toolbar, the container card with CPU and memory sparklines, the live log stream, and the right-hand panel on the Networking tab showing exposure intent, network memberships, published ports, and a runtime drift check. The full tab strip (Anatomy, Activity, Doctor, Drift, Dossier, Environment, Networking, Storage) is visible across the top of the panel. ### Stack management diff --git a/docs/features/resources.mdx b/docs/features/resources.mdx index 8596496e..599455df 100644 --- a/docs/features/resources.mdx +++ b/docs/features/resources.mdx @@ -11,13 +11,13 @@ The **Resources** tab shows everything Docker is storing on your host, broken do ## Reclaim hero -When there is reclaimable disk space (unused images, stopped containers, or dangling volumes), an amber banner leads the view with the total amount you can free and a `·`-separated breakdown of what contributes to it (for example, `2 unused images · 10 dangling volumes`). Click **Review & prune** to open a confirmation dialog that lists the exact items that will be removed (capped in the preview with an "and N more" note when the list is long). Confirm only after the plan is ready; Sencho rechecks the list at execute time and skips anything that is no longer eligible. +Once enabled for a node, an amber banner leads the view whenever there is reclaimable disk space (unused images, stopped containers, or dangling volumes), showing the total amount you can free and a `·`-separated breakdown of what contributes to it (for example, `2 unused images · 10 dangling volumes`). Click **Review & prune** to open a confirmation dialog that lists the exact items that will be removed (capped in the preview with an "and N more" note when the list is long). Confirm only after the plan is ready; Sencho rechecks the list at execute time and skips anything that is no longer eligible. The hero stays hidden when there is nothing to reclaim, keeping the view focused on the rest of your inventory. To set the banner aside without pruning, use the **×** in its top-right corner. It stays hidden on that browser until the reclaimable total grows past the amount it held when you dismissed it, so a small, stubborn remainder will not keep reappearing while a genuine new build-up still surfaces. -To keep the banner off for a node entirely, open **Settings → Monitoring → Docker & Storage** and switch off **Show reclaimable-space banner**. It is on by default and applies per node. +The banner is off by default and applies per node. To turn it on, open **Settings → Monitoring → Docker & Storage** and switch on **Show reclaimable-space banner**. The banner and the **Review & prune** action are admin-only. Read-only roles still see the rest of the page but cannot trigger destructive operations. diff --git a/docs/features/stack-drift.mdx b/docs/features/stack-drift.mdx index 2297f106..81cf7404 100644 --- a/docs/features/stack-drift.mdx +++ b/docs/features/stack-drift.mdx @@ -121,11 +121,11 @@ Drift events also appear in the stack's **Activity** tab alongside deploys, rest The tab bar in the stack detail view showing Anatomy, Activity, Dossier, Drift, Environment, and Compose Labels tabs with Drift selected, and separate Files and Edit compose buttons to the right 1. Click any stack in the sidebar to open it. -2. In the right-hand panel, switch to the **Drift** tab. If the tab row doesn't fit the panel width, scroll it to reveal Drift alongside the stack's other tabs (Anatomy, Activity, Dossier, Environment, Networking, and so on). +2. In the right-hand panel, switch to the **Drift** tab. If the tab row doesn't fit the panel width, scroll it to reveal Drift alongside the stack's other tabs (Anatomy, Activity, Doctor, Dossier, Environment, Networking, and so on). 3. Read the status badge and any findings. 4. Click **re-check** after editing the Compose file or after a manual Docker operation to refresh the ledger. diff --git a/docs/features/stack-management.mdx b/docs/features/stack-management.mdx index 36f49582..5683a83c 100644 --- a/docs/features/stack-management.mdx +++ b/docs/features/stack-management.mdx @@ -257,7 +257,7 @@ The structured viewer holds up to 10,000 lines; older entries are dropped from t ## Anatomy panel -The right column of the stack view is a tabbed panel: Anatomy, Activity, Dossier, Drift, Environment, Compose Labels, Networking, Doctor, and Storage. Tabs appear only when the data they need is available, and the row scrolls horizontally (with a chevron button) when there are more tabs than fit. +The right column of the stack view is a tabbed panel: Anatomy, Activity, Doctor, Drift, Dossier, Environment, Compose Labels, Networking, and Storage. Tabs appear only when the data they need is available, and the row scrolls horizontally (with a chevron button) when there are more tabs than fit. Anatomy panel with the Anatomy tab active, showing services, ports, volumes, restart, env_file, network, and source rows plus the tab row diff --git a/docs/getting-started/introduction.mdx b/docs/getting-started/introduction.mdx index cd1a11d8..5793fc79 100644 --- a/docs/getting-started/introduction.mdx +++ b/docs/getting-started/introduction.mdx @@ -52,7 +52,7 @@ Opening a stack gives you the day-to-day workspace: - Running stacks expose **Restart**, **Stop**, **Take down**, and **Update**; stopped stacks expose **Start** and **Update**. The overflow menu holds less frequent actions such as rollback, config scan, and delete. - Container rows show health, uptime, published ports, live CPU and memory, network activity, logs, and service actions. - The logs panel can run in **Structured** mode or **Raw terminal** mode. -- The right panel provides tabs for **Anatomy**, **Activity**, **Dossier**, **Drift**, **Environment**, **Compose Labels**, **Networking**, **Doctor**, and **Storage**, with **Files** and **Edit** controls for browsing stack files and editing compose or env content. +- The right panel provides tabs for **Anatomy**, **Activity**, **Doctor**, **Drift**, **Dossier**, **Environment**, **Compose Labels**, **Networking**, and **Storage**, with **Files** and **Edit** controls for browsing stack files and editing compose or env content. ## Fleet operations diff --git a/docs/reference/contact.mdx b/docs/reference/contact.mdx index da79ba9b..bc080cc1 100644 --- a/docs/reference/contact.mdx +++ b/docs/reference/contact.mdx @@ -12,7 +12,7 @@ Sencho provides dedicated email channels for different types of inquiries. Use t Priority email support, reserved for Admiral license holders: Monday to Friday, 09:00-17:00 America/New_York, with a one-business-day first-response target. This is not a contractual SLA or 24/7 service. -Every user, Community and Admiral alike, can reach [Documentation](https://docs.sencho.io) and [GitHub Issues](https://github.com/studio-saelix/sencho/issues) from **Settings → Help → Support** in the app. Admiral adds the priority email channel above on the same page. +Every user, Community and Admiral alike, can reach [Documentation](https://docs.sencho.io), [GitHub Issues](https://github.com/studio-saelix/sencho/issues), and [Discord](https://discord.gg/rvXAszRGSc) from **Settings → Help → Support** in the app. Admiral adds the priority email channel above on the same page. ## General inquiries diff --git a/docs/reference/settings.mdx b/docs/reference/settings.mdx index 42ce8d58..2c2e1a03 100644 --- a/docs/reference/settings.mdx +++ b/docs/reference/settings.mdx @@ -145,7 +145,7 @@ A live preview card shows a sample fleet-status tile so you can see a color choi | Control | What it does | |---------|--------------| -| **Navigation style** | **Smart bar** (recommended default): primary destinations stay visible in the top bar and the rest live under **More**. **Classic bar** keeps the full horizontal strip of destinations. **Compact launcher** puts every destination in a menu, with optional quick links. | +| **Navigation style** | **Smart bar** (recommended default): primary destinations stay visible in the top bar and the rest live under **More**. **Classic bar** keeps the full horizontal strip of destinations (retiring soon; a callout appears while it is selected). **Compact launcher** puts every destination in a menu, with optional quick links. | | **Top navigation labels** | On by default. Shows text labels beside the top navigation icons; turn off for a more compact bar with icons only. | Deploy-progress behavior and the diff-preview-before-save step are stack workflow preferences and live in their own [Stacks](#stacks) section under Infrastructure. @@ -293,7 +293,7 @@ Configure the reclaimable-space alert, the reclaimable-space banner, and automat | Setting | Default | Description | |---------|---------|-------------| | **Reclaimable Docker data threshold** | 5 GiB | Alert when reclaimable Docker data (images, volumes, build cache that `docker prune` could free) exceeds this size. Set to `0` to disable the alert. | -| **Show reclaimable-space banner** | On | Show the reclaimable-space banner at the top of the Resource Hub when this node has unused images, stopped containers, or dangling volumes to clear. | +| **Show reclaimable-space banner** | Off | Show the reclaimable-space banner at the top of the Resource Hub when this node has unused images, stopped containers, or dangling volumes to clear. | ### Image cleanup @@ -403,7 +403,7 @@ Quick reference: Configure external destinations for alert notifications. Four agent types are available on separate tabs: **Discord**, **Slack**, **Webhook**, and **Apprise**. The masthead publishes a **CHANNELS** pill showing how many agents are enabled (for example, `2/4`). -**Delivery retries** (admin-only) sets how many extra in-process attempts (0 to 3, default 0) this node makes after a transient channel failure, with a fixed one-second delay between attempts. There is no durable queue; ambiguous network failures can produce duplicate notifications. +Below the channel tabs, **Delivery retries** (admin-only) sets how many extra in-process attempts (0 to 3, default 0) this node makes after a transient channel failure, with a fixed one-second delay between attempts. There is no durable queue; ambiguous network failures can produce duplicate notifications. For each agent: @@ -721,6 +721,7 @@ Links to help resources, with an additional channel for Admiral operators. |----------|-------------| | **Documentation** | Opens docs.sencho.io. | | **GitHub Issues** | Report bugs and request features on GitHub. | +| **Discord** | Chat with the community and the team. | ### Admiral support diff --git a/e2e/desktop-navigation.spec.ts b/e2e/desktop-navigation.spec.ts index eaf6bedf..58195ca9 100644 --- a/e2e/desktop-navigation.spec.ts +++ b/e2e/desktop-navigation.spec.ts @@ -43,7 +43,8 @@ test.describe('Desktop navigation styles', () => { await setTopNavMode(page, 'smart'); await expect(page.locator('[data-sn-chrome="topbar"]')).toHaveAttribute('data-sn-nav-mode', 'smart'); await page.getByRole('button', { name: 'More navigation' }).click(); - await expect(page.locator('.font-heading').filter({ hasText: 'More' })).toBeVisible(); + await expect(page.getByRole('menuitem', { name: /Logs/i })).toBeVisible(); + await expect(page.locator('.font-heading').filter({ hasText: 'More' })).toHaveCount(0); await page.getByRole('menuitem', { name: /Logs/i }).click(); await expect(page.locator('body')).toContainText(/Logs|Central|Observability/i); }); diff --git a/frontend/src/components/EditorLayout/CreateStackDialog.tsx b/frontend/src/components/EditorLayout/CreateStackDialog.tsx index 66944243..f49c4c72 100644 --- a/frontend/src/components/EditorLayout/CreateStackDialog.tsx +++ b/frontend/src/components/EditorLayout/CreateStackDialog.tsx @@ -487,59 +487,57 @@ export function CreateStackDialog({ open, onOpenChange, onStackCreated, onStacks {createMode === 'docker-run' && (
- - -
- - setNewStackName(e.target.value)} - disabled={creatingFromDockerRun} - /> + +
+ + setNewStackName(e.target.value)} + disabled={creatingFromDockerRun} + /> +
+
+ +