123 lines
3.5 KiB
TypeScript
123 lines
3.5 KiB
TypeScript
import {
|
|
clearWorkspaceArchivePending,
|
|
markWorkspaceArchivePending,
|
|
} from "@/contexts/session-workspace-upserts";
|
|
import { useSessionStore, type WorkspaceDescriptor } from "@/stores/session-store";
|
|
import { resolveWorkspaceMapKeyByIdentity } from "@/utils/workspace-execution";
|
|
|
|
export interface WorkspaceArchiveTarget {
|
|
serverId: string;
|
|
workspaceId: string;
|
|
workspaceDirectory?: string | null;
|
|
}
|
|
|
|
interface WorkspaceArchiveClient {
|
|
archiveWorkspace: (workspaceId: string) => Promise<{ error: string | null }>;
|
|
}
|
|
|
|
interface OptimisticWorkspaceArchiveSnapshot {
|
|
workspace: WorkspaceDescriptor | null;
|
|
}
|
|
|
|
export interface WorkspaceArchiveFailure {
|
|
workspaceId: string;
|
|
error: unknown;
|
|
}
|
|
|
|
function isWorkspaceArchiveFailure(error: unknown): error is WorkspaceArchiveFailure {
|
|
return (
|
|
typeof error === "object" &&
|
|
error !== null &&
|
|
"workspaceId" in error &&
|
|
typeof error.workspaceId === "string" &&
|
|
"error" in error
|
|
);
|
|
}
|
|
|
|
function hideWorkspaceOptimistically(
|
|
workspace: WorkspaceArchiveTarget,
|
|
): OptimisticWorkspaceArchiveSnapshot {
|
|
const workspaces = useSessionStore.getState().sessions[workspace.serverId]?.workspaces;
|
|
const workspaceKey = resolveWorkspaceMapKeyByIdentity({
|
|
workspaces,
|
|
workspaceId: workspace.workspaceId,
|
|
});
|
|
const snapshot = workspaceKey ? (workspaces?.get(workspaceKey) ?? null) : null;
|
|
markWorkspaceArchivePending({
|
|
serverId: workspace.serverId,
|
|
workspaceId: workspace.workspaceId,
|
|
workspaceDirectory: workspace.workspaceDirectory,
|
|
});
|
|
useSessionStore.getState().removeWorkspace(workspace.serverId, workspace.workspaceId);
|
|
return { workspace: snapshot };
|
|
}
|
|
|
|
function restoreOptimisticallyHiddenWorkspace(input: {
|
|
serverId: string;
|
|
workspaceId: string;
|
|
snapshot: OptimisticWorkspaceArchiveSnapshot;
|
|
}): void {
|
|
clearWorkspaceArchivePending({
|
|
serverId: input.serverId,
|
|
workspaceId: input.workspaceId,
|
|
});
|
|
if (input.snapshot.workspace) {
|
|
useSessionStore.getState().mergeWorkspaces(input.serverId, [input.snapshot.workspace]);
|
|
}
|
|
}
|
|
|
|
async function archiveWorkspaceOrThrow(input: {
|
|
client: WorkspaceArchiveClient;
|
|
workspaceId: string;
|
|
}): Promise<void> {
|
|
const payload = await input.client.archiveWorkspace(input.workspaceId);
|
|
if (payload.error) {
|
|
throw new Error(payload.error);
|
|
}
|
|
}
|
|
|
|
export async function archiveWorkspaceOptimistically(input: {
|
|
client: WorkspaceArchiveClient;
|
|
workspace: WorkspaceArchiveTarget;
|
|
afterHide?: () => void;
|
|
}): Promise<void> {
|
|
const snapshot = hideWorkspaceOptimistically(input.workspace);
|
|
input.afterHide?.();
|
|
|
|
try {
|
|
await archiveWorkspaceOrThrow({
|
|
client: input.client,
|
|
workspaceId: input.workspace.workspaceId,
|
|
});
|
|
} catch (error) {
|
|
restoreOptimisticallyHiddenWorkspace({
|
|
serverId: input.workspace.serverId,
|
|
workspaceId: input.workspace.workspaceId,
|
|
snapshot,
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function archiveWorkspacesOptimistically(input: {
|
|
client: WorkspaceArchiveClient;
|
|
workspaces: WorkspaceArchiveTarget[];
|
|
}): Promise<WorkspaceArchiveFailure[]> {
|
|
const results = await Promise.allSettled(
|
|
input.workspaces.map(async (workspace) => {
|
|
try {
|
|
await archiveWorkspaceOptimistically({
|
|
client: input.client,
|
|
workspace,
|
|
});
|
|
} catch (error) {
|
|
throw { workspaceId: workspace.workspaceId, error } satisfies WorkspaceArchiveFailure;
|
|
}
|
|
}),
|
|
);
|
|
|
|
return results.flatMap((result) =>
|
|
result.status === "rejected" && isWorkspaceArchiveFailure(result.reason) ? [result.reason] : [],
|
|
);
|
|
}
|