Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/chrome/src/ui/install.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<div class="install-copy">
<p id="browser-label" class="eyebrow" aria-live="polite" data-i18n="install.checking">Checking your browser…</p>
<h1 id="install-title" data-i18n="install.installed">WebBrain installed</h1>
<p class="intro" data-i18n="install.open_panel.body">Open WebBrain next to this page to finish setup.</p>
<p id="install-intro" class="intro" aria-live="polite" data-i18n="install.open_panel.body">Open WebBrain next to this page to finish setup.</p>

<button id="open-panel-button" class="open-panel-button" type="button" disabled>
<span id="open-panel-label" data-i18n="install.open_panel">Open Side Panel</span>
Expand Down
19 changes: 18 additions & 1 deletion src/chrome/src/ui/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ export function getBrowserGuide(browserKey) {
return GUIDES[browserKey] || GUIDES.unknown;
}

export function advanceInstallGuide({
guide,
documentLike = globalThis.document,
translate = t,
} = {}) {
const title = documentLike?.getElementById?.('install-title');
const intro = documentLike?.getElementById?.('install-intro');
if (!guide?.nextKey || !title || !intro) return false;

title.dataset.i18n = 'install.pin.title';
intro.dataset.i18n = guide.nextKey;
title.textContent = translate('install.pin.title');
intro.textContent = translate(guide.nextKey);
return true;
}

