perf(startup): lazy load dashboard runtime surfaces
This commit is contained in:
parent
f8b96d12d3
commit
08725c4e33
2 changed files with 197 additions and 85 deletions
|
|
@ -7,7 +7,7 @@
|
||||||
* Only rendered in Electron mode.
|
* Only rendered in Electron mode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { lazy, Suspense, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CODEX_ACCOUNT_STARTUP_IDLE_DELAY_MS,
|
CODEX_ACCOUNT_STARTUP_IDLE_DELAY_MS,
|
||||||
|
|
@ -35,13 +35,10 @@ import {
|
||||||
} from '@renderer/components/runtime/providerConnectionUi';
|
} from '@renderer/components/runtime/providerConnectionUi';
|
||||||
import { ProviderModelBadges } from '@renderer/components/runtime/ProviderModelBadges';
|
import { ProviderModelBadges } from '@renderer/components/runtime/ProviderModelBadges';
|
||||||
import { getProviderRuntimeBackendSummary } from '@renderer/components/runtime/ProviderRuntimeBackendSelector';
|
import { getProviderRuntimeBackendSummary } from '@renderer/components/runtime/ProviderRuntimeBackendSelector';
|
||||||
import { ProviderRuntimeSettingsDialog } from '@renderer/components/runtime/ProviderRuntimeSettingsDialog';
|
|
||||||
import {
|
import {
|
||||||
getProviderTerminalCommand,
|
getProviderTerminalCommand,
|
||||||
getProviderTerminalLogoutCommand,
|
getProviderTerminalLogoutCommand,
|
||||||
} from '@renderer/components/runtime/providerTerminalCommands';
|
} from '@renderer/components/runtime/providerTerminalCommands';
|
||||||
import { TerminalLogPanel } from '@renderer/components/terminal/TerminalLogPanel';
|
|
||||||
import { TerminalModal } from '@renderer/components/terminal/TerminalModal';
|
|
||||||
import { useCliInstaller } from '@renderer/hooks/useCliInstaller';
|
import { useCliInstaller } from '@renderer/hooks/useCliInstaller';
|
||||||
import {
|
import {
|
||||||
loadDashboardCliStatusBannerCollapsed,
|
loadDashboardCliStatusBannerCollapsed,
|
||||||
|
|
@ -113,6 +110,22 @@ const ATLAS_CLOUD_CODING_PLAN_URL = 'https://www.atlascloud.ai/console/coding-pl
|
||||||
const ATLAS_CLOUD_DESCRIPTION =
|
const ATLAS_CLOUD_DESCRIPTION =
|
||||||
"Atlas Cloud is a full-modal AI inference platform that gives developers a single AI API to access video generation, image generation, and LLM APIs. Instead of managing multiple vendor integrations, you connect once and get unified access to 300+ curated models across all modalities. Check out Atlas Cloud's new coding plan promotion for more budget-friendly API access.";
|
"Atlas Cloud is a full-modal AI inference platform that gives developers a single AI API to access video generation, image generation, and LLM APIs. Instead of managing multiple vendor integrations, you connect once and get unified access to 300+ curated models across all modalities. Check out Atlas Cloud's new coding plan promotion for more budget-friendly API access.";
|
||||||
|
|
||||||
|
const ProviderRuntimeSettingsDialog = lazy(() =>
|
||||||
|
import('@renderer/components/runtime/ProviderRuntimeSettingsDialog').then((module) => ({
|
||||||
|
default: module.ProviderRuntimeSettingsDialog,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
const TerminalLogPanel = lazy(() =>
|
||||||
|
import('@renderer/components/terminal/TerminalLogPanel').then((module) => ({
|
||||||
|
default: module.TerminalLogPanel,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
const TerminalModal = lazy(() =>
|
||||||
|
import('@renderer/components/terminal/TerminalModal').then((module) => ({
|
||||||
|
default: module.TerminalModal,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
const DashboardRateLimitChips = ({
|
const DashboardRateLimitChips = ({
|
||||||
providerId,
|
providerId,
|
||||||
items,
|
items,
|
||||||
|
|
@ -1655,50 +1668,58 @@ export const CliStatusBanner = (): React.JSX.Element | null => {
|
||||||
const installedAuxiliaryUi =
|
const installedAuxiliaryUi =
|
||||||
renderCliStatus !== null ? (
|
renderCliStatus !== null ? (
|
||||||
<>
|
<>
|
||||||
<ProviderRuntimeSettingsDialog
|
{manageDialogOpen && (
|
||||||
open={manageDialogOpen}
|
<Suspense fallback={null}>
|
||||||
onOpenChange={handleManageDialogOpenChange}
|
<ProviderRuntimeSettingsDialog
|
||||||
providers={visibleCliProviders}
|
open={manageDialogOpen}
|
||||||
projectPath={selectedProjectPath}
|
onOpenChange={handleManageDialogOpenChange}
|
||||||
initialProviderId={
|
providers={visibleCliProviders}
|
||||||
visibleCliProviders.some((provider) => provider.providerId === manageProviderId)
|
projectPath={selectedProjectPath}
|
||||||
? manageProviderId
|
initialProviderId={
|
||||||
: (visibleCliProviders[0]?.providerId ?? 'anthropic')
|
visibleCliProviders.some((provider) => provider.providerId === manageProviderId)
|
||||||
}
|
? manageProviderId
|
||||||
initialRuntimeProviderId={manageRuntimeProviderId}
|
: (visibleCliProviders[0]?.providerId ?? 'anthropic')
|
||||||
initialRuntimeProviderAction={manageRuntimeProviderId ? 'connect' : null}
|
}
|
||||||
providerStatusLoading={cliProviderStatusLoading}
|
initialRuntimeProviderId={manageRuntimeProviderId}
|
||||||
disabled={isBusy || cliStatusLoading || !renderCliStatus.binaryPath}
|
initialRuntimeProviderAction={manageRuntimeProviderId ? 'connect' : null}
|
||||||
codexRuntimeStatus={codexRuntimeStatus}
|
providerStatusLoading={cliProviderStatusLoading}
|
||||||
codexRuntimeStatusLoading={codexRuntimeStatusLoading}
|
disabled={isBusy || cliStatusLoading || !renderCliStatus.binaryPath}
|
||||||
onInstallCodexRuntime={() => installCodexRuntime()}
|
codexRuntimeStatus={codexRuntimeStatus}
|
||||||
onSelectBackend={handleProviderBackendChange}
|
codexRuntimeStatusLoading={codexRuntimeStatusLoading}
|
||||||
onRefreshProvider={handleProviderRefresh}
|
onInstallCodexRuntime={() => installCodexRuntime()}
|
||||||
onRequestLogin={(providerId) => setProviderTerminal({ providerId, action: 'login' })}
|
onSelectBackend={handleProviderBackendChange}
|
||||||
/>
|
onRefreshProvider={handleProviderRefresh}
|
||||||
|
onRequestLogin={(providerId) => setProviderTerminal({ providerId, action: 'login' })}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
{providerTerminal && renderCliStatus.binaryPath && (
|
{providerTerminal && renderCliStatus.binaryPath && (
|
||||||
<TerminalModal
|
<Suspense fallback={null}>
|
||||||
title={`${getHumanRuntimeDisplayName(renderCliStatus, multimodelEnabled)} ${
|
<TerminalModal
|
||||||
providerTerminal.action === 'login' ? 'Login' : 'Logout'
|
title={`${getHumanRuntimeDisplayName(renderCliStatus, multimodelEnabled)} ${
|
||||||
}: ${getProviderLabel(providerTerminal.providerId)}`}
|
providerTerminal.action === 'login' ? 'Login' : 'Logout'
|
||||||
command={renderCliStatus.binaryPath}
|
}: ${getProviderLabel(providerTerminal.providerId)}`}
|
||||||
args={providerTerminalCommand?.args}
|
command={renderCliStatus.binaryPath}
|
||||||
env={providerTerminalCommand?.env}
|
args={providerTerminalCommand?.args}
|
||||||
onClose={() => {
|
env={providerTerminalCommand?.env}
|
||||||
setProviderTerminal(null);
|
onClose={() => {
|
||||||
recheckAuthState();
|
setProviderTerminal(null);
|
||||||
}}
|
recheckAuthState();
|
||||||
onExit={() => {
|
}}
|
||||||
recheckAuthState();
|
onExit={() => {
|
||||||
}}
|
recheckAuthState();
|
||||||
autoCloseOnSuccessMs={3000}
|
}}
|
||||||
successMessage={
|
autoCloseOnSuccessMs={3000}
|
||||||
providerTerminal.action === 'login' ? 'Authentication updated' : 'Provider logged out'
|
successMessage={
|
||||||
}
|
providerTerminal.action === 'login'
|
||||||
failureMessage={
|
? 'Authentication updated'
|
||||||
providerTerminal.action === 'login' ? 'Authentication failed' : 'Logout failed'
|
: 'Provider logged out'
|
||||||
}
|
}
|
||||||
/>
|
failureMessage={
|
||||||
|
providerTerminal.action === 'login' ? 'Authentication failed' : 'Logout failed'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
@ -1877,7 +1898,9 @@ export const CliStatusBanner = (): React.JSX.Element | null => {
|
||||||
Installing {runtimeDisplayName}...
|
Installing {runtimeDisplayName}...
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<TerminalLogPanel chunks={installerRawChunks} />
|
<Suspense fallback={null}>
|
||||||
|
<TerminalLogPanel chunks={installerRawChunks} />
|
||||||
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -2250,45 +2273,47 @@ export const CliStatusBanner = (): React.JSX.Element | null => {
|
||||||
</div>
|
</div>
|
||||||
{installedAuxiliaryUi}
|
{installedAuxiliaryUi}
|
||||||
{showLoginTerminal && renderCliStatus.binaryPath && (
|
{showLoginTerminal && renderCliStatus.binaryPath && (
|
||||||
<TerminalModal
|
<Suspense fallback={null}>
|
||||||
title={`${getHumanRuntimeDisplayName(renderCliStatus, multimodelEnabled)} Login`}
|
<TerminalModal
|
||||||
command={renderCliStatus.binaryPath}
|
title={`${getHumanRuntimeDisplayName(renderCliStatus, multimodelEnabled)} Login`}
|
||||||
args={['auth', 'login']}
|
command={renderCliStatus.binaryPath}
|
||||||
onClose={() => {
|
args={['auth', 'login']}
|
||||||
setShowLoginTerminal(false);
|
onClose={() => {
|
||||||
setIsVerifyingAuth(true);
|
setShowLoginTerminal(false);
|
||||||
void (async () => {
|
setIsVerifyingAuth(true);
|
||||||
try {
|
void (async () => {
|
||||||
await invalidateCliStatus();
|
try {
|
||||||
if (multimodelEnabled) {
|
await invalidateCliStatus();
|
||||||
await bootstrapCliStatus({ multimodelEnabled: true });
|
if (multimodelEnabled) {
|
||||||
} else {
|
await bootstrapCliStatus({ multimodelEnabled: true });
|
||||||
await fetchCliStatus();
|
} else {
|
||||||
|
await fetchCliStatus();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setIsVerifyingAuth(false);
|
||||||
}
|
}
|
||||||
} finally {
|
})();
|
||||||
setIsVerifyingAuth(false);
|
}}
|
||||||
}
|
onExit={() => {
|
||||||
})();
|
setIsVerifyingAuth(true);
|
||||||
}}
|
void (async () => {
|
||||||
onExit={() => {
|
try {
|
||||||
setIsVerifyingAuth(true);
|
await invalidateCliStatus();
|
||||||
void (async () => {
|
if (multimodelEnabled) {
|
||||||
try {
|
await bootstrapCliStatus({ multimodelEnabled: true });
|
||||||
await invalidateCliStatus();
|
} else {
|
||||||
if (multimodelEnabled) {
|
await fetchCliStatus();
|
||||||
await bootstrapCliStatus({ multimodelEnabled: true });
|
}
|
||||||
} else {
|
} finally {
|
||||||
await fetchCliStatus();
|
setIsVerifyingAuth(false);
|
||||||
}
|
}
|
||||||
} finally {
|
})();
|
||||||
setIsVerifyingAuth(false);
|
}}
|
||||||
}
|
autoCloseOnSuccessMs={4000}
|
||||||
})();
|
successMessage="Login complete"
|
||||||
}}
|
failureMessage="Login failed"
|
||||||
autoCloseOnSuccessMs={4000}
|
/>
|
||||||
successMessage="Login complete"
|
</Suspense>
|
||||||
failureMessage="Login failed"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,14 @@ vi.mock('@renderer/store', () => {
|
||||||
import { CliStatusBanner } from '@renderer/components/dashboard/CliStatusBanner';
|
import { CliStatusBanner } from '@renderer/components/dashboard/CliStatusBanner';
|
||||||
import { CliStatusSection } from '@renderer/components/settings/sections/CliStatusSection';
|
import { CliStatusSection } from '@renderer/components/settings/sections/CliStatusSection';
|
||||||
|
|
||||||
|
async function flushLazyImports(): Promise<void> {
|
||||||
|
await Promise.resolve();
|
||||||
|
await Promise.resolve();
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
setTimeout(resolve, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function createInstalledCliStatus(
|
function createInstalledCliStatus(
|
||||||
overrides?: Partial<Record<string, unknown>>
|
overrides?: Partial<Record<string, unknown>>
|
||||||
): Record<string, unknown> {
|
): Record<string, unknown> {
|
||||||
|
|
@ -450,6 +458,63 @@ describe('CLI status visibility during completed install state', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps the dashboard terminal modal unmounted until login is requested', 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 flushLazyImports();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(host.querySelector('[data-testid="terminal-modal"]')).toBeNull();
|
||||||
|
|
||||||
|
const loginButton = Array.from(host.querySelectorAll('button')).find(
|
||||||
|
(button) => button.textContent?.trim() === 'Login'
|
||||||
|
);
|
||||||
|
expect(loginButton).not.toBeUndefined();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
loginButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||||
|
await flushLazyImports();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(host.querySelector('[data-testid="terminal-modal"]')).not.toBeNull();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
root.unmount();
|
||||||
|
await flushLazyImports();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads the installer terminal log only while installation is active', async () => {
|
||||||
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
||||||
|
storeState.cliInstallerState = 'installing';
|
||||||
|
storeState.cliInstallerRawChunks = ['installing...\n'];
|
||||||
|
|
||||||
|
const host = document.createElement('div');
|
||||||
|
document.body.appendChild(host);
|
||||||
|
const root = createRoot(host);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
root.render(React.createElement(CliStatusBanner));
|
||||||
|
await flushLazyImports();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(host.textContent).toContain('terminal-log');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
root.unmount();
|
||||||
|
await flushLazyImports();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('shows an OpenCode install action on the dashboard when the OpenCode CLI is missing', async () => {
|
it('shows an OpenCode install action on the dashboard when the OpenCode CLI is missing', async () => {
|
||||||
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
||||||
storeState.cliInstallerState = 'idle';
|
storeState.cliInstallerState = 'idle';
|
||||||
|
|
@ -1089,6 +1154,15 @@ describe('CLI status visibility during completed install state', () => {
|
||||||
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
|
||||||
storeState.cliInstallerState = 'idle';
|
storeState.cliInstallerState = 'idle';
|
||||||
storeState.fetchCliProviderStatus = vi.fn(() => Promise.reject(new Error('refresh failed')));
|
storeState.fetchCliProviderStatus = vi.fn(() => Promise.reject(new Error('refresh failed')));
|
||||||
|
storeState.cliStatus = createInstalledCliStatus({
|
||||||
|
flavor: 'agent_teams_orchestrator',
|
||||||
|
displayName: 'Multimodel runtime',
|
||||||
|
supportsSelfUpdate: false,
|
||||||
|
showVersionDetails: false,
|
||||||
|
showBinaryPath: false,
|
||||||
|
authLoggedIn: true,
|
||||||
|
providers: [createCodexNativeRolloutProvider()],
|
||||||
|
});
|
||||||
|
|
||||||
const host = document.createElement('div');
|
const host = document.createElement('div');
|
||||||
document.body.appendChild(host);
|
document.body.appendChild(host);
|
||||||
|
|
@ -1099,6 +1173,19 @@ describe('CLI status visibility during completed install state', () => {
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(providerRuntimeSettingsDialogProps).toBeNull();
|
||||||
|
|
||||||
|
const manageButton = Array.from(host.querySelectorAll('button')).find(
|
||||||
|
(button) => button.textContent?.trim() === 'Manage'
|
||||||
|
);
|
||||||
|
expect(manageButton).not.toBeUndefined();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
manageButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
||||||
|
await Promise.resolve();
|
||||||
|
await Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
const onSelectBackend = providerRuntimeSettingsDialogProps?.onSelectBackend;
|
const onSelectBackend = providerRuntimeSettingsDialogProps?.onSelectBackend;
|
||||||
expect(onSelectBackend).toBeTypeOf('function');
|
expect(onSelectBackend).toBeTypeOf('function');
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue