You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

workflow-history-store.tsx 3.4KB

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