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.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. nodes: state.nodes.map((node: Node) => ({ ...node, data: { ...node.data, selected: false } })),
  49. edges: state.edges.map((edge: Edge) => ({ ...edge, selected: false }) as Edge),
  50. })
  51. },
  52. subscribe: store.subscribe,
  53. temporal: store.temporal,
  54. }),
  55. [store],
  56. ),
  57. shortcutsEnabled,
  58. setShortcutsEnabled,
  59. }
  60. }
  61. function createStore({
  62. nodes: storeNodes,
  63. edges: storeEdges,
  64. }: {
  65. nodes: Node[]
  66. edges: Edge[]
  67. }): WorkflowHistoryStoreApi {
  68. const store = create(temporal<WorkflowHistoryState>(
  69. (set, get) => {
  70. return {
  71. workflowHistoryEvent: undefined,
  72. nodes: storeNodes,
  73. edges: storeEdges,
  74. getNodes: () => get().nodes,
  75. setNodes: (nodes: Node[]) => set({ nodes }),
  76. setEdges: (edges: Edge[]) => set({ edges }),
  77. }
  78. },
  79. {
  80. equality: (pastState, currentState) =>
  81. isDeepEqual(pastState, currentState),
  82. },
  83. ),
  84. )
  85. return store
  86. }
  87. export type WorkflowHistoryStore = {
  88. nodes: Node[]
  89. edges: Edge[]
  90. workflowHistoryEvent: WorkflowHistoryEvent | undefined
  91. }
  92. export type WorkflowHistoryActions = {
  93. setNodes?: (nodes: Node[]) => void
  94. setEdges?: (edges: Edge[]) => void
  95. }
  96. export type WorkflowHistoryState = WorkflowHistoryStore & WorkflowHistoryActions
  97. type WorkflowHistoryStoreContextType = {
  98. store: ReturnType<typeof createStore> | null
  99. shortcutsEnabled: boolean
  100. setShortcutsEnabled: (enabled: boolean) => void
  101. }
  102. export type WorkflowHistoryStoreApi = StoreApi<WorkflowHistoryState> & { temporal: StoreApi<TemporalState<WorkflowHistoryState>> }
  103. export type WorkflowWithHistoryProviderProps = {
  104. nodes: Node[]
  105. edges: Edge[]
  106. children: ReactNode
  107. }