style(portal): flatten operator console sections

This commit is contained in:
rcourtman
2026-03-27 23:07:56 +00:00
parent d4a9f69ff1
commit 219d3b37a0
6 changed files with 107 additions and 51 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
{
"source_hash": "46e32b3f10be76cc7ecaf28e84ea41b97ba549984641bbc401f9b9cd5484880a",
"source_hash": "7a0f2e57cde80096b6b3e6f00199572003416ff27bb9288a1228175a2e70bf63",
"build_inputs": [
"package.json",
"tsconfig.json",
+45 -24
View File
@@ -275,8 +275,8 @@ header .logout-btn:hover,
align-items: start;
border: 1px solid var(--line);
border-radius: var(--radius-lg);
background: #e9eef3;
box-shadow: 0 22px 48px rgba(10, 25, 41, 0.08);
background: #ffffff;
box-shadow: 0 24px 52px rgba(10, 25, 41, 0.08);
overflow: hidden;
}
.portal-shell-nav {
@@ -381,8 +381,8 @@ header .logout-btn:hover,
.portal-shell-main {
min-width: 0;
min-height: 820px;
padding: 0 0 24px;
background: #f3f6fa;
padding: 0 0 28px;
background: #f7f9fb;
}
.portal-shell-main > .portal-content-panel {
display: none !important;
@@ -392,9 +392,9 @@ header .logout-btn:hover,
grid-template-columns: minmax(0, 1fr) auto;
gap: 18px;
align-items: center;
padding: 18px 22px 16px;
padding: 16px 24px 14px;
border-bottom: 1px solid var(--line);
background: rgba(255, 255, 255, 0.84);
background: rgba(255, 255, 255, 0.98);
}
.portal-account-bar-copy {
display: flex;
@@ -471,7 +471,7 @@ header .logout-btn:hover,
gap: 26px;
}
.portal-content-panel {
padding: 16px 22px 0;
padding: 18px 24px 0;
}
.portal-top-section,
.service-section {
@@ -560,11 +560,11 @@ header .logout-btn:hover,
.account-content-panel-overview,
.account-content-panel-workspaces,
.account-content-panel-team {
padding: 16px;
border: 1px solid var(--line);
border-radius: 14px;
background: #edf2f6;
box-shadow: 0 10px 22px rgba(10, 25, 41, 0.04);
padding: 0;
border: none;
border-radius: 0;
background: transparent;
box-shadow: none;
}
.account-command-deck,
.account-overview-card,
@@ -619,12 +619,12 @@ header .logout-btn:hover,
.account-command-deck {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
gap: 14px;
align-items: stretch;
padding: 14px;
border: 1px solid var(--line);
border-radius: 12px;
background: rgba(255, 255, 255, 0.72);
padding: 0;
border: none;
border-radius: 0;
background: transparent;
}
.account-overview-card {
display: grid;
@@ -834,8 +834,24 @@ header .logout-btn:hover,
color: var(--ink-soft);
}
.account-stage-header {
padding: 0 0 14px;
border-bottom: 1px solid var(--line);
padding: 0 2px 12px;
border-bottom: none;
margin-bottom: 0;
}
.account-stage-header h3 {
margin: 8px 0 0;
font-size: 24px;
line-height: 1.02;
letter-spacing: -0.05em;
}
.account-stage-header p {
margin: 10px 0 0;
max-width: 820px;
font-size: 14px;
line-height: 1.65;
color: var(--ink-soft);
}
.account-stage-header-overview {
margin-bottom: 14px;
}
.workspace-list-wrap {
@@ -846,6 +862,7 @@ header .logout-btn:hover,
border: 1px solid var(--line);
border-radius: 14px;
background: #fff;
box-shadow: var(--shadow-sm);
}
.workspace-list-toolbar {
display: flex;
@@ -998,12 +1015,12 @@ header .logout-btn:hover,
.workspace-operations-shell {
display: grid;
grid-template-columns: minmax(0, 1.42fr) minmax(360px, 1fr);
gap: 14px;
gap: 16px;
align-items: start;
padding: 14px;
border: 1px solid var(--line);
border-radius: 12px;
background: rgba(255, 255, 255, 0.68);
padding: 0;
border: none;
border-radius: 0;
background: transparent;
}
.workspace-operations-main,
.workspace-operations-detail {
@@ -1011,6 +1028,7 @@ header .logout-btn:hover,
}
.workspace-management-panel {
min-height: 100%;
box-shadow: var(--shadow-sm);
}
.workspace-management-panel.visible,
.team-section.visible .team-management-panel {
@@ -1241,6 +1259,9 @@ header .logout-btn:hover,
gap: 14px;
align-items: start;
}
.team-management-panel {
box-shadow: var(--shadow-sm);
}
.team-side-column {
display: flex;
flex-direction: column;
+1 -1
View File
@@ -1829,7 +1829,7 @@
addWorkspaceForm = '<div class="add-workspace-form" id="add-ws-form-' + escapeAttr(account.id) + '"><label for="ws-name-' + escapeAttr(account.id) + '">Workspace name (for example, a client name)</label><input type="text" id="ws-name-' + escapeAttr(account.id) + '" placeholder="Acme Corp" maxlength="80" autocomplete="off"><div class="form-actions"><button type="button" class="btn-primary" data-action="create-workspace" data-account-id="' + escapeAttr(account.id) + '">Create workspace</button><button type="button" class="btn-secondary" data-action="toggle-add-workspace" data-account-id="' + escapeAttr(account.id) + '">Cancel</button><div class="spinner" id="ws-spinner-' + escapeAttr(account.id) + '" hidden></div></div></div>';
}
}
return '<section class="account-content-panel account-content-panel-overview"><div class="account-command-deck"><div class="account-overview-card"><div class="account-overview-lead"><div class="account-panel-kicker">Hosted posture</div><h3>' + escapeHTML(postureTitle) + "</h3><p>" + escapeHTML(postureCopy) + '</p><div class="account-overview-callout">' + escapeHTML(
return '<section class="account-content-panel account-content-panel-overview"><div class="account-stage-header account-stage-header-overview"><div><div class="account-panel-kicker">Overview</div><h3>Hosted posture</h3><p>Start here to judge fleet posture, pick the next operator action, and keep commercial account work separate from hosted operations.</p></div></div><div class="account-command-deck"><div class="account-overview-card"><div class="account-overview-lead"><div class="account-panel-kicker">Fleet posture</div><h3>' + escapeHTML(postureTitle) + "</h3><p>" + escapeHTML(postureCopy) + '</p><div class="account-overview-callout">' + escapeHTML(
account.kind === "msp" ? "Use this console to run client workspaces, account billing, and operator access from one place." : "Use this console to run hosted workspaces, account billing, and operator access from one place."
) + '</div></div><div class="account-metric-strip"><div class="account-stat-card account-stat-card-inline"><span class="account-stat-label">Active workspaces</span><span class="account-stat-value">' + String(activeCount) + '</span></div><div class="account-stat-card account-stat-card-inline"><span class="account-stat-label">Healthy</span><span class="account-stat-value account-stat-healthy">' + String(healthyCount) + '</span></div><div class="account-stat-card account-stat-card-inline"><span class="account-stat-label">Checking</span><span class="account-stat-value account-stat-checking">' + String(checkingCount) + '</span></div><div class="account-stat-card account-stat-card-inline"><span class="account-stat-label">Needs attention</span><span class="account-stat-value account-stat-unhealthy">' + String(unhealthyCount) + "</span></div></div></div>" + addWorkspaceForm + '<div class="account-overview-secondary"><div class="overview-side-card overview-side-card-primary"><div class="account-panel-kicker">Next move</div><h4>' + escapeHTML(nextStepTitle) + "</h4><p>" + escapeHTML(nextStepCopy) + "</p>" + nextStepChecklist + nextStepActions + "</div>" + renderAttentionPanel(workspaces) + "</div></div></section>";
}
@@ -142,9 +142,12 @@ describe('shell view', function() {
expect(html).toContain('Add workspace');
expect(html).toContain('Manage billing');
expect(html).toContain('Manage team');
expect(html).toContain('Hosted posture');
expect(html).toContain('Start here to judge fleet posture');
expect(html).toContain('Next move');
expect(html).toContain('Start in Workspaces');
expect(html).toContain('Hosted posture needs review');
expect(html).toContain('Fleet posture');
expect(html).toContain('Use this console to run client workspaces, account billing, and operator access from one place.');
expect(html).toContain('Open workspaces');
expect(html).toContain('Review team access');
@@ -416,10 +416,17 @@ function renderAccountOverviewSection(account: PortalAccountSummary): string {
return (
'<section class="account-content-panel account-content-panel-overview">' +
'<div class="account-stage-header account-stage-header-overview">' +
'<div>' +
'<div class="account-panel-kicker">Overview</div>' +
'<h3>Hosted posture</h3>' +
'<p>Start here to judge fleet posture, pick the next operator action, and keep commercial account work separate from hosted operations.</p>' +
'</div>' +
'</div>' +
'<div class="account-command-deck">' +
'<div class="account-overview-card">' +
'<div class="account-overview-lead">' +
'<div class="account-panel-kicker">Hosted posture</div>' +
'<div class="account-panel-kicker">Fleet posture</div>' +
'<h3>' + escapeHTML(postureTitle) + '</h3>' +
'<p>' + escapeHTML(postureCopy) + '</p>' +
'<div class="account-overview-callout">' + escapeHTML(account.kind === 'msp'
+49 -24
View File
@@ -288,8 +288,8 @@ header .logout-btn:hover,
align-items: start;
border: 1px solid var(--line);
border-radius: var(--radius-lg);
background: #e9eef3;
box-shadow: 0 22px 48px rgba(10, 25, 41, 0.08);
background: #ffffff;
box-shadow: 0 24px 52px rgba(10, 25, 41, 0.08);
overflow: hidden;
}
@@ -411,8 +411,8 @@ header .logout-btn:hover,
.portal-shell-main {
min-width: 0;
min-height: 820px;
padding: 0 0 24px;
background: #f3f6fa;
padding: 0 0 28px;
background: #f7f9fb;
}
.portal-shell-main > .portal-content-panel {
@@ -424,9 +424,9 @@ header .logout-btn:hover,
grid-template-columns: minmax(0, 1fr) auto;
gap: 18px;
align-items: center;
padding: 18px 22px 16px;
padding: 16px 24px 14px;
border-bottom: 1px solid var(--line);
background: rgba(255, 255, 255, 0.84);
background: rgba(255, 255, 255, 0.98);
}
.portal-account-bar-copy {
@@ -516,7 +516,7 @@ header .logout-btn:hover,
}
.portal-content-panel {
padding: 16px 22px 0;
padding: 18px 24px 0;
}
.portal-top-section,
@@ -620,11 +620,11 @@ header .logout-btn:hover,
.account-content-panel-overview,
.account-content-panel-workspaces,
.account-content-panel-team {
padding: 16px;
border: 1px solid var(--line);
border-radius: 14px;
background: #edf2f6;
box-shadow: 0 10px 22px rgba(10, 25, 41, 0.04);
padding: 0;
border: none;
border-radius: 0;
background: transparent;
box-shadow: none;
}
.account-command-deck,
@@ -684,12 +684,12 @@ header .logout-btn:hover,
.account-command-deck {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
gap: 14px;
align-items: stretch;
padding: 14px;
border: 1px solid var(--line);
border-radius: 12px;
background: rgba(255, 255, 255, 0.72);
padding: 0;
border: none;
border-radius: 0;
background: transparent;
}
.account-overview-card {
@@ -929,8 +929,27 @@ header .logout-btn:hover,
}
.account-stage-header {
padding: 0 0 14px;
border-bottom: 1px solid var(--line);
padding: 0 2px 12px;
border-bottom: none;
margin-bottom: 0;
}
.account-stage-header h3 {
margin: 8px 0 0;
font-size: 24px;
line-height: 1.02;
letter-spacing: -0.05em;
}
.account-stage-header p {
margin: 10px 0 0;
max-width: 820px;
font-size: 14px;
line-height: 1.65;
color: var(--ink-soft);
}
.account-stage-header-overview {
margin-bottom: 14px;
}
@@ -942,6 +961,7 @@ header .logout-btn:hover,
border: 1px solid var(--line);
border-radius: 14px;
background: #fff;
box-shadow: var(--shadow-sm);
}
.workspace-list-toolbar {
@@ -1116,12 +1136,12 @@ header .logout-btn:hover,
.workspace-operations-shell {
display: grid;
grid-template-columns: minmax(0, 1.42fr) minmax(360px, 1fr);
gap: 14px;
gap: 16px;
align-items: start;
padding: 14px;
border: 1px solid var(--line);
border-radius: 12px;
background: rgba(255, 255, 255, 0.68);
padding: 0;
border: none;
border-radius: 0;
background: transparent;
}
.workspace-operations-main,
@@ -1131,6 +1151,7 @@ header .logout-btn:hover,
.workspace-management-panel {
min-height: 100%;
box-shadow: var(--shadow-sm);
}
.workspace-management-panel.visible,
@@ -1398,6 +1419,10 @@ header .logout-btn:hover,
align-items: start;
}
.team-management-panel {
box-shadow: var(--shadow-sm);
}
.team-side-column {
display: flex;
flex-direction: column;