@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.
- package/README.md +92 -3
- package/dist/src/composable.d.ts +74 -8
- package/dist/src/composable.d.ts.map +1 -1
- package/dist/src/composable.js +348 -0
- package/dist/src/composables/operation-log.d.ts +136 -0
- package/dist/src/composables/operation-log.d.ts.map +1 -0
- package/dist/src/composables/operation-log.js +221 -0
- package/dist/src/doctype.d.ts +9 -1
- package/dist/src/doctype.d.ts.map +1 -1
- package/dist/{doctype.js → src/doctype.js} +9 -3
- package/dist/src/exceptions.d.ts +2 -3
- package/dist/src/exceptions.d.ts.map +1 -1
- package/dist/{exceptions.js → src/exceptions.js} +5 -11
- package/dist/src/field-triggers.d.ts +178 -0
- package/dist/src/field-triggers.d.ts.map +1 -0
- package/dist/src/field-triggers.js +564 -0
- package/dist/src/index.d.ts +12 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +18 -0
- package/dist/src/plugins/index.d.ts +11 -13
- package/dist/src/plugins/index.d.ts.map +1 -1
- package/dist/src/plugins/index.js +90 -0
- package/dist/src/registry.d.ts +9 -3
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/{registry.js → src/registry.js} +14 -1
- package/dist/src/stonecrop.d.ts +350 -114
- package/dist/src/stonecrop.d.ts.map +1 -1
- package/dist/src/stonecrop.js +251 -0
- package/dist/src/stores/hst.d.ts +157 -0
- package/dist/src/stores/hst.d.ts.map +1 -0
- package/dist/src/stores/hst.js +483 -0
- package/dist/src/stores/index.d.ts +5 -1
- package/dist/src/stores/index.d.ts.map +1 -1
- package/dist/{stores → src/stores}/index.js +4 -1
- package/dist/src/stores/operation-log.d.ts +268 -0
- package/dist/src/stores/operation-log.d.ts.map +1 -0
- package/dist/src/stores/operation-log.js +571 -0
- package/dist/src/types/field-triggers.d.ts +186 -0
- package/dist/src/types/field-triggers.d.ts.map +1 -0
- package/dist/src/types/field-triggers.js +4 -0
- package/dist/src/types/index.d.ts +13 -2
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +4 -0
- package/dist/src/types/operation-log.d.ts +165 -0
- package/dist/src/types/operation-log.d.ts.map +1 -0
- package/dist/src/types/registry.d.ts +11 -0
- package/dist/src/types/registry.d.ts.map +1 -0
- package/dist/src/types/registry.js +0 -0
- package/dist/stonecrop.d.ts +1555 -159
- package/dist/stonecrop.js +1974 -7035
- package/dist/stonecrop.js.map +1 -1
- package/dist/stonecrop.umd.cjs +4 -8
- package/dist/stonecrop.umd.cjs.map +1 -1
- package/dist/tests/setup.d.ts +5 -0
- package/dist/tests/setup.d.ts.map +1 -0
- package/dist/tests/setup.js +15 -0
- package/package.json +18 -16
- package/src/composable.ts +481 -33
- package/src/composables/operation-log.ts +254 -0
- package/src/doctype.ts +9 -3
- package/src/exceptions.ts +5 -12
- package/src/field-triggers.ts +671 -0
- package/src/index.ts +50 -4
- package/src/plugins/index.ts +70 -22
- package/src/registry.ts +18 -3
- package/src/stonecrop.ts +246 -151
- package/src/stores/hst.ts +703 -0
- package/src/stores/index.ts +6 -1
- package/src/stores/operation-log.ts +671 -0
- package/src/types/field-triggers.ts +201 -0
- package/src/types/index.ts +17 -6
- package/src/types/operation-log.ts +205 -0
- package/src/types/registry.ts +10 -0
- package/dist/composable.js +0 -51
- package/dist/index.js +0 -6
- package/dist/plugins/index.js +0 -49
- package/dist/src/stores/data.d.ts +0 -11
- package/dist/src/stores/data.d.ts.map +0 -1
- package/dist/stores/data.js +0 -7
- package/src/stores/data.ts +0 -8
- /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
|
|
12
|
-
|
|
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
|
-
})
|