diff --git a/web/app/components/workflow/store/workflow/skill-editor/dirty-slice.ts b/web/app/components/workflow/store/workflow/skill-editor/dirty-slice.ts index bba7a00622..b01d38f958 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/dirty-slice.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/dirty-slice.ts @@ -1,14 +1,14 @@ import type { StateCreator } from 'zustand' +import type { DirtySliceShape, SkillEditorSliceShape } from './types' -export type DirtySliceShape = { - dirtyContents: Map - setDraftContent: (fileId: string, content: string) => void - clearDraftContent: (fileId: string) => void - isDirty: (fileId: string) => boolean - getDraftContent: (fileId: string) => string | undefined -} +export type { DirtySliceShape } from './types' -export const createDirtySlice: StateCreator = (set, get) => ({ +export const createDirtySlice: StateCreator< + SkillEditorSliceShape, + [], + [], + DirtySliceShape +> = (set, get) => ({ dirtyContents: new Map(), setDraftContent: (fileId: string, content: string) => { diff --git a/web/app/components/workflow/store/workflow/skill-editor/file-operations-menu-slice.ts b/web/app/components/workflow/store/workflow/skill-editor/file-operations-menu-slice.ts index 8b0b5fd15c..1a8e4ff68e 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/file-operations-menu-slice.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/file-operations-menu-slice.ts @@ -1,15 +1,14 @@ import type { StateCreator } from 'zustand' +import type { FileOperationsMenuSliceShape, SkillEditorSliceShape } from './types' -export type FileOperationsMenuSliceShape = { - contextMenu: { - top: number - left: number - nodeId: string - } | null - setContextMenu: (menu: FileOperationsMenuSliceShape['contextMenu']) => void -} +export type { FileOperationsMenuSliceShape } from './types' -export const createFileOperationsMenuSlice: StateCreator = set => ({ +export const createFileOperationsMenuSlice: StateCreator< + SkillEditorSliceShape, + [], + [], + FileOperationsMenuSliceShape +> = set => ({ contextMenu: null, setContextMenu: (contextMenu) => { diff --git a/web/app/components/workflow/store/workflow/skill-editor/file-tree-slice.ts b/web/app/components/workflow/store/workflow/skill-editor/file-tree-slice.ts index 498c2846ab..50ef2e57c5 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/file-tree-slice.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/file-tree-slice.ts @@ -1,17 +1,14 @@ import type { StateCreator } from 'zustand' +import type { FileTreeSliceShape, OpensObject, SkillEditorSliceShape } from './types' -export type OpensObject = Record +export type { FileTreeSliceShape, OpensObject } from './types' -export type FileTreeSliceShape = { - expandedFolderIds: Set - setExpandedFolderIds: (ids: Set) => void - toggleFolder: (folderId: string) => void - revealFile: (ancestorFolderIds: string[]) => void - setExpandedFromOpens: (opens: OpensObject) => void - getOpensObject: () => OpensObject -} - -export const createFileTreeSlice: StateCreator = (set, get) => ({ +export const createFileTreeSlice: StateCreator< + SkillEditorSliceShape, + [], + [], + FileTreeSliceShape +> = (set, get) => ({ expandedFolderIds: new Set(), setExpandedFolderIds: (ids: Set) => { diff --git a/web/app/components/workflow/store/workflow/skill-editor/index.ts b/web/app/components/workflow/store/workflow/skill-editor/index.ts index 10e77aacd1..247e503805 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/index.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/index.ts @@ -1,24 +1,17 @@ import type { StateCreator } from 'zustand' -import type { DirtySliceShape } from './dirty-slice' -import type { FileOperationsMenuSliceShape } from './file-operations-menu-slice' -import type { FileTreeSliceShape } from './file-tree-slice' -import type { MetadataSliceShape } from './metadata-slice' -import type { TabSliceShape } from './tab-slice' +import type { SkillEditorSliceShape } from './types' import { createDirtySlice } from './dirty-slice' import { createFileOperationsMenuSlice } from './file-operations-menu-slice' import { createFileTreeSlice } from './file-tree-slice' import { createMetadataSlice } from './metadata-slice' import { createTabSlice } from './tab-slice' -export type SkillEditorSliceShape - = TabSliceShape - & FileTreeSliceShape - & DirtySliceShape - & MetadataSliceShape - & FileOperationsMenuSliceShape - & { - resetSkillEditor: () => void - } +export type { DirtySliceShape } from './dirty-slice' +export type { FileOperationsMenuSliceShape } from './file-operations-menu-slice' +export type { FileTreeSliceShape } from './file-tree-slice' +export type { MetadataSliceShape } from './metadata-slice' +export type { OpenTabOptions, TabSliceShape } from './tab-slice' +export type { SkillEditorSliceShape } from './types' export const createSkillEditorSlice: StateCreator = (...args) => ({ ...createTabSlice(...args), @@ -35,7 +28,7 @@ export const createSkillEditorSlice: StateCreator = (...a previewTabId: null, expandedFolderIds: new Set(), dirtyContents: new Map(), - fileMetadata: new Map>(), + fileMetadata: new Map>(), dirtyMetadataIds: new Set(), contextMenu: null, }) diff --git a/web/app/components/workflow/store/workflow/skill-editor/metadata-slice.ts b/web/app/components/workflow/store/workflow/skill-editor/metadata-slice.ts index 393ba99091..002809b53e 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/metadata-slice.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/metadata-slice.ts @@ -1,21 +1,18 @@ import type { StateCreator } from 'zustand' +import type { MetadataSliceShape, SkillEditorSliceShape } from './types' -export type MetadataSliceShape = { - fileMetadata: Map> - dirtyMetadataIds: Set - setFileMetadata: (fileId: string, metadata: Record) => void - setDraftMetadata: (fileId: string, metadata: Record) => void - clearDraftMetadata: (fileId: string) => void - clearFileMetadata: (fileId: string) => void - isMetadataDirty: (fileId: string) => boolean - getFileMetadata: (fileId: string) => Record | undefined -} +export type { MetadataSliceShape } from './types' -export const createMetadataSlice: StateCreator = (set, get) => ({ - fileMetadata: new Map>(), +export const createMetadataSlice: StateCreator< + SkillEditorSliceShape, + [], + [], + MetadataSliceShape +> = (set, get) => ({ + fileMetadata: new Map>(), dirtyMetadataIds: new Set(), - setFileMetadata: (fileId: string, metadata: Record) => { + setFileMetadata: (fileId: string, metadata: Record) => { const { fileMetadata } = get() const nextMap = new Map(fileMetadata) if (metadata) @@ -25,7 +22,7 @@ export const createMetadataSlice: StateCreator = (set, get) set({ fileMetadata: nextMap }) }, - setDraftMetadata: (fileId: string, metadata: Record) => { + setDraftMetadata: (fileId: string, metadata: Record) => { const { fileMetadata, dirtyMetadataIds } = get() const nextMap = new Map(fileMetadata) nextMap.set(fileId, metadata || {}) diff --git a/web/app/components/workflow/store/workflow/skill-editor/tab-slice.ts b/web/app/components/workflow/store/workflow/skill-editor/tab-slice.ts index 41ce5aba85..80514ad112 100644 --- a/web/app/components/workflow/store/workflow/skill-editor/tab-slice.ts +++ b/web/app/components/workflow/store/workflow/skill-editor/tab-slice.ts @@ -1,30 +1,14 @@ import type { StateCreator } from 'zustand' +import type { OpenTabOptions, SkillEditorSliceShape, TabSliceShape } from './types' -export type OpenTabOptions = { - /** true = Pinned (permanent), false/undefined = Preview (temporary) */ - pinned?: boolean -} +export type { OpenTabOptions, TabSliceShape } from './types' -export type TabSliceShape = { - /** Ordered list of open tab file IDs */ - openTabIds: string[] - /** Currently active tab file ID */ - activeTabId: string | null - /** Current preview tab file ID (at most one) */ - previewTabId: string | null - /** Open a file tab with optional pinned mode */ - openTab: (fileId: string, options?: OpenTabOptions) => void - /** Close a tab */ - closeTab: (fileId: string) => void - /** Activate an existing tab */ - activateTab: (fileId: string) => void - /** Convert preview tab to pinned tab */ - pinTab: (fileId: string) => void - /** Check if a tab is in preview mode */ - isPreviewTab: (fileId: string) => boolean -} - -export const createTabSlice: StateCreator = (set, get) => ({ +export const createTabSlice: StateCreator< + SkillEditorSliceShape, + [], + [], + TabSliceShape +> = (set, get) => ({ openTabIds: [], activeTabId: null, previewTabId: null, @@ -73,9 +57,9 @@ export const createTabSlice: StateCreator = (set, get) => ({ newActiveTabId = null } - const newPreviewTabId = previewTabId === fileId - ? null - : (previewTabId && newOpenTabIds.includes(previewTabId) ? previewTabId : null) + let newPreviewTabId: string | null = null + if (previewTabId !== fileId && previewTabId && newOpenTabIds.includes(previewTabId)) + newPreviewTabId = previewTabId set({ openTabIds: newOpenTabIds, diff --git a/web/app/components/workflow/store/workflow/skill-editor/types.ts b/web/app/components/workflow/store/workflow/skill-editor/types.ts new file mode 100644 index 0000000000..791010fff1 --- /dev/null +++ b/web/app/components/workflow/store/workflow/skill-editor/types.ts @@ -0,0 +1,63 @@ +export type OpenTabOptions = { + pinned?: boolean +} + +export type TabSliceShape = { + openTabIds: string[] + activeTabId: string | null + previewTabId: string | null + openTab: (fileId: string, options?: OpenTabOptions) => void + closeTab: (fileId: string) => void + activateTab: (fileId: string) => void + pinTab: (fileId: string) => void + isPreviewTab: (fileId: string) => boolean +} + +export type OpensObject = Record + +export type FileTreeSliceShape = { + expandedFolderIds: Set + setExpandedFolderIds: (ids: Set) => void + toggleFolder: (folderId: string) => void + revealFile: (ancestorFolderIds: string[]) => void + setExpandedFromOpens: (opens: OpensObject) => void + getOpensObject: () => OpensObject +} + +export type DirtySliceShape = { + dirtyContents: Map + setDraftContent: (fileId: string, content: string) => void + clearDraftContent: (fileId: string) => void + isDirty: (fileId: string) => boolean + getDraftContent: (fileId: string) => string | undefined +} + +export type MetadataSliceShape = { + fileMetadata: Map> + dirtyMetadataIds: Set + setFileMetadata: (fileId: string, metadata: Record) => void + setDraftMetadata: (fileId: string, metadata: Record) => void + clearDraftMetadata: (fileId: string) => void + clearFileMetadata: (fileId: string) => void + isMetadataDirty: (fileId: string) => boolean + getFileMetadata: (fileId: string) => Record | undefined +} + +export type FileOperationsMenuSliceShape = { + contextMenu: { + top: number + left: number + nodeId: string + } | null + setContextMenu: (menu: FileOperationsMenuSliceShape['contextMenu']) => void +} + +export type SkillEditorSliceShape + = TabSliceShape + & FileTreeSliceShape + & DirtySliceShape + & MetadataSliceShape + & FileOperationsMenuSliceShape + & { + resetSkillEditor: () => void + }