From 42a3deac1d0d7614b8fe861f33b4041d67077af7 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 27 Mar 2026 23:44:31 +0000 Subject: [PATCH] style(portal): tighten stable overview and workspace desk --- .../cloudcp/portal/dist/build_manifest.json | 2 +- internal/cloudcp/portal/dist/portal_app.css | 45 +++++++++++++--- internal/cloudcp/portal/dist/portal_app.js | 4 +- .../portal/frontend/src/shell_view.test.ts | 6 +-- .../cloudcp/portal/frontend/src/shell_view.ts | 21 +++++--- .../cloudcp/portal/frontend/src/styles.css | 51 ++++++++++++++++--- 6 files changed, 101 insertions(+), 28 deletions(-) diff --git a/internal/cloudcp/portal/dist/build_manifest.json b/internal/cloudcp/portal/dist/build_manifest.json index 2967777d98..401499c368 100644 --- a/internal/cloudcp/portal/dist/build_manifest.json +++ b/internal/cloudcp/portal/dist/build_manifest.json @@ -1,5 +1,5 @@ { - "source_hash": "5c0116abefe33e38423a53786fa29fe46555d46fa8bc8dcea9ca2063cb1a7cc2", + "source_hash": "af74be942dbe9fa37b8c3eb059ba5434ea54ab2369d0d3da5c570049f5caab6b", "build_inputs": [ "package.json", "tsconfig.json", diff --git a/internal/cloudcp/portal/dist/portal_app.css b/internal/cloudcp/portal/dist/portal_app.css index b21f0980e6..4304600efa 100644 --- a/internal/cloudcp/portal/dist/portal_app.css +++ b/internal/cloudcp/portal/dist/portal_app.css @@ -720,6 +720,37 @@ header .logout-btn:hover, .overview-side-card-primary { background: var(--panel-strong); } +.overview-side-card-stable { + display: flex; + flex-direction: column; + gap: 12px; +} +.overview-stable-list { + display: flex; + flex-direction: column; + gap: 10px; +} +.overview-stable-item { + display: flex; + flex-direction: column; + gap: 4px; + padding: 12px 0; + border-top: 1px solid var(--line); +} +.overview-stable-item:first-child { + padding-top: 2px; + border-top: none; +} +.overview-stable-item strong { + font-size: 13px; + line-height: 1.3; + color: var(--ink); +} +.overview-stable-item span { + font-size: 12px; + line-height: 1.55; + color: var(--ink-soft); +} .overview-next-checklist { display: flex; flex-direction: column; @@ -1053,8 +1084,8 @@ header .logout-btn:hover, margin-top: 16px; display: flex; flex-direction: column; - gap: 12px; - padding: 16px; + gap: 10px; + padding: 14px; border-radius: var(--radius-sm); background: var(--panel-muted); color: var(--ink-soft); @@ -1067,13 +1098,13 @@ header .logout-btn:hover, .workspace-management-empty-grid { display: grid; grid-template-columns: minmax(0, 1fr); - gap: 12px; + gap: 10px; } .workspace-management-empty-card { display: flex; flex-direction: column; - gap: 10px; - padding: 14px; + gap: 8px; + padding: 12px; border: 1px solid var(--line); border-radius: 12px; background: #fff; @@ -1106,13 +1137,13 @@ header .logout-btn:hover, .workspace-management-empty-checklist { display: flex; flex-direction: column; - gap: 10px; + gap: 8px; } .workspace-management-empty-check { display: flex; flex-direction: column; gap: 4px; - padding: 12px; + padding: 10px 11px; border: 1px solid var(--line); border-radius: 10px; background: rgba(255, 255, 255, 0.78); diff --git a/internal/cloudcp/portal/dist/portal_app.js b/internal/cloudcp/portal/dist/portal_app.js index 317b0c022d..31b6ed9cb4 100644 --- a/internal/cloudcp/portal/dist/portal_app.js +++ b/internal/cloudcp/portal/dist/portal_app.js @@ -1765,7 +1765,7 @@ function renderAttentionPanel(workspaces) { var attention = attentionWorkspaces(workspaces); if (!attention.length) { - return '

Fleet is stable

Every visible hosted workspace currently reports a healthy posture.

'; + return '

Fleet is stable

Every visible hosted workspace currently reports a healthy posture.

Healthy nowAll visible hosted workspaces are clear for routine operator work.
Use Team only for changeKeep roster edits explicit instead of mixing them into normal workspace work.
Keep billing separateUse account services only when the task is commercial, not operational.
'; } var items = attention.slice(0, 3).map(function(workspace) { return '
' + escapeHTML(workspace.display_name) + "" + escapeHTML(workspaceStatusCopy(workspace)) + "
" + healthBadgeHTML(workspace) + "
"; @@ -1855,7 +1855,7 @@ workspaceDeskActions += ''; } workspaceDeskActions += ''; - workspaceManagement = '

Review one workspace at a time

Select a workspace from the fleet to review its lifecycle state and run explicit management actions.

Choose a workspace from the fleet to open its management desk.

Keep account-wide actions close

Use the desk for one workspace at a time while keeping billing, team, and create-workspace actions within reach.

' + workspaceDeskActions + '
1. Pick the workspaceSelect a fleet row to bring its health, lifecycle, and next action into this desk.
2. Check posture firstTreat checking or needs-attention workspaces as review work, not routine operations.
3. Escalate account changes separatelyBilling and team changes stay account-wide even when you are focused on one workspace.
'; + workspaceManagement = '

Review one workspace at a time

Select a workspace from the fleet to review its lifecycle state and run explicit management actions.

Pick a workspace to open its operator desk.

Keep account actions close

Workspace review happens here while billing, team, and create-workspace actions stay within reach.

' + workspaceDeskActions + '
Pick the workspaceSelect a fleet row to load its health, lifecycle, and next management action.
Read posture firstTreat checking or needs-attention workspaces as review work, not routine operations.
Escalate account changes separatelyBilling and team changes stay account-wide even when you are focused on one workspace.
'; } var workspaceHTML = workspaces.length ? '
Review the hosted fleet, open a workspace, and keep lifecycle actions explicit.
' + String(workspaces.length) + ' total' + String(healthyCount) + ' healthy' + String(checkingCount) + ' checking' + String(unhealthyCount) + ' needs attention
WorkspaceHealthLifecycleActions
' + workspaces.map(function(workspace) { return renderWorkspaceCard(account, workspace, accountAPIBasePath); diff --git a/internal/cloudcp/portal/frontend/src/shell_view.test.ts b/internal/cloudcp/portal/frontend/src/shell_view.test.ts index 100c9518b6..a43da0e3dd 100644 --- a/internal/cloudcp/portal/frontend/src/shell_view.test.ts +++ b/internal/cloudcp/portal/frontend/src/shell_view.test.ts @@ -168,9 +168,9 @@ describe('shell view', function() { expect(html).toContain('Open workspace'); expect(html).toContain('data-action="select-workspace"'); expect(html).toContain('Workspace management'); - expect(html).toContain('Choose a workspace from the fleet to open its management desk.'); - expect(html).toContain('Review flow'); - expect(html).toContain('Pick the workspace'); + expect(html).toContain('Pick a workspace to open its operator desk.'); + expect(html).toContain('Desk flow'); + expect(html).toContain('Read posture first'); expect(html).toContain('Escalate account changes separately'); expect(html).toContain('data-action="clear-workspace-selection"'); expect(html).toContain('Team management'); diff --git a/internal/cloudcp/portal/frontend/src/shell_view.ts b/internal/cloudcp/portal/frontend/src/shell_view.ts index 97ccab3baf..234c7f5f07 100644 --- a/internal/cloudcp/portal/frontend/src/shell_view.ts +++ b/internal/cloudcp/portal/frontend/src/shell_view.ts @@ -163,10 +163,15 @@ function renderAttentionPanel(workspaces: PortalWorkspaceSummary[]): string { var attention = attentionWorkspaces(workspaces); if (!attention.length) { return ( - '
' + + '
' + '' + '

Fleet is stable

' + '

Every visible hosted workspace currently reports a healthy posture.

' + + '
' + + '
Healthy nowAll visible hosted workspaces are clear for routine operator work.
' + + '
Use Team only for changeKeep roster edits explicit instead of mixing them into normal workspace work.
' + + '
Keep billing separateUse account services only when the task is commercial, not operational.
' + + '
' + '
' ); } @@ -513,20 +518,20 @@ function renderAccountWorkspaceSection(account: PortalAccountSummary, accountAPI '
' + - '
Choose a workspace from the fleet to open its management desk.
' + + '
Pick a workspace to open its operator desk.
' + '
' + '
' + '' + - '

Keep account-wide actions close

' + - '

Use the desk for one workspace at a time while keeping billing, team, and create-workspace actions within reach.

' + + '

Keep account actions close

' + + '

Workspace review happens here while billing, team, and create-workspace actions stay within reach.

' + '
' + workspaceDeskActions + '
' + '
' + '
' + - '' + + '' + '
' + - '
1. Pick the workspaceSelect a fleet row to bring its health, lifecycle, and next action into this desk.
' + - '
2. Check posture firstTreat checking or needs-attention workspaces as review work, not routine operations.
' + - '
3. Escalate account changes separatelyBilling and team changes stay account-wide even when you are focused on one workspace.
' + + '
Pick the workspaceSelect a fleet row to load its health, lifecycle, and next management action.
' + + '
Read posture firstTreat checking or needs-attention workspaces as review work, not routine operations.
' + + '
Escalate account changes separatelyBilling and team changes stay account-wide even when you are focused on one workspace.
' + '
' + '
' + '
' + diff --git a/internal/cloudcp/portal/frontend/src/styles.css b/internal/cloudcp/portal/frontend/src/styles.css index 23bcf7fe49..8be276ea33 100644 --- a/internal/cloudcp/portal/frontend/src/styles.css +++ b/internal/cloudcp/portal/frontend/src/styles.css @@ -795,6 +795,43 @@ header .logout-btn:hover, background: var(--panel-strong); } +.overview-side-card-stable { + display: flex; + flex-direction: column; + gap: 12px; +} + +.overview-stable-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.overview-stable-item { + display: flex; + flex-direction: column; + gap: 4px; + padding: 12px 0; + border-top: 1px solid var(--line); +} + +.overview-stable-item:first-child { + padding-top: 2px; + border-top: none; +} + +.overview-stable-item strong { + font-size: 13px; + line-height: 1.3; + color: var(--ink); +} + +.overview-stable-item span { + font-size: 12px; + line-height: 1.55; + color: var(--ink-soft); +} + .overview-next-checklist { display: flex; flex-direction: column; @@ -1181,8 +1218,8 @@ header .logout-btn:hover, margin-top: 16px; display: flex; flex-direction: column; - gap: 12px; - padding: 16px; + gap: 10px; + padding: 14px; border-radius: var(--radius-sm); background: var(--panel-muted); color: var(--ink-soft); @@ -1197,14 +1234,14 @@ header .logout-btn:hover, .workspace-management-empty-grid { display: grid; grid-template-columns: minmax(0, 1fr); - gap: 12px; + gap: 10px; } .workspace-management-empty-card { display: flex; flex-direction: column; - gap: 10px; - padding: 14px; + gap: 8px; + padding: 12px; border: 1px solid var(--line); border-radius: 12px; background: #fff; @@ -1242,14 +1279,14 @@ header .logout-btn:hover, .workspace-management-empty-checklist { display: flex; flex-direction: column; - gap: 10px; + gap: 8px; } .workspace-management-empty-check { display: flex; flex-direction: column; gap: 4px; - padding: 12px; + padding: 10px 11px; border: 1px solid var(--line); border-radius: 10px; background: rgba(255, 255, 255, 0.78);