@stonecrop/stonecrop 0.4.36 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +92 -3
  2. package/dist/src/composable.d.ts +74 -8
  3. package/dist/src/composable.d.ts.map +1 -1
  4. package/dist/src/composable.js +348 -0
  5. package/dist/src/composables/operation-log.d.ts +136 -0
  6. package/dist/src/composables/operation-log.d.ts.map +1 -0
  7. package/dist/src/composables/operation-log.js +221 -0
  8. package/dist/src/doctype.d.ts +9 -1
  9. package/dist/src/doctype.d.ts.map +1 -1
  10. package/dist/{doctype.js → src/doctype.js} +9 -3
  11. package/dist/src/exceptions.d.ts +2 -3
  12. package/dist/src/exceptions.d.ts.map +1 -1
  13. package/dist/{exceptions.js → src/exceptions.js} +5 -11
  14. package/dist/src/field-triggers.d.ts +178 -0
  15. package/dist/src/field-triggers.d.ts.map +1 -0
  16. package/dist/src/field-triggers.js +564 -0
  17. package/dist/src/index.d.ts +12 -4
  18. package/dist/src/index.d.ts.map +1 -1
  19. package/dist/src/index.js +18 -0
  20. package/dist/src/plugins/index.d.ts +11 -13
  21. package/dist/src/plugins/index.d.ts.map +1 -1
  22. package/dist/src/plugins/index.js +90 -0
  23. package/dist/src/registry.d.ts +9 -3
  24. package/dist/src/registry.d.ts.map +1 -1
  25. package/dist/{registry.js → src/registry.js} +14 -1
  26. package/dist/src/stonecrop.d.ts +350 -114
  27. package/dist/src/stonecrop.d.ts.map +1 -1
  28. package/dist/src/stonecrop.js +251 -0
  29. package/dist/src/stores/hst.d.ts +157 -0
  30. package/dist/src/stores/hst.d.ts.map +1 -0
  31. package/dist/src/stores/hst.js +483 -0
  32. package/dist/src/stores/index.d.ts +5 -1
  33. package/dist/src/stores/index.d.ts.map +1 -1
  34. package/dist/{stores → src/stores}/index.js +4 -1
  35. package/dist/src/stores/operation-log.d.ts +268 -0
  36. package/dist/src/stores/operation-log.d.ts.map +1 -0
  37. package/dist/src/stores/operation-log.js +571 -0
  38. package/dist/src/types/field-triggers.d.ts +186 -0
  39. package/dist/src/types/field-triggers.d.ts.map +1 -0
  40. package/dist/src/types/field-triggers.js +4 -0
  41. package/dist/src/types/index.d.ts +13 -2
  42. package/dist/src/types/index.d.ts.map +1 -1
  43. package/dist/src/types/index.js +4 -0
  44. package/dist/src/types/operation-log.d.ts +165 -0
  45. package/dist/src/types/operation-log.d.ts.map +1 -0
  46. package/dist/src/types/registry.d.ts +11 -0
  47. package/dist/src/types/registry.d.ts.map +1 -0
  48. package/dist/src/types/registry.js +0 -0
  49. package/dist/stonecrop.d.ts +1555 -159
  50. package/dist/stonecrop.js +1974 -7035
  51. package/dist/stonecrop.js.map +1 -1
  52. package/dist/stonecrop.umd.cjs +4 -8
  53. package/dist/stonecrop.umd.cjs.map +1 -1
  54. package/dist/tests/setup.d.ts +5 -0
  55. package/dist/tests/setup.d.ts.map +1 -0
  56. package/dist/tests/setup.js +15 -0
  57. package/package.json +18 -16
  58. package/src/composable.ts +481 -33
  59. package/src/composables/operation-log.ts +254 -0
  60. package/src/doctype.ts +9 -3
  61. package/src/exceptions.ts +5 -12
  62. package/src/field-triggers.ts +671 -0
  63. package/src/index.ts +50 -4
  64. package/src/plugins/index.ts +70 -22
  65. package/src/registry.ts +18 -3
  66. package/src/stonecrop.ts +246 -151
  67. package/src/stores/hst.ts +703 -0
  68. package/src/stores/index.ts +6 -1
  69. package/src/stores/operation-log.ts +671 -0
  70. package/src/types/field-triggers.ts +201 -0
  71. package/src/types/index.ts +17 -6
  72. package/src/types/operation-log.ts +205 -0
  73. package/src/types/registry.ts +10 -0
  74. package/dist/composable.js +0 -51
  75. package/dist/index.js +0 -6
  76. package/dist/plugins/index.js +0 -49
  77. package/dist/src/stores/data.d.ts +0 -11
  78. package/dist/src/stores/data.d.ts.map +0 -1
  79. package/dist/stores/data.js +0 -7
  80. package/src/stores/data.ts +0 -8
  81. /package/dist/{types/index.js → src/types/operation-log.js} +0 -0
