mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
style(portal): tighten stable overview and workspace desk
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"source_hash": "5c0116abefe33e38423a53786fa29fe46555d46fa8bc8dcea9ca2063cb1a7cc2",
|
||||
"source_hash": "af74be942dbe9fa37b8c3eb059ba5434ea54ab2369d0d3da5c570049f5caab6b",
|
||||
"build_inputs": [
|
||||
"package.json",
|
||||
"tsconfig.json",
|
||||
|
||||
+38
-7
@@ -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);
|
||||
|
||||
+2
-2
@@ -1765,7 +1765,7 @@
|
||||
function renderAttentionPanel(workspaces) {
|
||||
var attention = attentionWorkspaces(workspaces);
|
||||
if (!attention.length) {
|
||||
return '<div class="overview-side-card"><div class="account-panel-kicker">Attention</div><h4>Fleet is stable</h4><p>Every visible hosted workspace currently reports a healthy posture.</p></div>';
|
||||
return '<div class="overview-side-card overview-side-card-stable"><div class="account-panel-kicker">Attention</div><h4>Fleet is stable</h4><p>Every visible hosted workspace currently reports a healthy posture.</p><div class="overview-stable-list"><div class="overview-stable-item"><strong>Healthy now</strong><span>All visible hosted workspaces are clear for routine operator work.</span></div><div class="overview-stable-item"><strong>Use Team only for change</strong><span>Keep roster edits explicit instead of mixing them into normal workspace work.</span></div><div class="overview-stable-item"><strong>Keep billing separate</strong><span>Use account services only when the task is commercial, not operational.</span></div></div></div>';
|
||||
}
|
||||
var items = attention.slice(0, 3).map(function(workspace) {
|
||||
return '<div class="overview-alert-row"><div class="overview-alert-main"><strong>' + escapeHTML(workspace.display_name) + "</strong><span>" + escapeHTML(workspaceStatusCopy(workspace)) + "</span></div>" + healthBadgeHTML(workspace) + "</div>";
|
||||
@@ -1855,7 +1855,7 @@
|
||||
workspaceDeskActions += '<button type="button" class="btn-secondary btn-compact" data-action="open-billing" data-account-id="' + escapeAttr(account.id) + '">Manage billing</button>';
|
||||
}
|
||||
workspaceDeskActions += '<button type="button" class="btn-secondary btn-compact" data-action="toggle-team" data-account-id="' + escapeAttr(account.id) + '" data-shell-target="team">Manage team</button>';
|
||||
workspaceManagement = '<section class="workspace-management-panel" id="workspace-management-' + escapeAttr(account.id) + '"><div class="workspace-management-header"><div><div class="account-panel-kicker">Workspace management</div><h3>Review one workspace at a time</h3><p>Select a workspace from the fleet to review its lifecycle state and run explicit management actions.</p></div><button type="button" class="btn-secondary btn-compact" id="workspace-management-close-' + escapeAttr(account.id) + '" data-action="clear-workspace-selection" data-account-id="' + escapeAttr(account.id) + '">Done</button></div><div class="workspace-management-empty" id="workspace-management-empty-' + escapeAttr(account.id) + '"><div class="workspace-management-empty-copy">Choose a workspace from the fleet to open its management desk.</div><div class="workspace-management-empty-grid"><div class="workspace-management-empty-card"><div class="account-panel-kicker">Account desk</div><h4>Keep account-wide actions close</h4><p>Use the desk for one workspace at a time while keeping billing, team, and create-workspace actions within reach.</p><div class="workspace-management-empty-actions">' + workspaceDeskActions + '</div></div><div class="workspace-management-empty-card workspace-management-empty-card-muted"><div class="account-panel-kicker">Review flow</div><div class="workspace-management-empty-checklist"><div class="workspace-management-empty-check"><strong>1. Pick the workspace</strong><span>Select a fleet row to bring its health, lifecycle, and next action into this desk.</span></div><div class="workspace-management-empty-check"><strong>2. Check posture first</strong><span>Treat checking or needs-attention workspaces as review work, not routine operations.</span></div><div class="workspace-management-empty-check"><strong>3. Escalate account changes separately</strong><span>Billing and team changes stay account-wide even when you are focused on one workspace.</span></div></div></div></div></div><div class="workspace-management-content" id="workspace-management-content-' + escapeAttr(account.id) + '" hidden><div class="workspace-management-meta" id="workspace-management-meta-' + escapeAttr(account.id) + '"></div><h4 id="workspace-management-title-' + escapeAttr(account.id) + '"></h4><p class="workspace-management-summary" id="workspace-management-summary-' + escapeAttr(account.id) + '"></p><div class="workspace-management-facts"><div class="workspace-management-fact"><span>Health</span><strong id="workspace-management-health-' + escapeAttr(account.id) + '"></strong></div><div class="workspace-management-fact"><span>Lifecycle</span><strong id="workspace-management-lifecycle-' + escapeAttr(account.id) + '"></strong></div><div class="workspace-management-fact"><span>Created</span><strong id="workspace-management-created-' + escapeAttr(account.id) + '"></strong></div></div><div class="workspace-management-guidance" id="workspace-management-guidance-' + escapeAttr(account.id) + '"></div><div class="workspace-management-actions"><button type="button" class="btn-danger" id="workspace-management-action-' + escapeAttr(account.id) + '" data-action="workspace-action" data-account-id="' + escapeAttr(account.id) + '">Manage workspace</button></div></div></section>';
|
||||
workspaceManagement = '<section class="workspace-management-panel" id="workspace-management-' + escapeAttr(account.id) + '"><div class="workspace-management-header"><div><div class="account-panel-kicker">Workspace management</div><h3>Review one workspace at a time</h3><p>Select a workspace from the fleet to review its lifecycle state and run explicit management actions.</p></div><button type="button" class="btn-secondary btn-compact" id="workspace-management-close-' + escapeAttr(account.id) + '" data-action="clear-workspace-selection" data-account-id="' + escapeAttr(account.id) + '">Done</button></div><div class="workspace-management-empty" id="workspace-management-empty-' + escapeAttr(account.id) + '"><div class="workspace-management-empty-copy">Pick a workspace to open its operator desk.</div><div class="workspace-management-empty-grid"><div class="workspace-management-empty-card"><div class="account-panel-kicker">Account desk</div><h4>Keep account actions close</h4><p>Workspace review happens here while billing, team, and create-workspace actions stay within reach.</p><div class="workspace-management-empty-actions">' + workspaceDeskActions + '</div></div><div class="workspace-management-empty-card workspace-management-empty-card-muted"><div class="account-panel-kicker">Desk flow</div><div class="workspace-management-empty-checklist"><div class="workspace-management-empty-check"><strong>Pick the workspace</strong><span>Select a fleet row to load its health, lifecycle, and next management action.</span></div><div class="workspace-management-empty-check"><strong>Read posture first</strong><span>Treat checking or needs-attention workspaces as review work, not routine operations.</span></div><div class="workspace-management-empty-check"><strong>Escalate account changes separately</strong><span>Billing and team changes stay account-wide even when you are focused on one workspace.</span></div></div></div></div></div><div class="workspace-management-content" id="workspace-management-content-' + escapeAttr(account.id) + '" hidden><div class="workspace-management-meta" id="workspace-management-meta-' + escapeAttr(account.id) + '"></div><h4 id="workspace-management-title-' + escapeAttr(account.id) + '"></h4><p class="workspace-management-summary" id="workspace-management-summary-' + escapeAttr(account.id) + '"></p><div class="workspace-management-facts"><div class="workspace-management-fact"><span>Health</span><strong id="workspace-management-health-' + escapeAttr(account.id) + '"></strong></div><div class="workspace-management-fact"><span>Lifecycle</span><strong id="workspace-management-lifecycle-' + escapeAttr(account.id) + '"></strong></div><div class="workspace-management-fact"><span>Created</span><strong id="workspace-management-created-' + escapeAttr(account.id) + '"></strong></div></div><div class="workspace-management-guidance" id="workspace-management-guidance-' + escapeAttr(account.id) + '"></div><div class="workspace-management-actions"><button type="button" class="btn-danger" id="workspace-management-action-' + escapeAttr(account.id) + '" data-action="workspace-action" data-account-id="' + escapeAttr(account.id) + '">Manage workspace</button></div></div></section>';
|
||||
}
|
||||
var workspaceHTML = workspaces.length ? '<div class="workspace-list-wrap"><div class="workspace-list-toolbar"><div class="workspace-list-summary">Review the hosted fleet, open a workspace, and keep lifecycle actions explicit.</div><div class="workspace-list-stats"><span class="workspace-list-stat"><strong>' + String(workspaces.length) + '</strong> total</span><span class="workspace-list-stat"><strong>' + String(healthyCount) + '</strong> healthy</span><span class="workspace-list-stat"><strong>' + String(checkingCount) + '</strong> checking</span><span class="workspace-list-stat workspace-list-stat-attention"><strong>' + String(unhealthyCount) + '</strong> needs attention</span></div></div><div class="workspace-list-head"><span>Workspace</span><span>Health</span><span>Lifecycle</span><span>Actions</span></div><div class="workspace-list">' + workspaces.map(function(workspace) {
|
||||
return renderWorkspaceCard(account, workspace, accountAPIBasePath);
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -163,10 +163,15 @@ function renderAttentionPanel(workspaces: PortalWorkspaceSummary[]): string {
|
||||
var attention = attentionWorkspaces(workspaces);
|
||||
if (!attention.length) {
|
||||
return (
|
||||
'<div class="overview-side-card">' +
|
||||
'<div class="overview-side-card overview-side-card-stable">' +
|
||||
'<div class="account-panel-kicker">Attention</div>' +
|
||||
'<h4>Fleet is stable</h4>' +
|
||||
'<p>Every visible hosted workspace currently reports a healthy posture.</p>' +
|
||||
'<div class="overview-stable-list">' +
|
||||
'<div class="overview-stable-item"><strong>Healthy now</strong><span>All visible hosted workspaces are clear for routine operator work.</span></div>' +
|
||||
'<div class="overview-stable-item"><strong>Use Team only for change</strong><span>Keep roster edits explicit instead of mixing them into normal workspace work.</span></div>' +
|
||||
'<div class="overview-stable-item"><strong>Keep billing separate</strong><span>Use account services only when the task is commercial, not operational.</span></div>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
@@ -513,20 +518,20 @@ function renderAccountWorkspaceSection(account: PortalAccountSummary, accountAPI
|
||||
'<div class="workspace-management-empty" id="workspace-management-empty-' +
|
||||
escapeAttr(account.id) +
|
||||
'">' +
|
||||
'<div class="workspace-management-empty-copy">Choose a workspace from the fleet to open its management desk.</div>' +
|
||||
'<div class="workspace-management-empty-copy">Pick a workspace to open its operator desk.</div>' +
|
||||
'<div class="workspace-management-empty-grid">' +
|
||||
'<div class="workspace-management-empty-card">' +
|
||||
'<div class="account-panel-kicker">Account desk</div>' +
|
||||
'<h4>Keep account-wide actions close</h4>' +
|
||||
'<p>Use the desk for one workspace at a time while keeping billing, team, and create-workspace actions within reach.</p>' +
|
||||
'<h4>Keep account actions close</h4>' +
|
||||
'<p>Workspace review happens here while billing, team, and create-workspace actions stay within reach.</p>' +
|
||||
'<div class="workspace-management-empty-actions">' + workspaceDeskActions + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="workspace-management-empty-card workspace-management-empty-card-muted">' +
|
||||
'<div class="account-panel-kicker">Review flow</div>' +
|
||||
'<div class="account-panel-kicker">Desk flow</div>' +
|
||||
'<div class="workspace-management-empty-checklist">' +
|
||||
'<div class="workspace-management-empty-check"><strong>1. Pick the workspace</strong><span>Select a fleet row to bring its health, lifecycle, and next action into this desk.</span></div>' +
|
||||
'<div class="workspace-management-empty-check"><strong>2. Check posture first</strong><span>Treat checking or needs-attention workspaces as review work, not routine operations.</span></div>' +
|
||||
'<div class="workspace-management-empty-check"><strong>3. Escalate account changes separately</strong><span>Billing and team changes stay account-wide even when you are focused on one workspace.</span></div>' +
|
||||
'<div class="workspace-management-empty-check"><strong>Pick the workspace</strong><span>Select a fleet row to load its health, lifecycle, and next management action.</span></div>' +
|
||||
'<div class="workspace-management-empty-check"><strong>Read posture first</strong><span>Treat checking or needs-attention workspaces as review work, not routine operations.</span></div>' +
|
||||
'<div class="workspace-management-empty-check"><strong>Escalate account changes separately</strong><span>Billing and team changes stay account-wide even when you are focused on one workspace.</span></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user