@svgrid/enterprise 2.6.1 → 2.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/ExpressionEditorHarness.svelte +47 -0
- package/dist/ExpressionEditorHarness.svelte.d.ts +15 -0
- package/dist/SvAdvancedFilter.svelte +208 -0
- package/dist/SvAdvancedFilter.svelte.d.ts +37 -0
- package/dist/SvExpressionEditor.svelte +251 -123
- package/dist/SvGridEditPanel.svelte +1157 -1157
- package/dist/advanced-filter/expr-columns-from-grid.d.ts +30 -0
- package/dist/advanced-filter/expr-columns-from-grid.js +44 -0
- package/dist/advanced-filter-enable.d.ts +5 -0
- package/dist/advanced-filter-enable.js +35 -0
- package/dist/cdn/svgrid-enterprise.svelte-external.js +8274 -7706
- package/dist/designer/assets/GridMenus-DuogVgW0.js +7 -0
- package/dist/designer/assets/SvGrid.helpers-C6wxF55r.js +1 -0
- package/dist/designer/assets/SvGridCellEditor-CMtmQINJ.js +2 -0
- package/dist/designer/assets/{SvListBox-BVzVfCG3.js → SvListBox-CWCIPM4P.js} +1 -1
- package/dist/designer/assets/editor-registry-BB1Qb5mp.js +1 -0
- package/dist/designer/assets/{index-CKdwDseq.js → index-aTVomkp-.js} +43 -43
- package/dist/designer/assets/js-scroller.svelte-C7LaeUEW.js +110 -0
- package/dist/designer/assets/row-drag-touch-IuJPEt0z.js +1 -0
- package/dist/designer/assets/src-B5lLfIhK.css +1 -0
- package/dist/designer/assets/src-DLoHsbp5.js +2893 -0
- package/dist/designer/index.html +7 -5
- package/dist/expressions/builder-tree.d.ts +62 -0
- package/dist/expressions/builder-tree.js +133 -0
- package/dist/expressions/compile.d.ts +14 -0
- package/dist/expressions/compile.js +286 -0
- package/dist/expressions/expression-columns.d.ts +1 -11
- package/dist/expressions/expression-columns.js +40 -11
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/install.js +2 -0
- package/dist/node/studio.js +61 -13
- package/dist/sources/rest.js +25 -0
- package/dist/sources/supabase.js +49 -3
- package/dist/studio/emit-project.js +2125 -2125
- package/dist/studio/ui-components.generated.js +33 -0
- package/dist/sveltekit/in-memory.js +96 -3
- package/dist/sveltekit/query-plan.d.ts +32 -1
- package/dist/sveltekit/query-plan.js +88 -1
- package/dist/sveltekit/sql.d.ts +20 -0
- package/dist/sveltekit/sql.js +26 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/dist/designer/assets/GridMenus-CW-rnHS9.js +0 -7
- package/dist/designer/assets/js-scroller.svelte-tHanKJx0.js +0 -110
- package/dist/designer/assets/src-DCKhP5Xy.css +0 -1
- package/dist/designer/assets/src-DLsSdh3J.js +0 -2893
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
## What it adds
|
|
26
26
|
|
|
27
|
-
- **Data export** - Excel (`.xlsx`), PDF,
|
|
27
|
+
- **Data export** - Excel (`.xlsx`), PDF, styled HTML and XML, with theme-matched styling, headers/footers, and image support. CSV, TSV and JSON export (and copy-to-clipboard) are free in `@svgrid/grid`; Enterprise adds the paid formats and a single `exportGrid()` entry point over all of them.
|
|
28
28
|
- **Data import** - read Excel / CSV / TSV / JSON into typed rows with column auto-mapping, type inference, and per-row validation, plus a ready-made `SvImportDialog`.
|
|
29
29
|
- **Paginated print** - opens a clean, paginated, printable view of the grid with title and page breaks.
|
|
30
30
|
- **Pivot tables** - drag-and-drop pivot Designer with row/column/value fields, aggregation, drill-through to source rows, and pivot-to-chart.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Test-only harness for `SvExpressionEditor`.
|
|
4
|
+
*
|
|
5
|
+
* Runes cannot live in a `.ts` test file, and the behaviour under test is
|
|
6
|
+
* specifically "a parent reassigns `value`" - so the parent has to be a real
|
|
7
|
+
* component. This is also the shape of the real thing: a preset button, or a
|
|
8
|
+
* saved filter being loaded, replacing the expression from outside.
|
|
9
|
+
*/
|
|
10
|
+
import SvExpressionEditor from './SvExpressionEditor.svelte'
|
|
11
|
+
import type { ExprColumn } from './expressions/expression-columns'
|
|
12
|
+
import type { PredicateExpr } from './expressions/expression-types'
|
|
13
|
+
|
|
14
|
+
type Props = {
|
|
15
|
+
columns: ReadonlyArray<ExprColumn>
|
|
16
|
+
initial: PredicateExpr
|
|
17
|
+
/** Applied to `value` when the "preset" button is clicked. */
|
|
18
|
+
preset: PredicateExpr
|
|
19
|
+
onChange?: (v: PredicateExpr) => void
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let { columns, initial, preset, onChange }: Props = $props()
|
|
23
|
+
|
|
24
|
+
let value = $state<PredicateExpr>(initial)
|
|
25
|
+
let emissions = $state(0)
|
|
26
|
+
|
|
27
|
+
export function currentValue(): PredicateExpr {
|
|
28
|
+
return value
|
|
29
|
+
}
|
|
30
|
+
export function emissionCount(): number {
|
|
31
|
+
return emissions
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<button type="button" data-testid="apply-preset" onclick={() => (value = preset)}>
|
|
36
|
+
preset
|
|
37
|
+
</button>
|
|
38
|
+
<span data-testid="emissions">{emissions}</span>
|
|
39
|
+
|
|
40
|
+
<SvExpressionEditor
|
|
41
|
+
{columns}
|
|
42
|
+
bind:value
|
|
43
|
+
onChange={(v) => {
|
|
44
|
+
emissions += 1
|
|
45
|
+
onChange?.(v)
|
|
46
|
+
}}
|
|
47
|
+
/>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ExprColumn } from './expressions/expression-columns';
|
|
2
|
+
import type { PredicateExpr } from './expressions/expression-types';
|
|
3
|
+
type Props = {
|
|
4
|
+
columns: ReadonlyArray<ExprColumn>;
|
|
5
|
+
initial: PredicateExpr;
|
|
6
|
+
/** Applied to `value` when the "preset" button is clicked. */
|
|
7
|
+
preset: PredicateExpr;
|
|
8
|
+
onChange?: (v: PredicateExpr) => void;
|
|
9
|
+
};
|
|
10
|
+
declare const ExpressionEditorHarness: import("svelte").Component<Props, {
|
|
11
|
+
currentValue: () => PredicateExpr;
|
|
12
|
+
emissionCount: () => number;
|
|
13
|
+
}, "">;
|
|
14
|
+
type ExpressionEditorHarness = ReturnType<typeof ExpressionEditorHarness>;
|
|
15
|
+
export default ExpressionEditorHarness;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SvAdvancedFilter - the advanced-filter panel (Pro).
|
|
4
|
+
*
|
|
5
|
+
* Mounted beside the grid by the consumer, like `<SvGridAlerts>`; there is no
|
|
6
|
+
* grid-side renderer to register.
|
|
7
|
+
*
|
|
8
|
+
* The panel holds a DRAFT expression and only pushes it to the grid on Apply.
|
|
9
|
+
* `SvExpressionEditor` emits on every keystroke, which is right for an alert
|
|
10
|
+
* rule editor but would re-run the whole filter pipeline per character here.
|
|
11
|
+
* Holding the draft also makes the live "matches N" counter a genuine preview
|
|
12
|
+
* of what Apply would do, rather than a lagging echo of what already happened.
|
|
13
|
+
*/
|
|
14
|
+
import { untrack } from 'svelte'
|
|
15
|
+
import SvExpressionEditor from './SvExpressionEditor.svelte'
|
|
16
|
+
import { exprColumnsFromGrid } from './advanced-filter/expr-columns-from-grid'
|
|
17
|
+
import type { ExprColumn } from './expressions/expression-columns'
|
|
18
|
+
import type { PredicateExpr } from './expressions/expression-types'
|
|
19
|
+
|
|
20
|
+
type MinimalApi = {
|
|
21
|
+
getColumns(): ReadonlyArray<{
|
|
22
|
+
id: string
|
|
23
|
+
field?: string
|
|
24
|
+
header: string
|
|
25
|
+
visible: boolean
|
|
26
|
+
editorType?: string
|
|
27
|
+
}>
|
|
28
|
+
getData?: () => ReadonlyArray<Record<string, unknown>>
|
|
29
|
+
setAdvancedFilter(expr: unknown): void
|
|
30
|
+
getAdvancedFilter(): unknown
|
|
31
|
+
isAdvancedFilterActive(): boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type Props = {
|
|
35
|
+
/** The grid's API, from `onApiReady` / `bind:api`. */
|
|
36
|
+
api: MinimalApi
|
|
37
|
+
/** Rows for the live match preview. Defaults to the grid's own data. */
|
|
38
|
+
rows?: ReadonlyArray<Record<string, unknown>>
|
|
39
|
+
/** Override the derived column list. */
|
|
40
|
+
columns?: ReadonlyArray<ExprColumn>
|
|
41
|
+
/** Include columns the user has hidden. Default false. */
|
|
42
|
+
includeHidden?: boolean
|
|
43
|
+
/** Called after Apply / Clear with the expression now on the grid. */
|
|
44
|
+
onApply?: (expr: PredicateExpr | null) => void
|
|
45
|
+
/**
|
|
46
|
+
* The expression the panel shows, bindable. Assign it to drive the panel
|
|
47
|
+
* from outside - a preset button, a saved view - and the draft re-seeds to
|
|
48
|
+
* match. Without this a parent that calls `api.setAdvancedFilter()` itself
|
|
49
|
+
* would filter the grid while the panel kept showing its old draft.
|
|
50
|
+
*/
|
|
51
|
+
expression?: PredicateExpr | null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let {
|
|
55
|
+
api,
|
|
56
|
+
rows,
|
|
57
|
+
columns,
|
|
58
|
+
includeHidden = false,
|
|
59
|
+
onApply,
|
|
60
|
+
expression = $bindable<PredicateExpr | null>(undefined as never),
|
|
61
|
+
}: Props = $props()
|
|
62
|
+
|
|
63
|
+
const EMPTY: PredicateExpr = { kind: 'const', value: true }
|
|
64
|
+
|
|
65
|
+
const resolvedColumns = $derived(
|
|
66
|
+
columns ?? exprColumnsFromGrid(api, { includeHidden }),
|
|
67
|
+
)
|
|
68
|
+
const previewRows = $derived(rows ?? api.getData?.() ?? [])
|
|
69
|
+
|
|
70
|
+
/** The expression currently ON the grid, seeded once from it. */
|
|
71
|
+
let applied = $state<PredicateExpr | null>(
|
|
72
|
+
(untrack(() => api.getAdvancedFilter()) as PredicateExpr | null) ?? null,
|
|
73
|
+
)
|
|
74
|
+
/** What the editor is editing. Not pushed until Apply. */
|
|
75
|
+
let draft = $state<PredicateExpr>(applied ?? EMPTY)
|
|
76
|
+
|
|
77
|
+
const isDirty = $derived(JSON.stringify(draft) !== JSON.stringify(applied ?? EMPTY))
|
|
78
|
+
const canClear = $derived(applied != null)
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Follow an externally assigned `expression`. Compared by reference so the
|
|
82
|
+
* panel's own writes below are skipped and this cannot loop.
|
|
83
|
+
*/
|
|
84
|
+
let lastSynced = $state<PredicateExpr | null | undefined>(undefined)
|
|
85
|
+
$effect(() => {
|
|
86
|
+
const incoming = expression
|
|
87
|
+
if (incoming === undefined || incoming === untrack(() => lastSynced)) return
|
|
88
|
+
untrack(() => {
|
|
89
|
+
lastSynced = incoming
|
|
90
|
+
applied = incoming
|
|
91
|
+
draft = incoming ?? { kind: 'const', value: true }
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
function apply() {
|
|
96
|
+
api.setAdvancedFilter(draft as never)
|
|
97
|
+
applied = draft
|
|
98
|
+
lastSynced = draft
|
|
99
|
+
expression = draft
|
|
100
|
+
onApply?.(draft)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function clear() {
|
|
104
|
+
api.setAdvancedFilter(null)
|
|
105
|
+
applied = null
|
|
106
|
+
lastSynced = null
|
|
107
|
+
expression = null
|
|
108
|
+
// Reassign so the editor re-seeds - it compares by reference.
|
|
109
|
+
draft = { kind: 'const', value: true }
|
|
110
|
+
onApply?.(null)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function revert() {
|
|
114
|
+
draft = applied ?? { kind: 'const', value: true }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** True when an expression is set but no engine is registered to run it. */
|
|
118
|
+
const inactive = $derived(applied != null && !api.isAdvancedFilterActive())
|
|
119
|
+
</script>
|
|
120
|
+
|
|
121
|
+
<section class="sv-adv-filter" aria-label="Advanced filter">
|
|
122
|
+
<header class="sv-adv-filter__head">
|
|
123
|
+
<h2 class="sv-adv-filter__title">Advanced filter</h2>
|
|
124
|
+
{#if applied}
|
|
125
|
+
<span class="sv-adv-filter__badge" aria-label="A filter is applied">Active</span>
|
|
126
|
+
{/if}
|
|
127
|
+
</header>
|
|
128
|
+
|
|
129
|
+
{#if inactive}
|
|
130
|
+
<p class="sv-adv-filter__warn" role="status">
|
|
131
|
+
A filter is set but no advanced-filter engine is registered, so no rows are
|
|
132
|
+
being removed. Call <code>enableAdvancedFilter()</code> from
|
|
133
|
+
<code>@svgrid/enterprise</code>.
|
|
134
|
+
</p>
|
|
135
|
+
{/if}
|
|
136
|
+
|
|
137
|
+
<SvExpressionEditor columns={resolvedColumns} bind:value={draft} rows={previewRows} />
|
|
138
|
+
|
|
139
|
+
<footer class="sv-adv-filter__actions">
|
|
140
|
+
<button type="button" class="sv-adv-filter__btn is-primary" disabled={!isDirty} onclick={apply}>
|
|
141
|
+
Apply
|
|
142
|
+
</button>
|
|
143
|
+
<button type="button" class="sv-adv-filter__btn" disabled={!isDirty} onclick={revert}>
|
|
144
|
+
Revert
|
|
145
|
+
</button>
|
|
146
|
+
<button type="button" class="sv-adv-filter__btn" disabled={!canClear} onclick={clear}>
|
|
147
|
+
Clear
|
|
148
|
+
</button>
|
|
149
|
+
</footer>
|
|
150
|
+
</section>
|
|
151
|
+
|
|
152
|
+
<style>
|
|
153
|
+
.sv-adv-filter {
|
|
154
|
+
display: flex;
|
|
155
|
+
flex-direction: column;
|
|
156
|
+
gap: 0.75rem;
|
|
157
|
+
padding: 1rem;
|
|
158
|
+
border: 1px solid var(--sg-border);
|
|
159
|
+
border-radius: 8px;
|
|
160
|
+
background: var(--sg-bg);
|
|
161
|
+
color: var(--sg-fg);
|
|
162
|
+
}
|
|
163
|
+
.sv-adv-filter__head {
|
|
164
|
+
display: flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
gap: 0.5rem;
|
|
167
|
+
}
|
|
168
|
+
.sv-adv-filter__title {
|
|
169
|
+
margin: 0;
|
|
170
|
+
font-size: 0.95rem;
|
|
171
|
+
font-weight: 600;
|
|
172
|
+
}
|
|
173
|
+
.sv-adv-filter__badge {
|
|
174
|
+
font-size: 0.7rem;
|
|
175
|
+
font-weight: 600;
|
|
176
|
+
padding: 0.1rem 0.4rem;
|
|
177
|
+
border-radius: 9999px;
|
|
178
|
+
background: var(--sg-accent);
|
|
179
|
+
color: var(--sg-on-accent);
|
|
180
|
+
}
|
|
181
|
+
.sv-adv-filter__warn {
|
|
182
|
+
margin: 0;
|
|
183
|
+
font-size: 0.8rem;
|
|
184
|
+
color: var(--sg-muted);
|
|
185
|
+
}
|
|
186
|
+
.sv-adv-filter__actions {
|
|
187
|
+
display: flex;
|
|
188
|
+
gap: 0.5rem;
|
|
189
|
+
}
|
|
190
|
+
.sv-adv-filter__btn {
|
|
191
|
+
padding: 0.35rem 0.75rem;
|
|
192
|
+
border-radius: 6px;
|
|
193
|
+
border: 1px solid var(--sg-border);
|
|
194
|
+
background: var(--sg-bg);
|
|
195
|
+
color: var(--sg-fg);
|
|
196
|
+
font-size: 0.85rem;
|
|
197
|
+
cursor: pointer;
|
|
198
|
+
}
|
|
199
|
+
.sv-adv-filter__btn:disabled {
|
|
200
|
+
opacity: 0.5;
|
|
201
|
+
cursor: default;
|
|
202
|
+
}
|
|
203
|
+
.sv-adv-filter__btn.is-primary {
|
|
204
|
+
background: var(--sg-accent);
|
|
205
|
+
color: var(--sg-on-accent);
|
|
206
|
+
border-color: var(--sg-accent);
|
|
207
|
+
}
|
|
208
|
+
</style>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ExprColumn } from './expressions/expression-columns';
|
|
2
|
+
import type { PredicateExpr } from './expressions/expression-types';
|
|
3
|
+
type MinimalApi = {
|
|
4
|
+
getColumns(): ReadonlyArray<{
|
|
5
|
+
id: string;
|
|
6
|
+
field?: string;
|
|
7
|
+
header: string;
|
|
8
|
+
visible: boolean;
|
|
9
|
+
editorType?: string;
|
|
10
|
+
}>;
|
|
11
|
+
getData?: () => ReadonlyArray<Record<string, unknown>>;
|
|
12
|
+
setAdvancedFilter(expr: unknown): void;
|
|
13
|
+
getAdvancedFilter(): unknown;
|
|
14
|
+
isAdvancedFilterActive(): boolean;
|
|
15
|
+
};
|
|
16
|
+
type Props = {
|
|
17
|
+
/** The grid's API, from `onApiReady` / `bind:api`. */
|
|
18
|
+
api: MinimalApi;
|
|
19
|
+
/** Rows for the live match preview. Defaults to the grid's own data. */
|
|
20
|
+
rows?: ReadonlyArray<Record<string, unknown>>;
|
|
21
|
+
/** Override the derived column list. */
|
|
22
|
+
columns?: ReadonlyArray<ExprColumn>;
|
|
23
|
+
/** Include columns the user has hidden. Default false. */
|
|
24
|
+
includeHidden?: boolean;
|
|
25
|
+
/** Called after Apply / Clear with the expression now on the grid. */
|
|
26
|
+
onApply?: (expr: PredicateExpr | null) => void;
|
|
27
|
+
/**
|
|
28
|
+
* The expression the panel shows, bindable. Assign it to drive the panel
|
|
29
|
+
* from outside - a preset button, a saved view - and the draft re-seeds to
|
|
30
|
+
* match. Without this a parent that calls `api.setAdvancedFilter()` itself
|
|
31
|
+
* would filter the grid while the panel kept showing its old draft.
|
|
32
|
+
*/
|
|
33
|
+
expression?: PredicateExpr | null;
|
|
34
|
+
};
|
|
35
|
+
declare const SvAdvancedFilter: import("svelte").Component<Props, {}, "expression">;
|
|
36
|
+
type SvAdvancedFilter = ReturnType<typeof SvAdvancedFilter>;
|
|
37
|
+
export default SvAdvancedFilter;
|