@@ -0,0 +1,254 @@
1
+ import { useMagicKeys, whenever } from '@vueuse/core'
2
+ import { storeToRefs } from 'pinia'
3
+ import { inject } from 'vue'
4
+
5
+ import type { HSTNode } from '../stores/hst'
6
+ import { useOperationLogStore } from '../stores/operation-log'
7
+ import type { OperationLogConfig } from '../types/operation-log'
8
+
9
+ /**
10
+ * Composable for operation log management
11
+ * Provides easy access to undo/redo functionality and operation history
12
+ *
13
+ * @param config - Optional configuration for the operation log
14
+ * @returns Operation log interface
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const { undo, redo, canUndo, canRedo, operations, configure } = useOperationLog()
19
+ *
20
+ * // Configure the log
21
+ * configure({
22
+ * maxOperations: 50,
23
+ * enableCrossTabSync: true,
24
+ * enablePersistence: true
25
+ * })
26
+ *
27
+ * // Undo/redo
28
+ * await undo(hstStore)
29
+ * await redo(hstStore)
30
+ * ```
31
+ *
32
+ * @public
33
+ */
34
+ export function useOperationLog(config?: Partial<OperationLogConfig>) {
35
+ // Try to use the injected store from the Stonecrop plugin first
36
+ // This ensures we use the same Pinia instance as the app
37
+ const injectedStore = inject<ReturnType<typeof useOperationLogStore> | undefined>('$operationLogStore', undefined)
38
+ const store = injectedStore || useOperationLogStore()
39
+
40
+ // Apply configuration if provided
41
+ if (config) {
42
+ store.configure(config)
43
+ }
44
+
45
+ // Extract reactive state
46
+ const { operations, currentIndex, undoRedoState, canUndo, canRedo, undoCount, redoCount } = storeToRefs(store)
47
+
48
+ /**
49
+ * Undo the last operation
50
+ */
51
+ function undo(hstStore: HSTNode): boolean {
52
+ return store.undo(hstStore)
53
+ }
54
+
55
+ /**
56
+ * Redo the next operation
57
+ */
58
+ function redo(hstStore: HSTNode): boolean {
59
+ return store.redo(hstStore)
60
+ }
61
+
62
+ /**
63
+ * Start a batch operation
64
+ */
65
+ function startBatch() {
66
+ store.startBatch()
67
+ }
68
+
69
+ /**
70
+ * Commit the current batch
71
+ */
72
+ function commitBatch(description?: string): string | null {
73
+ return store.commitBatch(description)
74
+ }
75
+
76
+ /**
77
+ * Cancel the current batch
78
+ */
79
+ function cancelBatch() {
80
+ store.cancelBatch()
81
+ }
82
+
83
+ /**
84
+ * Clear all operations
85
+ */
86
+ function clear() {
87
+ store.clear()
88
+ }
89
+
90
+ /**
91
+ * Get operations for a specific doctype/record
92
+ */
93
+ function getOperationsFor(doctype: string, recordId?: string) {
94
+ return store.getOperationsFor(doctype, recordId)
95
+ }
96
+
97
+ /**
98
+ * Get a snapshot of the operation log
99
+ */
100
+ function getSnapshot() {
101
+ return store.getSnapshot()
102
+ }
103
+
104
+ /**
105
+ * Mark an operation as irreversible
106
+ * @param operationId - The ID of the operation to mark
107
+ * @param reason - The reason why the operation is irreversible
108
+ */
109
+ function markIrreversible(operationId: string, reason: string) {
110
+ store.markIrreversible(operationId, reason)
111
+ }
112
+
113
+ /**
114
+ * Log an action execution (stateless actions like print, email, etc.)
115
+ * @param doctype - The doctype the action was executed on
116
+ * @param actionName - The name of the action that was executed
117
+ * @param recordIds - Optional array of record IDs the action was executed on
118
+ * @param result - The result of the action execution
119
+ * @param error - Optional error message if action failed
120
+ * @returns The operation ID
121
+ */
122
+ function logAction(
123
+ doctype: string,
124
+ actionName: string,
125
+ recordIds?: string[],
126
+ result: 'success' | 'failure' | 'pending' = 'success',
127
+ error?: string
128
+ ): string {
129
+ return store.logAction(doctype, actionName, recordIds, result, error)
130
+ }
131
+
132
+ /**
133
+ * Update configuration
134
+ * @param options - Configuration options to update
135
+ */
136
+ function configure(options: Partial<OperationLogConfig>) {
137
+ store.configure(options)
138
+ }
139
+
140
+ return {
141
+ // State
142
+ operations,
143
+ currentIndex,
144
+ undoRedoState,
145
+ canUndo,
146
+ canRedo,
147
+ undoCount,
148
+ redoCount,
149
+
150
+ // Methods
151
+ undo,
152
+ redo,
153
+ startBatch,
154
+ commitBatch,
155
+ cancelBatch,
156
+ clear,
157
+ getOperationsFor,
158
+ getSnapshot,
159
+ markIrreversible,
160
+ logAction,
161
+ configure,
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Keyboard shortcut handler for undo/redo
167
+ * Automatically binds Ctrl+Z (undo) and Ctrl+Shift+Z/Ctrl+Y (redo) using VueUse
168
+ *
169
+ * @param hstStore - The HST store to operate on
170
+ * @param enabled - Whether shortcuts are enabled (default: true)
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * import { onMounted } from 'vue'
175
+ *
176
+ * const stonecrop = useStonecrop({ doctype, recordId })
177
+ * useUndoRedoShortcuts(stonecrop.hstStore)
178
+ * ```
179
+ *
180
+ * @public
181
+ */
182
+ export function useUndoRedoShortcuts(hstStore: HSTNode, enabled = true) {
183
+ if (!enabled) return
184
+
185
+ const { undo, redo, canUndo, canRedo } = useOperationLog()
186
+ const keys = useMagicKeys()
187
+
188
+ // Undo shortcuts: Ctrl+Z or Cmd+Z (Mac)
189
+ whenever(keys['Ctrl+Z'], () => {
190
+ if (canUndo.value) {
191
+ undo(hstStore)
192
+ }
193
+ })
194
+
195
+ whenever(keys['Meta+Z'], () => {
196
+ if (canUndo.value) {
197
+ undo(hstStore)
198
+ }
199
+ })
200
+
201
+ // Redo shortcuts: Ctrl+Shift+Z, Cmd+Shift+Z (Mac), or Ctrl+Y
202
+ whenever(keys['Ctrl+Shift+Z'], () => {
203
+ if (canRedo.value) {
204
+ redo(hstStore)
205
+ }
206
+ })
207
+
208
+ whenever(keys['Meta+Shift+Z'], () => {
209
+ if (canRedo.value) {
210
+ redo(hstStore)
211
+ }
212
+ })
213
+
214
+ whenever(keys['Ctrl+Y'], () => {
215
+ if (canRedo.value) {
216
+ redo(hstStore)
217
+ }
218
+ })
219
+ }
220
+
221
+ /**
222
+ * Batch operation helper
223
+ * Wraps a function execution in a batch operation
224
+ *
225
+ * @param fn - The function to execute within a batch
226
+ * @param description - Optional description for the batch
227
+ * @returns The batch operation ID
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * const { withBatch } = useOperationLog()
232
+ *
233
+ * const batchId = await withBatch(() => {
234
+ * hstStore.set('task.123.title', 'New Title')
235
+ * hstStore.set('task.123.status', 'active')
236
+ * hstStore.set('task.123.priority', 'high')
237
+ * }, 'Update task details')
238
+ * ```
239
+ *
240
+ * @public
241
+ */
242
+ export async function withBatch<T>(fn: () => T | Promise<T>, description?: string): Promise<string | null> {
243
+ const { startBatch, commitBatch, cancelBatch } = useOperationLog()
244
+
245
+ startBatch()
246
+
247
+ try {
248
+ await fn()
249
+ return commitBatch(description)
250
+ } catch (error) {
251
+ cancelBatch()
252
+ throw error
253
+ }
254
+ }
package/src/doctype.ts CHANGED
@@ -29,7 +29,7 @@ export default class DoctypeMeta {
29
29
  readonly workflow: ImmutableDoctype['workflow']
30
30
 
31
31
  /**
32
- * The doctype actions
32
+ * The doctype actions and field triggers
33
33
  * @public
34
34
  * @readonly
35
35
  */
@@ -41,9 +41,15 @@ export default class DoctypeMeta {
41
41
  * @readonly
42
42
  */
43
43
  readonly component?: Component
44
- // TODO: allow different components for different views; probably
45
- // should be defined in the schema instead?
46
44
 
45
+ /**
46
+ * Creates a new DoctypeMeta instance
47
+ * @param doctype - The doctype name
48
+ * @param schema - The doctype schema definition
49
+ * @param workflow - The doctype workflow configuration (XState machine)
50
+ * @param actions - The doctype actions and field triggers
51
+ * @param component - Optional Vue component for rendering the doctype
52
+ */
47
53
  constructor(
48
54
  doctype: string,
49
55
  schema: ImmutableDoctype['schema'],
package/src/exceptions.ts CHANGED
@@ -8,16 +8,9 @@
8
8
  * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error|Error}
9
9
  * @public
10
10
  */
11
- export function NotImplementedError(message: string) {
12
- this.message = message || ''
11
+ export class NotImplementedError extends Error {
12
+ constructor(message: string = '') {
13
+ super(message)
14
+ this.name = 'NotImplemented'
15
+ }
13
16
  }
14
-
15
- NotImplementedError.prototype = Object.create(Error.prototype, {
16
- constructor: { value: NotImplementedError },
17
- name: { value: 'NotImplemented' },
18
- stack: {
19
- get: function () {
20
- return new Error().stack
21
- },
22
- },
23
- })