/**
* Keep the open calls in the click handler's synchronous turn. Both Chrome's
* sidePanel.open() and Firefox's sidebarAction.open() require a user gesture.
Expand Down Expand Up @@ -124,7 +140,8 @@ async function hydrateGuide() {
openButton.classList.remove('is-opening');
openButton.disabled = false;
openButton.removeAttribute('aria-busy');
status.textContent = t(guide.nextKey);
advanceInstallGuide({ guide });
status.textContent = '';
reportInstalledPanelOpened({ build, tabId: installTab?.id }).catch(() => {});
}).catch(() => {
openButton.classList.remove('is-opening');
Expand Down
2 changes: 1 addition & 1 deletion src/firefox/src/ui/install.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<div class="install-copy">
<p id="browser-label" class="eyebrow" aria-live="polite" data-i18n="install.checking">Checking your browser…</p>
<h1 id="install-title" data-i18n="install.installed">WebBrain installed</h1>
<p class="intro" data-i18n="install.open_panel.body">Open WebBrain next to this page to finish setup.</p>
<p id="install-intro" class="intro" aria-live="polite" data-i18n="install.open_panel.body">Open WebBrain next to this page to finish setup.</p>

<button id="open-panel-button" class="open-panel-button" type="button" disabled>
<span id="open-panel-label" data-i18n="install.open_sidebar">Open Sidebar</span>
Expand Down
19 changes: 18 additions & 1 deletion src/firefox/src/ui/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ export function getBrowserGuide(browserKey) {
return GUIDES[browserKey] || GUIDES.unknown;
}

export function advanceInstallGuide({
guide,
documentLike = globalThis.document,
translate = t,
} = {}) {
const title = documentLike?.getElementById?.('install-title');
const intro = documentLike?.getElementById?.('install-intro');
if (!guide?.nextKey || !title || !intro) return false;

title.dataset.i18n = 'install.pin.title';
intro.dataset.i18n = guide.nextKey;
title.textContent = translate('install.pin.title');
intro.textContent = translate(guide.nextKey);
return true;
}

/**
* Keep the open calls in the click handler's synchronous turn. Both Chrome's
* sidePanel.open() and Firefox's sidebarAction.open() require a user gesture.
Expand Down Expand Up @@ -124,7 +140,8 @@ async function hydrateGuide() {
openButton.classList.remove('is-opening');
openButton.disabled = false;
openButton.removeAttribute('aria-busy');
status.textContent = t(guide.nextKey);
advanceInstallGuide({ guide });
status.textContent = '';
reportInstalledPanelOpened({ build, tabId: installTab?.id }).catch(() => {});
}).catch(() => {
openButton.classList.remove('is-opening');
Expand Down
24 changes: 22 additions & 2 deletions test/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -20474,6 +20474,7 @@ test('first install opens a browser-aware panel launcher without fake toolbar co
`${label}: onInstalled should pass install details to the guide gate`,
);
assert.match(html, /id="open-panel-button"/, `${label}: install guide should provide a real panel-open action`);
assert.match(html, /id="install-intro"[^>]*aria-live="polite"/, `${label}: changing install guidance should be announced accessibly`);
assert.match(html, /id="open-panel-button"[^>]*\sdisabled(?:\s|>)/, `${label}: install CTA should start disabled until hydration binds its click handler`);
assert.match(
installJs,
Expand All @@ -20496,8 +20497,8 @@ test('first install opens a browser-aware panel launcher without fake toolbar co
assert.doesNotMatch(installJs, /classList\.(?:add|remove)\('is-open'\)/, `${label}: install logic should not apply the retired success-green state`);
assert.match(
installJs,
/Promise\.resolve\(opening\)\.then\(\(\) => \{[\s\S]*?reportInstalledPanelOpened\(\{ build, tabId: installTab\?\.id \}\)[\s\S]*?\}\)\.catch/,
`${label}: install page should report panel bookkeeping only after a successful open`,
/Promise\.resolve\(opening\)\.then\(\(\) => \{[\s\S]*?advanceInstallGuide\(\{ guide \}\);[\s\S]*?reportInstalledPanelOpened\(\{ build, tabId: installTab\?\.id \}\)[\s\S]*?\}\)\.catch/,
`${label}: a successful panel open should advance the guide before background bookkeeping`,
);

assert.equal(
Expand Down Expand Up @@ -20547,6 +20548,25 @@ test('first install opens a browser-aware panel launcher without fake toolbar co
assert.equal(installModule.getBrowserGuide('vivaldi').nextKey, 'install.pin.next', `${label}: Chromium install pages should preview the pin step without coachmark-only spatial copy`);
assert.equal(installModule.getBrowserGuide('vivaldi').failureKey, 'install.open_failed_chromium', `${label}: Chromium browsers should receive shortcut and Extensions-menu recovery`);

const guideCopy = {
'install.pin.title': 'Pin WebBrain',
[installModule.getBrowserGuide(label === 'firefox' ? 'firefox' : 'chrome').nextKey]: 'Browser-specific next step',
};
const guideNodes = {
'install-title': { dataset: { i18n: 'install.installed' }, textContent: 'WebBrain installed' },
'install-intro': { dataset: { i18n: 'install.open_panel.body' }, textContent: 'Open WebBrain' },
};
const guideAdvanced = installModule.advanceInstallGuide({
guide: installModule.getBrowserGuide(label === 'firefox' ? 'firefox' : 'chrome'),
documentLike: { getElementById: (id) => guideNodes[id] || null },
translate: (key) => guideCopy[key],
});
assert.equal(guideAdvanced, true, `${label}: successful open should advance the install guide`);
assert.equal(guideNodes['install-title'].textContent, 'Pin WebBrain', `${label}: successful open should replace the stale installed heading`);
assert.equal(guideNodes['install-intro'].textContent, 'Browser-specific next step', `${label}: successful open should show native next-step guidance`);
assert.equal(guideNodes['install-title'].dataset.i18n, 'install.pin.title', `${label}: locale refresh should preserve the advanced heading`);
assert.equal(guideNodes['install-intro'].dataset.i18n, installModule.getBrowserGuide(label === 'firefox' ? 'firefox' : 'chrome').nextKey, `${label}: locale refresh should preserve the browser-specific guidance`);

const calls = [];
const messages = [];
if (label === 'chrome') {
Expand Down
Loading