@svgrid/enterprise 3.1.21 → 3.1.22
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/SvGridRowCount.svelte +23 -0
- package/dist/SvGridRowCount.svelte.d.ts +6 -0
- package/dist/cdn/svgrid-enterprise.svelte-external.js +8691 -8479
- package/dist/designer/assets/GridFooter-DKMfZpL4.js +2 -0
- package/dist/designer/assets/GridMenus-DWDghydL.js +6 -0
- package/dist/designer/assets/{PinSplitter-C5AwA1xV.js → PinSplitter-BfIjd7pi.js} +1 -1
- package/dist/designer/assets/grid-extension.svelte-G1ng0xd2.js +1 -0
- package/dist/designer/assets/index-9APkRkTg.css +1 -0
- package/dist/designer/assets/{index-DLJjuVA4.js → index-ICCQKTGR.js} +324 -324
- package/dist/designer/index.html +3 -3
- package/dist/expressions/compile.js +11 -7
- package/dist/expressions/evaluate.js +4 -0
- package/dist/expressions/expression-columns.d.ts +4 -1
- package/dist/expressions/expression-columns.js +12 -3
- package/dist/expressions/parse.js +19 -7
- package/dist/filter-labels.d.ts +16 -0
- package/dist/filter-labels.js +83 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7 -0
- package/dist/install.js +8 -0
- package/dist/node/studio.js +12 -5
- package/dist/relative-date-core.d.ts +40 -0
- package/dist/relative-date-core.js +85 -0
- package/dist/relative-dates.d.ts +28 -0
- package/dist/relative-dates.js +61 -0
- package/dist/row-count.d.ts +28 -0
- package/dist/row-count.js +39 -0
- package/dist/sort-blanks.d.ts +8 -0
- package/dist/sort-blanks.js +47 -0
- package/dist/studio/ui-components.generated.js +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/wc/GridFooter-CKC4L36O.js +162 -0
- package/dist/wc/{GridMenus-DVGuqp2l.js → GridMenus-h7RsvcmI.js} +320 -303
- package/dist/wc/{PinSplitter-Btco0txr.js → PinSplitter-BN6ybmjs.js} +1 -1
- package/dist/wc/grid-extension.svelte-CDf5EUyz.js +27 -0
- package/dist/wc/sv-sheet-element.js +6775 -6767
- package/package.json +3 -3
- package/dist/designer/assets/GridFooter-CKBVItAU.js +0 -2
- package/dist/designer/assets/GridMenus-Dzwu7M9r.js +0 -6
- package/dist/designer/assets/grid-extension.svelte-BZ7AqyJI.js +0 -1
- package/dist/designer/assets/index-WCxj6WfJ.css +0 -1
- package/dist/wc/GridFooter-BgoA77TJ.js +0 -145
- package/dist/wc/grid-extension.svelte-CucBS4FL.js +0 -20
package/dist/designer/index.html
CHANGED
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>SvGrid Studio - Designer</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/index-
|
|
7
|
+
<script type="module" crossorigin src="./assets/index-ICCQKTGR.js"></script>
|
|
8
8
|
<link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-Dd_uD5pT.js">
|
|
9
9
|
<link rel="modulepreload" crossorigin href="./assets/disclose-version-CIm4S9xS.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="./assets/cell-formatting-JoxA0t65.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="./assets/SvGrid.helpers-BF2QRcNt.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="./assets/sv-grid-scrollbar-B9N6Wuj0.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="./assets/grid-extension.svelte-G1ng0xd2.js">
|
|
13
14
|
<link rel="modulepreload" crossorigin href="./assets/editor-contract-Bpoa7A5g.js">
|
|
14
15
|
<link rel="modulepreload" crossorigin href="./assets/date-format-B8JbEtIG.js">
|
|
15
16
|
<link rel="modulepreload" crossorigin href="./assets/list-option-BP_dWS66.js">
|
|
16
17
|
<link rel="modulepreload" crossorigin href="./assets/SvListBox-fn160gSB.js">
|
|
17
|
-
<link rel="modulepreload" crossorigin href="./assets/grid-extension.svelte-BZ7AqyJI.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/editor-registry-BjP16H0v.js">
|
|
19
19
|
<link rel="modulepreload" crossorigin href="./assets/preload-helper-HclGiUj8.js">
|
|
20
20
|
<link rel="modulepreload" crossorigin href="./assets/popover-CUkLsvRX.js">
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
<link rel="stylesheet" crossorigin href="./assets/SvMenuList-DJ47ba1h.css">
|
|
46
46
|
<link rel="stylesheet" crossorigin href="./assets/SvGridChart-BgLuPO7I.css">
|
|
47
47
|
<link rel="stylesheet" crossorigin href="./assets/SvGridChartPanel-4Pc8y5yO.css">
|
|
48
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
48
|
+
<link rel="stylesheet" crossorigin href="./assets/index-9APkRkTg.css">
|
|
49
49
|
</head>
|
|
50
50
|
<body>
|
|
51
51
|
<div id="app"></div>
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* constants.
|
|
22
22
|
*/
|
|
23
23
|
import { compileExcelFilter } from '@svgrid/grid/filtering';
|
|
24
|
+
import { compileRelativeDateFilter, isRelativeDateOperator } from '../relative-date-core.js';
|
|
24
25
|
import { getPredicateKind } from './kinds.js';
|
|
25
26
|
const num = (v) => typeof v === 'number' ? v : v == null || v === '' ? NaN : Number(v);
|
|
26
27
|
const BUILTINS = {
|
|
@@ -258,13 +259,16 @@ function compileInternal(expr, opts, aggs) {
|
|
|
258
259
|
return test ?? (() => true);
|
|
259
260
|
}
|
|
260
261
|
case 'cmp': {
|
|
261
|
-
// The needle-side work happens once, here.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
262
|
+
// The needle-side work happens once, here. The relative date operators
|
|
263
|
+
// are this package's, not the grid's.
|
|
264
|
+
const test = isRelativeDateOperator(expr.op)
|
|
265
|
+
? compileRelativeDateFilter(expr.op)
|
|
266
|
+
: compileExcelFilter({
|
|
267
|
+
id: expr.column,
|
|
268
|
+
operator: expr.op,
|
|
269
|
+
value: expr.value,
|
|
270
|
+
valueTo: expr.valueTo,
|
|
271
|
+
}, { locale: opts.locale });
|
|
268
272
|
const column = expr.column;
|
|
269
273
|
return (row) => test(opts.getValue(row, column));
|
|
270
274
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* exactly; scalar maths and change detection are handled here.
|
|
5
5
|
*/
|
|
6
6
|
import { applyExcelFilter } from '@svgrid/grid/filtering';
|
|
7
|
+
import { compileRelativeDateFilter, isRelativeDateOperator } from '../relative-date-core.js';
|
|
7
8
|
import { getPredicateKind } from './kinds.js';
|
|
8
9
|
function readValue(ctx, row, columnId) {
|
|
9
10
|
if (ctx.getValue)
|
|
@@ -168,6 +169,9 @@ export function evaluatePredicate(expr, ctx) {
|
|
|
168
169
|
case 'not':
|
|
169
170
|
return !evaluatePredicate(expr.expr, ctx);
|
|
170
171
|
case 'cmp':
|
|
172
|
+
// The relative date operators are this package's, not the grid's.
|
|
173
|
+
if (isRelativeDateOperator(expr.op))
|
|
174
|
+
return compileRelativeDateFilter(expr.op)(readValue(ctx, ctx.row, expr.column));
|
|
171
175
|
return applyExcelFilter(readValue(ctx, ctx.row, expr.column), { id: expr.column, operator: expr.op, value: expr.value, valueTo: expr.valueTo }, { locale: ctx.locale });
|
|
172
176
|
case 'scalarCmp':
|
|
173
177
|
return compareScalar(evaluateScalar(expr.left, ctx), expr.op, evaluateScalar(expr.right, ctx));
|
|
@@ -27,7 +27,10 @@ export declare const OPERATORS: ReadonlyArray<OperatorMeta>;
|
|
|
27
27
|
export declare function operatorMeta(op: ExcelFilterOperator): OperatorMeta;
|
|
28
28
|
/** Operators valid for a column type (defaults to the text set). */
|
|
29
29
|
export declare function operatorsForType(type: ExprColumnType | undefined): OperatorMeta[];
|
|
30
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Whether an operator needs no value input: the grid catalogue's, or one of
|
|
32
|
+
* the relative date operators this package adds.
|
|
33
|
+
*/
|
|
31
34
|
export declare function isValueless(op: ExcelFilterOperator): boolean;
|
|
32
35
|
/** Whether an operator takes a multi-value token list. */
|
|
33
36
|
export declare function isSetOperator(op: ExcelFilterOperator): boolean;
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// Imported from the `/filtering` subpath, not the package root: the root would
|
|
17
17
|
// drag SvGrid.svelte into a module that is otherwise pure logic.
|
|
18
18
|
import { isRangeOperator as gridIsRangeOperator, isSetOperator as gridIsSetOperator, isValuelessOperator as gridIsValuelessOperator, } from '@svgrid/grid/filtering';
|
|
19
|
+
import { isRelativeDateOperator } from '../relative-date-core.js';
|
|
19
20
|
const TEXT = ['text'];
|
|
20
21
|
const NUM = ['number'];
|
|
21
22
|
const DATES = ['date', 'datetime'];
|
|
@@ -40,11 +41,16 @@ const OPERATOR_PRESENTATION = [
|
|
|
40
41
|
{ value: 'notIn', label: 'Not in', types: ['text', 'number'] },
|
|
41
42
|
{ value: 'isBlank', label: 'Is blank', types: ALL },
|
|
42
43
|
{ value: 'isNotBlank', label: 'Is not blank', types: ALL },
|
|
44
|
+
{ value: 'today', label: 'Is today', types: DATES },
|
|
45
|
+
{ value: 'beforeToday', label: 'Before today', types: DATES },
|
|
46
|
+
{ value: 'afterToday', label: 'After today', types: DATES },
|
|
47
|
+
{ value: 'next7Days', label: 'In the next 7 days', types: DATES },
|
|
48
|
+
{ value: 'last7Days', label: 'In the last 7 days', types: DATES },
|
|
43
49
|
];
|
|
44
50
|
/** The full operator catalogue, ordered as the editor should present it. */
|
|
45
51
|
export const OPERATORS = OPERATOR_PRESENTATION.map((op) => ({
|
|
46
52
|
...op,
|
|
47
|
-
...(
|
|
53
|
+
...(isValueless(op.value) ? { valueless: true } : {}),
|
|
48
54
|
...(gridIsSetOperator(op.value) ? { set: true } : {}),
|
|
49
55
|
...(gridIsRangeOperator(op.value) ? { range: true } : {}),
|
|
50
56
|
}));
|
|
@@ -58,9 +64,12 @@ export function operatorsForType(type) {
|
|
|
58
64
|
const t = type ?? 'text';
|
|
59
65
|
return OPERATORS.filter((op) => op.types.includes(t));
|
|
60
66
|
}
|
|
61
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Whether an operator needs no value input: the grid catalogue's, or one of
|
|
69
|
+
* the relative date operators this package adds.
|
|
70
|
+
*/
|
|
62
71
|
export function isValueless(op) {
|
|
63
|
-
return gridIsValuelessOperator(op);
|
|
72
|
+
return gridIsValuelessOperator(op) || isRelativeDateOperator(op);
|
|
64
73
|
}
|
|
65
74
|
/** Whether an operator takes a multi-value token list. */
|
|
66
75
|
export function isSetOperator(op) {
|
|
@@ -5,7 +5,19 @@ const KEYWORDS = new Set([
|
|
|
5
5
|
'AND', 'OR', 'NOT', 'TRUE', 'FALSE', 'NULL',
|
|
6
6
|
'CONTAINS', 'STARTSWITH', 'ENDSWITH', 'MATCHES',
|
|
7
7
|
'IN', 'BETWEEN', 'ISBLANK', 'ISNOTBLANK',
|
|
8
|
+
'ISTODAY', 'BEFORETODAY', 'AFTERTODAY', 'INNEXT7DAYS', 'INLAST7DAYS',
|
|
8
9
|
]);
|
|
10
|
+
/** The operators that take no value, written after the column: `Due ISTODAY`. */
|
|
11
|
+
const POSTFIX_OPS = {
|
|
12
|
+
ISBLANK: 'isBlank',
|
|
13
|
+
ISNOTBLANK: 'isNotBlank',
|
|
14
|
+
ISTODAY: 'today',
|
|
15
|
+
BEFORETODAY: 'beforeToday',
|
|
16
|
+
AFTERTODAY: 'afterToday',
|
|
17
|
+
INNEXT7DAYS: 'next7Days',
|
|
18
|
+
INLAST7DAYS: 'last7Days',
|
|
19
|
+
};
|
|
20
|
+
const POSTFIX_KEYWORD = Object.fromEntries(Object.entries(POSTFIX_OPS).map(([kw, op]) => [op, kw]));
|
|
9
21
|
const AGG_KEYWORDS = new Set(['SUM', 'AVG', 'COUNT']);
|
|
10
22
|
function tokenize(input) {
|
|
11
23
|
const tokens = [];
|
|
@@ -192,9 +204,10 @@ class Parser {
|
|
|
192
204
|
const left = this.parseScalar();
|
|
193
205
|
const t = this.peek();
|
|
194
206
|
// Postfix valueless keyword ops.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
207
|
+
const postfix = t.kind === 'kw' ? POSTFIX_OPS[t.value] : undefined;
|
|
208
|
+
if (postfix) {
|
|
209
|
+
this.next();
|
|
210
|
+
return { kind: 'cmp', column: this.expectColumn(left), op: postfix };
|
|
198
211
|
}
|
|
199
212
|
// Keyword text/set/range ops.
|
|
200
213
|
if (t.kind === 'kw') {
|
|
@@ -424,10 +437,9 @@ export function stringifyPredicate(expr, columns = []) {
|
|
|
424
437
|
return getPredicateKind(expr.type)?.describe?.(expr.payload, (id) => columnLabel(columns, id)) ?? `[${expr.type}]`;
|
|
425
438
|
case 'cmp': {
|
|
426
439
|
const col = columnRefText(columns, expr.column);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
return `${col} ISNOTBLANK`;
|
|
440
|
+
const postfix = POSTFIX_KEYWORD[expr.op];
|
|
441
|
+
if (postfix)
|
|
442
|
+
return `${col} ${postfix}`;
|
|
431
443
|
if (expr.op === 'between')
|
|
432
444
|
return `${col} BETWEEN ${litText(expr.value)} AND ${litText(expr.valueTo)}`;
|
|
433
445
|
if (expr.op === 'in' || expr.op === 'notIn') {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type FacetOption = {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
hint?: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* The checklist as the cells show it. Exported for tests and for a custom
|
|
8
|
+
* menu; `enableFilterLabels` wires it into every grid.
|
|
9
|
+
*/
|
|
10
|
+
export declare function labelFacetOptions(ctrl: any, column: any, options: ReadonlyArray<FacetOption>): FacetOption[];
|
|
11
|
+
/**
|
|
12
|
+
* Label every grid's filter checklists as their cells show them. Idempotent;
|
|
13
|
+
* also invoked by {@link installEnterprise}.
|
|
14
|
+
*/
|
|
15
|
+
export declare function enableFilterLabels(): void;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter checklist labels - the column filter's value list shows each value
|
|
3
|
+
* the way its cell shows it, while the filter still matches the raw value. A
|
|
4
|
+
* status stored as MARKED_AS_FAILED and drawn as "Failed" is offered as
|
|
5
|
+
* "Failed", so a column's accessor can stay the raw value that sorting needs.
|
|
6
|
+
*
|
|
7
|
+
* The label comes from the first of these the column has: a `cell` renderer
|
|
8
|
+
* that returns a string, static `editorOptions` labels, then `formatter` /
|
|
9
|
+
* `format`. Text values are ordered by label; number and date values stay in
|
|
10
|
+
* value order. It plugs into the grid's `facetOptions` seam, which runs in the
|
|
11
|
+
* menu chunk.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { enableFilterLabels } from '@svgrid/enterprise'
|
|
15
|
+
* enableFilterLabels()
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { columnDataType, registerGridExtension } from '@svgrid/grid';
|
|
19
|
+
import { hasValidLicense } from './license.js';
|
|
20
|
+
import { emitUnlicensedNudge } from './watermark.js';
|
|
21
|
+
/** The text a cell shows for `raw` in `row`, or null when the column draws markup only. */
|
|
22
|
+
function cellText(ctrl, column, raw, row) {
|
|
23
|
+
const def = column.columnDef;
|
|
24
|
+
if (typeof def.cell === 'function') {
|
|
25
|
+
const rendered = def.cell({
|
|
26
|
+
cell: { id: `${row.id}_${column.id}`, row, column, getValue: () => raw, getContext: () => ({}) },
|
|
27
|
+
row,
|
|
28
|
+
column,
|
|
29
|
+
table: ctrl.grid,
|
|
30
|
+
getValue: () => raw,
|
|
31
|
+
});
|
|
32
|
+
if (typeof rendered === 'string' || typeof rendered === 'number')
|
|
33
|
+
return String(rendered);
|
|
34
|
+
}
|
|
35
|
+
// Static lists only: a function or promise source would fetch.
|
|
36
|
+
if (Array.isArray(def.editorOptions))
|
|
37
|
+
return ctrl.formatListCellValue(column, raw, row);
|
|
38
|
+
if (def.formatter || def.format)
|
|
39
|
+
return ctrl.formatCellValue(column, raw, row);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The checklist as the cells show it. Exported for tests and for a custom
|
|
44
|
+
* menu; `enableFilterLabels` wires it into every grid.
|
|
45
|
+
*/
|
|
46
|
+
export function labelFacetOptions(ctrl, column, options) {
|
|
47
|
+
// One row per distinct value, found once per menu open.
|
|
48
|
+
const wanted = new Set(options.map((o) => o.value));
|
|
49
|
+
const rowFor = new Map();
|
|
50
|
+
for (const row of ctrl.grid.getRowModel().rows) {
|
|
51
|
+
if (rowFor.size === wanted.size)
|
|
52
|
+
break;
|
|
53
|
+
const raw = row.getCellValueByColumnId(column.id);
|
|
54
|
+
const key = String(raw ?? '');
|
|
55
|
+
if (wanted.has(key) && !rowFor.has(key))
|
|
56
|
+
rowFor.set(key, { raw, row });
|
|
57
|
+
}
|
|
58
|
+
const out = options.map((o) => {
|
|
59
|
+
const hit = o.value === '' ? undefined : rowFor.get(o.value);
|
|
60
|
+
const text = hit ? cellText(ctrl, column, hit.raw, hit.row) : null;
|
|
61
|
+
return text == null ? o : { ...o, label: text };
|
|
62
|
+
});
|
|
63
|
+
// Numbers and dates keep value order ("$1,000" would collate before "$200").
|
|
64
|
+
const type = columnDataType(column.columnDef);
|
|
65
|
+
if (type === 'number' || type === 'date' || type === 'dateString')
|
|
66
|
+
return out;
|
|
67
|
+
return out.sort((a, b) => a.value === '' || b.value === ''
|
|
68
|
+
? (a.value === '' ? 0 : 1) - (b.value === '' ? 0 : 1)
|
|
69
|
+
: a.label.localeCompare(b.label, undefined, { numeric: true }));
|
|
70
|
+
}
|
|
71
|
+
let enabled = false;
|
|
72
|
+
/**
|
|
73
|
+
* Label every grid's filter checklists as their cells show them. Idempotent;
|
|
74
|
+
* also invoked by {@link installEnterprise}.
|
|
75
|
+
*/
|
|
76
|
+
export function enableFilterLabels() {
|
|
77
|
+
if (enabled)
|
|
78
|
+
return;
|
|
79
|
+
enabled = true;
|
|
80
|
+
registerGridExtension({ facetOptions: labelFacetOptions });
|
|
81
|
+
if (!hasValidLicense())
|
|
82
|
+
emitUnlicensedNudge();
|
|
83
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,10 @@ export { enableBoardView, SvGridBoard } from './board.js';
|
|
|
12
12
|
export { enableGalleryView, SvGridGallery } from './gallery.js';
|
|
13
13
|
export * from './gantt/index.js';
|
|
14
14
|
export { enableSelectionBar, SvGridSelectionBar } from './selection-bar.js';
|
|
15
|
+
export { enableRelativeDateFilters, resolveRelativeDateFilter, compileRelativeDateFilter, isRelativeDateOperator, relativeDateOperators, RELATIVE_DATE_OPERATOR_IDS, type RelativeDateOperator, } from './relative-dates.js';
|
|
16
|
+
export { enableFilterLabels, labelFacetOptions } from './filter-labels.js';
|
|
17
|
+
export { enableRowCount, getRowCounts, SvGridRowCount } from './row-count.js';
|
|
18
|
+
export { blanksLast, blanksFirst, type BlanksSortType } from './sort-blanks.js';
|
|
15
19
|
export { applyBulkEdit, bulkEditableFields, bulkEditInitialValues, coerceBulkValue, type BulkEditField, type BulkEditResult } from './bulk-edit.js';
|
|
16
20
|
export { default as SvGridBulkEditDrawer } from './SvGridBulkEditDrawer.svelte';
|
|
17
21
|
export { enablePivot } from './pivot-enable.js';
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,13 @@ export * from './gantt/index.js';
|
|
|
33
33
|
// the renderer so `<SvGrid selectionBar={...}>` floats a bar over the grid while
|
|
34
34
|
// rows are selected. The prop + its config types live in @svgrid/grid.
|
|
35
35
|
export { enableSelectionBar, SvGridSelectionBar } from './selection-bar.js';
|
|
36
|
+
// Filter and sort additions for every grid (Pro), each through a grid seam so
|
|
37
|
+
// the free grid carries none of it: relative date operators, checklist labels
|
|
38
|
+
// taken from the cells, a status-bar row count, and blanks held at one end.
|
|
39
|
+
export { enableRelativeDateFilters, resolveRelativeDateFilter, compileRelativeDateFilter, isRelativeDateOperator, relativeDateOperators, RELATIVE_DATE_OPERATOR_IDS, } from './relative-dates.js';
|
|
40
|
+
export { enableFilterLabels, labelFacetOptions } from './filter-labels.js';
|
|
41
|
+
export { enableRowCount, getRowCounts, SvGridRowCount } from './row-count.js';
|
|
42
|
+
export { blanksLast, blanksFirst } from './sort-blanks.js';
|
|
36
43
|
// Bulk edit engine behind the bar's `editFields` button - exported so an app
|
|
37
44
|
// can drive the same write from its own UI.
|
|
38
45
|
export { applyBulkEdit, bulkEditableFields, bulkEditInitialValues, coerceBulkValue } from './bulk-edit.js';
|
package/dist/install.js
CHANGED
|
@@ -12,6 +12,9 @@ import { enableBoardView } from './board.js';
|
|
|
12
12
|
import { enableGalleryView } from './gallery.js';
|
|
13
13
|
import { enableGanttView } from './gantt/gantt.js';
|
|
14
14
|
import { enableSelectionBar } from './selection-bar.js';
|
|
15
|
+
import { enableRelativeDateFilters } from './relative-dates.js';
|
|
16
|
+
import { enableFilterLabels } from './filter-labels.js';
|
|
17
|
+
import { enableRowCount } from './row-count.js';
|
|
15
18
|
import { enableAdvancedFilter } from './advanced-filter-enable.js';
|
|
16
19
|
import { enablePivot } from './pivot-enable.js';
|
|
17
20
|
import { registerSheetKeymap } from './sheet-enable.js';
|
|
@@ -52,6 +55,11 @@ export function installEnterprise(api) {
|
|
|
52
55
|
// Register the Gantt view (no-op without the `gantt` prop).
|
|
53
56
|
enableGanttView();
|
|
54
57
|
enableSelectionBar();
|
|
58
|
+
// Relative date operators, cell-text checklist labels and the status-bar row
|
|
59
|
+
// count (each a no-op until a grid uses it).
|
|
60
|
+
enableRelativeDateFilters();
|
|
61
|
+
enableFilterLabels();
|
|
62
|
+
enableRowCount();
|
|
55
63
|
// Register the export engine so built-in AI exports (aiExport) can write the
|
|
56
64
|
// enterprise formats (xlsx / pdf / ...); free grids without it get the plan only.
|
|
57
65
|
registerExportProvider(exportGrid);
|
package/dist/node/studio.js
CHANGED
|
@@ -2242,8 +2242,15 @@ var kinds = /* @__PURE__ */ new Map();
|
|
|
2242
2242
|
function getPredicateKind(type) {
|
|
2243
2243
|
return kinds.get(type);
|
|
2244
2244
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2245
|
+
Object.fromEntries(Object.entries({
|
|
2246
|
+
ISBLANK: "isBlank",
|
|
2247
|
+
ISNOTBLANK: "isNotBlank",
|
|
2248
|
+
ISTODAY: "today",
|
|
2249
|
+
BEFORETODAY: "beforeToday",
|
|
2250
|
+
AFTERTODAY: "afterToday",
|
|
2251
|
+
INNEXT7DAYS: "next7Days",
|
|
2252
|
+
INLAST7DAYS: "last7Days"
|
|
2253
|
+
}).map(([kw, op]) => [op, kw]));
|
|
2247
2254
|
/** Every column id referenced anywhere in a predicate (deduped, in order). */
|
|
2248
2255
|
function collectColumnRefs(expr) {
|
|
2249
2256
|
const out = /* @__PURE__ */ new Set();
|
|
@@ -9336,7 +9343,7 @@ var GENERATED_UI_SURFACE = {
|
|
|
9336
9343
|
"key": "statusBar",
|
|
9337
9344
|
"label": "Status Bar",
|
|
9338
9345
|
"type": "boolean",
|
|
9339
|
-
"description": "Excel-style status bar under the grid showing live aggregates of the selected cell range (count, numeric count, sum, average, min, max). `true` shows the default set; pass `{ aggregates: [...] }` to choose which.
|
|
9346
|
+
"description": "Excel-style status bar under the grid showing live aggregates of the selected cell range (count, numeric count, sum, average, min, max). `true` shows the default set; pass `{ aggregates: [...] }` to choose which. The aggregates need `enableCellSelection`. `rows: true` adds a row count that is always shown, \"250 rows\" or \"12 of 250 rows\" while filters hide some, once `@svgrid/enterprise`'s `enableRowCount()` has run. `{ rows: true, aggregates: [] }` shows the count alone.",
|
|
9340
9347
|
"group": "common"
|
|
9341
9348
|
},
|
|
9342
9349
|
{
|
|
@@ -16499,7 +16506,7 @@ function hasFieldConditions(schema) {
|
|
|
16499
16506
|
*
|
|
16500
16507
|
* `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
|
|
16501
16508
|
*/
|
|
16502
|
-
var SVGRID_VERSION = "3.1.
|
|
16509
|
+
var SVGRID_VERSION = "3.1.22";
|
|
16503
16510
|
/**
|
|
16504
16511
|
* The version of `@svgrid/grid`, which releases on its own line: enterprise is
|
|
16505
16512
|
* on 3.1.x while the grid is on 3.0.x.
|
|
@@ -16512,7 +16519,7 @@ var SVGRID_VERSION = "3.1.21";
|
|
|
16512
16519
|
*
|
|
16513
16520
|
* `version.test.ts` asserts this matches packages/grid/package.json.
|
|
16514
16521
|
*/
|
|
16515
|
-
var GRID_VERSION = "3.0.
|
|
16522
|
+
var GRID_VERSION = "3.0.21";
|
|
16516
16523
|
//#endregion
|
|
16517
16524
|
//#region src/studio/emit-project.ts
|
|
16518
16525
|
var has = (blocks, kind) => blocks.some((b) => b.config.kind === kind);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The relative date operators' semantics, with no grid import: what the
|
|
3
|
+
* filter menu (relative-dates.ts) and the expression engine both run, so a
|
|
4
|
+
* server that evaluates expressions loads none of the grid.
|
|
5
|
+
*/
|
|
6
|
+
declare module '@svgrid/grid/filtering' {
|
|
7
|
+
interface FilterOperatorExtensions {
|
|
8
|
+
today: true;
|
|
9
|
+
beforeToday: true;
|
|
10
|
+
afterToday: true;
|
|
11
|
+
next7Days: true;
|
|
12
|
+
last7Days: true;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** The relative date operator ids, in menu order. */
|
|
16
|
+
export declare const RELATIVE_DATE_OPERATOR_IDS: readonly ["today", "beforeToday", "afterToday", "next7Days", "last7Days"];
|
|
17
|
+
export type RelativeDateOperator = (typeof RELATIVE_DATE_OPERATOR_IDS)[number];
|
|
18
|
+
/** Whether `op` is one of the relative date operators. */
|
|
19
|
+
export declare function isRelativeDateOperator(op: string): op is RelativeDateOperator;
|
|
20
|
+
/**
|
|
21
|
+
* The test for one relative date operator. "Today" is read once, here, so a
|
|
22
|
+
* page left open past midnight keeps the old day until the filter changes.
|
|
23
|
+
* A blank or unparseable cell never matches.
|
|
24
|
+
*/
|
|
25
|
+
export declare function compileRelativeDateFilter(op: RelativeDateOperator, now?: Date): (cellValue: unknown) => boolean;
|
|
26
|
+
/**
|
|
27
|
+
* A relative date filter as the absolute one it means today, for a backend
|
|
28
|
+
* with no "today" of its own: `beforeToday` becomes `lessThan` today's date,
|
|
29
|
+
* `next7Days` becomes `between` today and a week out, and so on, with dates as
|
|
30
|
+
* local 'YYYY-MM-DD'. Any other filter is returned as it is.
|
|
31
|
+
*
|
|
32
|
+
* A server data source gets this applied for it. Under `externalFilter` the
|
|
33
|
+
* `onFiltersChange` payload keeps the relative operator, so a saved view still
|
|
34
|
+
* means "overdue" tomorrow; call this when you build the query.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveRelativeDateFilter<T extends {
|
|
37
|
+
operator: string;
|
|
38
|
+
value?: unknown;
|
|
39
|
+
valueTo?: unknown;
|
|
40
|
+
}>(filter: T, now?: Date): T;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** The relative date operator ids, in menu order. */
|
|
2
|
+
export const RELATIVE_DATE_OPERATOR_IDS = ['today', 'beforeToday', 'afterToday', 'next7Days', 'last7Days'];
|
|
3
|
+
const DAY_MS = 86400000;
|
|
4
|
+
/** Whether `op` is one of the relative date operators. */
|
|
5
|
+
export function isRelativeDateOperator(op) {
|
|
6
|
+
return RELATIVE_DATE_OPERATOR_IDS.includes(op);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A value as a count of local calendar days, or NaN. A bare 'YYYY-MM-DD' is
|
|
10
|
+
* that day in local time; `new Date()` would read it as UTC midnight, the day
|
|
11
|
+
* before anywhere west of Greenwich.
|
|
12
|
+
*/
|
|
13
|
+
function localDayNumber(value) {
|
|
14
|
+
let d;
|
|
15
|
+
if (value instanceof Date)
|
|
16
|
+
d = value;
|
|
17
|
+
else if (typeof value === 'number')
|
|
18
|
+
d = new Date(value);
|
|
19
|
+
else if (typeof value === 'string' && value.trim()) {
|
|
20
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim());
|
|
21
|
+
d = m ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : new Date(value);
|
|
22
|
+
}
|
|
23
|
+
else
|
|
24
|
+
return NaN;
|
|
25
|
+
if (Number.isNaN(d.getTime()))
|
|
26
|
+
return NaN;
|
|
27
|
+
return Math.round(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()) / DAY_MS);
|
|
28
|
+
}
|
|
29
|
+
/** The inclusive range of local day numbers an operator keeps. */
|
|
30
|
+
function dayRange(op, now) {
|
|
31
|
+
const t = localDayNumber(now);
|
|
32
|
+
switch (op) {
|
|
33
|
+
case 'today':
|
|
34
|
+
return [t, t];
|
|
35
|
+
case 'beforeToday':
|
|
36
|
+
return [-Infinity, t - 1];
|
|
37
|
+
case 'afterToday':
|
|
38
|
+
return [t + 1, Infinity];
|
|
39
|
+
case 'next7Days':
|
|
40
|
+
return [t, t + 7];
|
|
41
|
+
case 'last7Days':
|
|
42
|
+
return [t - 7, t];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Local 'YYYY-MM-DD' for a day number from `localDayNumber`. */
|
|
46
|
+
function isoFromDayNumber(day) {
|
|
47
|
+
return new Date(day * DAY_MS).toISOString().slice(0, 10);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The test for one relative date operator. "Today" is read once, here, so a
|
|
51
|
+
* page left open past midnight keeps the old day until the filter changes.
|
|
52
|
+
* A blank or unparseable cell never matches.
|
|
53
|
+
*/
|
|
54
|
+
export function compileRelativeDateFilter(op, now = new Date()) {
|
|
55
|
+
const [lo, hi] = dayRange(op, now);
|
|
56
|
+
return (cellValue) => {
|
|
57
|
+
const day = localDayNumber(cellValue);
|
|
58
|
+
return day >= lo && day <= hi;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A relative date filter as the absolute one it means today, for a backend
|
|
63
|
+
* with no "today" of its own: `beforeToday` becomes `lessThan` today's date,
|
|
64
|
+
* `next7Days` becomes `between` today and a week out, and so on, with dates as
|
|
65
|
+
* local 'YYYY-MM-DD'. Any other filter is returned as it is.
|
|
66
|
+
*
|
|
67
|
+
* A server data source gets this applied for it. Under `externalFilter` the
|
|
68
|
+
* `onFiltersChange` payload keeps the relative operator, so a saved view still
|
|
69
|
+
* means "overdue" tomorrow; call this when you build the query.
|
|
70
|
+
*/
|
|
71
|
+
export function resolveRelativeDateFilter(filter, now = new Date()) {
|
|
72
|
+
if (!isRelativeDateOperator(filter.operator))
|
|
73
|
+
return filter;
|
|
74
|
+
const op = filter.operator;
|
|
75
|
+
const [lo, hi] = dayRange(op, now);
|
|
76
|
+
const out = { ...filter };
|
|
77
|
+
delete out.valueTo;
|
|
78
|
+
if (op === 'beforeToday')
|
|
79
|
+
Object.assign(out, { operator: 'lessThan', value: isoFromDayNumber(hi + 1) });
|
|
80
|
+
else if (op === 'afterToday')
|
|
81
|
+
Object.assign(out, { operator: 'greaterThan', value: isoFromDayNumber(lo - 1) });
|
|
82
|
+
else
|
|
83
|
+
Object.assign(out, { operator: 'between', value: isoFromDayNumber(lo), valueTo: isoFromDayNumber(hi) });
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relative date filters - five date operators measured from today, in whole
|
|
3
|
+
* local days: Today, Before today (overdue), After today, Next 7 days and
|
|
4
|
+
* Last 7 days. They take no value, so picking one in a date column's filter
|
|
5
|
+
* menu filters at once. They plug into the grid's `filterOperators` seam, so a
|
|
6
|
+
* grid without this module carries none of the code.
|
|
7
|
+
*
|
|
8
|
+
* Like the rest of Enterprise it runs without a license key during the
|
|
9
|
+
* evaluation; the grid shows the watermark and a one-time console notice.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { enableRelativeDateFilters } from '@svgrid/enterprise'
|
|
13
|
+
* enableRelativeDateFilters()
|
|
14
|
+
* // then: a column with cellDataType 'date' or 'dateString' offers them
|
|
15
|
+
* api.setFilter('due', { operator: 'beforeToday' })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { type GridFilterOperator } from '@svgrid/grid';
|
|
19
|
+
import { type RelativeDateOperator } from './relative-date-core.js';
|
|
20
|
+
export { RELATIVE_DATE_OPERATOR_IDS, isRelativeDateOperator, compileRelativeDateFilter, resolveRelativeDateFilter, type RelativeDateOperator, } from './relative-date-core.js';
|
|
21
|
+
/** The operators as the grid's `filterOperators` seam takes them. */
|
|
22
|
+
export declare const relativeDateOperators: Record<RelativeDateOperator, GridFilterOperator>;
|
|
23
|
+
/**
|
|
24
|
+
* Add the relative date operators to every grid's date filters. Idempotent:
|
|
25
|
+
* call it once at app start or from each component that uses them. Also
|
|
26
|
+
* invoked by {@link installEnterprise}.
|
|
27
|
+
*/
|
|
28
|
+
export declare function enableRelativeDateFilters(): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relative date filters - five date operators measured from today, in whole
|
|
3
|
+
* local days: Today, Before today (overdue), After today, Next 7 days and
|
|
4
|
+
* Last 7 days. They take no value, so picking one in a date column's filter
|
|
5
|
+
* menu filters at once. They plug into the grid's `filterOperators` seam, so a
|
|
6
|
+
* grid without this module carries none of the code.
|
|
7
|
+
*
|
|
8
|
+
* Like the rest of Enterprise it runs without a license key during the
|
|
9
|
+
* evaluation; the grid shows the watermark and a one-time console notice.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { enableRelativeDateFilters } from '@svgrid/enterprise'
|
|
13
|
+
* enableRelativeDateFilters()
|
|
14
|
+
* // then: a column with cellDataType 'date' or 'dateString' offers them
|
|
15
|
+
* api.setFilter('due', { operator: 'beforeToday' })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { getGridExtension, registerGridExtension } from '@svgrid/grid';
|
|
19
|
+
import { hasValidLicense } from './license.js';
|
|
20
|
+
import { emitUnlicensedNudge } from './watermark.js';
|
|
21
|
+
import { compileRelativeDateFilter, resolveRelativeDateFilter, } from './relative-date-core.js';
|
|
22
|
+
export { RELATIVE_DATE_OPERATOR_IDS, isRelativeDateOperator, compileRelativeDateFilter, resolveRelativeDateFilter, } from './relative-date-core.js';
|
|
23
|
+
const LABELS = {
|
|
24
|
+
today: 'Today',
|
|
25
|
+
beforeToday: 'Before today',
|
|
26
|
+
afterToday: 'After today',
|
|
27
|
+
next7Days: 'Next 7 days',
|
|
28
|
+
last7Days: 'Last 7 days',
|
|
29
|
+
};
|
|
30
|
+
function operator(op) {
|
|
31
|
+
return {
|
|
32
|
+
label: LABELS[op],
|
|
33
|
+
types: ['date'],
|
|
34
|
+
valueless: true,
|
|
35
|
+
compile: () => compileRelativeDateFilter(op),
|
|
36
|
+
toServer: (filter) => resolveRelativeDateFilter(filter),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** The operators as the grid's `filterOperators` seam takes them. */
|
|
40
|
+
export const relativeDateOperators = {
|
|
41
|
+
today: operator('today'),
|
|
42
|
+
beforeToday: operator('beforeToday'),
|
|
43
|
+
afterToday: operator('afterToday'),
|
|
44
|
+
next7Days: operator('next7Days'),
|
|
45
|
+
last7Days: operator('last7Days'),
|
|
46
|
+
};
|
|
47
|
+
let enabled = false;
|
|
48
|
+
/**
|
|
49
|
+
* Add the relative date operators to every grid's date filters. Idempotent:
|
|
50
|
+
* call it once at app start or from each component that uses them. Also
|
|
51
|
+
* invoked by {@link installEnterprise}.
|
|
52
|
+
*/
|
|
53
|
+
export function enableRelativeDateFilters() {
|
|
54
|
+
if (enabled)
|
|
55
|
+
return;
|
|
56
|
+
enabled = true;
|
|
57
|
+
// Another module may have added operators of its own; keep them.
|
|
58
|
+
registerGridExtension({ filterOperators: { ...getGridExtension()?.filterOperators, ...relativeDateOperators } });
|
|
59
|
+
if (!hasValidLicense())
|
|
60
|
+
emitUnlicensedNudge();
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row count - "250 rows", or "12 of 250 rows" while filters hide some, at the
|
|
3
|
+
* start of the grid's status bar, and the same two numbers from code.
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { enableRowCount, getRowCounts } from '@svgrid/enterprise'
|
|
7
|
+
* enableRowCount()
|
|
8
|
+
* // <SvGrid {data} {columns} statusBar={{ rows: true, aggregates: [] }} />
|
|
9
|
+
* const { total, filtered } = getRowCounts(api)
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
import { type RowData, type SvGridApi, type TableFeatures } from '@svgrid/grid';
|
|
13
|
+
/**
|
|
14
|
+
* Draw the row count in every grid whose `statusBar` sets `rows: true`.
|
|
15
|
+
* Idempotent; also invoked by {@link installEnterprise}.
|
|
16
|
+
*/
|
|
17
|
+
export declare function enableRowCount(): void;
|
|
18
|
+
/**
|
|
19
|
+
* How many rows the grid holds (`total`) and how many pass the current
|
|
20
|
+
* filters (`filtered`), for an "X of Y" of your own. Pagination changes
|
|
21
|
+
* neither. With grouping on, `filtered` counts the group rows too. Under
|
|
22
|
+
* `externalPagination` both come from the `rowCount` you pass.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getRowCounts<TFeatures extends TableFeatures, TData extends RowData>(api: SvGridApi<TFeatures, TData>): {
|
|
25
|
+
total: number;
|
|
26
|
+
filtered: number;
|
|
27
|
+
};
|
|
28
|
+
export { default as SvGridRowCount } from './SvGridRowCount.svelte';
|