mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-11 14:00:29 +00:00
Make portal support copy concise and literal
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"source_hash": "efabad85565864017562509ae60da3b064b5d2dd20585cd8490be6d5f93452b7",
|
||||
"source_hash": "8b83790627c0212a6ef4ba62079f11e11236c4f806f391908614e1b17eb7fcba",
|
||||
"build_inputs": [
|
||||
"package.json",
|
||||
"tsconfig.json",
|
||||
|
||||
+60
-3
File diff suppressed because one or more lines are too long
@@ -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');
|
||||
|
||||
@@ -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
|
||||
? (
|
||||
'<div class="portal-support-route-card">' +
|
||||
'<div class="account-panel-kicker">Hosted workspace or access</div>' +
|
||||
'<h3>' + (hostedViewOnly ? 'Hosted review or owner/admin path failed' : 'Workspace or access path failed') + '</h3>' +
|
||||
'<p>' + (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.') + '</p>' +
|
||||
'<div class="account-panel-kicker">Workspaces or Access</div>' +
|
||||
'<h3>' + hostedSupportRouteTitle(hostedViewOnly) + '</h3>' +
|
||||
'<p>' + hostedSupportRouteDescription(hostedViewOnly) + '</p>' +
|
||||
'<div class="portal-support-points">' +
|
||||
'<div class="portal-support-point"><strong>' + (hostedViewOnly ? 'Review the same task' : 'Start from the same task') + '</strong><span>' + (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.') + '</span></div>' +
|
||||
'<div class="portal-support-point"><strong>' + (hostedViewOnly ? 'Name the blocked owner/admin action' : 'Keep the hosted context intact') + '</strong><span>' + (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.') + '</span></div>' +
|
||||
'<div class="portal-support-point"><strong>Task</strong><span>' + hostedSupportRouteTaskCopy(hostedViewOnly) + '</span></div>' +
|
||||
'<div class="portal-support-point"><strong>' + hostedSupportRouteContextLabel(hostedViewOnly) + '</strong><span>' + hostedSupportRouteContextCopy(hostedViewOnly) + '</span></div>' +
|
||||
'</div>' +
|
||||
'<div class="portal-support-actions">' +
|
||||
'<button type="button" class="btn-secondary btn-compact" data-shell-action="activate-section" data-shell-section="workspaces">Open Workspaces</button>' +
|
||||
@@ -1271,31 +1352,11 @@ function renderSupportSection(context: ShellViewContext): string {
|
||||
'</div>' +
|
||||
'<div class="portal-support-route-card">' +
|
||||
'<div class="account-panel-kicker">' + (showSelfHostedCommercial ? 'Billing' : 'Hosted billing') + '</div>' +
|
||||
'<h3>' + (hostedViewOnly
|
||||
? (showSelfHostedCommercial ? 'Billing or owner/admin path failed' : 'Hosted billing or owner/admin path failed')
|
||||
: (showSelfHostedCommercial ? 'Billing path failed' : 'Hosted billing path failed')) + '</h3>' +
|
||||
'<p>' + (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.')) + '</p>' +
|
||||
'<h3>' + billingSupportRouteTitle(hostedViewOnly, showSelfHostedCommercial) + '</h3>' +
|
||||
'<p>' + billingSupportRouteDescription(hostedViewOnly, showSelfHostedCommercial) + '</p>' +
|
||||
'<div class="portal-support-points">' +
|
||||
'<div class="portal-support-point"><strong>Name the billing job</strong><span>' + (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.')) + '</span></div>' +
|
||||
'<div class="portal-support-point"><strong>Keep the request intact</strong><span>' + (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.')) + '</span></div>' +
|
||||
'<div class="portal-support-point"><strong>Billing job</strong><span>' + billingSupportRouteJobCopy(hostedViewOnly, showSelfHostedCommercial) + '</span></div>' +
|
||||
'<div class="portal-support-point"><strong>Account or email</strong><span>' + billingSupportRouteAccountCopy(hostedViewOnly, showSelfHostedCommercial) + '</span></div>' +
|
||||
'</div>' +
|
||||
'<div class="portal-support-actions">' +
|
||||
'<button type="button" class="btn-secondary btn-compact" data-shell-action="activate-section" data-shell-section="billing">Open billing</button>' +
|
||||
@@ -1306,11 +1367,11 @@ function renderSupportSection(context: ShellViewContext): string {
|
||||
: (
|
||||
'<div class="portal-support-route-card">' +
|
||||
'<div class="account-panel-kicker">Self-hosted billing</div>' +
|
||||
'<h3>Self-hosted billing path failed</h3>' +
|
||||
'<p>Use this route only after a self-hosted billing, license, refund, or privacy job has failed to complete cleanly.</p>' +
|
||||
'<h3>Self-hosted billing failed</h3>' +
|
||||
'<p>Escalate only if a self-hosted billing task still fails.</p>' +
|
||||
'<div class="portal-support-points">' +
|
||||
'<div class="portal-support-point"><strong>Name the billing job</strong><span>Say whether the failed path was billing, licenses, refunds, or privacy.</span></div>' +
|
||||
'<div class="portal-support-point"><strong>Keep the purchase context intact</strong><span>Bring the same commercial email and the failed action instead of reopening the story.</span></div>' +
|
||||
'<div class="portal-support-point"><strong>Billing job</strong><span>Billing, licenses, refunds, or privacy.</span></div>' +
|
||||
'<div class="portal-support-point"><strong>Account or email</strong><span>Include the commercial billing email and the failed step.</span></div>' +
|
||||
'</div>' +
|
||||
'<div class="portal-support-actions">' +
|
||||
'<button type="button" class="btn-secondary btn-compact" data-shell-action="activate-section" data-shell-section="billing">Open billing</button>' +
|
||||
@@ -1320,25 +1381,13 @@ function renderSupportSection(context: ShellViewContext): string {
|
||||
);
|
||||
var runbookSteps = hasHostedAccounts
|
||||
? (
|
||||
'<div class="portal-support-runbook-step"><strong>1. Failed path</strong><span>' + (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.')) + '</span></div>' +
|
||||
'<div class="portal-support-runbook-step"><strong>2. Account or email</strong><span>' + (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.')) + '</span></div>' +
|
||||
'<div class="portal-support-runbook-step"><strong>1. Failed path</strong><span>' + supportRunbookPathCopy(hasHostedAccounts, hostedViewOnly, showSelfHostedCommercial) + '</span></div>' +
|
||||
'<div class="portal-support-runbook-step"><strong>2. Account or email</strong><span>' + supportRunbookAccountCopy(hasHostedAccounts, showSelfHostedCommercial) + '</span></div>' +
|
||||
'<div class="portal-support-runbook-step"><strong>3. Failed action</strong><span>Name the exact button, form, or billing step that failed and what happened next.</span></div>'
|
||||
)
|
||||
: (
|
||||
'<div class="portal-support-runbook-step"><strong>1. Billing job</strong><span>Say whether the blocked path was billing, licenses, refunds, or privacy.</span></div>' +
|
||||
'<div class="portal-support-runbook-step"><strong>2. Purchase email</strong><span>Include the commercial billing email used for the self-hosted purchase.</span></div>' +
|
||||
'<div class="portal-support-runbook-step"><strong>1. Billing job</strong><span>' + supportRunbookPathCopy(hasHostedAccounts, hostedViewOnly, showSelfHostedCommercial) + '</span></div>' +
|
||||
'<div class="portal-support-runbook-step"><strong>2. Account or email</strong><span>' + supportRunbookAccountCopy(hasHostedAccounts, showSelfHostedCommercial) + '</span></div>' +
|
||||
'<div class="portal-support-runbook-step"><strong>3. Failed action</strong><span>Name the exact button, form, or billing step that failed and what happened next.</span></div>'
|
||||
);
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user