workflow-history-store.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { type ReactNode, createContext, useContext, useMemo, useState } from 'react'
  2. import { type StoreApi, create } from 'zustand'
  3. import { type TemporalState, temporal } from 'zundo'
  4. import isDeepEqual from 'fast-deep-equal'
  5. import type { Edge, Node } from './types'
  6. import type { WorkflowHistoryEvent } from './hooks'
  7. export const WorkflowHistoryStoreContext = createContext<WorkflowHistoryStoreContextType>({ store: null, shortcutsEnabled: true, setShortcutsEnabled: () => {} })
  8. export const Provider = WorkflowHistoryStoreContext.Provider
  9. export function WorkflowHistoryProvider({
  10. nodes,
  11. edges,
  12. children,
  13. }: WorkflowWithHistoryProviderProps) {
  14. const [shortcutsEnabled, setShortcutsEnabled] = useState(true)
  15. const [store] = useState(() =>
  16. createStore({
  17. nodes,
  18. edges,
  19. }),
  20. )
  21. const contextValue = {
  22. store,
  23. shortcutsEnabled,
  24. setShortcutsEnabled,
  25. }
  26. return (
  27. <Provider value={contextValue}>
  28. {children}
  29. </Provider>
  30. )
  31. }
  32. export function useWorkflowHistoryStore() {
  33. const {
  34. store,
  35. shortcutsEnabled,
  36. setShortcutsEnabled,
  37. } = useContext(WorkflowHistoryStoreContext)
  38. if (store === null)
  39. throw new Error('useWorkflowHistoryStoreApi must be used within a WorkflowHistoryProvider')
  40. return {
  41. store: useMemo(
  42. () => ({
  43. getState: store.getState,
  44. setState: (state: WorkflowHistoryState) => {
  45. store.setState({
  46. workflowHistoryEvent: state.workflowHistoryEvent,
  47. nodes: state.nodes.map((node: Node) => ({ ...node, data: { ...node.data, selected: false } })),
  48. edges: state.edges.map((edge: Edge) => ({ ...edge, selected: false }) as Edge),
  49. })
  50. },
  51. subscribe: store.subscribe,
  52. temporal: store.temporal,
  53. }),
  54. [store],
  55. ),
  56. shortcutsEnabled,
  57. setShortcutsEnabled,
  58. }
  59. }
  60. function createStore({
  61. nodes: storeNodes,
  62. edges: storeEdges,
  63. }: {
  64. nodes: Node[]
  65. edges: Edge[]
  66. }): WorkflowHistoryStoreApi {
  67. const store = create(temporal<WorkflowHistoryState>(
  68. (set, get) => {
  69. return {
  70. workflowHistoryEvent: undefined,
  71. nodes: storeNodes,
  72. edges: storeEdges,
  73. getNodes: () => get().nodes,
  74. setNodes: (nodes: Node[]) => set({ nodes }),
  75. setEdges: (edges: Edge[]) => set({ edges }),
  76. }
  77. },
  78. {
  79. equality: (pastState, currentState) =>
  80. isDeepEqual(pastState, currentState),
  81. },
  82. ),
  83. )
  84. return store
  85. }
  86. export type WorkflowHistoryStore = {
  87. nodes: Node[]
  88. edges: Edge[]
  89. workflowHistoryEvent: WorkflowHistoryEvent | undefined
  90. }
  91. export type WorkflowHistoryActions = {
  92. setNodes?: (nodes: Node[]) => void
  93. setEdges?: (edges: Edge[]) => void
  94. }
  95. export type WorkflowHistoryState = WorkflowHistoryStore & WorkflowHistoryActions
  96. type WorkflowHistoryStoreContextType = {
  97. store: ReturnType<typeof createStore> | null
  98. shortcutsEnabled: boolean
  99. setShortcutsEnabled: (enabled: boolean) => void
  100. }
  101. export type WorkflowHistoryStoreApi = StoreApi<WorkflowHistoryState> & { temporal: StoreApi<TemporalState<WorkflowHistoryState>> }
  102. export type WorkflowWithHistoryProviderProps = {
  103. nodes: Node[]
  104. edges: Edge[]
  105. children: ReactNode
  106. }