* feat(files): edit workspace files on web Keep source buffers synchronized with host file changes and require an explicit overwrite or reload when revisions diverge. * feat(panels): surface and protect modified tabs Expose tooltip and modification state through the generic panel boundary so tabs can show stable metadata and guard every close route consistently. * fix(tests): use portable fake timeout handle * fix(files): harden editor conflict handling Preserve modified panel state across tab eviction, use precise revisions for optimistic writes, coalesce concurrent file watchers, and localize the editor interface. * fix(files): close editor concurrency gaps Coalesce clean reloads, preserve subscriber identities and file permissions, suspend pending saves during close confirmation, and carry precise revisions through file reads. * test(files): expect read revision metadata
49 lines
1.3 KiB
TypeScript
49 lines
1.3 KiB
TypeScript
import type { ComponentType } from "react";
|
|
import type { WorkspaceTabTarget } from "@/stores/workspace-tabs-store";
|
|
import type { SidebarStateBucket } from "@/utils/sidebar-agent-state";
|
|
|
|
export interface PanelIconProps {
|
|
size: number;
|
|
color: string;
|
|
}
|
|
|
|
export interface PanelDescriptor {
|
|
label: string;
|
|
subtitle: string;
|
|
tooltip: string;
|
|
titleState: "ready" | "loading";
|
|
icon: ComponentType<PanelIconProps>;
|
|
statusBucket: SidebarStateBucket | null;
|
|
}
|
|
|
|
export interface PanelDescriptorContext {
|
|
serverId: string;
|
|
workspaceId: string;
|
|
tabId: string;
|
|
}
|
|
|
|
export interface PanelRegistration<
|
|
K extends WorkspaceTabTarget["kind"] = WorkspaceTabTarget["kind"],
|
|
> {
|
|
kind: K;
|
|
component: ComponentType;
|
|
useDescriptor(
|
|
target: Extract<WorkspaceTabTarget, { kind: K }>,
|
|
context: PanelDescriptorContext,
|
|
): PanelDescriptor;
|
|
}
|
|
|
|
const panelRegistry = new Map<WorkspaceTabTarget["kind"], PanelRegistration>();
|
|
|
|
export function registerPanel<K extends WorkspaceTabTarget["kind"]>(
|
|
registration: PanelRegistration<K>,
|
|
): void {
|
|
panelRegistry.set(registration.kind, registration as unknown as PanelRegistration);
|
|
}
|
|
|
|
export function getPanelRegistration(
|
|
kind: WorkspaceTabTarget["kind"],
|
|
): PanelRegistration | undefined {
|
|
return panelRegistry.get(kind);
|
|
}
|