fix(extensions): keep extensions entry points available before auth

This commit is contained in:
777genius 2026-04-17 20:24:45 +03:00
parent 7b16cfe73b
commit 1ee139b66a
3 changed files with 50 additions and 5 deletions

View file

@ -387,6 +387,7 @@ const InstalledBanner = ({
() => filterMainScreenCliProviders(cliStatus.providers),
[cliStatus.providers]
);
const canOpenExtensions = cliStatus.installed;
const runtimeLabel = formatRuntimeLabel(cliStatus);
const runtimeAuthSummary = formatRuntimeAuthSummary(cliStatus, visibleProviders);
@ -471,8 +472,8 @@ const InstalledBanner = ({
disabled={isBusy || cliStatusLoading || multimodelBusy}
/>
</div>
{/* Extensions button — only when installed + authenticated */}
{cliStatus.authLoggedIn && (
{/* Extensions button — available whenever the runtime is installed */}
{canOpenExtensions && (
<button
onClick={openExtensionsTab}
className="flex shrink-0 items-center gap-1.5 rounded-md border px-3 py-1.5 text-xs font-medium transition-colors hover:bg-white/5"

View file

@ -163,6 +163,7 @@ export const CliStatusSection = (): React.JSX.Element | null => {
!cliStatus && cliStatusLoading && multimodelEnabled
? createLoadingMultimodelCliStatus()
: cliStatus;
const canOpenExtensions = effectiveCliStatus?.installed === true;
const showInstalledControls =
effectiveCliStatus !== null && (installerState === 'idle' || installerState === 'completed');
@ -396,7 +397,7 @@ export const CliStatusSection = (): React.JSX.Element | null => {
</button>
) : null}
{/* Extensions button — right-aligned */}
{effectiveCliStatus.authLoggedIn && (
{canOpenExtensions && (
<button
type="button"
onClick={openExtensionsTab}

View file

@ -283,6 +283,39 @@ describe('CLI status visibility during completed install state', () => {
});
});
it('keeps the dashboard Extensions button visible before authentication completes', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
storeState.cliStatus = createInstalledCliStatus({
authLoggedIn: false,
});
const host = document.createElement('div');
document.body.appendChild(host);
const root = createRoot(host);
await act(async () => {
root.render(React.createElement(CliStatusBanner));
await Promise.resolve();
});
const extensionsButton = Array.from(host.querySelectorAll('button')).find((button) =>
button.textContent?.includes('Extensions')
);
expect(extensionsButton).not.toBeNull();
await act(async () => {
extensionsButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
await Promise.resolve();
});
expect(storeState.openExtensionsTab).toHaveBeenCalledTimes(1);
await act(async () => {
root.unmount();
await Promise.resolve();
});
});
it('preserves dashboard runtime backend refresh errors for the manage dialog', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
storeState.cliInstallerState = 'idle';
@ -483,7 +516,7 @@ describe('CLI status visibility during completed install state', () => {
});
});
it('hides the settings Extensions button when the runtime is not authenticated yet', async () => {
it('keeps the settings Extensions button visible when the runtime is installed but not authenticated yet', async () => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
storeState.cliStatus = createInstalledCliStatus({
authLoggedIn: false,
@ -498,7 +531,17 @@ describe('CLI status visibility during completed install state', () => {
await Promise.resolve();
});
expect(host.textContent).not.toContain('Extensions');
const extensionsButton = Array.from(host.querySelectorAll('button')).find((button) =>
button.textContent?.includes('Extensions')
);
expect(extensionsButton).not.toBeNull();
await act(async () => {
extensionsButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
await Promise.resolve();
});
expect(storeState.openExtensionsTab).toHaveBeenCalledTimes(1);
await act(async () => {
root.unmount();