@anzusystems/common-admin 1.47.0-beta.dev-1782075999 → 1.47.0-beta.dev-1782078999

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/dist/labs.d.ts CHANGED
@@ -10,6 +10,7 @@ import { MaybeRefOrGetter } from 'vue';
10
10
  import { Method } from 'axios';
11
11
  import { PublicProps } from 'vue';
12
12
  import { Ref } from 'vue';
13
+ import { ShallowRef } from 'vue';
13
14
  import { ShallowUnwrapRef } from 'vue';
14
15
  import { UseDebounceFnReturn } from '@vueuse/shared';
15
16
  import { VNode } from 'vue';
@@ -907,6 +908,14 @@ export declare function createFilter<F extends readonly MakeFilterOption<string>
907
908
 
908
909
  export declare function createFilterStore<F extends readonly MakeFilterOption<string>[]>(filterFields: F): FilterData<F>;
909
910
 
911
+ /**
912
+ * Create a scope. The internal `effectScope` is NOT detached: it attaches to whatever scope creates
913
+ * it — the providing editor's component scope (so everything stops on its unmount) or a persisted
914
+ * ENTRY's scope (so a nested editor's own row scope outlives the editor exactly as its controller
915
+ * does).
916
+ */
917
+ export declare function createListEditorStateScope(): ListEditorStateScope;
918
+
910
919
  declare interface DatatableColumnsConfigMoreOptions {
911
920
  storeColumnsLocalStorage: string | boolean;
912
921
  disableActions: boolean;
@@ -1006,6 +1015,29 @@ declare type ExecuteRequestParams<T> = {
1006
1015
  object?: T;
1007
1016
  };
1008
1017
 
1018
+ /**
1019
+ * The shape a CONSUMER sees when it reads a list-editor handle through a template/function ref.
1020
+ * Vue's `expose` proxy unwraps every exposed ref, so the reactive fields (`hasUnsaved`, `hasErrors`,
1021
+ * `unsavedCount`, …) arrive as plain VALUES here, not `Ref`s: read `handle.hasUnsaved` (a boolean),
1022
+ * never `handle.hasUnsaved.value` (that is `undefined`). Type your `useTemplateRef` / collected-ref
1023
+ * maps with this so a stray `.value` is a compile error instead of a silently-dead guard/save-gate.
1024
+ */
1025
+ export declare type ExposedListEditorHandle<TItem extends Record<string, any>> = ShallowUnwrapRef<ListEditorHandle<TItem>>;
1026
+
1027
+ /**
1028
+ * Consumer-facing shape of a nested-list-editor handle read through a template/function ref — Vue's
1029
+ * `expose` proxy unwraps the exposed refs, so read `handle.hasUnsaved` (a boolean), not
1030
+ * `handle.hasUnsaved.value`. See {@link ExposedListEditorHandle}.
1031
+ *
1032
+ * The `ANestedSortableListEditor` component also exposes `hasUnsavedChanges` (a legacy alias of
1033
+ * `hasUnsaved`, likewise a ComputedRef → unwrapped to a boolean here) — included so it can't be
1034
+ * `.value`-read by accident. Its imperative-only extras (addAfterId / resetDirtyBaseline / expand /
1035
+ * reorder / …) are not refs and carry no unwrap hazard; intersect them in the consumer if you call them.
1036
+ */
1037
+ export declare type ExposedNestedListEditorHandle<TItem extends Record<string, any>> = ShallowUnwrapRef<NestedListEditorHandle<TItem>> & {
1038
+ hasUnsavedChanges: boolean;
1039
+ };
1040
+
1009
1041
  declare type FetchByIdsParams = {
1010
1042
  urlTemplate?: string;
1011
1043
  urlParams?: UrlParams;
@@ -1207,19 +1239,68 @@ export declare interface ListEditorHandle<TItem extends Record<string, any>> {
1207
1239
  /** Clear a deferred-deletion tombstone (the caller re-inserts the row, e.g. reorder Cancel). */
1208
1240
  restoreDeleted: (key: ListEditorKey) => void;
1209
1241
  moveItem: (fromIndex: number, toIndex: number) => void;
1242
+ /** Drop the "moved" flag for the given keys (or all) without touching edits/adds — e.g. reorder Cancel. */
1243
+ clearMoved: (keys?: Iterable<ListEditorKey>) => void;
1210
1244
  /** Escape hatch: a row form (e.g. vuelidate) reports its own validity instead of `validate`. */
1211
1245
  registerValidity: (key: ListEditorKey, isValid: () => boolean) => () => void;
1212
1246
  }
1213
1247
 
1214
1248
  export declare type ListEditorKey = DocId | IntegerId | string;
1215
1249
 
1216
- export declare const ListEditorValidationKey: InjectionKey<ListEditorValidationRegistry>;
1250
+ /**
1251
+ * The instance-bound controller options an editor re-supplies on EVERY (re)mount. `get`/`set` close
1252
+ * over the editor instance's `modelValue`/`emit`, and `factory`/`validate`/`dirtyExclude` over its
1253
+ * props — a remounted editor is a NEW instance, so a persisted controller must read all of them
1254
+ * through the live binding (see `useListEditorStateEntry`), never through the closures of the dead
1255
+ * instance that happened to create it.
1256
+ */
1257
+ export declare type ListEditorStateBindings<TItem extends Record<string, any>> = Pick<UseListEditorControllerOptions<TItem>, 'get' | 'set' | 'factory' | 'getKey' | 'position' | 'dirtyExclude' | 'validate'>;
1217
1258
 
1218
- export declare interface ListEditorValidationRegistry {
1219
- register: (key: ListEditorKey, state: Ref<ListEditorValidationState> | ComputedRef<ListEditorValidationState>) => void;
1220
- unregister: (key: ListEditorKey) => void;
1259
+ /** What a `state-key`'d editor gets back: its persisted handle + the scope to hand to ITS own rows. */
1260
+ export declare interface ListEditorStateEntry<THandle> {
1261
+ handle: THandle;
1262
+ /** Scope for this editor's `#item` slot subtree — persisted alongside the entry, so a
1263
+ * grand-nested `state-key`'d editor survives this editor's unmount too. */
1264
+ childScope: ListEditorStateScope | null;
1221
1265
  }
1222
1266
 
1267
+ /**
1268
+ * A keyed registry of list-editor state controllers, owned by an ANCESTOR (the editor that provides
1269
+ * it for its `#item` slot subtree) and living in that ancestor's `effectScope` — NOT in the scope of
1270
+ * the transient editor component that resolves it. That is the whole point: a nested editor's `#item`
1271
+ * slot is behind a `v-if`, so collapsing a row UNMOUNTS the nested editor; a component-owned
1272
+ * controller dies with it and a brand-new one re-baselines the already-edited data on re-expand,
1273
+ * losing amber / movedKeys / editedKeys / tombstones / the submitted (red-rail) flag.
1274
+ */
1275
+ export declare interface ListEditorStateScope {
1276
+ /** Unique per scope instance; namespaces the row prefixes this scope mints (and can prune). */
1277
+ readonly id: string;
1278
+ /**
1279
+ * First call for `key` CREATES the controller inside this scope (via `create`, from the calling
1280
+ * editor's own bindings) and registers it. Every later call REBINDS the registered controller to
1281
+ * the (new) calling instance's bindings and returns it — state intact.
1282
+ */
1283
+ resolve<TBindings extends object, THandle>(key: string, bindings: TBindings, create: (live: ShallowRef<TBindings>) => THandle, uid?: number | null): THandle;
1284
+ /**
1285
+ * The editor bound to `key` is unmounting: park the entry — its model accessors are swapped for a
1286
+ * frozen read + a no-op write so the orphaned controller can never read or write through the dead
1287
+ * instance's `modelValue`/`emit`. No-op when another instance has already rebound (mount-before-
1288
+ * unmount ordering), which is why the caller passes its uid.
1289
+ */
1290
+ release<TBindings extends object>(key: string, uid: number | null, park: (bindings: TBindings) => TBindings): void;
1291
+ /** Child scope of a registered entry (created lazily inside the entry's effect scope). */
1292
+ childScope(key: string): ListEditorStateScope | null;
1293
+ /** The state-key prefix for a row — hosts thread it down and suffix it per nested list. */
1294
+ prefixFor(rowKey: ListEditorKey): string;
1295
+ /** Dispose the entries of rows that no longer exist (keys minted from `prefixFor` only). */
1296
+ retainOwners(liveRowKeys: Iterable<ListEditorKey>): void;
1297
+ has(key: string): boolean;
1298
+ size(): number;
1299
+ dispose(): void;
1300
+ }
1301
+
1302
+ export declare const ListEditorStateScopeKey: InjectionKey<ListEditorStateScope>;
1303
+
1223
1304
  /** Per-row validity. `true` (or `{ valid: true }`) = VALID. Only `valid: false` blocks save. */
1224
1305
  export declare type ListEditorValidationResult = boolean | {
1225
1306
  valid: boolean;
@@ -1358,6 +1439,8 @@ export declare interface NestedListEditorHandle<TItem extends Record<string, any
1358
1439
  calculateSubtreeDepth: (node: NestedTreeNode<TItem>) => number;
1359
1440
  }
1360
1441
 
1442
+ export declare type NestedListEditorStateBindings<TItem extends Record<string, any>> = Pick<UseNestedListEditorControllerOptions<TItem>, 'get' | 'set' | 'factory' | 'getKey' | 'position' | 'parentField' | 'maxDepth' | 'dirtyExclude' | 'validate'>;
1443
+
1361
1444
  export declare interface NestedPositionHint {
1362
1445
  parentId?: ListEditorKey | null;
1363
1446
  afterId?: ListEditorKey;
@@ -1484,6 +1567,18 @@ declare interface Props<TItem extends Record<string, any>> {
1484
1567
  * internally. Either way the `ListEditorHandle` is reachable via `useTemplateRef`.
1485
1568
  */
1486
1569
  editor?: ListEditorHandle<TItem>;
1570
+ /**
1571
+ * Persist this editor's controller in the nearest ANCESTOR editor's row-state scope under this
1572
+ * key, instead of owning it. Use it for an editor rendered in another editor's `#item` slot: that
1573
+ * slot is behind a `v-if`, so collapsing the row unmounts this editor and a component-owned
1574
+ * controller would re-baseline the already-edited data on re-expand (losing amber, tombstones and
1575
+ * the red rail). Derive the key from the row slot's `stateKeyPrefix`, e.g.
1576
+ * `:state-key="`${stateKeyPrefix}:adverts`"`. Options stay declared here, on this tag: the
1577
+ * controller is built from THIS editor's `factory`/`get-key`/`position`/`dirty-exclude`/`validate`
1578
+ * and rebound to each new instance's model on remount. Ignored when `:editor` is passed, and a
1579
+ * no-op without an ancestor scope.
1580
+ */
1581
+ stateKey?: string;
1487
1582
  readonly?: boolean;
1488
1583
  disabled?: boolean;
1489
1584
  loading?: boolean;
@@ -1573,6 +1668,18 @@ declare interface Props_2<TItem extends Record<string, any>> {
1573
1668
  * relocation). When omitted the editor owns an internal controller.
1574
1669
  */
1575
1670
  editor?: ListEditorHandle<TItem>;
1671
+ /**
1672
+ * Persist this editor's controller in the nearest ANCESTOR editor's row-state scope under this
1673
+ * key, instead of owning it. Use it for an editor rendered in another editor's `#item` slot: that
1674
+ * slot is behind a `v-if`, so collapsing the row unmounts this editor and a component-owned
1675
+ * controller would re-baseline the already-edited data on re-expand (losing amber, moved rows,
1676
+ * tombstones and the red rail). Derive the key from the row slot's `stateKeyPrefix`, e.g.
1677
+ * `:state-key="`${stateKeyPrefix}:answers`"`. Options stay declared here, on this tag: the
1678
+ * controller is built from THIS editor's `factory`/`get-key`/`position`/`dirty-exclude`/`validate`
1679
+ * and rebound to each new instance's model on remount. Ignored when `:editor` is passed, and a
1680
+ * no-op without an ancestor scope.
1681
+ */
1682
+ stateKey?: string;
1576
1683
  readonly?: boolean;
1577
1684
  disabled?: boolean;
1578
1685
  loading?: boolean;
@@ -1671,6 +1778,15 @@ declare interface Props_3<TItem extends Record<string, any>> {
1671
1778
  * reachable via `useTemplateRef`.
1672
1779
  */
1673
1780
  editor?: NestedListEditorHandle<TItem>;
1781
+ /**
1782
+ * Persist this editor's controller in the nearest ANCESTOR editor's row-state scope under this
1783
+ * key, instead of owning it. Use it for an editor rendered in another editor's `#item` slot (that
1784
+ * slot is behind a `v-if`, so collapsing the row unmounts this editor and a component-owned
1785
+ * controller would re-baseline the already-edited tree on re-expand). Derive the key from the row
1786
+ * slot's `stateKeyPrefix`. Options stay declared here, on this tag. Ignored when `:editor` is
1787
+ * passed, and a no-op without an ancestor scope.
1788
+ */
1789
+ stateKey?: string;
1674
1790
  readonly?: boolean;
1675
1791
  disabled?: boolean;
1676
1792
  loading?: boolean;
@@ -1723,6 +1839,13 @@ declare interface Props_4 {
1723
1839
  dirtyLabels?: string[];
1724
1840
  }
1725
1841
 
1842
+ /**
1843
+ * Provide the row-state scope for an editor's `#item` slot subtree. A `state-key`'d editor passes
1844
+ * the `childScope` of its own persisted entry (so the chain survives at any depth); a plain editor
1845
+ * creates a component-owned scope that dies with it.
1846
+ */
1847
+ export declare function provideListEditorStateScope(inherited: ListEditorStateScope | null): ListEditorStateScope;
1848
+
1726
1849
  /**
1727
1850
  * Non-mutating renumber to sequential positions matching array order — the same
1728
1851
  * renumbering the editors apply on commit. Unchanged items stay reference-equal.
@@ -1820,6 +1943,13 @@ declare interface RowSlotProps<TItem extends Record<string, any>> {
1820
1943
  /** Aliases `dirty` here (no reorder mode → no `moved` to OR). Same field name as on sortable/nested variants. */
1821
1944
  unsaved: boolean;
1822
1945
  touch: boolean;
1946
+ /**
1947
+ * Row-scoped `state-key` prefix. Thread it down to any list editor rendered in this slot and set
1948
+ * its `:state-key="`${stateKeyPrefix}:someList`"` — that editor's controller then lives in THIS
1949
+ * editor's scope and survives the row collapsing (which unmounts the whole slot subtree). Entries
1950
+ * under this prefix are disposed when the row is removed.
1951
+ */
1952
+ stateKeyPrefix: string;
1823
1953
  actions: RowActions<TItem>;
1824
1954
  }
1825
1955
 
@@ -1839,6 +1969,13 @@ declare interface RowSlotProps_2<TItem extends Record<string, any>> {
1839
1969
  canMoveUp: boolean;
1840
1970
  canMoveDown: boolean;
1841
1971
  touch: boolean;
1972
+ /**
1973
+ * Row-scoped `state-key` prefix. Thread it down to any list editor rendered in this slot and set
1974
+ * its `:state-key="`${stateKeyPrefix}:someList`"` — that editor's controller then lives in THIS
1975
+ * editor's scope and survives the row collapsing (which unmounts the whole slot subtree). Entries
1976
+ * under this prefix are disposed when the row is removed.
1977
+ */
1978
+ stateKeyPrefix: string;
1842
1979
  actions: RowActions_2<TItem>;
1843
1980
  }
1844
1981
 
@@ -1872,6 +2009,13 @@ declare interface RowSlotProps_3<TItem extends Record<string, any>> {
1872
2009
  canOutdent: boolean;
1873
2010
  canAddChild: boolean;
1874
2011
  touch: boolean;
2012
+ /**
2013
+ * Row-scoped `state-key` prefix. Thread it down to any list editor rendered in this slot and set
2014
+ * its `:state-key="`${stateKeyPrefix}:someList`"` — that editor's controller then lives in THIS
2015
+ * editor's scope and survives the row collapsing (which unmounts the whole slot subtree). Entries
2016
+ * under this prefix are disposed when the row is removed.
2017
+ */
2018
+ stateKeyPrefix: string;
1875
2019
  actions: RowActions_3<TItem>;
1876
2020
  }
1877
2021
 
@@ -2107,9 +2251,14 @@ export declare function useFilterHelpers<F extends readonly MakeFilterOption<str
2107
2251
  * the view on an already-deleted entity (system error). This acknowledges the guard right before the
2108
2252
  * delete so the follow-up navigation proceeds without prompting. (QA 85050 batch 7 — BUG-08)
2109
2253
  *
2254
+ * If `onDelete` REJECTS (the delete failed and never navigated), the acknowledgement is undone
2255
+ * immediately (`unacknowledge()`) so a subsequently-dirtied navigation is still guarded (M1) — the
2256
+ * error is re-thrown so the caller's own handling runs. For this to catch failures, `onDelete` must
2257
+ * let its error propagate (don't swallow it in the action's try/catch).
2258
+ *
2110
2259
  * Usage: `@delete-record="guardedDelete(() => onDelete(id))"` or wrap the handler once.
2111
2260
  */
2112
- export declare function useGuardedDelete<A extends unknown[], R>(guard: Pick<UseUnsavedChangesGuardApi, 'acknowledge'>, onDelete: (...args: A) => R): (...args: A) => R;
2261
+ export declare function useGuardedDelete<A extends unknown[], R>(guard: Pick<UseUnsavedChangesGuardApi, 'acknowledge' | 'unacknowledge'>, onDelete: (...args: A) => R): (...args: A) => R | Promise<Awaited<R>>;
2113
2262
 
2114
2263
  export declare function useJobApi<JobType extends JobBase = JobBase>(client: () => AxiosInstance, system: string): {
2115
2264
  useFetchJobList: () => UseApiFetchListReturnType<JobType[]>;
@@ -2168,39 +2317,6 @@ export declare interface UseListEditorControllerOptions<TItem extends Record<str
2168
2317
  normalizeSaved?: (savedItems: TItem[]) => TItem[];
2169
2318
  }
2170
2319
 
2171
- export declare function useListEditorItemValidation(options: UseListEditorItemValidationOptions): void;
2172
-
2173
- declare interface UseListEditorItemValidationOptions {
2174
- /**
2175
- * Stable identity of the row in the editor's v-model. Pass a getter so the
2176
- * composable can re-register if the key ever swaps.
2177
- */
2178
- key: () => ListEditorKey;
2179
- /**
2180
- * Reactive validation state. Common shape: a computed reading vuelidate's
2181
- * `v$.$dirty && v$.$invalid` and returning 'invalid' or null.
2182
- *
2183
- * Prefer `invalid` (+ optional `dirty`) below: it lets the editor surface the
2184
- * error once the row is unsaved without relying on mount-relative `$anyDirty`.
2185
- * `state` is kept for callers that report 'valid'/'warning' or custom logic.
2186
- */
2187
- state?: Ref<ListEditorValidationState> | ComputedRef<ListEditorValidationState> | (() => ListEditorValidationState);
2188
- /**
2189
- * Whether the row's data fails validation right now (e.g. `() => v$.value.$invalid`).
2190
- * When provided, the row is flagged 'invalid' as soon as it is invalid AND the
2191
- * user has had a chance to fix it — i.e. the row is unsaved (added / modified)
2192
- * or `dirty` below is true. Untouched rows on initial load stay clear so a
2193
- * persisted-but-invalid record does not light up red before any interaction.
2194
- */
2195
- invalid?: () => boolean;
2196
- /**
2197
- * Optional extra "has been interacted with" signal OR-ed with the editor's
2198
- * unsaved tracking (e.g. `() => v$.value.$anyDirty`). Useful when unsaved
2199
- * tracking is disabled on the editor.
2200
- */
2201
- dirty?: () => boolean;
2202
- }
2203
-
2204
2320
  export declare interface UseListEditorOptions {
2205
2321
  keyField?: string;
2206
2322
  positionField?: string;
@@ -2209,23 +2325,16 @@ export declare interface UseListEditorOptions {
2209
2325
  }
2210
2326
 
2211
2327
  /**
2212
- * Registers a row's vuelidate state with the surrounding list editor so the
2213
- * row shows the red invalid rail (invalid + unsaved/dirty) instead of amber.
2214
- *
2215
- * This is the one blessed shape for row validity sentinels — domain sentinels
2216
- * call their validation composable and delegate here:
2328
+ * Resolve this editor's controller from the nearest ancestor scope under `stateKey` (or `null` when
2329
+ * the editor has no `state-key`, or no ancestor provides a scope → today's component-owned
2330
+ * controller, unchanged).
2217
2331
  *
2218
- * ```ts
2219
- * const item = computed(() => props.modelValue)
2220
- * const { v$ } = useReviewListItemValidation(item)
2221
- * useListEditorVuelidateSentinel(v$, () => item.value.id ?? item.value.position)
2222
- * ```
2223
- *
2224
- * `key` must return the same key the editor resolves for the row
2225
- * (its `key-field`) or the item's own id/position — the editor's validation
2226
- * registry accepts either.
2332
+ * The controller is built from the FIRST mounting instance's own props, but every instance-bound
2333
+ * option is read through `live` — the shallowRef the scope swaps on each (re)mount. `getKey` and
2334
+ * `position` are static per tag, so the controller reads them once (it derives its key field at
2335
+ * construction); everything else is indirected.
2227
2336
  */
2228
- export declare function useListEditorVuelidateSentinel(v$: Ref<VuelidateSentinelSource>, key: () => ListEditorKey): void;
2337
+ export declare function useListEditorStateEntry<TItem extends Record<string, any>>(stateKey: string | undefined, bindings: ListEditorStateBindings<TItem>): ListEditorStateEntry<ListEditorHandle<TItem>> | null;
2229
2338
 
2230
2339
  /**
2231
2340
  * Nested list editor core. Pure data behavior shared by ANestedSortableListEditor.
@@ -2286,6 +2395,9 @@ declare interface UseNestedListEditorOptions {
2286
2395
  expandedKeys?: Ref<Set<ListEditorKey>>;
2287
2396
  }
2288
2397
 
2398
+ /** Tree-shaped twin of `useListEditorStateEntry` for ANestedSortableListEditor. */
2399
+ export declare function useNestedListEditorStateEntry<TItem extends Record<string, any>>(stateKey: string | undefined, bindings: NestedListEditorStateBindings<TItem>): ListEditorStateEntry<NestedListEditorHandle<TItem>> | null;
2400
+
2289
2401
  /**
2290
2402
  * Aggregates per-parent child-editor unsaved-keys into one prefix-merged set.
2291
2403
  * Used by stacked editors (e.g. quiz: questions → answers) so the outer
@@ -2429,8 +2541,19 @@ declare interface UseUnsavedChangesGuardApi {
2429
2541
  * route/dialog/unload attempt proceeds without prompting. Useful right
2430
2542
  * before a programmatic navigation that the consumer has already
2431
2543
  * confirmed.
2544
+ *
2545
+ * The acknowledgement AUTO-EXPIRES after a few seconds if nothing consumes it
2546
+ * (see `ACKNOWLEDGE_TTL_MS`): a delete that acknowledges up-front but then FAILS
2547
+ * (throws, never navigates) must not leave the guard silently disarmed for the
2548
+ * next unrelated navigation. Consuming it (a real leave) clears the timer.
2432
2549
  */
2433
2550
  acknowledge: () => void;
2551
+ /**
2552
+ * Cancel a pending `acknowledge()` (disarm). Call from a delete's failure path
2553
+ * so a failed/aborted delete restores the guard immediately instead of waiting
2554
+ * for the TTL. No-op if nothing is acknowledged.
2555
+ */
2556
+ unacknowledge: () => void;
2434
2557
  }
2435
2558
 
2436
2559
  declare interface UseUnsavedChangesGuardOptions {
@@ -2505,15 +2628,6 @@ declare interface ViewBodySlotProps<TItem extends Record<string, any>> {
2505
2628
  };
2506
2629
  }
2507
2630
 
2508
- /**
2509
- * Minimal surface of a vuelidate instance the sentinel reads — any
2510
- * `useVuelidate()` return value is structurally assignable.
2511
- */
2512
- export declare interface VuelidateSentinelSource {
2513
- $invalid: boolean;
2514
- $anyDirty: boolean;
2515
- }
2516
-
2517
2631
  export { }
2518
2632
 
2519
2633
  declare global {