From 7bc9bb414d4ac3a901339705a08c8f6cd3c21bc2 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 27 Mar 2026 16:07:08 +0000 Subject: [PATCH] feat(portal): sharpen workspace fleet layout --- .../cloudcp/portal/dist/build_manifest.json | 2 +- internal/cloudcp/portal/dist/portal_app.css | 66 +++++++++++----- internal/cloudcp/portal/dist/portal_app.js | 4 +- .../cloudcp/portal/frontend/src/shell_view.ts | 20 +++-- .../cloudcp/portal/frontend/src/styles.css | 75 ++++++++++++++----- 5 files changed, 119 insertions(+), 48 deletions(-) diff --git a/internal/cloudcp/portal/dist/build_manifest.json b/internal/cloudcp/portal/dist/build_manifest.json index 5756dd9287..9ef5825dce 100644 --- a/internal/cloudcp/portal/dist/build_manifest.json +++ b/internal/cloudcp/portal/dist/build_manifest.json @@ -1,5 +1,5 @@ { - "source_hash": "3ee5dcea0783b4085b4a7feb3fd0dcee628b4280042752af29256a685db8a466", + "source_hash": "c60aecd13aa823a23de54658d2f067e93ce5d5d05b80cee353495dccbb3c07d2", "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 d7c997966e..bf5b04f20c 100644 --- a/internal/cloudcp/portal/dist/portal_app.css +++ b/internal/cloudcp/portal/dist/portal_app.css @@ -400,7 +400,7 @@ header .logout-btn:hover, .account-overview-card, .account-stat-card, .account-operations-panel, -.workspace-card, +.workspace-row, .workspace-management-panel, .team-management-panel, .add-workspace-form, @@ -511,29 +511,29 @@ header .logout-btn:hover, padding: 6px 4px 0; } .workspace-list { + display: flex; + flex-direction: column; + gap: 12px; +} +.workspace-row { display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 14px; -} -.workspace-card { - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 18px; + grid-template-columns: minmax(0, 1fr) auto; + gap: 16px; + align-items: center; padding: 18px; - min-height: 250px; } -.workspace-card-main { +.workspace-row-main { + display: grid; + grid-template-columns: minmax(0, 1.4fr) minmax(220px, 0.85fr); + gap: 18px; + align-items: center; +} +.workspace-row-title { display: flex; flex-direction: column; - gap: 12px; + gap: 10px; } -.workspace-card-topline { - display: flex; - flex-direction: column; - gap: 12px; -} -.workspace-title-group { +.workspace-row-heading { display: flex; flex-direction: column; gap: 8px; @@ -568,6 +568,28 @@ header .logout-btn:hover, line-height: 1.65; color: var(--ink-soft); } +.workspace-row-status-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} +.workspace-row-status-cell { + display: flex; + flex-direction: column; + gap: 8px; + min-height: 84px; + padding: 14px; + border: 1px solid var(--line); + border-radius: var(--radius-md); + background: var(--panel-muted); +} +.workspace-row-status-label { + font-size: 11px; + font-weight: 800; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--ink-muted); +} .workspace-state-label { font-size: 13px; font-weight: 700; @@ -932,6 +954,10 @@ header .logout-btn:hover, .service-grid { grid-template-columns: 1fr; } + .workspace-row, + .workspace-row-main { + grid-template-columns: 1fr; + } } @media (max-width: 720px) { header { @@ -960,9 +986,13 @@ header .logout-btn:hover, flex-direction: column; align-items: flex-start; } + .workspace-actions, .workspace-actions form, .workspace-actions .btn-primary, .workspace-actions .btn-secondary { width: 100%; } + .workspace-row-status-grid { + grid-template-columns: 1fr; + } } diff --git a/internal/cloudcp/portal/dist/portal_app.js b/internal/cloudcp/portal/dist/portal_app.js index c2f7dca77b..8c9cfb7c9a 100644 --- a/internal/cloudcp/portal/dist/portal_app.js +++ b/internal/cloudcp/portal/dist/portal_app.js @@ -1607,7 +1607,7 @@ var state = String(workspace.state || ""); var createdLabel = formatWorkspaceDate(workspace.created_at); var metaParts = [ - '' + escapeHTML(titleCase(state || "unknown")) + "" + '' + escapeHTML(workspace.id) + "" ]; if (createdLabel) { metaParts.push('Created ' + escapeHTML(createdLabel) + ""); @@ -1625,7 +1625,7 @@ if (account.can_manage && (state === "active" || state === "suspended" || state === "failed")) { manageAction = ''; } - return '

' + escapeHTML(workspace.display_name) + '

' + metaParts.join("") + '
' + healthBadgeHTML(workspace) + '' + escapeHTML(titleCase(state || "Unknown")) + '

' + escapeHTML(workspaceStatusCopy(workspace)) + '

' + openAction + manageAction + "
"; + return '

' + escapeHTML(workspace.display_name) + '

' + metaParts.join("") + '

' + escapeHTML(workspaceStatusCopy(workspace)) + '

Health' + healthBadgeHTML(workspace) + '
Lifecycle' + escapeHTML(titleCase(state || "Unknown")) + '
' + openAction + manageAction + "
"; } function renderAccountSection(account, accountAPIBasePath) { var workspaces = Array.isArray(account.workspaces) ? account.workspaces : []; diff --git a/internal/cloudcp/portal/frontend/src/shell_view.ts b/internal/cloudcp/portal/frontend/src/shell_view.ts index ff00f3ccaf..540c8d55e9 100644 --- a/internal/cloudcp/portal/frontend/src/shell_view.ts +++ b/internal/cloudcp/portal/frontend/src/shell_view.ts @@ -165,7 +165,7 @@ function renderWorkspaceCard(account: PortalAccountSummary, workspace: PortalWor var state = String(workspace.state || ''); var createdLabel = formatWorkspaceDate(workspace.created_at); var metaParts = [ - '' + escapeHTML(titleCase(state || 'unknown')) + '', + '' + escapeHTML(workspace.id) + '', ]; if (createdLabel) { metaParts.push('Created ' + escapeHTML(createdLabel) + ''); @@ -197,19 +197,25 @@ function renderWorkspaceCard(account: PortalAccountSummary, workspace: PortalWor } return ( - '
' + - '
' + - '
' + - '
' + + '
' + + '
' + + '
' + + '
' + '

' + escapeHTML(workspace.display_name) + '

' + '
' + metaParts.join('') + '
' + '
' + - '
' + + '

' + escapeHTML(workspaceStatusCopy(workspace)) + '

' + + '
' + + '
' + + '
' + + 'Health' + healthBadgeHTML(workspace) + + '
' + + '
' + + 'Lifecycle' + '' + escapeHTML(titleCase(state || 'Unknown')) + '' + '
' + '
' + - '

' + escapeHTML(workspaceStatusCopy(workspace)) + '

' + '
' + '
' + openAction + diff --git a/internal/cloudcp/portal/frontend/src/styles.css b/internal/cloudcp/portal/frontend/src/styles.css index 20f33336cd..ac71a6bdbf 100644 --- a/internal/cloudcp/portal/frontend/src/styles.css +++ b/internal/cloudcp/portal/frontend/src/styles.css @@ -433,7 +433,7 @@ header .logout-btn:hover, .account-overview-card, .account-stat-card, .account-operations-panel, -.workspace-card, +.workspace-row, .workspace-management-panel, .team-management-panel, .add-workspace-form, @@ -553,33 +553,33 @@ header .logout-btn:hover, } .workspace-list { + display: flex; + flex-direction: column; + gap: 12px; +} + +.workspace-row { display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 14px; -} - -.workspace-card { - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 18px; + grid-template-columns: minmax(0, 1fr) auto; + gap: 16px; + align-items: center; padding: 18px; - min-height: 250px; } -.workspace-card-main { +.workspace-row-main { + display: grid; + grid-template-columns: minmax(0, 1.4fr) minmax(220px, 0.85fr); + gap: 18px; + align-items: center; +} + +.workspace-row-title { display: flex; flex-direction: column; - gap: 12px; + gap: 10px; } -.workspace-card-topline { - display: flex; - flex-direction: column; - gap: 12px; -} - -.workspace-title-group { +.workspace-row-heading { display: flex; flex-direction: column; gap: 8px; @@ -619,6 +619,31 @@ header .logout-btn:hover, color: var(--ink-soft); } +.workspace-row-status-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} + +.workspace-row-status-cell { + display: flex; + flex-direction: column; + gap: 8px; + min-height: 84px; + padding: 14px; + border: 1px solid var(--line); + border-radius: var(--radius-md); + background: var(--panel-muted); +} + +.workspace-row-status-label { + font-size: 11px; + font-weight: 800; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--ink-muted); +} + .workspace-state-label { font-size: 13px; font-weight: 700; @@ -1045,6 +1070,11 @@ header .logout-btn:hover, .service-grid { grid-template-columns: 1fr; } + + .workspace-row, + .workspace-row-main { + grid-template-columns: 1fr; + } } @media (max-width: 720px) { @@ -1079,9 +1109,14 @@ header .logout-btn:hover, align-items: flex-start; } + .workspace-actions, .workspace-actions form, .workspace-actions .btn-primary, .workspace-actions .btn-secondary { width: 100%; } + + .workspace-row-status-grid { + grid-template-columns: 1fr; + } }