Files
paseo/packages/app/src/stores/create-flow-store.ts
T
Mohamed BoudraandClaude Opus 4.6 73eabd2eea feat: canonical workspace tab IDs with URL routing and draft agent tabs
Rewrite workspace tab management to use stable tab IDs (agent_, terminal_, draft_, file_) with
dedicated /tab/[tabId] routes, replace separate file-tabs store with unified workspace-tabs store,
support multiple concurrent draft agent tabs, and detect text files by content instead of extension allowlist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 20:11:55 +07:00

97 lines
2.6 KiB
TypeScript

import { create } from "zustand";
import type { UserMessageImageAttachment } from "@/types/stream";
export type CreateFlowLifecycleState = "active" | "abandoned" | "sent";
type PendingCreateAttempt = {
draftId: string;
serverId: string;
agentId: string | null;
clientMessageId: string;
text: string;
timestamp: number;
lifecycle: CreateFlowLifecycleState;
images?: UserMessageImageAttachment[];
};
type CreateFlowState = {
pendingByDraftId: Record<string, PendingCreateAttempt>;
setPending: (
pending: Omit<PendingCreateAttempt, "lifecycle">
) => void;
updateAgentId: (input: { draftId: string; agentId: string }) => void;
markLifecycle: (input: {
draftId: string;
lifecycle: CreateFlowLifecycleState;
}) => void;
rekeyDraft: (input: { fromDraftId: string; toDraftId: string }) => void;
clear: (input: { draftId: string }) => void;
clearAll: () => void;
};
export const useCreateFlowStore = create<CreateFlowState>((set) => ({
pendingByDraftId: {},
setPending: (pending) =>
set((state) => ({
pendingByDraftId: {
...state.pendingByDraftId,
[pending.draftId]: {
...pending,
lifecycle: "active",
},
},
})),
updateAgentId: ({ draftId, agentId }) =>
set((state) => {
const current = state.pendingByDraftId[draftId];
if (!current || current.agentId === agentId) {
return state;
}
return {
pendingByDraftId: {
...state.pendingByDraftId,
[draftId]: { ...current, agentId },
},
};
}),
markLifecycle: ({ draftId, lifecycle }) =>
set((state) => {
const current = state.pendingByDraftId[draftId];
if (!current || current.lifecycle === lifecycle) {
return state;
}
return {
pendingByDraftId: {
...state.pendingByDraftId,
[draftId]: { ...current, lifecycle },
},
};
}),
rekeyDraft: ({ fromDraftId, toDraftId }) =>
set((state) => {
const current = state.pendingByDraftId[fromDraftId];
if (!current) {
return state;
}
if (fromDraftId === toDraftId) {
return state;
}
const { [fromDraftId]: _removed, ...rest } = state.pendingByDraftId;
return {
pendingByDraftId: {
...rest,
[toDraftId]: { ...current, draftId: toDraftId },
},
};
}),
clear: ({ draftId }) =>
set((state) => {
if (!state.pendingByDraftId[draftId]) {
return state;
}
const { [draftId]: _removed, ...rest } = state.pendingByDraftId;
return { pendingByDraftId: rest };
}),
clearAll: () => set({ pendingByDraftId: {} }),
}));