1. Review attention itemsOpen the fleet and inspect any workspace marked as checking or needs attention.
2. Resolve operator blockersUse Team if the right people are not already attached to the hosted account.
3. Escalate billing separatelyKeep account billing or self-hosted license work out of the workspace review flow.
' : checkingCount > 0 ? '
1. Verify pending health checksOpen the workspaces still settling and confirm they are safe to operate.
2. Keep the roster leanReview Team only if a pending workspace needs a different operator mix.
3. Leave billing as a separate actionUse account services or billing only when the hosted fleet is already understood.
' : '
1. Use Workspaces for the next operational taskOpen a client workspace directly when you are ready to do hosted work.
2. Use Team for access changes onlyKeep roster changes explicit instead of mixing them into routine workspace work.
3. Use account services when the task is commercialLicenses, refunds, privacy, and self-hosted billing stay in their own section.
';
var nextStepActions = '";
if (account.can_manage) {
if (account.kind === "msp") {
@@ -1826,7 +1827,7 @@
}
return '
Hosted posture
' + escapeHTML(postureTitle) + "
" + escapeHTML(postureCopy) + '
' + 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."
- ) + '
Active workspaces' + String(activeCount) + '
Healthy' + String(healthyCount) + '
Checking' + String(checkingCount) + '
Needs attention' + String(unhealthyCount) + "
" + addWorkspaceForm + '
Next move
' + escapeHTML(nextStepTitle) + "
" + escapeHTML(nextStepCopy) + "
" + nextStepActions + "
" + renderAttentionPanel(workspaces) + "
";
+ ) + '
Active workspaces' + String(activeCount) + '
Healthy' + String(healthyCount) + '
Checking' + String(checkingCount) + '
Needs attention' + String(unhealthyCount) + "
" + addWorkspaceForm + '
Next move
' + escapeHTML(nextStepTitle) + "
" + escapeHTML(nextStepCopy) + "
" + nextStepChecklist + nextStepActions + "
" + renderAttentionPanel(workspaces) + "
";
}
function renderAccountWorkspaceSection(account, accountAPIBasePath) {
var workspaces = Array.isArray(account.workspaces) ? account.workspaces : [];
@@ -1872,7 +1873,7 @@
var hostedContent = accounts.map(function(account) {
return '
Open a billing, license, refund, or privacy flow from the service navigator. The active request stays here so the account-services area behaves like one operating desk instead of a list of disconnected tools.
Start here
BillingOpen Stripe customer portal access after verification.
LicensesRecover the latest active self-hosted license and invoice link.
RefundsConfirm eligibility before revoking active commercial access.
PrivacyRequest export or deletion without leaving Pulse Account.
What to expect
Verification firstEach flow confirms the commercial email before opening sensitive account actions.
One task at a timeThe active commercial request stays in this panel until you finish or switch tools.
Support stays closeIf billing, licenses, refunds, or privacy behave unexpectedly, escalate from this surface.
Open a billing, license, refund, or privacy flow from the service navigator. The active request stays here so this area behaves like one commercial operating desk.
Start here
Verify firstEach flow confirms the commercial email before opening sensitive actions.
One task at a timeKeep the active request in this desk until you finish or switch tools.
Available flows
BillingStripe customer portal access after verification.
LicensesRecover the latest active self-hosted license and invoice link.
RefundsConfirm eligibility before revoking active commercial access.
PrivacyRequest export or deletion without leaving Pulse Account.
Support
Escalate quicklyIf billing, licenses, refunds, or privacy behave unexpectedly, escalate from this surface.
";
}
function renderSignedOutPortalHTML(context) {
var statusHTML = "";
diff --git a/internal/cloudcp/portal/frontend/src/shell_view.test.ts b/internal/cloudcp/portal/frontend/src/shell_view.test.ts
index 03816d0fb4..25896acb2a 100644
--- a/internal/cloudcp/portal/frontend/src/shell_view.test.ts
+++ b/internal/cloudcp/portal/frontend/src/shell_view.test.ts
@@ -179,7 +179,9 @@ describe('shell view', function() {
expect(html).toContain('service-action-button');
expect(html).toContain('id="service-panel-empty"');
expect(html).toContain('Choose the next commercial action');
- expect(html).toContain('What to expect');
+ expect(html).toContain('Task desk');
+ expect(html).toContain('Available flows');
+ expect(html).toContain('Escalate quickly');
expect(html).toContain('id="open-retrieve-service"');
expect(html).toContain('id="data-service-panel"');
});
@@ -195,7 +197,8 @@ describe('shell view', function() {
expect(html).toContain('Pulse Account');
expect(html).toContain('Account console');
- expect(html).toContain('Use these tools for self-hosted commercial actions.');
+ expect(html).toContain('Use these account tools for self-hosted licenses, billing, refunds, and privacy actions.');
+ expect(html).toContain('Keep self-hosted commercial work here.');
expect(html).toContain('Account services');
expect(html).not.toContain('Self-hosted licenses and billing');
});
diff --git a/internal/cloudcp/portal/frontend/src/shell_view.ts b/internal/cloudcp/portal/frontend/src/shell_view.ts
index 7e15172fed..2897cc2e90 100644
--- a/internal/cloudcp/portal/frontend/src/shell_view.ts
+++ b/internal/cloudcp/portal/frontend/src/shell_view.ts
@@ -358,6 +358,29 @@ function renderAccountOverviewSection(account: PortalAccountSummary): string {
: checkingCount > 0
? 'The fleet is mostly healthy, but there are still workspaces waiting on a completed health check.'
: 'Hosted posture looks stable. Move into team or account services only if you need to change access or billing.';
+ var nextStepChecklist = unhealthyCount > 0
+ ? (
+ '
' +
+ '
1. Review attention itemsOpen the fleet and inspect any workspace marked as checking or needs attention.
' +
+ '
2. Resolve operator blockersUse Team if the right people are not already attached to the hosted account.
' +
+ '
3. Escalate billing separatelyKeep account billing or self-hosted license work out of the workspace review flow.
' +
+ '
'
+ )
+ : checkingCount > 0
+ ? (
+ '
' +
+ '
1. Verify pending health checksOpen the workspaces still settling and confirm they are safe to operate.
' +
+ '
2. Keep the roster leanReview Team only if a pending workspace needs a different operator mix.
' +
+ '
3. Leave billing as a separate actionUse account services or billing only when the hosted fleet is already understood.
' +
+ '
'
+ )
+ : (
+ '
' +
+ '
1. Use Workspaces for the next operational taskOpen a client workspace directly when you are ready to do hosted work.
' +
+ '
2. Use Team for access changes onlyKeep roster changes explicit instead of mixing them into routine workspace work.
' +
+ '
3. Use account services when the task is commercialLicenses, refunds, privacy, and self-hosted billing stay in their own section.
Use these tools for self-hosted commercial actions. Hosted workspace operations stay in Workspaces and Team.
' +
+ '
Keep self-hosted commercial work here. Hosted workspace operations stay in Workspaces and Team.
' +
'
' +
'
' +
renderServiceActionRow('open-manage-service', 'Billing', 'Manage subscriptions', 'Open Stripe billing access for existing self-hosted subscriptions without leaving the Pulse Account shell.', 'manage-service-panel', 'manage-inline-email', ['Invoices and plan changes', 'Subscription self-service']) +
@@ -777,33 +801,38 @@ export function renderAuthenticatedPortalHTML(context: ShellViewContext): string
'
' +
'
' +
'
' +
- '
Select a service
' +
+ '
Task desk
' +
'
Choose the next commercial action
' +
- '
Open a billing, license, refund, or privacy flow from the service navigator. The active request stays here so the account-services area behaves like one operating desk instead of a list of disconnected tools.
' +
- '
' +
- '
' +
+ '
Open a billing, license, refund, or privacy flow from the service navigator. The active request stays here so this area behaves like one commercial operating desk.
' +
+ '
' +
+ '
' +
'
Start here
' +
- '
' +
- '
BillingOpen Stripe customer portal access after verification.
' +
- '
LicensesRecover the latest active self-hosted license and invoice link.
' +
- '
RefundsConfirm eligibility before revoking active commercial access.
' +
- '
PrivacyRequest export or deletion without leaving Pulse Account.
' +
+ '
' +
+ '
Verify firstEach flow confirms the commercial email before opening sensitive actions.
' +
+ '
One task at a timeKeep the active request in this desk until you finish or switch tools.
' +
'
' +
'
' +
- '
' +
- '
What to expect
' +
- '
' +
- '
Verification firstEach flow confirms the commercial email before opening sensitive account actions.
' +
- '
One task at a timeThe active commercial request stays in this panel until you finish or switch tools.
' +
- '
Support stays closeIf billing, licenses, refunds, or privacy behave unexpectedly, escalate from this surface.
' +
+ '
' +
+ '
Available flows
' +
+ '
' +
+ '
BillingStripe customer portal access after verification.
' +
+ '
LicensesRecover the latest active self-hosted license and invoice link.
' +
+ '
RefundsConfirm eligibility before revoking active commercial access.
' +
+ '
PrivacyRequest export or deletion without leaving Pulse Account.
' +
'
' +
'
' +
+ '
' +
+ '
Support
' +
+ '
' +
+ '
Escalate quicklyIf billing, licenses, refunds, or privacy behave unexpectedly, escalate from this surface.