feat(web): make instance overview card-first
This commit is contained in:
+78
-23
@@ -1,7 +1,7 @@
|
||||
import { AuditPage, type AuditDataSource } from './audit/audit-page.js';
|
||||
import { createAuditApiDataSource } from './audit/audit-api-data-source.js';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { useControlPlaneEvents } from './events/use-control-plane-events.js';
|
||||
import { createEventStreamClient, type EventStreamClient } from './events/event-stream-client.js';
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
import { EsimModule, type EsimDataSource } from './instances/esim-module.js';
|
||||
import { OverviewSystemPage, type OverviewDataSource } from './instances/overview-system.js';
|
||||
import { InstanceEditor, type InstanceDataSource } from './instances/instance-crud.js';
|
||||
import { createInstanceApiDataSource } from './instances/instance-api-data-source.js';
|
||||
import { JobsPage, type JobsDataSource } from './jobs/jobs-page.js';
|
||||
import { createJobsApiDataSource } from './jobs/jobs-api-data-source.js';
|
||||
import { MessagesModule, type MessagesDataSource } from './instances/messages-module.js';
|
||||
@@ -198,6 +199,7 @@ function Page({
|
||||
return (
|
||||
<FleetPage
|
||||
{...(fleetDataSource ? { dataSource: fleetDataSource } : {})}
|
||||
{...(instanceDataSource ? { instanceDataSource } : {})}
|
||||
{...(fleetData ? { initialData: fleetData } : {})}
|
||||
refreshSignal={fleetRefreshSignal}
|
||||
/>
|
||||
@@ -407,6 +409,7 @@ export function AppShell({
|
||||
}: AppShellProps) {
|
||||
const defaultEventStreamClient = useMemo(() => createEventStreamClient(), []);
|
||||
const defaultFleetDataSource = useMemo(() => createFleetApiDataSource(), []);
|
||||
const defaultInstanceDataSource = useMemo(() => createInstanceApiDataSource(), []);
|
||||
const resolvedJobsDataSource = useMemo(
|
||||
() => jobsDataSource ?? createJobsApiDataSource(),
|
||||
[jobsDataSource],
|
||||
@@ -418,6 +421,50 @@ export function AppShell({
|
||||
const resolved = resolveRoute(pathname);
|
||||
const route = resolved.kind === 'redirect' ? resolveRoute(resolved.to ?? '/fleet') : resolved;
|
||||
const routeInstanceId = route.params?.instanceId;
|
||||
const resolvedInstanceDataSource = instanceDataSource ?? defaultInstanceDataSource;
|
||||
const [loadedInstance, setLoadedInstance] = useState<InstanceContext>();
|
||||
const [instanceLoading, setInstanceLoading] = useState(false);
|
||||
const [instanceLoadFailed, setInstanceLoadFailed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setLoadedInstance(undefined);
|
||||
setInstanceLoadFailed(false);
|
||||
if (!routeInstanceId || instance?.id === routeInstanceId) {
|
||||
setInstanceLoading(false);
|
||||
return;
|
||||
}
|
||||
let active = true;
|
||||
setInstanceLoading(true);
|
||||
void resolvedInstanceDataSource.get(routeInstanceId).then(
|
||||
(owner) => {
|
||||
if (!active) return;
|
||||
if (owner.id !== routeInstanceId) {
|
||||
setInstanceLoadFailed(true);
|
||||
setInstanceLoading(false);
|
||||
return;
|
||||
}
|
||||
setLoadedInstance({
|
||||
id: owner.id,
|
||||
name: owner.name,
|
||||
origin: owner.origin,
|
||||
status: 'unknown',
|
||||
authentication: 'unknown',
|
||||
freshness: 'unknown',
|
||||
});
|
||||
setInstanceLoading(false);
|
||||
},
|
||||
() => {
|
||||
if (!active) return;
|
||||
setInstanceLoadFailed(true);
|
||||
setInstanceLoading(false);
|
||||
},
|
||||
);
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [instance, resolvedInstanceDataSource, routeInstanceId]);
|
||||
|
||||
const routeInstance = instance?.id === routeInstanceId ? instance : loadedInstance;
|
||||
const refresh = useControlPlaneEvents(
|
||||
routeInstanceId,
|
||||
eventStreamClient ?? defaultEventStreamClient,
|
||||
@@ -455,28 +502,36 @@ export function AppShell({
|
||||
</ul>
|
||||
</nav>
|
||||
<main id="main-content" tabIndex={-1}>
|
||||
<Page
|
||||
route={route}
|
||||
fleetDataSource={fleetDataSource ?? defaultFleetDataSource}
|
||||
fleetData={fleetData}
|
||||
instance={instance}
|
||||
instanceDataSource={instanceDataSource}
|
||||
capabilities={capabilities}
|
||||
capabilityDataSource={capabilityDataSource}
|
||||
overviewDataSource={overviewDataSource}
|
||||
cellularDataSource={cellularDataSource}
|
||||
deviceNetworkDataSource={deviceNetworkDataSource}
|
||||
messagesDataSource={messagesDataSource}
|
||||
callsDataSource={callsDataSource}
|
||||
esimDataSource={esimDataSource}
|
||||
notificationsDataSource={notificationsDataSource}
|
||||
automationDataSource={automationDataSource}
|
||||
otaDataSource={otaDataSource}
|
||||
jobsDataSource={resolvedJobsDataSource}
|
||||
auditDataSource={resolvedAuditDataSource}
|
||||
fleetRefreshSignal={refresh.fleet}
|
||||
detailRefreshSignal={refresh.detail}
|
||||
/>
|
||||
{routeInstanceId && instanceLoading ? (
|
||||
<p role="status">正在加载实例…</p>
|
||||
) : routeInstanceId && instanceLoadFailed ? (
|
||||
<p role="alert" className="state-panel state-error">
|
||||
无法加载此实例,请返回总览后重试。
|
||||
</p>
|
||||
) : (
|
||||
<Page
|
||||
route={route}
|
||||
fleetDataSource={fleetDataSource ?? defaultFleetDataSource}
|
||||
fleetData={fleetData}
|
||||
instance={routeInstance}
|
||||
instanceDataSource={resolvedInstanceDataSource}
|
||||
capabilities={capabilities}
|
||||
capabilityDataSource={capabilityDataSource}
|
||||
overviewDataSource={overviewDataSource}
|
||||
cellularDataSource={cellularDataSource}
|
||||
deviceNetworkDataSource={deviceNetworkDataSource}
|
||||
messagesDataSource={messagesDataSource}
|
||||
callsDataSource={callsDataSource}
|
||||
esimDataSource={esimDataSource}
|
||||
notificationsDataSource={notificationsDataSource}
|
||||
automationDataSource={automationDataSource}
|
||||
otaDataSource={otaDataSource}
|
||||
jobsDataSource={resolvedJobsDataSource}
|
||||
auditDataSource={resolvedAuditDataSource}
|
||||
fleetRefreshSignal={refresh.fleet}
|
||||
detailRefreshSignal={refresh.detail}
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user