@svgrid/enterprise 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -81
- package/dist/cdn/svgrid-enterprise.svelte-external.js +22479 -10466
- package/dist/node/studio.js +11590 -2907
- package/package.json +31 -10
- package/src/SvAlertRuleEditor.svelte +294 -0
- package/src/SvAlertsManager.svelte +210 -0
- package/src/SvAlertsPanel.svelte +129 -0
- package/src/SvBoard.svelte +3 -1
- package/src/SvExpressionEditor.svelte +341 -0
- package/src/SvGridAlerts.dom.test.ts +113 -0
- package/src/SvGridAlerts.svelte +265 -0
- package/src/SvGridBoard.svelte +2355 -0
- package/src/SvGridEditPanel.svelte +849 -794
- package/src/SvGridScheduler.svelte +5334 -4410
- package/src/SvPivotDesigner.svelte +3 -3
- package/src/SvRecordDetail.svelte +6 -2
- package/src/SvSchedule.svelte +3 -1
- package/src/{ai-export-pdf.test.ts → ai-export-pdf.dom.test.ts} +4 -1
- package/src/{ai-export-xlsx.test.ts → ai-export-xlsx.dom.test.ts} +4 -1
- package/src/{ai-export.test.ts → ai-export.dom.test.ts} +5 -1
- package/src/alerts/alert-engine-attach.ts +165 -0
- package/src/alerts/alert-engine.test.ts +135 -0
- package/src/alerts/alert-engine.ts +260 -0
- package/src/alerts/alert-formats.test.ts +87 -0
- package/src/alerts/alert-formats.ts +77 -0
- package/src/alerts/alert-observer.test.ts +189 -0
- package/src/alerts/alert-observer.ts +208 -0
- package/src/alerts/alert-scheduler.ts +96 -0
- package/src/alerts/alert-storage.test.ts +54 -0
- package/src/alerts/alert-storage.ts +116 -0
- package/src/alerts/alert-store.svelte.ts +80 -0
- package/src/alerts/alert-types.ts +94 -0
- package/src/alerts.ts +28 -0
- package/src/board.dom.test.ts +941 -0
- package/src/board.ts +36 -0
- package/src/export.ts +13 -1
- package/src/expressions/evaluate.test.ts +111 -0
- package/src/expressions/evaluate.ts +228 -0
- package/src/expressions/expression-columns.ts +133 -0
- package/src/expressions/expression-types.ts +84 -0
- package/src/expressions/parse.test.ts +106 -0
- package/src/expressions/parse.ts +610 -0
- package/src/import.ts +2 -0
- package/src/index.ts +180 -46
- package/src/install.ts +12 -2
- package/src/pivot-enable.ts +44 -0
- package/src/scheduler-assignments.test.ts +97 -0
- package/src/scheduler-assignments.ts +134 -0
- package/src/scheduler-axis.test.ts +108 -0
- package/src/scheduler-axis.ts +238 -0
- package/src/scheduler-booking.test.ts +57 -0
- package/src/scheduler-booking.ts +63 -0
- package/src/scheduler-config.ts +179 -0
- package/src/scheduler-dependencies.test.ts +155 -0
- package/src/scheduler-dependencies.ts +223 -0
- package/src/scheduler-freebusy.test.ts +41 -0
- package/src/scheduler-freebusy.ts +36 -0
- package/src/scheduler-heatmap.test.ts +39 -0
- package/src/scheduler-heatmap.ts +55 -0
- package/src/scheduler-resource-tree.test.ts +84 -0
- package/src/scheduler-resource-tree.ts +107 -0
- package/src/scheduler-slots.test.ts +53 -0
- package/src/scheduler-slots.ts +94 -0
- package/src/scheduler-summary.test.ts +47 -0
- package/src/scheduler-summary.ts +81 -0
- package/src/sources/index.ts +1 -1
- package/src/sources/introspect-supabase.test.ts +13 -1
- package/src/sources/introspect-supabase.ts +20 -0
- package/src/studio/copilot-core.test.ts +45 -0
- package/src/studio/copilot-core.ts +65 -0
- package/src/studio/deploy-cli.test.ts +56 -0
- package/src/studio/deploy-cli.ts +100 -0
- package/src/studio/emit-project.test.ts +503 -18
- package/src/studio/emit-project.ts +829 -111
- package/src/studio/emit-schema.test.ts +17 -0
- package/src/studio/emit-schema.ts +166 -35
- package/src/studio/index.ts +25 -1
- package/src/studio/introspect-openapi.test.ts +84 -0
- package/src/studio/introspect-openapi.ts +252 -0
- package/src/studio/project.test.ts +57 -0
- package/src/studio/project.ts +193 -6
- package/src/studio/samples/crm.ts +282 -258
- package/src/studio/samples/fleet.ts +213 -186
- package/src/studio/samples/insurance.ts +223 -195
- package/src/studio/samples/inventory.ts +213 -182
- package/src/studio/samples/live-data.test.ts +99 -98
- package/src/studio/samples/live-data.ts +8 -10
- package/src/studio/samples/projects.ts +212 -190
- package/src/studio/samples/samples.test.ts +52 -0
- package/src/studio/samples/shared.ts +26 -6
- package/src/studio/samples/starter.ts +251 -0
- package/src/studio/samples/support.ts +209 -184
- package/src/studio/ui-components-surface.test.ts +185 -0
- package/src/studio/ui-components.generated.ts +5617 -0
- package/src/studio/ui-components.ts +641 -472
- package/src/sveltekit/sql-source.test.ts +13 -0
- package/src/sveltekit/sql-source.ts +11 -6
- package/src/upgrade-prompt.ts +2 -2
- package/src/watermark.ts +2 -2
- package/src/ai.test.ts +0 -522
- package/src/ai.ts +0 -1388
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
ExpressionParseError,
|
|
4
|
+
collectColumnRefs,
|
|
5
|
+
parsePredicate,
|
|
6
|
+
stringifyPredicate,
|
|
7
|
+
validateExpression,
|
|
8
|
+
} from './parse'
|
|
9
|
+
import { evaluatePredicate } from './evaluate'
|
|
10
|
+
import type { ExprColumn } from './expression-columns'
|
|
11
|
+
import type { PredicateExpr } from './expression-types'
|
|
12
|
+
|
|
13
|
+
const columns: ExprColumn[] = [
|
|
14
|
+
{ id: 'price', name: 'Unit Price', type: 'number' },
|
|
15
|
+
{ id: 'qty', name: 'Qty', type: 'number' },
|
|
16
|
+
{ id: 'name', name: 'Name', type: 'text' },
|
|
17
|
+
{ id: 'region', name: 'Region', type: 'text' },
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
describe('parsePredicate', () => {
|
|
21
|
+
it('parses a col-vs-literal comparison into a cmp node (grid-filter semantics)', () => {
|
|
22
|
+
const e = parsePredicate('price > 100', columns)
|
|
23
|
+
expect(e).toEqual({ kind: 'cmp', column: 'price', op: 'greaterThan', value: 100 })
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('resolves [Bracketed Name] references to ids', () => {
|
|
27
|
+
const e = parsePredicate('[Unit Price] >= 50', columns) as Extract<PredicateExpr, { kind: 'scalarCmp' }>
|
|
28
|
+
// >= has no cmp equivalent, so it becomes a scalarCmp over the resolved column id
|
|
29
|
+
expect(e.kind).toBe('scalarCmp')
|
|
30
|
+
expect(e.left).toEqual({ kind: 'col', id: 'price' })
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('parses keyword text/set/range operators', () => {
|
|
34
|
+
expect(parsePredicate('name CONTAINS "wid"', columns)).toEqual({ kind: 'cmp', column: 'name', op: 'contains', value: 'wid' })
|
|
35
|
+
expect(parsePredicate('region IN ("EU", "US")', columns)).toEqual({ kind: 'cmp', column: 'region', op: 'in', value: ['EU', 'US'] })
|
|
36
|
+
expect(parsePredicate('price BETWEEN 10 AND 20', columns)).toEqual({ kind: 'cmp', column: 'price', op: 'between', value: 10, valueTo: 20 })
|
|
37
|
+
expect(parsePredicate('name ISBLANK', columns)).toEqual({ kind: 'cmp', column: 'name', op: 'isBlank' })
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('honours AND/OR/NOT precedence and grouping', () => {
|
|
41
|
+
const e = parsePredicate('price > 100 AND (region = "EU" OR region = "US")', columns) as Extract<PredicateExpr, { kind: 'and' }>
|
|
42
|
+
expect(e.kind).toBe('and')
|
|
43
|
+
expect(e.parts[1]!.kind).toBe('or')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('parses cross-column scalar maths', () => {
|
|
47
|
+
const e = parsePredicate('price / qty >= 40', columns) as Extract<PredicateExpr, { kind: 'scalarCmp' }>
|
|
48
|
+
expect(e.kind).toBe('scalarCmp')
|
|
49
|
+
expect(e.op).toBe('>=')
|
|
50
|
+
expect(e.left).toEqual({ kind: 'bin', op: '/', left: { kind: 'col', id: 'price' }, right: { kind: 'col', id: 'qty' } })
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('throws a positioned error on a syntax problem', () => {
|
|
54
|
+
expect(() => parsePredicate('price >', columns)).toThrow(ExpressionParseError)
|
|
55
|
+
try {
|
|
56
|
+
parsePredicate('price @ 5', columns)
|
|
57
|
+
} catch (err) {
|
|
58
|
+
expect(err).toBeInstanceOf(ExpressionParseError)
|
|
59
|
+
expect((err as ExpressionParseError).pos).toBeGreaterThan(0)
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('parsed expressions evaluate correctly end to end', () => {
|
|
64
|
+
const e = parsePredicate('price > 100 AND region = "EU"', columns)
|
|
65
|
+
expect(evaluatePredicate(e, { row: { price: 120, region: 'EU' } })).toBe(true)
|
|
66
|
+
expect(evaluatePredicate(e, { row: { price: 120, region: 'US' } })).toBe(false)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe('stringifyPredicate', () => {
|
|
71
|
+
it('round-trips through parse for the common forms', () => {
|
|
72
|
+
for (const src of [
|
|
73
|
+
'price > 100',
|
|
74
|
+
'name CONTAINS "wid"',
|
|
75
|
+
'region IN ("EU", "US")',
|
|
76
|
+
'price BETWEEN 10 AND 20',
|
|
77
|
+
'name ISBLANK',
|
|
78
|
+
]) {
|
|
79
|
+
const ast = parsePredicate(src, columns)
|
|
80
|
+
const back = stringifyPredicate(ast, columns)
|
|
81
|
+
expect(stringifyPredicate(parsePredicate(back, columns), columns)).toBe(back)
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('writes [bracketed] names when a label has spaces', () => {
|
|
86
|
+
const ast = parsePredicate('price > 100', columns)
|
|
87
|
+
expect(stringifyPredicate(ast, columns)).toBe('[Unit Price] > 100')
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('validateExpression + collectColumnRefs', () => {
|
|
92
|
+
it('collects every referenced column id', () => {
|
|
93
|
+
const ast = parsePredicate('price / qty >= 40 AND region = "EU"', columns)
|
|
94
|
+
expect(collectColumnRefs(ast).sort()).toEqual(['price', 'qty', 'region'])
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('flags unknown columns and functions', () => {
|
|
98
|
+
const ast = parsePredicate('bogus > 5', columns)
|
|
99
|
+
expect(validateExpression(ast, columns)).toContain('Unknown column "bogus"')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('passes a sound expression', () => {
|
|
103
|
+
const ast = parsePredicate('price > 100', columns)
|
|
104
|
+
expect(validateExpression(ast, columns)).toEqual([])
|
|
105
|
+
})
|
|
106
|
+
})
|