@atscript/vue-table 0.1.132 → 0.1.134
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/as-action-form-dialog.cjs +42 -30
- package/dist/as-action-form-dialog.mjs +42 -30
- package/dist/{as-action-menu-content-C5qx9MPE.cjs → as-action-menu-content-C_D_Fepo.cjs} +1 -1
- package/dist/{as-action-menu-content-4UfcabUe.mjs → as-action-menu-content-rim8hAO9.mjs} +1 -1
- package/dist/{as-cell-array-2qmJ1lT2.mjs → as-cell-array-BWHkJX3I.mjs} +2 -2
- package/dist/{as-cell-array-iPeUnk2G.cjs → as-cell-array-D-8Pqlgo.cjs} +2 -2
- package/dist/as-cell-array.cjs +1 -1
- package/dist/as-cell-array.mjs +1 -1
- package/dist/{as-cell-date-DyixWKuS.cjs → as-cell-date-DviMJEqs.cjs} +2 -2
- package/dist/{as-cell-date-BwFgi6O0.mjs → as-cell-date-mGlnDeLP.mjs} +2 -2
- package/dist/as-cell-date.cjs +1 -1
- package/dist/as-cell-date.mjs +1 -1
- package/dist/{as-cell-json--95Xq6yq.mjs → as-cell-json-2I081xnO.mjs} +2 -2
- package/dist/{as-cell-json-Bvv2P7YV.cjs → as-cell-json-CaVB6e7V.cjs} +2 -2
- package/dist/as-cell-json.cjs +1 -1
- package/dist/as-cell-json.mjs +1 -1
- package/dist/{as-cell-number-DuPMOesI.cjs → as-cell-number-BnYbxOiG.cjs} +2 -2
- package/dist/{as-cell-number-DKRaS9pM.mjs → as-cell-number-CP2AZI9g.mjs} +2 -2
- package/dist/as-cell-number.cjs +1 -1
- package/dist/as-cell-number.mjs +1 -1
- package/dist/{as-cell-union-DJNsEKTi.cjs → as-cell-union-BjMP91PS.cjs} +3 -3
- package/dist/{as-cell-union-C9FukGqF.mjs → as-cell-union-NHpDCXty.mjs} +3 -3
- package/dist/as-cell-union.cjs +1 -1
- package/dist/as-cell-union.mjs +1 -1
- package/dist/as-column-menu.cjs +1 -1
- package/dist/as-column-menu.d.cts +1 -1
- package/dist/as-column-menu.d.mts +1 -1
- package/dist/as-column-menu.mjs +1 -1
- package/dist/{as-column-menu.vue-u_DNy3f-.d.cts → as-column-menu.vue-De7SRhj6.d.cts} +1 -1
- package/dist/{as-column-menu.vue-DL5N9mKR.d.mts → as-column-menu.vue-Dg0H1dOd.d.mts} +1 -1
- package/dist/{as-config-dialog-BehfqIGd.mjs → as-config-dialog-BUBHiVlf.mjs} +56 -35
- package/dist/{as-config-dialog-BOYWPYYH.cjs → as-config-dialog-DvBptYMS.cjs} +55 -34
- package/dist/as-config-dialog.cjs +1 -1
- package/dist/as-config-dialog.mjs +1 -1
- package/dist/{as-confirm-dialog-UwhDHysk.cjs → as-confirm-dialog-ByMfIG0A.cjs} +12 -9
- package/dist/{as-confirm-dialog-bpN4A-KN.mjs → as-confirm-dialog-G4ZoL_Xo.mjs} +12 -9
- package/dist/as-confirm-dialog.cjs +1 -1
- package/dist/as-confirm-dialog.mjs +1 -1
- package/dist/{as-filter-dialog-D1qzq-8b.mjs → as-filter-dialog-BJWH8cvc.mjs} +34 -26
- package/dist/{as-filter-dialog-Dh2Ylthb.cjs → as-filter-dialog-C2oyT0yt.cjs} +33 -25
- package/dist/as-filter-dialog.cjs +1 -1
- package/dist/as-filter-dialog.mjs +1 -1
- package/dist/{as-filter-field-DirBmnbb.mjs → as-filter-field-B2skq4K0.mjs} +4 -4
- package/dist/{as-filter-field-DRsDJdpx.cjs → as-filter-field-DxGfasQj.cjs} +4 -4
- package/dist/as-filter-field.cjs +1 -1
- package/dist/as-filter-field.mjs +1 -1
- package/dist/as-filter-input.cjs +1 -1
- package/dist/as-filter-input.mjs +1 -1
- package/dist/as-filters-Bhte22La.cjs +130 -0
- package/dist/as-filters-DogNVlqr.mjs +125 -0
- package/dist/as-filters.cjs +1 -1
- package/dist/as-filters.d.cts +1 -1
- package/dist/as-filters.d.mts +1 -1
- package/dist/as-filters.mjs +1 -1
- package/dist/as-filters.vue-BG_ysCkC.d.mts +65 -0
- package/dist/as-filters.vue-DcxDnWAU.d.cts +65 -0
- package/dist/{as-preset-dialog-CDqCAR7N.mjs → as-preset-dialog-BwHV6Y77.mjs} +71 -21
- package/dist/{as-preset-dialog-DpM06jqR.cjs → as-preset-dialog-D2a6nxEX.cjs} +75 -25
- package/dist/as-preset-dialog.cjs +1 -1
- package/dist/as-preset-dialog.mjs +1 -1
- package/dist/{as-preset-picker-CISaxEZ0.mjs → as-preset-picker-B0JnyAPA.mjs} +39 -15
- package/dist/{as-preset-picker-jUS_YDX8.cjs → as-preset-picker-DbkmapBx.cjs} +45 -21
- package/dist/as-preset-picker.cjs +1 -1
- package/dist/as-preset-picker.mjs +1 -1
- package/dist/{as-row-actions-xqJeAdQl.mjs → as-row-actions-BkIsJVBm.mjs} +24 -11
- package/dist/{as-row-actions-Bm6Bzyno.cjs → as-row-actions-CRg8LHGk.cjs} +24 -11
- package/dist/as-row-actions.cjs +1 -1
- package/dist/as-row-actions.d.cts +1 -1
- package/dist/as-row-actions.d.mts +1 -1
- package/dist/as-row-actions.mjs +1 -1
- package/dist/{as-row-actions.vue-Bvcc2tUN.d.cts → as-row-actions.vue-VpJsBAJ4.d.mts} +8 -0
- package/dist/{as-row-actions.vue-DUSDuoR2.d.mts → as-row-actions.vue-dn_DKcMm.d.cts} +8 -0
- package/dist/{as-table-CDSG2yED.mjs → as-table-BEvsX87E.mjs} +26 -8
- package/dist/{as-table-actions-DMxeaczm.mjs → as-table-actions-B5upF1bQ.mjs} +69 -18
- package/dist/{as-table-actions-gV4lqqxc.cjs → as-table-actions-B6sKd4sl.cjs} +68 -17
- package/dist/as-table-actions.cjs +1 -1
- package/dist/as-table-actions.d.cts +1 -1
- package/dist/as-table-actions.d.mts +1 -1
- package/dist/as-table-actions.mjs +1 -1
- package/dist/{as-table-actions.vue-B-cgiCXP.d.cts → as-table-actions.vue-CoxhpIlJ.d.mts} +2 -2
- package/dist/{as-table-actions.vue-ClMa0OD1.d.mts → as-table-actions.vue-Kic8m28V.d.cts} +2 -2
- package/dist/{as-table-base-BaTE3VSN.mjs → as-table-base-BxKBdIdS.mjs} +142 -47
- package/dist/{as-table-base-RG2TEIgV.cjs → as-table-base-DLuhKz69.cjs} +142 -47
- package/dist/{as-table-cell-value-D1JkTQt0.cjs → as-table-cell-value-BAi5yadc.cjs} +2 -2
- package/dist/{as-table-cell-value-CPcFxSOj.mjs → as-table-cell-value-BVcfhhCb.mjs} +2 -2
- package/dist/as-table-cell-value.cjs +1 -1
- package/dist/as-table-cell-value.mjs +1 -1
- package/dist/{as-table-header-cell-CIqlO6Lw.cjs → as-table-header-cell-Bv6q5iKA.cjs} +2 -2
- package/dist/{as-table-header-cell-Bdhl5Lox.mjs → as-table-header-cell-Xd3cvnII.mjs} +2 -2
- package/dist/as-table-header-cell.cjs +1 -1
- package/dist/as-table-header-cell.d.cts +1 -1
- package/dist/as-table-header-cell.d.mts +1 -1
- package/dist/as-table-header-cell.mjs +1 -1
- package/dist/{as-table-header-cell.vue-BCszzxtU.d.mts → as-table-header-cell.vue-AS6u4e6v.d.cts} +2 -2
- package/dist/{as-table-header-cell.vue-BzTzfGRo.d.cts → as-table-header-cell.vue-zKOmlzhT.d.mts} +2 -2
- package/dist/{as-table-root-BLReUbRH.mjs → as-table-root-C1A6JkwL.mjs} +112 -10
- package/dist/{as-table-root-DLJ_3Jf4.cjs → as-table-root-DlYjnZax.cjs} +112 -10
- package/dist/as-table-root.cjs +1 -1
- package/dist/as-table-root.d.cts +1 -1
- package/dist/as-table-root.d.mts +1 -1
- package/dist/as-table-root.mjs +1 -1
- package/dist/{as-table-root.vue-QMT93qPk.d.mts → as-table-root.vue-CWk9YgpG.d.mts} +257 -41
- package/dist/{as-table-root.vue-D0T3n-Vm.d.cts → as-table-root.vue-D94eypcL.d.cts} +258 -42
- package/dist/{as-table-status-Du4WLF4k.cjs → as-table-status-B2HPerJT.cjs} +54 -38
- package/dist/{as-table-status-DGTZlpyq.mjs → as-table-status-QzlBdSiR.mjs} +54 -38
- package/dist/{as-table-BWUPzjRn.cjs → as-table-vJbZyZVx.cjs} +26 -8
- package/dist/as-table.cjs +1 -1
- package/dist/as-table.d.cts +1 -1
- package/dist/as-table.d.mts +1 -1
- package/dist/as-table.mjs +1 -1
- package/dist/{as-table.vue-Ds7MEp37.d.cts → as-table.vue-BB1vaNL6.d.cts} +28 -4
- package/dist/{as-table.vue-Ce5606ZO.d.mts → as-table.vue-BUDFTCpo.d.mts} +28 -4
- package/dist/{as-window-table-DWujiUQy.mjs → as-window-table-BH0tDDnr.mjs} +107 -24
- package/dist/{as-window-table-jD_y9yet.cjs → as-window-table-Bl_q72WL.cjs} +107 -24
- package/dist/as-window-table.cjs +1 -1
- package/dist/as-window-table.d.cts +1 -1
- package/dist/as-window-table.d.mts +1 -1
- package/dist/as-window-table.mjs +1 -1
- package/dist/{as-window-table.vue-DfZF1Mux.d.mts → as-window-table.vue-Be2IA0Eb.d.cts} +27 -4
- package/dist/{as-window-table.vue-Bhf9BK8E.d.cts → as-window-table.vue-CLqFM2ff.d.mts} +27 -4
- package/dist/error-message-CfKpn_5w.cjs +18 -0
- package/dist/error-message-gNEXnnbb.mjs +13 -0
- package/dist/index.cjs +237 -41
- package/dist/index.d.cts +10 -10
- package/dist/index.d.mts +10 -10
- package/dist/index.mjs +230 -43
- package/dist/{types-ByU4O0Yf.d.mts → types--ex8BJIO.d.cts} +263 -5
- package/dist/{types-CTMxE_zA.d.cts → types-CBGaTR2Z.d.mts} +263 -5
- package/dist/{use-table-CyFcVtUN.mjs → use-table-BFhbfWgY.mjs} +48 -23
- package/dist/{use-table-component-K6xj1obF.mjs → use-table-component-CRmLHdqi.mjs} +1 -1
- package/dist/{use-table-component-DO_kvKSf.cjs → use-table-component-DS5NJPzs.cjs} +1 -1
- package/dist/{use-table-nav-bridge-uOQUDooh.cjs → use-table-nav-bridge-DS14D_rG.cjs} +1 -1
- package/dist/{use-table-nav-bridge-DeGeaQX-.mjs → use-table-nav-bridge-DzJN5v9a.mjs} +1 -1
- package/dist/{use-table-nvBq1dZ4.cjs → use-table-nvuZdgUd.cjs} +51 -20
- package/dist/{use-table-state-BxX3SpeW.mjs → use-table-state-mBXx11aH.mjs} +501 -105
- package/dist/{use-table-state-Oi2ds4_a.cjs → use-table-state-mhm-YWnu.cjs} +541 -109
- package/package.json +9 -9
- package/dist/as-filters-DCZTHjf5.cjs +0 -51
- package/dist/as-filters-beIud9sF.mjs +0 -46
- package/dist/as-filters.vue-DmECMd1v.d.mts +0 -10
- package/dist/as-filters.vue-fv-tRL2H.d.cts +0 -10
- package/dist/preset-aspect-display-IICxAlVo.mjs +0 -43
- package/dist/preset-aspect-display-TWwf6j1B.cjs +0 -72
- /package/dist/{as-cell-json-popover-Dkdv5Y9E.mjs → as-cell-json-popover-CH5bAcLE.mjs} +0 -0
- /package/dist/{as-cell-json-popover-BM2QLgfk.cjs → as-cell-json-popover-vty5vMjW.cjs} +0 -0
- /package/dist/{as-column-menu-kTIQfLTi.mjs → as-column-menu-BMTS3DO2.mjs} +0 -0
- /package/dist/{as-column-menu-fZVbJ9lU.cjs → as-column-menu-D_8NxujZ.cjs} +0 -0
- /package/dist/{as-filter-input-BM23TNeh.mjs → as-filter-input-C8KmOus8.mjs} +0 -0
- /package/dist/{as-filter-input-DJu2k9gO.cjs → as-filter-input-DUqpkTkg.cjs} +0 -0
- /package/dist/{format-cell-D1Ziv96Q.mjs → format-cell-Bx7wNc4X.mjs} +0 -0
- /package/dist/{format-cell-vCNTh4WZ.cjs → format-cell-DaxV6WIJ.cjs} +0 -0
- /package/dist/{get-cell-value-4rHKP-TG.cjs → get-cell-value-CJT4fk4y.cjs} +0 -0
- /package/dist/{get-cell-value-C8LLc_Rr.mjs → get-cell-value-Cb3X8nUn.mjs} +0 -0
- /package/dist/{use-cell-locale-MQXoONh5.mjs → use-cell-locale-CxQOQsns.mjs} +0 -0
- /package/dist/{use-cell-locale-BGBRQB7s.cjs → use-cell-locale-caG2Fzpc.cjs} +0 -0
- /package/dist/{use-has-emit-listener-hhOH8CBI.cjs → use-has-emit-listener-BaGFZDyM.cjs} +0 -0
- /package/dist/{use-has-emit-listener-BTMDIv2e.mjs → use-has-emit-listener-DrBbsLHQ.mjs} +0 -0
- /package/dist/{use-seed-on-open-Dg9I89fU.cjs → use-seed-on-open-9TSm1Vbv.cjs} +0 -0
- /package/dist/{use-seed-on-open-DO3A1kIb.mjs → use-seed-on-open-DSh4XFyp.mjs} +0 -0
- /package/dist/{use-table-column-handlers-ehreEzcx.cjs → use-table-column-handlers-BMrP0WY2.cjs} +0 -0
- /package/dist/{use-table-column-handlers-CpiiIniD.mjs → use-table-column-handlers-Bx3JERqs.mjs} +0 -0
- /package/dist/{use-table-selection-Cmiu1h4S.cjs → use-table-selection-DtCV3rhu.cjs} +0 -0
- /package/dist/{use-table-selection-C84z4OZy.mjs → use-table-selection-ULbKT2xW.mjs} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { t as getCellValue } from "./get-cell-value-Cb3X8nUn.mjs";
|
|
1
2
|
import { navigateHrefFor } from "@atscript/ui";
|
|
2
3
|
import { computed, inject, nextTick, onBeforeUnmount, onScopeDispose, provide, ref, shallowRef, toValue, watch } from "vue";
|
|
3
|
-
import { STANDARD_PRESET_ID, blockStartFor, buildTableQuery, debounce, fromWireSnapshot, isDirtyAgainst, isFilled, isSystemPresetId, pageAlignedBlocksFor, planFetch, reconcileColumnWidthDefaults, resolveAspectGate, resolveSystemPresets, sameColumnSet, sortersEqual, stateToUrlQueryString, togglePk, urlQueryStringToState, walkBackwardAbsorb, walkForwardAbsorb } from "@atscript/ui-table";
|
|
4
|
+
import { STANDARD_PRESET_ID, blockStartFor, buildTableQuery, cellAsString, debounce, derivePresetAspects, fromWireSnapshot, isDirtyAgainst, isFilled, isSystemPresetId, mergeDisplayColumns, mergeSorters, pageAlignedBlocksFor, planFetch, reconcileColumnWidthDefaults, resolveAspectGate, resolveSystemPresets, rowsToPks, sameColumnSet, sortRowsLocally, sortersEqual, stateToUrlQueryString, togglePk, urlQueryStringToState, walkBackwardAbsorb, walkForwardAbsorb } from "@atscript/ui-table";
|
|
4
5
|
import { formatIdentifier } from "@atscript/db-client";
|
|
5
6
|
//#region src/types.ts
|
|
6
7
|
/** UI-side sentinel for the synthesised row-delete processor. */
|
|
@@ -43,18 +44,25 @@ function rowActionGate(row) {
|
|
|
43
44
|
return names ? gateFor(new Set(names)) : null;
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
47
|
+
* Walk a `{default, others, rows}` triple once: keep the actions `gate`
|
|
48
|
+
* admits, then run each survivor through `map`. Both are optional — with
|
|
49
|
+
* neither, the input `buckets` reference comes back unchanged so source-array
|
|
50
|
+
* references stay stable downstream (no spurious recomputes in consumers that
|
|
51
|
+
* compare array identity). Shared by the single-row (`applyRowGate`), bulk
|
|
52
|
+
* (`applyRowsGate`) and per-screen-policy paths.
|
|
51
53
|
*/
|
|
52
|
-
function applyGate(buckets, gate) {
|
|
53
|
-
if (!gate) return buckets;
|
|
54
|
+
function applyGate(buckets, gate, map) {
|
|
55
|
+
if (!gate && !map) return buckets;
|
|
56
|
+
const keep = gate ?? (() => true);
|
|
57
|
+
const walk = (list) => {
|
|
58
|
+
const kept = gate ? list.filter(keep) : list;
|
|
59
|
+
return map ? kept.map(map) : kept;
|
|
60
|
+
};
|
|
61
|
+
const def = buckets.default;
|
|
54
62
|
return {
|
|
55
|
-
default:
|
|
56
|
-
others: buckets.others
|
|
57
|
-
rows: buckets.rows
|
|
63
|
+
default: def && keep(def) ? map ? map(def) : def : void 0,
|
|
64
|
+
others: walk(buckets.others),
|
|
65
|
+
rows: walk(buckets.rows)
|
|
58
66
|
};
|
|
59
67
|
}
|
|
60
68
|
/**
|
|
@@ -281,12 +289,16 @@ async function triggerAction(state, action, ctx, event) {
|
|
|
281
289
|
if (input === null) return;
|
|
282
290
|
state.actions.invoke(action, pk, {
|
|
283
291
|
event,
|
|
284
|
-
input
|
|
292
|
+
input,
|
|
293
|
+
row: ctx.row
|
|
285
294
|
});
|
|
286
295
|
return;
|
|
287
296
|
}
|
|
288
297
|
if (!await confirmAction(state, action, ctx)) return;
|
|
289
|
-
state.actions.invoke(action, pk, {
|
|
298
|
+
state.actions.invoke(action, pk, {
|
|
299
|
+
event,
|
|
300
|
+
row: ctx.row
|
|
301
|
+
});
|
|
290
302
|
}
|
|
291
303
|
/**
|
|
292
304
|
* Pick the `pk` argument to forward to `state.actions.invoke` based on the
|
|
@@ -308,6 +320,75 @@ function idsForAction(level, pk) {
|
|
|
308
320
|
return pk === void 0 ? [] : [pk];
|
|
309
321
|
}
|
|
310
322
|
//#endregion
|
|
323
|
+
//#region src/composables/state/row-actions-config.ts
|
|
324
|
+
/** The app definition behind a client-only action, or `undefined` for a server action. */
|
|
325
|
+
function localActionOf(action) {
|
|
326
|
+
return action.$local;
|
|
327
|
+
}
|
|
328
|
+
/** Wrap an app-owned action in the descriptor shape the row-actions cell renders. */
|
|
329
|
+
function toLocalActionInfo(local) {
|
|
330
|
+
return {
|
|
331
|
+
name: local.name,
|
|
332
|
+
label: local.label,
|
|
333
|
+
level: "row",
|
|
334
|
+
processor: "custom",
|
|
335
|
+
value: "",
|
|
336
|
+
icon: local.icon,
|
|
337
|
+
intent: local.intent,
|
|
338
|
+
promptText: local.promptText,
|
|
339
|
+
$local: local
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Render-time href for a row action, whichever kind it is: a client-only
|
|
344
|
+
* action builds its own from the row — still mapped through
|
|
345
|
+
* `state.resolveHref`, so router base paths apply exactly as they do for a
|
|
346
|
+
* server `navigate` action — and a server action goes through
|
|
347
|
+
* {@link actionHref}.
|
|
348
|
+
*/
|
|
349
|
+
function rowActionHref(state, action, id, row) {
|
|
350
|
+
const local = localActionOf(action);
|
|
351
|
+
if (local) return local.href && row !== void 0 ? state.resolveHref(local.href(row)) : void 0;
|
|
352
|
+
return actionHref(state, action, id);
|
|
353
|
+
}
|
|
354
|
+
const EMPTY = Object.freeze([]);
|
|
355
|
+
/** The identity policy — used when no `RowActionsConfig` is wired. */
|
|
356
|
+
const PASS_THROUGH = {
|
|
357
|
+
apply: (buckets) => buckets,
|
|
358
|
+
extra: () => EMPTY
|
|
359
|
+
};
|
|
360
|
+
/** Compile a per-screen {@link RowActionsConfig} into a {@link RowActionsPolicy}. */
|
|
361
|
+
function compileRowActionsConfig(config) {
|
|
362
|
+
if (!config) return PASS_THROUGH;
|
|
363
|
+
const include = config.include ? new Set(config.include) : null;
|
|
364
|
+
const exclude = config.exclude ? new Set(config.exclude) : null;
|
|
365
|
+
const overrides = config.overrides;
|
|
366
|
+
const gate = (a) => (!include || include.has(a.name)) && !exclude?.has(a.name);
|
|
367
|
+
const decorate = overrides ? (action) => {
|
|
368
|
+
const patch = overrides[action.name];
|
|
369
|
+
if (!patch) return action;
|
|
370
|
+
const next = { ...action };
|
|
371
|
+
for (const key of [
|
|
372
|
+
"label",
|
|
373
|
+
"icon",
|
|
374
|
+
"intent",
|
|
375
|
+
"promptText"
|
|
376
|
+
]) {
|
|
377
|
+
const value = patch[key];
|
|
378
|
+
if (value !== void 0) next[key] = value;
|
|
379
|
+
}
|
|
380
|
+
return next;
|
|
381
|
+
} : void 0;
|
|
382
|
+
const locals = (config.extra ?? []).filter((local) => !exclude?.has(local.name));
|
|
383
|
+
return {
|
|
384
|
+
apply: (buckets) => applyGate(buckets, gate, decorate),
|
|
385
|
+
extra: (row) => {
|
|
386
|
+
if (locals.length === 0) return EMPTY;
|
|
387
|
+
return (row === void 0 ? locals : locals.filter((l) => l.enabled?.(row) !== false)).map(toLocalActionInfo);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
//#endregion
|
|
311
392
|
//#region src/composables/state/create-actions.ts
|
|
312
393
|
const REMOVE_NAME = REMOVE_PROCESSOR;
|
|
313
394
|
const REMOVE_DEFAULTS = {
|
|
@@ -340,13 +421,16 @@ function createActions(opts) {
|
|
|
340
421
|
let result;
|
|
341
422
|
try {
|
|
342
423
|
switch (action.processor) {
|
|
343
|
-
case "custom":
|
|
424
|
+
case "custom": {
|
|
425
|
+
const local = localActionOf(action);
|
|
426
|
+
if (local?.onInvoke) await local.onInvoke(callOpts?.row ?? {}, Array.isArray(pk) ? pk[0] : pk);
|
|
344
427
|
result = {
|
|
345
428
|
ok: true,
|
|
346
429
|
kind: "custom",
|
|
347
430
|
dispatched: true
|
|
348
431
|
};
|
|
349
432
|
break;
|
|
433
|
+
}
|
|
350
434
|
case "navigate":
|
|
351
435
|
await opts.client.action(action.name, pk);
|
|
352
436
|
result = {
|
|
@@ -478,7 +562,18 @@ function buildRemoveAction(opts) {
|
|
|
478
562
|
}
|
|
479
563
|
//#endregion
|
|
480
564
|
//#region src/composables/state/create-selection.ts
|
|
481
|
-
|
|
565
|
+
/** Shared verdicts — frozen, so the common case allocates nothing per row. */
|
|
566
|
+
const SELECTABLE = Object.freeze({ ok: true });
|
|
567
|
+
const NOT_SELECTABLE = Object.freeze({ ok: false });
|
|
568
|
+
/** Normalise a {@link RowSelectableHook} return value. `""` carries no reason. */
|
|
569
|
+
function verdictOf(value) {
|
|
570
|
+
if (value === void 0 || value === true) return SELECTABLE;
|
|
571
|
+
return value ? {
|
|
572
|
+
ok: false,
|
|
573
|
+
reason: value
|
|
574
|
+
} : NOT_SELECTABLE;
|
|
575
|
+
}
|
|
576
|
+
function createSelectionApi(opts, getActiveRow, activeIndex) {
|
|
482
577
|
const selectedRows = opts?.selectedRows ?? shallowRef([]);
|
|
483
578
|
const selectedCount = computed(() => selectedRows.value.length);
|
|
484
579
|
const rowValueFn = opts?.rowValueFn ?? ((row) => row);
|
|
@@ -486,10 +581,49 @@ function createSelectionApi(opts, getActiveRow) {
|
|
|
486
581
|
function isPkSelected(pk) {
|
|
487
582
|
return selectedSet.value.has(pk);
|
|
488
583
|
}
|
|
584
|
+
const rowSelectable = ref();
|
|
585
|
+
function isRowSelectable(row, index) {
|
|
586
|
+
const hook = rowSelectable.value;
|
|
587
|
+
if (!hook) return SELECTABLE;
|
|
588
|
+
return verdictOf(hook(row, {
|
|
589
|
+
index,
|
|
590
|
+
get selected() {
|
|
591
|
+
return isPkSelected(rowValueFn(row));
|
|
592
|
+
}
|
|
593
|
+
}));
|
|
594
|
+
}
|
|
595
|
+
function selectableRows(rows) {
|
|
596
|
+
if (!rowSelectable.value) return rows;
|
|
597
|
+
return rows.filter((row, index) => isRowSelectable(row, index).ok);
|
|
598
|
+
}
|
|
599
|
+
function selectableCount(rows) {
|
|
600
|
+
if (!rowSelectable.value) return rows.length;
|
|
601
|
+
let n = 0;
|
|
602
|
+
for (let i = 0; i < rows.length; i++) if (isRowSelectable(rows[i], i).ok) n++;
|
|
603
|
+
return n;
|
|
604
|
+
}
|
|
605
|
+
function selectAll(rows, indexOf) {
|
|
606
|
+
if (!rowSelectable.value) {
|
|
607
|
+
selectedRows.value = rowsToPks(rows, rowValueFn);
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const out = [];
|
|
611
|
+
const seen = /* @__PURE__ */ new Set();
|
|
612
|
+
for (let i = 0; i < rows.length; i++) {
|
|
613
|
+
const row = rows[i];
|
|
614
|
+
const pk = rowValueFn(row);
|
|
615
|
+
if (seen.has(pk)) continue;
|
|
616
|
+
if (!isRowSelectable(row, indexOf ? indexOf(i) : i).ok && !isPkSelected(pk)) continue;
|
|
617
|
+
seen.add(pk);
|
|
618
|
+
out.push(pk);
|
|
619
|
+
}
|
|
620
|
+
selectedRows.value = out;
|
|
621
|
+
}
|
|
489
622
|
function toggleActiveSelection(mode) {
|
|
490
623
|
if (mode === "none") return;
|
|
491
624
|
const row = getActiveRow();
|
|
492
625
|
if (row === void 0) return;
|
|
626
|
+
if (!isRowSelectable(row, activeIndex.value).ok) return;
|
|
493
627
|
selectedRows.value = togglePk(selectedRows.value, rowValueFn(row), mode);
|
|
494
628
|
}
|
|
495
629
|
return {
|
|
@@ -498,6 +632,11 @@ function createSelectionApi(opts, getActiveRow) {
|
|
|
498
632
|
selectedSet,
|
|
499
633
|
rowValueFn,
|
|
500
634
|
isPkSelected,
|
|
635
|
+
rowSelectable,
|
|
636
|
+
isRowSelectable,
|
|
637
|
+
selectableRows,
|
|
638
|
+
selectableCount,
|
|
639
|
+
selectAll,
|
|
501
640
|
toggleActiveSelection
|
|
502
641
|
};
|
|
503
642
|
}
|
|
@@ -551,6 +690,38 @@ function createMainActionRegistry(opts) {
|
|
|
551
690
|
}
|
|
552
691
|
//#endregion
|
|
553
692
|
//#region src/composables/state/create-nav-controller.ts
|
|
693
|
+
/**
|
|
694
|
+
* Elements that own Enter / Space (and a pointer drag) themselves.
|
|
695
|
+
* `[contenteditable]` is matched separately because `contenteditable="false"`
|
|
696
|
+
* must NOT count.
|
|
697
|
+
*/
|
|
698
|
+
const INTERACTIVE_SELECTOR = "button, a[href], input, select, textarea, summary, [role=button], [role=link], [role=checkbox], [role=menuitem], [role=switch], [role=tab], [role=option]";
|
|
699
|
+
/**
|
|
700
|
+
* True when the key event started on an interactive element inside a cell,
|
|
701
|
+
* so table nav must not consume Enter / Space. The walk runs from
|
|
702
|
+
* `event.target` up to `event.currentTarget` — the element the handler is
|
|
703
|
+
* bound on — and stops at the cell / row boundary, so a wrapper outside the
|
|
704
|
+
* table can never make a whole table inert. A handler bound ON the
|
|
705
|
+
* interactive element itself (the search-input bridge) is therefore never
|
|
706
|
+
* guarded: the walk has nothing to cross. An interactive element opts BACK
|
|
707
|
+
* IN to table nav — e.g. a cell whose button should not swallow Enter —
|
|
708
|
+
* with `data-as-nav-keys`.
|
|
709
|
+
*/
|
|
710
|
+
function isInteractiveKeyTarget(event) {
|
|
711
|
+
let el = event.target;
|
|
712
|
+
const stop = event.currentTarget;
|
|
713
|
+
while (el && el !== stop && typeof el.matches === "function") {
|
|
714
|
+
const tag = el.tagName;
|
|
715
|
+
if (tag === "TD" || tag === "TH" || tag === "TR" || tag === "TBODY" || tag === "TABLE") return false;
|
|
716
|
+
if (el.matches("button, a[href], input, select, textarea, summary, [role=button], [role=link], [role=checkbox], [role=menuitem], [role=switch], [role=tab], [role=option]") || isEditable(el)) return !el.hasAttribute("data-as-nav-keys");
|
|
717
|
+
el = el.parentElement;
|
|
718
|
+
}
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
function isEditable(el) {
|
|
722
|
+
const attr = el.getAttribute("contenteditable");
|
|
723
|
+
return attr !== null && attr !== "false";
|
|
724
|
+
}
|
|
554
725
|
function createNavController(inputs) {
|
|
555
726
|
const { activeIndex, navMode, totalCount, results, viewportRowCount, topIndex, hasMainActionAvailable, requestMainAction, toggleActiveSelection } = inputs;
|
|
556
727
|
const navViewportRowCount = ref(0);
|
|
@@ -600,6 +771,7 @@ function createNavController(inputs) {
|
|
|
600
771
|
const enterAction = opts?.enterAction ?? "main-action";
|
|
601
772
|
const mode = opts?.mode ?? "none";
|
|
602
773
|
const key = event.key;
|
|
774
|
+
const guarded = (key === "Enter" || key === " ") && isInteractiveKeyTarget(event);
|
|
603
775
|
const meta = event.metaKey;
|
|
604
776
|
const ctrl = event.ctrlKey;
|
|
605
777
|
const alt = event.altKey;
|
|
@@ -650,11 +822,13 @@ function createNavController(inputs) {
|
|
|
650
822
|
return;
|
|
651
823
|
case " ":
|
|
652
824
|
if (mode === "none") return;
|
|
825
|
+
if (guarded) return;
|
|
653
826
|
event.preventDefault();
|
|
654
827
|
toggleActiveSelection(mode);
|
|
655
828
|
return;
|
|
656
829
|
case "Enter":
|
|
657
830
|
if (enterAction === "passthrough") return;
|
|
831
|
+
if (guarded) return;
|
|
658
832
|
event.preventDefault();
|
|
659
833
|
if (enterAction === "toggle-select") {
|
|
660
834
|
toggleActiveSelection(mode);
|
|
@@ -679,6 +853,67 @@ function createNavController(inputs) {
|
|
|
679
853
|
handleNavKey
|
|
680
854
|
};
|
|
681
855
|
}
|
|
856
|
+
/**
|
|
857
|
+
* `@keydown` handler for a row's SELECTION CONTROL (the leading checkbox),
|
|
858
|
+
* shared by `<AsTableBase>` and `<AsWindowTableBase>`. The control carries
|
|
859
|
+
* `role="checkbox"`, so the tbody-level nav handler deliberately leaves
|
|
860
|
+
* Space to it (see {@link isInteractiveKeyTarget}) — this is where it lands.
|
|
861
|
+
*
|
|
862
|
+
* Keys other than Space, and `select="none"`, fall through untouched; only
|
|
863
|
+
* once the press is ours do we consume it, so the Reka-wrapped rendering
|
|
864
|
+
* modes (which never bind this handler) keep Space for their own item.
|
|
865
|
+
* Selectability is NOT re-checked here: `toggleActiveSelection` gates on
|
|
866
|
+
* `rowSelectable` itself, which is the single place that rule lives.
|
|
867
|
+
*/
|
|
868
|
+
function onSelectControlKeydown(event, index, mode, state) {
|
|
869
|
+
if (event.key !== " ") return;
|
|
870
|
+
if (mode === "none") return;
|
|
871
|
+
event.preventDefault();
|
|
872
|
+
event.stopPropagation();
|
|
873
|
+
state.setActive(index);
|
|
874
|
+
state.toggleActiveSelection(mode);
|
|
875
|
+
}
|
|
876
|
+
//#endregion
|
|
877
|
+
//#region src/composables/preset-aspect-display.ts
|
|
878
|
+
const ASPECT_LABELS = {
|
|
879
|
+
columns: "Displayed Columns",
|
|
880
|
+
filters: "Displayed Filters",
|
|
881
|
+
filterOps: "Filter conditions",
|
|
882
|
+
sorters: "Sorters",
|
|
883
|
+
itemsPerPage: "Page size"
|
|
884
|
+
};
|
|
885
|
+
const ASPECT_ICONS = {
|
|
886
|
+
columns: "i-as-columns",
|
|
887
|
+
filters: "i-as-filter",
|
|
888
|
+
filterOps: "i-as-filter-ops",
|
|
889
|
+
sorters: "i-as-sorters",
|
|
890
|
+
itemsPerPage: "i-as-pin"
|
|
891
|
+
};
|
|
892
|
+
/**
|
|
893
|
+
* Resolve the aspects a stored preset claims. Prefers the server-stamped
|
|
894
|
+
* `aspects` column (cheap), falls back to deriving from `data.content` for
|
|
895
|
+
* older rows or first paint after save before reload settles.
|
|
896
|
+
*/
|
|
897
|
+
function aspectsOf(row, availableAspects) {
|
|
898
|
+
if (Array.isArray(row.aspects) && row.aspects.length > 0) return row.aspects.filter((a) => availableAspects.includes(a));
|
|
899
|
+
const wire = row.data?.content;
|
|
900
|
+
if (!wire) return [];
|
|
901
|
+
return derivePresetAspects(wire).filter((a) => availableAspects.includes(a));
|
|
902
|
+
}
|
|
903
|
+
function readPresetLabel(row) {
|
|
904
|
+
return row.label ?? row.data?.label ?? row.id;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Display name for the row's owner. `userLabel` (server-stamped via the
|
|
908
|
+
* host's `getUserLabel` hook) is preferred so the UI shows "Alice" rather
|
|
909
|
+
* than `usr_abc123`. `fallback` is returned when no name is available —
|
|
910
|
+
* picker uses `""`, dialog uses `"—"`.
|
|
911
|
+
*/
|
|
912
|
+
function ownerNameOf(row, fallback = "") {
|
|
913
|
+
if (typeof row.userLabel === "string" && row.userLabel.length > 0) return row.userLabel;
|
|
914
|
+
if (typeof row.user === "string" && row.user.length > 0) return row.user;
|
|
915
|
+
return fallback;
|
|
916
|
+
}
|
|
682
917
|
//#endregion
|
|
683
918
|
//#region src/composables/state/create-preset-state.ts
|
|
684
919
|
const DEFAULT_AVAILABLE_ASPECTS = [
|
|
@@ -705,6 +940,26 @@ function defaultColumnPaths(o) {
|
|
|
705
940
|
function createPresetState(opts) {
|
|
706
941
|
const availableAspects = opts.availableAspects ?? DEFAULT_AVAILABLE_ASPECTS;
|
|
707
942
|
const availableSet = new Set(availableAspects);
|
|
943
|
+
const systemAspects = opts.systemAspects ? availableAspects.filter((a) => opts.systemAspects.includes(a)) : availableAspects;
|
|
944
|
+
const lastError = ref(null);
|
|
945
|
+
let trackDepth = 0;
|
|
946
|
+
/**
|
|
947
|
+
* Every public mutator runs through here: it is the one place a preset
|
|
948
|
+
* write failure is recorded. Clears `lastError` on the outermost entry,
|
|
949
|
+
* records the failure and RETHROWS so the caller can react too.
|
|
950
|
+
*/
|
|
951
|
+
async function track(fn) {
|
|
952
|
+
if (trackDepth === 0) lastError.value = null;
|
|
953
|
+
trackDepth++;
|
|
954
|
+
try {
|
|
955
|
+
return await fn();
|
|
956
|
+
} catch (err) {
|
|
957
|
+
lastError.value = err instanceof Error ? err : new Error(String(err));
|
|
958
|
+
throw err;
|
|
959
|
+
} finally {
|
|
960
|
+
trackDepth--;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
708
963
|
const dialogOpen = ref(false);
|
|
709
964
|
const gate = ref(false);
|
|
710
965
|
const ready = computed(() => opts.presetsHandle ? gate.value : true);
|
|
@@ -795,6 +1050,20 @@ function createPresetState(opts) {
|
|
|
795
1050
|
if (!mask) return true;
|
|
796
1051
|
return mask[aspect] === true;
|
|
797
1052
|
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Aspects the preset `id` OWNS, i.e. the ones applying it may write:
|
|
1055
|
+
* a system preset owns `systemAspects`, a stored preset owns what its
|
|
1056
|
+
* snapshot claims, and "no preset" (a raw snapshot, or an id with no row)
|
|
1057
|
+
* owns everything available. The one answer every aspect-scoped surface
|
|
1058
|
+
* asks for — apply, system-snapshot expansion, the picker badges and
|
|
1059
|
+
* Save-as mask, the manage dialog rows.
|
|
1060
|
+
*/
|
|
1061
|
+
function ownedAspects(id) {
|
|
1062
|
+
if (!id) return availableAspects;
|
|
1063
|
+
if (isSystemPresetId(id)) return systemAspects;
|
|
1064
|
+
const row = presetsById.value.get(id);
|
|
1065
|
+
return row ? aspectsOf(row, availableAspects) : availableAspects;
|
|
1066
|
+
}
|
|
798
1067
|
function captureSnapshot(mask) {
|
|
799
1068
|
const out = {};
|
|
800
1069
|
for (const aspect of availableAspects) {
|
|
@@ -834,7 +1103,7 @@ function createPresetState(opts) {
|
|
|
834
1103
|
function apply(idOrSnapshot) {
|
|
835
1104
|
const { snapshot, nextActiveId } = resolveSnapshot(idOrSnapshot);
|
|
836
1105
|
const isSystem = typeof idOrSnapshot === "string" && nextActiveId !== null && isSystemPresetId(nextActiveId);
|
|
837
|
-
for (const aspect of
|
|
1106
|
+
for (const aspect of ownedAspects(nextActiveId)) {
|
|
838
1107
|
const value = snapshot[aspect];
|
|
839
1108
|
ASPECT_HANDLERS[aspect].apply(opts, value, isSystem);
|
|
840
1109
|
}
|
|
@@ -860,9 +1129,12 @@ function createPresetState(opts) {
|
|
|
860
1129
|
* "claims all aspects in `availableAspects`" per spec §3.7. Stored presets
|
|
861
1130
|
* keep dict-form opt-in (untouched).
|
|
862
1131
|
*/
|
|
863
|
-
function expandSystemSnapshot(snapshot) {
|
|
864
|
-
const out = {
|
|
865
|
-
|
|
1132
|
+
function expandSystemSnapshot(snapshot, id) {
|
|
1133
|
+
const out = {};
|
|
1134
|
+
const owned = ownedAspects(id);
|
|
1135
|
+
const ownedSet = new Set(owned);
|
|
1136
|
+
for (const [key, value] of Object.entries(snapshot)) if (ownedSet.has(key)) out[key] = value;
|
|
1137
|
+
for (const aspect of owned) {
|
|
866
1138
|
const handler = ASPECT_HANDLERS[aspect];
|
|
867
1139
|
if (!handler.expandDefault) continue;
|
|
868
1140
|
if (out[aspect] !== void 0) continue;
|
|
@@ -873,7 +1145,7 @@ function createPresetState(opts) {
|
|
|
873
1145
|
const activeSnapshot = computed(() => {
|
|
874
1146
|
const id = activeId.value;
|
|
875
1147
|
if (!id) return {};
|
|
876
|
-
if (isSystemPresetId(id)) return expandSystemSnapshot(systemPresetsById.value.get(id)?.content ?? {});
|
|
1148
|
+
if (isSystemPresetId(id)) return expandSystemSnapshot(systemPresetsById.value.get(id)?.content ?? {}, id);
|
|
877
1149
|
const row = presetsById.value.get(id);
|
|
878
1150
|
if (!row) return {};
|
|
879
1151
|
const wire = row.data?.content;
|
|
@@ -884,48 +1156,64 @@ function createPresetState(opts) {
|
|
|
884
1156
|
if (!opts.presetsHandle) throw new Error("[vue-table] presets feature not configured (preset.url missing)");
|
|
885
1157
|
return opts.presetsHandle;
|
|
886
1158
|
}
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
}
|
|
898
|
-
async function saveAs(label, saveOpts = {}) {
|
|
899
|
-
const id = await requirePresets().savePresetAs(label, captureSnapshot(saveOpts.aspects), { public: saveOpts.public });
|
|
900
|
-
clearLocalDraft();
|
|
901
|
-
return id;
|
|
902
|
-
}
|
|
903
|
-
async function rename(id, label) {
|
|
904
|
-
await requirePresets().renamePreset(id, label);
|
|
905
|
-
}
|
|
906
|
-
async function remove(id) {
|
|
907
|
-
const handle = requirePresets();
|
|
908
|
-
const wasActive = activeId.value === id;
|
|
909
|
-
await handle.deletePreset(id);
|
|
910
|
-
if (wasActive) {
|
|
911
|
-
apply(STANDARD_PRESET_ID);
|
|
1159
|
+
function saveActive() {
|
|
1160
|
+
return track(async () => {
|
|
1161
|
+
const handle = requirePresets();
|
|
1162
|
+
const id = activeId.value;
|
|
1163
|
+
if (!id) throw new Error("[vue-table] saveActive: no active preset");
|
|
1164
|
+
if (isSystemPresetId(id)) throw new Error("[vue-table] saveActive: system presets cannot be overwritten");
|
|
1165
|
+
const existing = activeSnapshot.value;
|
|
1166
|
+
const mask = {};
|
|
1167
|
+
for (const aspect of availableAspects) if (existing[aspect] !== void 0) mask[aspect] = true;
|
|
1168
|
+
await handle.savePreset(captureSnapshot(mask));
|
|
912
1169
|
clearLocalDraft();
|
|
913
|
-
}
|
|
1170
|
+
});
|
|
914
1171
|
}
|
|
915
|
-
|
|
916
|
-
|
|
1172
|
+
function saveAs(label, saveOpts = {}) {
|
|
1173
|
+
return track(async () => {
|
|
1174
|
+
const id = await requirePresets().savePresetAs(label, captureSnapshot(saveOpts.aspects), { public: saveOpts.public });
|
|
1175
|
+
clearLocalDraft();
|
|
1176
|
+
return id;
|
|
1177
|
+
});
|
|
917
1178
|
}
|
|
918
|
-
|
|
919
|
-
|
|
1179
|
+
function rename(id, label) {
|
|
1180
|
+
return track(async () => {
|
|
1181
|
+
await requirePresets().renamePreset(id, label);
|
|
1182
|
+
});
|
|
920
1183
|
}
|
|
921
|
-
|
|
922
|
-
|
|
1184
|
+
function remove(id) {
|
|
1185
|
+
return track(async () => {
|
|
1186
|
+
const handle = requirePresets();
|
|
1187
|
+
const wasActive = activeId.value === id;
|
|
1188
|
+
await handle.deletePreset(id);
|
|
1189
|
+
if (wasActive) {
|
|
1190
|
+
apply(STANDARD_PRESET_ID);
|
|
1191
|
+
clearLocalDraft();
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
923
1194
|
}
|
|
924
|
-
|
|
925
|
-
|
|
1195
|
+
function togglePublic(id) {
|
|
1196
|
+
return track(async () => {
|
|
1197
|
+
await requirePresets().togglePublic(id);
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
function setDefault(id) {
|
|
1201
|
+
return track(async () => {
|
|
1202
|
+
await requirePresets().setDefault(id);
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
function toggleFav(id) {
|
|
1206
|
+
return track(async () => {
|
|
1207
|
+
await requirePresets().toggleFav(id);
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
function setFavorites(ids) {
|
|
1211
|
+
return track(async () => {
|
|
1212
|
+
await requirePresets().setFavorites(ids);
|
|
1213
|
+
});
|
|
926
1214
|
}
|
|
927
1215
|
function batch(fn) {
|
|
928
|
-
return opts.presetsHandle ? opts.presetsHandle.batch(fn) : fn();
|
|
1216
|
+
return track(() => opts.presetsHandle ? opts.presetsHandle.batch(fn) : fn());
|
|
929
1217
|
}
|
|
930
1218
|
function resolveDefaultId() {
|
|
931
1219
|
const pinned = (userConf.value?.data)?.defaultPresetId;
|
|
@@ -941,7 +1229,7 @@ function createPresetState(opts) {
|
|
|
941
1229
|
stop();
|
|
942
1230
|
const id = resolveDefaultId();
|
|
943
1231
|
const { snapshot, nextActiveId } = resolveSnapshot(id);
|
|
944
|
-
const base = isSystemPresetId(id) ? expandSystemSnapshot(snapshot) : snapshot;
|
|
1232
|
+
const base = isSystemPresetId(id) ? expandSystemSnapshot(snapshot, id) : snapshot;
|
|
945
1233
|
const draftEnabled = !!(opts.draftHandle && opts.persistDrafts);
|
|
946
1234
|
apply(draftEnabled ? opts.draftHandle.hydrate(base) : base);
|
|
947
1235
|
activeId.value = nextActiveId;
|
|
@@ -960,6 +1248,8 @@ function createPresetState(opts) {
|
|
|
960
1248
|
systemPresets,
|
|
961
1249
|
systemPresetsById,
|
|
962
1250
|
availableAspects,
|
|
1251
|
+
systemAspects,
|
|
1252
|
+
ownedAspects,
|
|
963
1253
|
available,
|
|
964
1254
|
activeId,
|
|
965
1255
|
activeSnapshot,
|
|
@@ -982,7 +1272,8 @@ function createPresetState(opts) {
|
|
|
982
1272
|
setDefault,
|
|
983
1273
|
toggleFav,
|
|
984
1274
|
setFavorites,
|
|
985
|
-
batch
|
|
1275
|
+
batch,
|
|
1276
|
+
lastError
|
|
986
1277
|
},
|
|
987
1278
|
internals: {
|
|
988
1279
|
gate,
|
|
@@ -1233,17 +1524,21 @@ const DEFAULT_BLOCK_SIZE = 100;
|
|
|
1233
1524
|
const DEFAULT_DRAG_RELEASE_DEBOUNCE_MS = 300;
|
|
1234
1525
|
const DEFAULT_ITEMS_PER_PAGE = 25;
|
|
1235
1526
|
let _tblUid = 0;
|
|
1527
|
+
/** Shared empty sorter list — keeps `splitSorters` identity-stable. */
|
|
1528
|
+
const EMPTY_SORTERS = Object.freeze([]);
|
|
1236
1529
|
/**
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1240
|
-
* scope so it's not recreated on every fetch.
|
|
1530
|
+
* Build the value reader used for in-memory sorting: a display column's
|
|
1531
|
+
* `sortValue(row)` wins for its own key, everything else reads the row by
|
|
1532
|
+
* path. Returns `getCellValue` itself when no display column defines one.
|
|
1241
1533
|
*/
|
|
1242
|
-
function
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
if (
|
|
1246
|
-
return
|
|
1534
|
+
function createSortValueReader(display) {
|
|
1535
|
+
const map = /* @__PURE__ */ new Map();
|
|
1536
|
+
for (const d of display ?? []) if (d.sortValue) map.set(d.key, d.sortValue);
|
|
1537
|
+
if (map.size === 0) return getCellValue;
|
|
1538
|
+
return (row, field) => {
|
|
1539
|
+
const fn = map.get(field);
|
|
1540
|
+
return fn ? fn(row) : getCellValue(row, field);
|
|
1541
|
+
};
|
|
1247
1542
|
}
|
|
1248
1543
|
/**
|
|
1249
1544
|
* Promise-based dialog slot. A second `request()` while one is open
|
|
@@ -1252,17 +1547,20 @@ function cellAsString(v) {
|
|
|
1252
1547
|
*/
|
|
1253
1548
|
function createRequestSlot(cancelValue) {
|
|
1254
1549
|
const r = shallowRef(null);
|
|
1550
|
+
const display = shallowRef(null);
|
|
1255
1551
|
function request(body) {
|
|
1256
1552
|
if (r.value) {
|
|
1257
1553
|
r.value.resolve(cancelValue);
|
|
1258
1554
|
r.value = null;
|
|
1259
1555
|
}
|
|
1260
|
-
|
|
1556
|
+
const promise = new Promise((resolve) => {
|
|
1261
1557
|
r.value = {
|
|
1262
1558
|
...body,
|
|
1263
1559
|
resolve
|
|
1264
1560
|
};
|
|
1265
1561
|
});
|
|
1562
|
+
display.value = r.value;
|
|
1563
|
+
return promise;
|
|
1266
1564
|
}
|
|
1267
1565
|
function accept(value) {
|
|
1268
1566
|
const req = r.value;
|
|
@@ -1276,11 +1574,16 @@ function createRequestSlot(cancelValue) {
|
|
|
1276
1574
|
r.value = null;
|
|
1277
1575
|
req.resolve(cancelValue);
|
|
1278
1576
|
}
|
|
1577
|
+
function release() {
|
|
1578
|
+
if (r.value === null) display.value = null;
|
|
1579
|
+
}
|
|
1279
1580
|
return {
|
|
1280
1581
|
ref: r,
|
|
1582
|
+
display,
|
|
1281
1583
|
request,
|
|
1282
1584
|
accept,
|
|
1283
|
-
dismiss
|
|
1585
|
+
dismiss,
|
|
1586
|
+
release
|
|
1284
1587
|
};
|
|
1285
1588
|
}
|
|
1286
1589
|
function createTableState(opts) {
|
|
@@ -1311,6 +1614,13 @@ function createTableState(opts) {
|
|
|
1311
1614
|
});
|
|
1312
1615
|
const rowDelete = ref(false);
|
|
1313
1616
|
const includeActions = ref(false);
|
|
1617
|
+
const rowActions = ref(void 0);
|
|
1618
|
+
/**
|
|
1619
|
+
* The per-screen row-action policy, compiled once per config change instead
|
|
1620
|
+
* of once per row per render — and read by every surface that renders row
|
|
1621
|
+
* actions, so the cell and the selection toolbar can't drift apart.
|
|
1622
|
+
*/
|
|
1623
|
+
const rowActionsPolicy = computed(() => compileRowActionsConfig(rowActions.value));
|
|
1314
1624
|
const filters = shallowRef({});
|
|
1315
1625
|
const results = shallowRef([]);
|
|
1316
1626
|
const resultsStart = ref(0);
|
|
@@ -1360,6 +1670,7 @@ function createTableState(opts) {
|
|
|
1360
1670
|
presetsHandle: opts.preset?.presetsHandle,
|
|
1361
1671
|
draftHandle: opts.preset?.draftHandle,
|
|
1362
1672
|
availableAspects: opts.preset?.availableAspects,
|
|
1673
|
+
systemAspects: opts.preset?.systemAspects,
|
|
1363
1674
|
persistDrafts: opts.preset?.persistDrafts,
|
|
1364
1675
|
fallbackSystemPresets: opts.preset?.fallbackSystemPresets
|
|
1365
1676
|
});
|
|
@@ -1372,8 +1683,10 @@ function createTableState(opts) {
|
|
|
1372
1683
|
message
|
|
1373
1684
|
});
|
|
1374
1685
|
}
|
|
1686
|
+
const confirmDisplay = promptSlot.display;
|
|
1375
1687
|
const acceptPrompt = () => promptSlot.accept(true);
|
|
1376
1688
|
const dismissPrompt = promptSlot.dismiss;
|
|
1689
|
+
const releaseConfirm = promptSlot.release;
|
|
1377
1690
|
const formSlot = createRequestSlot(null);
|
|
1378
1691
|
const actionFormRequest = formSlot.ref;
|
|
1379
1692
|
function requestActionInput(action, ctx) {
|
|
@@ -1383,8 +1696,10 @@ function createTableState(opts) {
|
|
|
1383
1696
|
preferredId: ctx.preferredId
|
|
1384
1697
|
});
|
|
1385
1698
|
}
|
|
1699
|
+
const actionFormDisplay = formSlot.display;
|
|
1386
1700
|
const acceptActionForm = formSlot.accept;
|
|
1387
1701
|
const dismissActionForm = formSlot.dismiss;
|
|
1702
|
+
const releaseActionForm = formSlot.release;
|
|
1388
1703
|
const stateUid = `tbl-${++_tblUid}`;
|
|
1389
1704
|
function rowId(absIndex) {
|
|
1390
1705
|
return `${stateUid}-row-${absIndex}`;
|
|
@@ -1392,23 +1707,65 @@ function createTableState(opts) {
|
|
|
1392
1707
|
let generation = 0;
|
|
1393
1708
|
let queryDetected = false;
|
|
1394
1709
|
let skipPaginationWatch = 0;
|
|
1395
|
-
|
|
1710
|
+
/**
|
|
1711
|
+
* Paths of client-owned columns — they have no server field behind them, so
|
|
1712
|
+
* they are stripped from `$select` and from `$sort`. Recomputed only when
|
|
1713
|
+
* the column set changes.
|
|
1714
|
+
*/
|
|
1715
|
+
const localColumnPaths = computed(() => {
|
|
1716
|
+
const out = /* @__PURE__ */ new Set();
|
|
1717
|
+
for (const c of allColumns.value) if (c.local) out.add(c.path);
|
|
1718
|
+
return out;
|
|
1719
|
+
});
|
|
1720
|
+
/**
|
|
1721
|
+
* The active sorters split by who applies them: `server` goes into `$sort`,
|
|
1722
|
+
* `local` targets a client-owned column and is applied in memory. One pass,
|
|
1723
|
+
* one dependency — the two halves are complements.
|
|
1724
|
+
*/
|
|
1725
|
+
const splitSorters = computed(() => {
|
|
1726
|
+
const paths = localColumnPaths.value;
|
|
1727
|
+
if (paths.size === 0) return {
|
|
1728
|
+
local: EMPTY_SORTERS,
|
|
1729
|
+
server: sorters.value
|
|
1730
|
+
};
|
|
1731
|
+
const local = [];
|
|
1732
|
+
const server = [];
|
|
1733
|
+
for (const s of sorters.value) (paths.has(s.field) ? local : server).push(s);
|
|
1734
|
+
return {
|
|
1735
|
+
local,
|
|
1736
|
+
server
|
|
1737
|
+
};
|
|
1738
|
+
});
|
|
1739
|
+
/** `true` while the query deliberately drops user sorters to keep search relevance. */
|
|
1740
|
+
function sortersIgnored() {
|
|
1741
|
+
return ignoreSortersWhenSearched.value && !!searchTerm.value;
|
|
1742
|
+
}
|
|
1743
|
+
/** Reads the value a sorter orders by — a display column's `sortValue` wins. */
|
|
1744
|
+
const sortValueOf = createSortValueReader(opts.displayColumns);
|
|
1745
|
+
function applyLocalSort(rows) {
|
|
1746
|
+
if (queryOpts?.preSorted) return rows;
|
|
1747
|
+
if (splitSorters.value.local.length === 0 || sortersIgnored()) return rows;
|
|
1748
|
+
return sortRowsLocally(rows, queryOpts?.forceSorters?.length ? mergeSorters(queryOpts.forceSorters, sorters.value) : sorters.value, sortValueOf);
|
|
1749
|
+
}
|
|
1750
|
+
function buildCurrentQuery(buildOpts) {
|
|
1396
1751
|
const available = tableDef.value?.fetchableFields ?? new Set(allColumns.value.map((c) => c.path));
|
|
1397
1752
|
const extra = /* @__PURE__ */ new Set();
|
|
1398
1753
|
for (const c of columns.value) for (const p of c.selectWith ?? []) if (available.has(p)) extra.add(p);
|
|
1399
1754
|
if (queryOpts?.alwaysSelected) {
|
|
1400
1755
|
for (const p of queryOpts.alwaysSelected) if (available.has(p)) extra.add(p);
|
|
1401
1756
|
}
|
|
1757
|
+
const localPaths = localColumnPaths.value;
|
|
1758
|
+
const requested = buildOpts?.columnPaths ?? columnNames.value;
|
|
1402
1759
|
return buildTableQuery({
|
|
1403
|
-
visibleColumnPaths:
|
|
1760
|
+
visibleColumnPaths: localPaths.size ? requested.filter((p) => !localPaths.has(p)) : requested,
|
|
1404
1761
|
extraSelect: extra.size ? [...extra] : void 0,
|
|
1405
|
-
sorters:
|
|
1762
|
+
sorters: splitSorters.value.server,
|
|
1406
1763
|
forceSorters: queryOpts?.forceSorters,
|
|
1407
1764
|
filters: filters.value,
|
|
1408
1765
|
forceFilters: queryOpts?.forceFilters,
|
|
1409
1766
|
search: searchTerm.value || void 0,
|
|
1410
|
-
ignoreSorters:
|
|
1411
|
-
includeActions: includeActions.value
|
|
1767
|
+
ignoreSorters: sortersIgnored(),
|
|
1768
|
+
includeActions: buildOpts?.includeActions ?? includeActions.value
|
|
1412
1769
|
});
|
|
1413
1770
|
}
|
|
1414
1771
|
function dispatchPages(query, page, size) {
|
|
@@ -1426,6 +1783,10 @@ function createTableState(opts) {
|
|
|
1426
1783
|
/** -1 == nothing active. */
|
|
1427
1784
|
const activeIndex = ref(-1);
|
|
1428
1785
|
const navMode = ref("pagination");
|
|
1786
|
+
const isQueryBlocked = computed(() => {
|
|
1787
|
+
const blocked = queryOpts?.blockQuery;
|
|
1788
|
+
return typeof blocked === "function" ? !!blocked() : !!blocked;
|
|
1789
|
+
});
|
|
1429
1790
|
const { windowCache, windowLoading, errors, topIndex, viewportRowCount, dataAt, loadingAt, errorAt, loadRange, queryNext, clearSettlements, resetWindow, disposeDebounces } = createWindowFetcher({
|
|
1430
1791
|
blockSize,
|
|
1431
1792
|
dragReleaseDebounceMs,
|
|
@@ -1435,7 +1796,7 @@ function createTableState(opts) {
|
|
|
1435
1796
|
resultsStart,
|
|
1436
1797
|
queryingNext,
|
|
1437
1798
|
getGeneration: () => generation,
|
|
1438
|
-
isQueryBlocked: () =>
|
|
1799
|
+
isQueryBlocked: () => isQueryBlocked.value,
|
|
1439
1800
|
buildCurrentQuery,
|
|
1440
1801
|
dispatchPages,
|
|
1441
1802
|
reportError
|
|
@@ -1445,7 +1806,7 @@ function createTableState(opts) {
|
|
|
1445
1806
|
if (idx < 0) return void 0;
|
|
1446
1807
|
return navMode.value === "window" ? dataAt(idx) : results.value[idx];
|
|
1447
1808
|
}
|
|
1448
|
-
const { selectedRows, selectedCount, rowValueFn, isPkSelected, toggleActiveSelection } = createSelectionApi(selectionOpts, getActiveRow);
|
|
1809
|
+
const { selectedRows, selectedCount, rowValueFn, isPkSelected, rowSelectable, isRowSelectable, selectableRows, selectableCount, selectAll, toggleActiveSelection } = createSelectionApi(selectionOpts, getActiveRow, activeIndex);
|
|
1449
1810
|
const { actions } = createActions({
|
|
1450
1811
|
tableDef,
|
|
1451
1812
|
client,
|
|
@@ -1481,7 +1842,7 @@ function createTableState(opts) {
|
|
|
1481
1842
|
toggleActiveSelection
|
|
1482
1843
|
});
|
|
1483
1844
|
async function runQuery(kind, silent = false) {
|
|
1484
|
-
if (
|
|
1845
|
+
if (isQueryBlocked.value) return;
|
|
1485
1846
|
mustRefresh.value = false;
|
|
1486
1847
|
if (!silent && kind !== "initial" && topIndex.value !== 0) topIndex.value = 0;
|
|
1487
1848
|
const thisGen = ++generation;
|
|
@@ -1522,7 +1883,7 @@ function createTableState(opts) {
|
|
|
1522
1883
|
let pendingSilent = true;
|
|
1523
1884
|
let queryFlushScheduled = false;
|
|
1524
1885
|
function scheduleQuery(kind = "query", opts) {
|
|
1525
|
-
if (
|
|
1886
|
+
if (isQueryBlocked.value) return;
|
|
1526
1887
|
if (tableDef.value === null) return;
|
|
1527
1888
|
pendingScheduledKind = pendingScheduledKind ?? kind;
|
|
1528
1889
|
if (!(opts?.silent ?? false)) {
|
|
@@ -1552,7 +1913,7 @@ function createTableState(opts) {
|
|
|
1552
1913
|
async function queryImmediate(opts) {
|
|
1553
1914
|
pendingScheduledKind = null;
|
|
1554
1915
|
pendingSilent = true;
|
|
1555
|
-
if (
|
|
1916
|
+
if (isQueryBlocked.value) return;
|
|
1556
1917
|
if (tableDef.value === null) return;
|
|
1557
1918
|
await runQuery("query", opts?.silent ?? false);
|
|
1558
1919
|
}
|
|
@@ -1610,7 +1971,13 @@ function createTableState(opts) {
|
|
|
1610
1971
|
rowValueFn,
|
|
1611
1972
|
resolveHref: opts.actions?.resolveHref ?? ((url) => url),
|
|
1612
1973
|
isPkSelected,
|
|
1974
|
+
rowSelectable,
|
|
1975
|
+
isRowSelectable,
|
|
1976
|
+
selectableRows,
|
|
1977
|
+
selectableCount,
|
|
1978
|
+
selectAll,
|
|
1613
1979
|
rowDelete,
|
|
1980
|
+
rowActions,
|
|
1614
1981
|
includeActions,
|
|
1615
1982
|
activeIndex,
|
|
1616
1983
|
navMode,
|
|
@@ -1625,18 +1992,27 @@ function createTableState(opts) {
|
|
|
1625
1992
|
registerMainActionListener,
|
|
1626
1993
|
actions,
|
|
1627
1994
|
confirmRequest,
|
|
1995
|
+
confirmDisplay,
|
|
1628
1996
|
prompt: promptFn,
|
|
1629
1997
|
acceptPrompt,
|
|
1630
1998
|
dismissPrompt,
|
|
1999
|
+
releaseConfirm,
|
|
1631
2000
|
actionFormRequest,
|
|
2001
|
+
actionFormDisplay,
|
|
1632
2002
|
requestActionInput,
|
|
1633
2003
|
acceptActionForm,
|
|
1634
2004
|
dismissActionForm,
|
|
2005
|
+
releaseActionForm,
|
|
1635
2006
|
query,
|
|
1636
2007
|
queryImmediate,
|
|
1637
2008
|
queryNext,
|
|
1638
2009
|
loadRange,
|
|
1639
2010
|
invalidate,
|
|
2011
|
+
buildQuery: buildCurrentQuery,
|
|
2012
|
+
fetchPage: dispatchPages,
|
|
2013
|
+
localColumnPaths,
|
|
2014
|
+
applyLocalSort,
|
|
2015
|
+
rowActionsPolicy,
|
|
1640
2016
|
dataAt,
|
|
1641
2017
|
loadingAt,
|
|
1642
2018
|
errorAt,
|
|
@@ -1777,7 +2153,7 @@ function createTableState(opts) {
|
|
|
1777
2153
|
lastEmittedUrl = serializeStateForUrl();
|
|
1778
2154
|
nextTick(() => {
|
|
1779
2155
|
hydratingFromUrl = false;
|
|
1780
|
-
if (wasQueryDetected && !
|
|
2156
|
+
if (wasQueryDetected && !isQueryBlocked.value && tableDef.value !== null) scheduleQuery();
|
|
1781
2157
|
});
|
|
1782
2158
|
}
|
|
1783
2159
|
const debouncedFilterQuery = debounce(() => {
|
|
@@ -1795,6 +2171,11 @@ function createTableState(opts) {
|
|
|
1795
2171
|
if (sortersEqual(prev, next)) return;
|
|
1796
2172
|
if (searchTerm.value) setIgnoreSortersInternal(false);
|
|
1797
2173
|
if (!queryDetected) return;
|
|
2174
|
+
const paths = localColumnPaths.value;
|
|
2175
|
+
if (paths.size > 0) {
|
|
2176
|
+
const keep = (s) => !paths.has(s.field);
|
|
2177
|
+
if (sortersEqual(prev.filter(keep), next.filter(keep))) return;
|
|
2178
|
+
}
|
|
1798
2179
|
requestRefresh();
|
|
1799
2180
|
}, { immediate: false });
|
|
1800
2181
|
watch(() => searchTerm.value, (next, prev) => {
|
|
@@ -1838,9 +2219,11 @@ function createTableState(opts) {
|
|
|
1838
2219
|
watch([
|
|
1839
2220
|
() => tableDef.value,
|
|
1840
2221
|
() => queryOpts?.urlQueryReady?.value ?? true,
|
|
1841
|
-
presetGateOpen
|
|
1842
|
-
|
|
2222
|
+
presetGateOpen,
|
|
2223
|
+
() => isQueryBlocked.value
|
|
2224
|
+
], ([def, urlReady, presetReady, blocked]) => {
|
|
1843
2225
|
if (queryDetected) return;
|
|
2226
|
+
if (blocked) return;
|
|
1844
2227
|
if (def === null || !urlReady || !presetReady) return;
|
|
1845
2228
|
if (queryOpts?.queryOnMount === false) return;
|
|
1846
2229
|
if (allColumns.value.length === 0) return;
|
|
@@ -1848,6 +2231,11 @@ function createTableState(opts) {
|
|
|
1848
2231
|
queryDetected = true;
|
|
1849
2232
|
scheduleQuery("initial");
|
|
1850
2233
|
});
|
|
2234
|
+
watch(() => isQueryBlocked.value, (blocked) => {
|
|
2235
|
+
if (blocked || !queryDetected) return;
|
|
2236
|
+
if (tableDef.value === null) return;
|
|
2237
|
+
scheduleQuery();
|
|
2238
|
+
});
|
|
1851
2239
|
onScopeDispose(() => {
|
|
1852
2240
|
debouncedFilterQuery.cancel();
|
|
1853
2241
|
disposeDebounces();
|
|
@@ -1858,10 +2246,11 @@ function createTableState(opts) {
|
|
|
1858
2246
|
state,
|
|
1859
2247
|
internals: {
|
|
1860
2248
|
init(def) {
|
|
1861
|
-
|
|
1862
|
-
|
|
2249
|
+
const merged = mergeDisplayColumns(def.columns, opts.displayColumns ?? []);
|
|
2250
|
+
allColumns.value = merged;
|
|
2251
|
+
const reconciled = reconcileColumnWidthDefaults(merged, columnWidths.value);
|
|
1863
2252
|
if (reconciled !== columnWidths.value) columnWidths.value = reconciled;
|
|
1864
|
-
if (columnNames.value.length === 0) columnNames.value =
|
|
2253
|
+
if (columnNames.value.length === 0) columnNames.value = merged.map((c) => c.path);
|
|
1865
2254
|
tableDef.value = def;
|
|
1866
2255
|
},
|
|
1867
2256
|
resetPagination
|
|
@@ -1875,6 +2264,7 @@ function createTableState(opts) {
|
|
|
1875
2264
|
*/
|
|
1876
2265
|
function createStaticTableState(opts) {
|
|
1877
2266
|
let _state = null;
|
|
2267
|
+
let fetcher = null;
|
|
1878
2268
|
const queryFn = (q, page, size) => {
|
|
1879
2269
|
if (!_state) return Promise.resolve({
|
|
1880
2270
|
data: [],
|
|
@@ -1883,13 +2273,21 @@ function createStaticTableState(opts) {
|
|
|
1883
2273
|
itemsPerPage: size,
|
|
1884
2274
|
pages: 1
|
|
1885
2275
|
});
|
|
1886
|
-
|
|
2276
|
+
fetcher ??= buildStaticQueryFn(opts, _state);
|
|
2277
|
+
return fetcher(q, page, size);
|
|
1887
2278
|
};
|
|
1888
2279
|
const result = createTableState({
|
|
1889
2280
|
client: {},
|
|
1890
2281
|
selection: opts.selection,
|
|
1891
2282
|
limit: opts.limit,
|
|
1892
|
-
|
|
2283
|
+
displayColumns: opts.displayColumns,
|
|
2284
|
+
model: opts.model,
|
|
2285
|
+
actions: opts.actions,
|
|
2286
|
+
query: {
|
|
2287
|
+
fn: queryFn,
|
|
2288
|
+
queryOnMount: opts.queryOnMount,
|
|
2289
|
+
preSorted: true
|
|
2290
|
+
}
|
|
1893
2291
|
});
|
|
1894
2292
|
_state = result.state;
|
|
1895
2293
|
result.state.loadingMetadata.value = false;
|
|
@@ -1921,26 +2319,24 @@ function createStaticTableState(opts) {
|
|
|
1921
2319
|
}
|
|
1922
2320
|
function buildStaticQueryFn(opts, state) {
|
|
1923
2321
|
const searchPaths = opts.searchPaths ?? [];
|
|
2322
|
+
const sortValueOf = createSortValueReader(opts.displayColumns);
|
|
2323
|
+
let sortedFrom = null;
|
|
2324
|
+
let sortedBy = null;
|
|
2325
|
+
let sorted = [];
|
|
2326
|
+
function sortedRows(all) {
|
|
2327
|
+
const by = state.sorters.value;
|
|
2328
|
+
if (all !== sortedFrom || by !== sortedBy) {
|
|
2329
|
+
sorted = sortRowsLocally(all, by, sortValueOf);
|
|
2330
|
+
sortedFrom = all;
|
|
2331
|
+
sortedBy = by;
|
|
2332
|
+
}
|
|
2333
|
+
return sorted;
|
|
2334
|
+
}
|
|
1924
2335
|
return (_query, page, size) => {
|
|
1925
|
-
|
|
2336
|
+
const all = toValue(opts.rows);
|
|
2337
|
+
let filtered = opts.localSort === false ? all : sortedRows(all);
|
|
1926
2338
|
const term = state.searchTerm.value.trim().toLowerCase();
|
|
1927
|
-
if (term && searchPaths.length > 0) filtered = filtered.filter((row) => searchPaths.some((p) => cellAsString(row
|
|
1928
|
-
const active = state.sorters.value;
|
|
1929
|
-
if (active.length > 0) filtered = filtered.toSorted((a, b) => {
|
|
1930
|
-
for (const s of active) {
|
|
1931
|
-
const dir = s.direction === "desc" ? -1 : 1;
|
|
1932
|
-
const av = a[s.field];
|
|
1933
|
-
const bv = b[s.field];
|
|
1934
|
-
if (typeof av === "number" && typeof bv === "number") {
|
|
1935
|
-
if (av < bv) return -dir;
|
|
1936
|
-
if (av > bv) return dir;
|
|
1937
|
-
} else {
|
|
1938
|
-
const cmp = cellAsString(av).localeCompare(cellAsString(bv));
|
|
1939
|
-
if (cmp !== 0) return cmp * dir;
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
return 0;
|
|
1943
|
-
});
|
|
2339
|
+
if (term && searchPaths.length > 0) filtered = filtered.filter((row) => searchPaths.some((p) => cellAsString(getCellValue(row, p)).toLowerCase().includes(term)));
|
|
1944
2340
|
const start = (page - 1) * size;
|
|
1945
2341
|
return Promise.resolve({
|
|
1946
2342
|
data: filtered.slice(start, start + size),
|
|
@@ -1994,4 +2390,4 @@ function useRegisterMainActionListener(state, listener, enabled) {
|
|
|
1994
2390
|
});
|
|
1995
2391
|
}
|
|
1996
2392
|
//#endregion
|
|
1997
|
-
export { isModClick as _, useTableContext as a,
|
|
2393
|
+
export { isModClick as C, ROW_ACTIONS_TYPE as D, ROW_ACTIONS_PATH as E, intentToScope as S, triggerAction as T, ariaLabelFor as _, useTableContext as a, extractIdentifier as b, ASPECT_ICONS as c, readPresetLabel as d, INTERACTIVE_SELECTOR as f, applyRowsGate as g, applyRowGate as h, useRegisterMainActionListener as i, ASPECT_LABELS as l, rowActionHref as m, createTableState as n, useTableContextOptional as o, onSelectControlKeydown as p, provideTableContext as r, DEFAULT_AVAILABLE_ASPECTS as s, createStaticTableState as t, ownerNameOf as u, collectIdentifiers as v, isPlainLeftClick as w, intentClass as x, createNavigateGestures as y };
|