mirror of
https://github.com/langgenius/dify.git
synced 2026-01-19 11:45:05 +08:00
Compare commits
2 Commits
c0a76220dd
...
2f081fa6fa
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f081fa6fa | |||
| 3b27d9e819 |
@ -1,14 +1,14 @@
|
||||
import type { StateCreator } from 'zustand'
|
||||
import type { DirtySliceShape, SkillEditorSliceShape } from './types'
|
||||
|
||||
export type DirtySliceShape = {
|
||||
dirtyContents: Map<string, string>
|
||||
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<DirtySliceShape> = (set, get) => ({
|
||||
export const createDirtySlice: StateCreator<
|
||||
SkillEditorSliceShape,
|
||||
[],
|
||||
[],
|
||||
DirtySliceShape
|
||||
> = (set, get) => ({
|
||||
dirtyContents: new Map<string, string>(),
|
||||
|
||||
setDraftContent: (fileId: string, content: string) => {
|
||||
|
||||
@ -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<FileOperationsMenuSliceShape> = set => ({
|
||||
export const createFileOperationsMenuSlice: StateCreator<
|
||||
SkillEditorSliceShape,
|
||||
[],
|
||||
[],
|
||||
FileOperationsMenuSliceShape
|
||||
> = set => ({
|
||||
contextMenu: null,
|
||||
|
||||
setContextMenu: (contextMenu) => {
|
||||
|
||||
@ -1,17 +1,14 @@
|
||||
import type { StateCreator } from 'zustand'
|
||||
import type { FileTreeSliceShape, OpensObject, SkillEditorSliceShape } from './types'
|
||||
|
||||
export type OpensObject = Record<string, boolean>
|
||||
export type { FileTreeSliceShape, OpensObject } from './types'
|
||||
|
||||
export type FileTreeSliceShape = {
|
||||
expandedFolderIds: Set<string>
|
||||
setExpandedFolderIds: (ids: Set<string>) => void
|
||||
toggleFolder: (folderId: string) => void
|
||||
revealFile: (ancestorFolderIds: string[]) => void
|
||||
setExpandedFromOpens: (opens: OpensObject) => void
|
||||
getOpensObject: () => OpensObject
|
||||
}
|
||||
|
||||
export const createFileTreeSlice: StateCreator<FileTreeSliceShape> = (set, get) => ({
|
||||
export const createFileTreeSlice: StateCreator<
|
||||
SkillEditorSliceShape,
|
||||
[],
|
||||
[],
|
||||
FileTreeSliceShape
|
||||
> = (set, get) => ({
|
||||
expandedFolderIds: new Set<string>(),
|
||||
|
||||
setExpandedFolderIds: (ids: Set<string>) => {
|
||||
|
||||
@ -1,52 +1,36 @@
|
||||
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<SkillEditorSliceShape> = (set, get, store) => {
|
||||
// Type assertion via unknown to allow composition with other slices in a larger store
|
||||
// This is safe because all slice creators only use set/get for their own properties
|
||||
const tabArgs = [set, get, store] as unknown as Parameters<StateCreator<TabSliceShape>>
|
||||
const fileTreeArgs = [set, get, store] as unknown as Parameters<StateCreator<FileTreeSliceShape>>
|
||||
const dirtyArgs = [set, get, store] as unknown as Parameters<StateCreator<DirtySliceShape>>
|
||||
const metadataArgs = [set, get, store] as unknown as Parameters<StateCreator<MetadataSliceShape>>
|
||||
const menuArgs = [set, get, store] as unknown as Parameters<StateCreator<FileOperationsMenuSliceShape>>
|
||||
|
||||
return {
|
||||
...createTabSlice(...tabArgs),
|
||||
...createFileTreeSlice(...fileTreeArgs),
|
||||
...createDirtySlice(...dirtyArgs),
|
||||
...createMetadataSlice(...metadataArgs),
|
||||
...createFileOperationsMenuSlice(...menuArgs),
|
||||
export const createSkillEditorSlice: StateCreator<SkillEditorSliceShape> = (...args) => ({
|
||||
...createTabSlice(...args),
|
||||
...createFileTreeSlice(...args),
|
||||
...createDirtySlice(...args),
|
||||
...createMetadataSlice(...args),
|
||||
...createFileOperationsMenuSlice(...args),
|
||||
|
||||
resetSkillEditor: () => {
|
||||
const [set] = args
|
||||
set({
|
||||
openTabIds: [],
|
||||
activeTabId: null,
|
||||
previewTabId: null,
|
||||
expandedFolderIds: new Set<string>(),
|
||||
dirtyContents: new Map<string, string>(),
|
||||
fileMetadata: new Map<string, Record<string, any>>(),
|
||||
fileMetadata: new Map<string, Record<string, unknown>>(),
|
||||
dirtyMetadataIds: new Set<string>(),
|
||||
contextMenu: null,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,21 +1,18 @@
|
||||
import type { StateCreator } from 'zustand'
|
||||
import type { MetadataSliceShape, SkillEditorSliceShape } from './types'
|
||||
|
||||
export type MetadataSliceShape = {
|
||||
fileMetadata: Map<string, Record<string, any>>
|
||||
dirtyMetadataIds: Set<string>
|
||||
setFileMetadata: (fileId: string, metadata: Record<string, any>) => void
|
||||
setDraftMetadata: (fileId: string, metadata: Record<string, any>) => void
|
||||
clearDraftMetadata: (fileId: string) => void
|
||||
clearFileMetadata: (fileId: string) => void
|
||||
isMetadataDirty: (fileId: string) => boolean
|
||||
getFileMetadata: (fileId: string) => Record<string, any> | undefined
|
||||
}
|
||||
export type { MetadataSliceShape } from './types'
|
||||
|
||||
export const createMetadataSlice: StateCreator<MetadataSliceShape> = (set, get) => ({
|
||||
fileMetadata: new Map<string, Record<string, any>>(),
|
||||
export const createMetadataSlice: StateCreator<
|
||||
SkillEditorSliceShape,
|
||||
[],
|
||||
[],
|
||||
MetadataSliceShape
|
||||
> = (set, get) => ({
|
||||
fileMetadata: new Map<string, Record<string, unknown>>(),
|
||||
dirtyMetadataIds: new Set<string>(),
|
||||
|
||||
setFileMetadata: (fileId: string, metadata: Record<string, any>) => {
|
||||
setFileMetadata: (fileId: string, metadata: Record<string, unknown>) => {
|
||||
const { fileMetadata } = get()
|
||||
const nextMap = new Map(fileMetadata)
|
||||
if (metadata)
|
||||
@ -25,7 +22,7 @@ export const createMetadataSlice: StateCreator<MetadataSliceShape> = (set, get)
|
||||
set({ fileMetadata: nextMap })
|
||||
},
|
||||
|
||||
setDraftMetadata: (fileId: string, metadata: Record<string, any>) => {
|
||||
setDraftMetadata: (fileId: string, metadata: Record<string, unknown>) => {
|
||||
const { fileMetadata, dirtyMetadataIds } = get()
|
||||
const nextMap = new Map(fileMetadata)
|
||||
nextMap.set(fileId, metadata || {})
|
||||
|
||||
@ -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<TabSliceShape> = (set, get) => ({
|
||||
export const createTabSlice: StateCreator<
|
||||
SkillEditorSliceShape,
|
||||
[],
|
||||
[],
|
||||
TabSliceShape
|
||||
> = (set, get) => ({
|
||||
openTabIds: [],
|
||||
activeTabId: null,
|
||||
previewTabId: null,
|
||||
@ -73,9 +57,9 @@ export const createTabSlice: StateCreator<TabSliceShape> = (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,
|
||||
|
||||
@ -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<string, boolean>
|
||||
|
||||
export type FileTreeSliceShape = {
|
||||
expandedFolderIds: Set<string>
|
||||
setExpandedFolderIds: (ids: Set<string>) => void
|
||||
toggleFolder: (folderId: string) => void
|
||||
revealFile: (ancestorFolderIds: string[]) => void
|
||||
setExpandedFromOpens: (opens: OpensObject) => void
|
||||
getOpensObject: () => OpensObject
|
||||
}
|
||||
|
||||
export type DirtySliceShape = {
|
||||
dirtyContents: Map<string, string>
|
||||
setDraftContent: (fileId: string, content: string) => void
|
||||
clearDraftContent: (fileId: string) => void
|
||||
isDirty: (fileId: string) => boolean
|
||||
getDraftContent: (fileId: string) => string | undefined
|
||||
}
|
||||
|
||||
export type MetadataSliceShape = {
|
||||
fileMetadata: Map<string, Record<string, unknown>>
|
||||
dirtyMetadataIds: Set<string>
|
||||
setFileMetadata: (fileId: string, metadata: Record<string, unknown>) => void
|
||||
setDraftMetadata: (fileId: string, metadata: Record<string, unknown>) => void
|
||||
clearDraftMetadata: (fileId: string) => void
|
||||
clearFileMetadata: (fileId: string) => void
|
||||
isMetadataDirty: (fileId: string) => boolean
|
||||
getFileMetadata: (fileId: string) => Record<string, unknown> | 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
|
||||
}
|
||||
Reference in New Issue
Block a user