diff --git a/docs/release-control/v6/internal/PULSE_ACCOUNT_PORTAL_SPEC.md b/docs/release-control/v6/internal/PULSE_ACCOUNT_PORTAL_SPEC.md
index c67462ccf..b7b14746d 100644
--- a/docs/release-control/v6/internal/PULSE_ACCOUNT_PORTAL_SPEC.md
+++ b/docs/release-control/v6/internal/PULSE_ACCOUNT_PORTAL_SPEC.md
@@ -269,6 +269,9 @@ Core rules:
the exact state or action (for example `Manage access`, `Hosted billing
attached`, `Email support`, or `Failed to load roster`) instead of
shorthand such as `Manage`, `Hosted`, `Email`, or generic alert labels.
+ Support copy follows the same rule: escalation surfaces must name the
+ exact task path, account/email, and failed step in short literal wording,
+ not long procedural prose.
## Screen Model
diff --git a/docs/release-control/v6/internal/subsystems/api-contracts.md b/docs/release-control/v6/internal/subsystems/api-contracts.md
index 593d918c0..da5ed8a7b 100644
--- a/docs/release-control/v6/internal/subsystems/api-contracts.md
+++ b/docs/release-control/v6/internal/subsystems/api-contracts.md
@@ -378,7 +378,9 @@ rendered. The same typed contract applies to shell badges, section labels,
context chips, route labels, and error headings: they must render the exact
action or state (`Manage access`, `Hosted billing attached`, `Email support`,
`Failed to load roster`) instead of shorthand such as `Manage`, `Hosted`, or
-generic alert labels.
+generic alert labels. Support copy is part of the same typed contract:
+escalation surfaces must render short literal path/account/action wording
+instead of longer procedural prose.
That same typed overview contract must also preserve a sharp, high-density enterprise visual aesthetic (e.g. Cloudflare/GCP density standards) across all portal scenarios, removing gradients and heavy box-shadows to ensure a calm, rigorous visual language with standard 256px sidebars, Inter-grade typography, clean text-transform rules, and cleanly unboxed typography without excessive pills or stacked metrics.
plus a package-local `tsc --noEmit` gate, so future account-shell work should
extend the typed source boundary instead of reviving opaque global runtime
diff --git a/docs/release-control/v6/internal/subsystems/cloud-paid.md b/docs/release-control/v6/internal/subsystems/cloud-paid.md
index 066765d3e..bed0be695 100644
--- a/docs/release-control/v6/internal/subsystems/cloud-paid.md
+++ b/docs/release-control/v6/internal/subsystems/cloud-paid.md
@@ -945,7 +945,10 @@ the runtime already knows the concrete state, action, or failure being shown.
That includes shell badges, section labels, context chips, route labels, and
error headings: they must use the exact action or state (`Manage access`,
`Hosted billing attached`, `Email support`, `Failed to load roster`) instead
-of shorthand such as `Manage`, `Hosted`, or generic alert labels.
+of shorthand such as `Manage`, `Hosted`, or generic alert labels. Support
+copy follows the same contract: escalation guidance must stay short and typed
+to the exact task path, account/email, and failed step instead of drifting
+into longer procedural prose.
That same canonical shell/runtime boundary now also owns the bootstrap truth
for when self-hosted commercial history is relevant. Hosted-only accounts must
not render self-hosted license, refund, privacy, or support-escalation copy
diff --git a/internal/cloudcp/portal/dist/build_manifest.json b/internal/cloudcp/portal/dist/build_manifest.json
index 9107f04ad..ee11d29c8 100644
--- a/internal/cloudcp/portal/dist/build_manifest.json
+++ b/internal/cloudcp/portal/dist/build_manifest.json
@@ -1,5 +1,5 @@
{
- "source_hash": "efabad85565864017562509ae60da3b064b5d2dd20585cd8490be6d5f93452b7",
+ "source_hash": "8b83790627c0212a6ef4ba62079f11e11236c4f806f391908614e1b17eb7fcba",
"build_inputs": [
"package.json",
"tsconfig.json",
diff --git a/internal/cloudcp/portal/dist/portal_app.js b/internal/cloudcp/portal/dist/portal_app.js
index 55da4e11a..5c1afd0a2 100644
--- a/internal/cloudcp/portal/dist/portal_app.js
+++ b/internal/cloudcp/portal/dist/portal_app.js
@@ -2032,6 +2032,63 @@
}
return ["Escalation only", "Open Billing first", supportEmail ? "Email support" : "Support route"];
}
+ function supportLeadCopy(hasHostedAccounts2, hostedViewOnly, showSelfHostedCommercial) {
+ if (!hasHostedAccounts2) return "Use Support only after Billing fails.";
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial ? "Use Support only after Workspaces review, Access review, owner/admin handoff, or Billing fails." : "Use Support only after Workspaces review, Access review, owner/admin handoff, or hosted Billing fails.";
+ }
+ return showSelfHostedCommercial ? "Use Support only after Workspaces, Access, or Billing fails." : "Use Support only after Workspaces, Access, or hosted Billing fails.";
+ }
+ function hostedSupportRouteTitle(hostedViewOnly) {
+ return hostedViewOnly ? "Review or owner/admin handoff failed" : "Workspace or access failed";
+ }
+ function hostedSupportRouteDescription(hostedViewOnly) {
+ return hostedViewOnly ? "Recheck the same workspace or roster first. Escalate only if the required owner or admin change still cannot complete." : "Retry the same workspace or access task first. Escalate only if the same task still fails.";
+ }
+ function hostedSupportRouteTaskCopy(hostedViewOnly) {
+ return hostedViewOnly ? "Use Workspaces for workspace state or Access for roster state before you escalate." : "Use Workspaces for lifecycle work or Access for roster work before you escalate.";
+ }
+ function hostedSupportRouteContextLabel(hostedViewOnly) {
+ return hostedViewOnly ? "Owner/admin handoff" : "Failed step";
+ }
+ function hostedSupportRouteContextCopy(hostedViewOnly) {
+ return hostedViewOnly ? "Include the account, workspace, and the change that still needs owner or admin action." : "Include the account, workspace, and the failed step.";
+ }
+ function billingSupportRouteTitle(hostedViewOnly, showSelfHostedCommercial) {
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial ? "Billing or owner/admin handoff failed" : "Hosted billing or owner/admin handoff failed";
+ }
+ return showSelfHostedCommercial ? "Billing failed" : "Hosted billing failed";
+ }
+ function billingSupportRouteDescription(hostedViewOnly, showSelfHostedCommercial) {
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial ? "Escalate only if hosted billing still needs owner/admin action or a self-hosted billing task still fails." : "Escalate only if hosted billing still needs owner/admin action or still fails.";
+ }
+ return showSelfHostedCommercial ? "Escalate only if hosted billing or a self-hosted billing task still fails." : "Escalate only if hosted billing still fails.";
+ }
+ function billingSupportRouteJobCopy(hostedViewOnly, showSelfHostedCommercial) {
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial ? "Hosted billing, licenses, refunds, or privacy. Say if hosted billing still needed owner/admin action." : "Hosted billing. Say if it still needed owner/admin action.";
+ }
+ return showSelfHostedCommercial ? "Hosted billing, licenses, refunds, or privacy." : "Hosted billing.";
+ }
+ function billingSupportRouteAccountCopy(hostedViewOnly, showSelfHostedCommercial) {
+ if (showSelfHostedCommercial) {
+ return "Include the hosted account for hosted billing or the billing email for self-hosted work.";
+ }
+ return hostedViewOnly ? "Include the hosted account that still needed owner/admin billing action." : "Include the hosted account for the failed billing step.";
+ }
+ function supportRunbookPathCopy(hasHostedAccounts2, hostedViewOnly, showSelfHostedCommercial) {
+ if (!hasHostedAccounts2) return "Billing, licenses, refunds, or privacy.";
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial ? "Workspaces review, Access review, owner/admin handoff, hosted billing, licenses, refunds, or privacy." : "Workspaces review, Access review, owner/admin handoff, or hosted billing.";
+ }
+ return showSelfHostedCommercial ? "Workspaces, Access, hosted billing, licenses, refunds, or privacy." : "Workspaces, Access, or hosted billing.";
+ }
+ function supportRunbookAccountCopy(hasHostedAccounts2, showSelfHostedCommercial) {
+ if (!hasHostedAccounts2) return "Commercial billing email used for the self-hosted purchase.";
+ return showSelfHostedCommercial ? "Hosted account and workspace when relevant, or billing email for self-hosted work." : "Hosted account and workspace, or hosted billing account.";
+ }
function hasHostedAccounts(accounts) {
return accounts.length > 0;
}
@@ -2447,10 +2504,10 @@
}
}
var hostedViewOnly = hasHostedAccounts2 && !canManageHostedTasks;
- var supportLead = hasHostedAccounts2 ? hostedViewOnly ? showSelfHostedCommercial ? "Use support only when the same Workspaces review, Access review, owner/admin, or Billing path has already stopped you." : "Use support only when the same Workspaces review, Access review, owner/admin, or hosted Billing path has already stopped you." : showSelfHostedCommercial ? "Use support only when the Workspaces, Access, or Billing path has already stopped you." : "Use support only when the Workspaces, Access, or hosted Billing path has already stopped you." : "Use support only when the Billing path has already stopped you.";
+ var supportLead = supportLeadCopy(hasHostedAccounts2, hostedViewOnly, showSelfHostedCommercial);
var supportChips = supportSectionChipLabels(hasHostedAccounts2, hostedViewOnly, supportEmail);
- var routeCards = hasHostedAccounts2 ? '
Hosted workspace or access
' + (hostedViewOnly ? "Hosted review or owner/admin path failed" : "Workspace or access path failed") + "
" + (hostedViewOnly ? "Go back to the hosted task first. Review the same workspace or roster here, then have an owner or admin run the blocked change before you escalate." : "Go back to the hosted task first. Escalate only when the same workspace or access path still cannot finish the job.") + '
' + (hostedViewOnly ? "Review the same task" : "Start from the same task") + "" + (hostedViewOnly ? "Use Workspaces to confirm workspace state and Access to confirm the current roster before you escalate." : "Use Workspaces for lifecycle issues and Access for roster issues before you escalate.") + '
' + (hostedViewOnly ? "Name the blocked owner/admin action" : "Keep the hosted context intact") + "" + (hostedViewOnly ? "Include the account, workspace, and the lifecycle or access change that still needs an owner or admin." : "Include the account, workspace, and failed action so support inherits the same request.") + '
" + (hostedViewOnly ? showSelfHostedCommercial ? "Use this route only after the relevant billing job has failed, or the affected hosted account still needs an owner or admin to finish hosted billing." : "Use this route only after the affected hosted account still needs an owner or admin to finish hosted billing and that path still cannot complete cleanly." : showSelfHostedCommercial ? "Use this route only after hosted billing or one self-hosted billing job has failed to complete cleanly." : "Use this route only after hosted billing has failed to complete cleanly.") + '
Name the billing job' + (hostedViewOnly ? showSelfHostedCommercial ? "Say whether the failed path was hosted billing, licenses, refunds, or privacy, and whether hosted billing still needed an owner or admin." : "Say whether the failed path was hosted billing and whether the account still needed an owner or admin to open it." : showSelfHostedCommercial ? "Say whether the failed path was hosted billing, licenses, refunds, or privacy." : "Say whether the failed path was hosted billing.") + '
Keep the request intact' + (hostedViewOnly ? showSelfHostedCommercial ? "Bring the same account or billing email and the failed owner/admin or billing step instead of reopening the story." : "Bring the same hosted account and the failed billing or owner/admin step instead of reopening the story." : showSelfHostedCommercial ? "Bring the same account or billing email and the failed action instead of reopening the story." : "Bring the same hosted account and the failed billing action instead of reopening the story.") + '
1. Failed path' + (hostedViewOnly ? showSelfHostedCommercial ? "Say whether the blocked path was Workspaces review, Access review, owner/admin hosted change, hosted billing, licenses, refunds, or privacy." : "Say whether the blocked path was Workspaces review, Access review, owner/admin hosted change, or hosted billing." : showSelfHostedCommercial ? "Say whether the blocked path was Workspaces, Access, hosted billing, licenses, refunds, or privacy." : "Say whether the blocked path was Workspaces, Access, or hosted billing.") + '
2. Account or email' + (hostedViewOnly ? showSelfHostedCommercial ? "Include the hosted account and workspace for the blocked review or owner/admin path, or the commercial billing email for self-hosted work." : "Include the hosted account and workspace or hosted billing account that still needed owner/admin action." : showSelfHostedCommercial ? "Include the hosted account and workspace when relevant, or the commercial billing email for self-hosted work." : "Include the hosted account and workspace or hosted billing account that the failed path belongs to.") + '
3. Failed actionName the exact button, form, or billing step that failed and what happened next.
' : '
1. Billing jobSay whether the blocked path was billing, licenses, refunds, or privacy.
2. Purchase emailInclude the commercial billing email used for the self-hosted purchase.
3. Failed actionName the exact button, form, or billing step that failed and what happened next.
2. Account or email' + supportRunbookAccountCopy(hasHostedAccounts2, showSelfHostedCommercial) + '
3. Failed actionName the exact button, form, or billing step that failed and what happened next.
';
return '
Support
Escalation only
' + escapeHTML(supportLead) + "
" + renderSectionContextChips(supportChips) + '
' + routeCards + '
What to send
Send these details
Send the failed path, account or email, and failed action.
' + runbookSteps + "
";
}
function renderHeaderHTML(context) {
diff --git a/internal/cloudcp/portal/frontend/src/shell_view.test.ts b/internal/cloudcp/portal/frontend/src/shell_view.test.ts
index 0575d315d..1a006e347 100644
--- a/internal/cloudcp/portal/frontend/src/shell_view.test.ts
+++ b/internal/cloudcp/portal/frontend/src/shell_view.test.ts
@@ -213,11 +213,11 @@ describe('shell view', function() {
expect(html).toContain('Escalation only');
expect(html).toContain('Open Workspaces, Access, or Billing first');
expect(html).toContain('Email support');
- expect(html).toContain('Hosted workspace or access');
- expect(html).toContain('Workspace or access path failed');
+ expect(html).toContain('Workspaces or Access');
+ expect(html).toContain('Workspace or access failed');
expect(html).toContain('Open Workspaces');
expect(html).toContain('Open Access');
- expect(html).toContain('Hosted billing path failed');
+ expect(html).toContain('Hosted billing failed');
expect(html).toContain('Send these details');
expect(html).toContain('What to send');
expect(html).toContain('Open billing');
@@ -274,7 +274,7 @@ describe('shell view', function() {
expect(html).toContain('id="billing-detail-shell" hidden');
expect(html).toContain('data-account-billing-action="clear-billing-panel"');
expect(html).toContain('id="data-billing-panel"');
- expect(html).toContain('Billing path failed');
+ expect(html).toContain('Billing failed');
expect(html).toContain('licenses, refunds, or privacy');
expect(html).toContain('Escalate with the same hosted billing action or self-hosted path and the exact failed step.');
});
@@ -403,24 +403,24 @@ describe('shell view', function() {
expect(html).toContain('Review the hosted roster here. An owner or admin must make changes.');
expect(html).toContain('Hosted billing is attached here, but an owner or admin must open it.');
expect(html).toContain('Escalation only after the review, owner/admin, or billing path is exhausted.');
- expect(html).toContain('Use support only when the same Workspaces review, Access review, owner/admin, or hosted Billing path has already stopped you.');
+ expect(html).toContain('Use Support only after Workspaces review, Access review, owner/admin handoff, or hosted Billing fails.');
expect(html).toContain('Review Workspaces or Access, or contact owner/admin first');
expect(html).toContain('Email support');
- expect(html).toContain('Hosted workspace or access');
- expect(html).toContain('Hosted review or owner/admin path failed');
- expect(html).toContain('Review the same workspace or roster here, then have an owner or admin run the blocked change before you escalate.');
- expect(html).toContain('Review the same task');
- expect(html).toContain('Use Workspaces to confirm workspace state and Access to confirm the current roster before you escalate.');
- expect(html).toContain('Name the blocked owner/admin action');
- expect(html).toContain('Include the account, workspace, and the lifecycle or access change that still needs an owner or admin.');
+ expect(html).toContain('Workspaces or Access');
+ expect(html).toContain('Review or owner/admin handoff failed');
+ expect(html).toContain('Recheck the same workspace or roster first. Escalate only if the required owner or admin change still cannot complete.');
+ expect(html).toContain('Task');
+ expect(html).toContain('Use Workspaces for workspace state or Access for roster state before you escalate.');
+ expect(html).toContain('Owner/admin handoff');
+ expect(html).toContain('Include the account, workspace, and the change that still needs owner or admin action.');
expect(html).toContain('Open Workspaces');
expect(html).toContain('Open Access');
- expect(html).toContain('Hosted billing or owner/admin path failed');
- expect(html).toContain('Use this route only after the affected hosted account still needs an owner or admin to finish hosted billing and that path still cannot complete cleanly.');
- expect(html).toContain('Say whether the failed path was hosted billing and whether the account still needed an owner or admin to open it.');
- expect(html).toContain('Bring the same hosted account and the failed billing or owner/admin step instead of reopening the story.');
- expect(html).toContain('Say whether the blocked path was Workspaces review, Access review, owner/admin hosted change, or hosted billing.');
- expect(html).toContain('Include the hosted account and workspace or hosted billing account that still needed owner/admin action.');
+ expect(html).toContain('Hosted billing or owner/admin handoff failed');
+ expect(html).toContain('Escalate only if hosted billing still needs owner/admin action or still fails.');
+ expect(html).toContain('Hosted billing. Say if it still needed owner/admin action.');
+ expect(html).toContain('Include the hosted account that still needed owner/admin billing action.');
+ expect(html).toContain('Workspaces review, Access review, owner/admin handoff, or hosted billing.');
+ expect(html).toContain('Hosted account and workspace, or hosted billing account.');
expect(html).toContain('data-can-manage="false"');
expect(html).not.toContain('Invite people, change roles, and remove account access.');
expect(html).not.toContain('Open a workspace, review lifecycle state, or create one.');
@@ -647,9 +647,9 @@ describe('shell view', function() {
expect(html).toContain('Self-hosted billing available');
expect(html).toContain('Open Billing first');
expect(html).toContain('Email support');
- expect(html).toContain('Use support only when the Billing path has already stopped you.');
- expect(html).toContain('Self-hosted billing path failed');
- expect(html).toContain('Purchase email');
+ expect(html).toContain('Use Support only after Billing fails.');
+ expect(html).toContain('Self-hosted billing failed');
+ expect(html).toContain('Account or email');
expect(html).toContain('No hosted billing attached');
expect(html).not.toContain('Escalate with the same hosted billing action or self-hosted path and the exact failed step.');
expect(html).not.toContain('Workspace or access path failed');
diff --git a/internal/cloudcp/portal/frontend/src/shell_view.ts b/internal/cloudcp/portal/frontend/src/shell_view.ts
index a9cd6462a..210969b9b 100644
--- a/internal/cloudcp/portal/frontend/src/shell_view.ts
+++ b/internal/cloudcp/portal/frontend/src/shell_view.ts
@@ -131,6 +131,101 @@ function supportSectionChipLabels(hasHostedAccounts: boolean, hostedViewOnly: bo
return ['Escalation only', 'Open Billing first', supportEmail ? 'Email support' : 'Support route'];
}
+function supportLeadCopy(hasHostedAccounts: boolean, hostedViewOnly: boolean, showSelfHostedCommercial: boolean): string {
+ if (!hasHostedAccounts) return 'Use Support only after Billing fails.';
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial
+ ? 'Use Support only after Workspaces review, Access review, owner/admin handoff, or Billing fails.'
+ : 'Use Support only after Workspaces review, Access review, owner/admin handoff, or hosted Billing fails.';
+ }
+ return showSelfHostedCommercial
+ ? 'Use Support only after Workspaces, Access, or Billing fails.'
+ : 'Use Support only after Workspaces, Access, or hosted Billing fails.';
+}
+
+function hostedSupportRouteTitle(hostedViewOnly: boolean): string {
+ return hostedViewOnly ? 'Review or owner/admin handoff failed' : 'Workspace or access failed';
+}
+
+function hostedSupportRouteDescription(hostedViewOnly: boolean): string {
+ return hostedViewOnly
+ ? 'Recheck the same workspace or roster first. Escalate only if the required owner or admin change still cannot complete.'
+ : 'Retry the same workspace or access task first. Escalate only if the same task still fails.';
+}
+
+function hostedSupportRouteTaskCopy(hostedViewOnly: boolean): string {
+ return hostedViewOnly
+ ? 'Use Workspaces for workspace state or Access for roster state before you escalate.'
+ : 'Use Workspaces for lifecycle work or Access for roster work before you escalate.';
+}
+
+function hostedSupportRouteContextLabel(hostedViewOnly: boolean): string {
+ return hostedViewOnly ? 'Owner/admin handoff' : 'Failed step';
+}
+
+function hostedSupportRouteContextCopy(hostedViewOnly: boolean): string {
+ return hostedViewOnly
+ ? 'Include the account, workspace, and the change that still needs owner or admin action.'
+ : 'Include the account, workspace, and the failed step.';
+}
+
+function billingSupportRouteTitle(hostedViewOnly: boolean, showSelfHostedCommercial: boolean): string {
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial ? 'Billing or owner/admin handoff failed' : 'Hosted billing or owner/admin handoff failed';
+ }
+ return showSelfHostedCommercial ? 'Billing failed' : 'Hosted billing failed';
+}
+
+function billingSupportRouteDescription(hostedViewOnly: boolean, showSelfHostedCommercial: boolean): string {
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial
+ ? 'Escalate only if hosted billing still needs owner/admin action or a self-hosted billing task still fails.'
+ : 'Escalate only if hosted billing still needs owner/admin action or still fails.';
+ }
+ return showSelfHostedCommercial
+ ? 'Escalate only if hosted billing or a self-hosted billing task still fails.'
+ : 'Escalate only if hosted billing still fails.';
+}
+
+function billingSupportRouteJobCopy(hostedViewOnly: boolean, showSelfHostedCommercial: boolean): string {
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial
+ ? 'Hosted billing, licenses, refunds, or privacy. Say if hosted billing still needed owner/admin action.'
+ : 'Hosted billing. Say if it still needed owner/admin action.';
+ }
+ return showSelfHostedCommercial
+ ? 'Hosted billing, licenses, refunds, or privacy.'
+ : 'Hosted billing.';
+}
+
+function billingSupportRouteAccountCopy(hostedViewOnly: boolean, showSelfHostedCommercial: boolean): string {
+ if (showSelfHostedCommercial) {
+ return 'Include the hosted account for hosted billing or the billing email for self-hosted work.';
+ }
+ return hostedViewOnly
+ ? 'Include the hosted account that still needed owner/admin billing action.'
+ : 'Include the hosted account for the failed billing step.';
+}
+
+function supportRunbookPathCopy(hasHostedAccounts: boolean, hostedViewOnly: boolean, showSelfHostedCommercial: boolean): string {
+ if (!hasHostedAccounts) return 'Billing, licenses, refunds, or privacy.';
+ if (hostedViewOnly) {
+ return showSelfHostedCommercial
+ ? 'Workspaces review, Access review, owner/admin handoff, hosted billing, licenses, refunds, or privacy.'
+ : 'Workspaces review, Access review, owner/admin handoff, or hosted billing.';
+ }
+ return showSelfHostedCommercial
+ ? 'Workspaces, Access, hosted billing, licenses, refunds, or privacy.'
+ : 'Workspaces, Access, or hosted billing.';
+}
+
+function supportRunbookAccountCopy(hasHostedAccounts: boolean, showSelfHostedCommercial: boolean): string {
+ if (!hasHostedAccounts) return 'Commercial billing email used for the self-hosted purchase.';
+ return showSelfHostedCommercial
+ ? 'Hosted account and workspace when relevant, or billing email for self-hosted work.'
+ : 'Hosted account and workspace, or hosted billing account.';
+}
+
function hasHostedAccounts(accounts: PortalAccountSummary[]): boolean {
return accounts.length > 0;
}
@@ -1237,31 +1332,17 @@ function renderSupportSection(context: ShellViewContext): string {
}
}
var hostedViewOnly = hasHostedAccounts && !canManageHostedTasks;
- var supportLead = hasHostedAccounts
- ? (hostedViewOnly
- ? (showSelfHostedCommercial
- ? 'Use support only when the same Workspaces review, Access review, owner/admin, or Billing path has already stopped you.'
- : 'Use support only when the same Workspaces review, Access review, owner/admin, or hosted Billing path has already stopped you.')
- : (showSelfHostedCommercial
- ? 'Use support only when the Workspaces, Access, or Billing path has already stopped you.'
- : 'Use support only when the Workspaces, Access, or hosted Billing path has already stopped you.'))
- : 'Use support only when the Billing path has already stopped you.';
+ var supportLead = supportLeadCopy(hasHostedAccounts, hostedViewOnly, showSelfHostedCommercial);
var supportChips = supportSectionChipLabels(hasHostedAccounts, hostedViewOnly, supportEmail);
var routeCards = hasHostedAccounts
? (
'
' +
- '
Hosted workspace or access
' +
- '
' + (hostedViewOnly ? 'Hosted review or owner/admin path failed' : 'Workspace or access path failed') + '
' +
- '
' + (hostedViewOnly
- ? 'Go back to the hosted task first. Review the same workspace or roster here, then have an owner or admin run the blocked change before you escalate.'
- : 'Go back to the hosted task first. Escalate only when the same workspace or access path still cannot finish the job.') + '
' + (hostedViewOnly ? 'Review the same task' : 'Start from the same task') + '' + (hostedViewOnly
- ? 'Use Workspaces to confirm workspace state and Access to confirm the current roster before you escalate.'
- : 'Use Workspaces for lifecycle issues and Access for roster issues before you escalate.') + '
' +
- '
' + (hostedViewOnly ? 'Name the blocked owner/admin action' : 'Keep the hosted context intact') + '' + (hostedViewOnly
- ? 'Include the account, workspace, and the lifecycle or access change that still needs an owner or admin.'
- : 'Include the account, workspace, and failed action so support inherits the same request.') + '
' + (hostedViewOnly
- ? (showSelfHostedCommercial
- ? 'Use this route only after the relevant billing job has failed, or the affected hosted account still needs an owner or admin to finish hosted billing.'
- : 'Use this route only after the affected hosted account still needs an owner or admin to finish hosted billing and that path still cannot complete cleanly.')
- : (showSelfHostedCommercial
- ? 'Use this route only after hosted billing or one self-hosted billing job has failed to complete cleanly.'
- : 'Use this route only after hosted billing has failed to complete cleanly.')) + '
Name the billing job' + (hostedViewOnly
- ? (showSelfHostedCommercial
- ? 'Say whether the failed path was hosted billing, licenses, refunds, or privacy, and whether hosted billing still needed an owner or admin.'
- : 'Say whether the failed path was hosted billing and whether the account still needed an owner or admin to open it.')
- : (showSelfHostedCommercial
- ? 'Say whether the failed path was hosted billing, licenses, refunds, or privacy.'
- : 'Say whether the failed path was hosted billing.')) + '
' +
- '
Keep the request intact' + (hostedViewOnly
- ? (showSelfHostedCommercial
- ? 'Bring the same account or billing email and the failed owner/admin or billing step instead of reopening the story.'
- : 'Bring the same hosted account and the failed billing or owner/admin step instead of reopening the story.')
- : (showSelfHostedCommercial
- ? 'Bring the same account or billing email and the failed action instead of reopening the story.'
- : 'Bring the same hosted account and the failed billing action instead of reopening the story.')) + '
1. Failed path' + (hostedViewOnly
- ? (showSelfHostedCommercial
- ? 'Say whether the blocked path was Workspaces review, Access review, owner/admin hosted change, hosted billing, licenses, refunds, or privacy.'
- : 'Say whether the blocked path was Workspaces review, Access review, owner/admin hosted change, or hosted billing.')
- : (showSelfHostedCommercial
- ? 'Say whether the blocked path was Workspaces, Access, hosted billing, licenses, refunds, or privacy.'
- : 'Say whether the blocked path was Workspaces, Access, or hosted billing.')) + '
' +
- '
2. Account or email' + (hostedViewOnly
- ? (showSelfHostedCommercial
- ? 'Include the hosted account and workspace for the blocked review or owner/admin path, or the commercial billing email for self-hosted work.'
- : 'Include the hosted account and workspace or hosted billing account that still needed owner/admin action.')
- : (showSelfHostedCommercial
- ? 'Include the hosted account and workspace when relevant, or the commercial billing email for self-hosted work.'
- : 'Include the hosted account and workspace or hosted billing account that the failed path belongs to.')) + '