@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.
Files changed (101) hide show
  1. package/README.md +95 -81
  2. package/dist/cdn/svgrid-enterprise.svelte-external.js +22479 -10466
  3. package/dist/node/studio.js +11590 -2907
  4. package/package.json +31 -10
  5. package/src/SvAlertRuleEditor.svelte +294 -0
  6. package/src/SvAlertsManager.svelte +210 -0
  7. package/src/SvAlertsPanel.svelte +129 -0
  8. package/src/SvBoard.svelte +3 -1
  9. package/src/SvExpressionEditor.svelte +341 -0
  10. package/src/SvGridAlerts.dom.test.ts +113 -0
  11. package/src/SvGridAlerts.svelte +265 -0
  12. package/src/SvGridBoard.svelte +2355 -0
  13. package/src/SvGridEditPanel.svelte +849 -794
  14. package/src/SvGridScheduler.svelte +5334 -4410
  15. package/src/SvPivotDesigner.svelte +3 -3
  16. package/src/SvRecordDetail.svelte +6 -2
  17. package/src/SvSchedule.svelte +3 -1
  18. package/src/{ai-export-pdf.test.ts → ai-export-pdf.dom.test.ts} +4 -1
  19. package/src/{ai-export-xlsx.test.ts → ai-export-xlsx.dom.test.ts} +4 -1
  20. package/src/{ai-export.test.ts → ai-export.dom.test.ts} +5 -1
  21. package/src/alerts/alert-engine-attach.ts +165 -0
  22. package/src/alerts/alert-engine.test.ts +135 -0
  23. package/src/alerts/alert-engine.ts +260 -0
  24. package/src/alerts/alert-formats.test.ts +87 -0
  25. package/src/alerts/alert-formats.ts +77 -0
  26. package/src/alerts/alert-observer.test.ts +189 -0
  27. package/src/alerts/alert-observer.ts +208 -0
  28. package/src/alerts/alert-scheduler.ts +96 -0
  29. package/src/alerts/alert-storage.test.ts +54 -0
  30. package/src/alerts/alert-storage.ts +116 -0
  31. package/src/alerts/alert-store.svelte.ts +80 -0
  32. package/src/alerts/alert-types.ts +94 -0
  33. package/src/alerts.ts +28 -0
  34. package/src/board.dom.test.ts +941 -0
  35. package/src/board.ts +36 -0
  36. package/src/export.ts +13 -1
  37. package/src/expressions/evaluate.test.ts +111 -0
  38. package/src/expressions/evaluate.ts +228 -0
  39. package/src/expressions/expression-columns.ts +133 -0
  40. package/src/expressions/expression-types.ts +84 -0
  41. package/src/expressions/parse.test.ts +106 -0
  42. package/src/expressions/parse.ts +610 -0
  43. package/src/import.ts +2 -0
  44. package/src/index.ts +180 -46
  45. package/src/install.ts +12 -2
  46. package/src/pivot-enable.ts +44 -0
  47. package/src/scheduler-assignments.test.ts +97 -0
  48. package/src/scheduler-assignments.ts +134 -0
  49. package/src/scheduler-axis.test.ts +108 -0
  50. package/src/scheduler-axis.ts +238 -0
  51. package/src/scheduler-booking.test.ts +57 -0
  52. package/src/scheduler-booking.ts +63 -0
  53. package/src/scheduler-config.ts +179 -0
  54. package/src/scheduler-dependencies.test.ts +155 -0
  55. package/src/scheduler-dependencies.ts +223 -0
  56. package/src/scheduler-freebusy.test.ts +41 -0
  57. package/src/scheduler-freebusy.ts +36 -0
  58. package/src/scheduler-heatmap.test.ts +39 -0
  59. package/src/scheduler-heatmap.ts +55 -0
  60. package/src/scheduler-resource-tree.test.ts +84 -0
  61. package/src/scheduler-resource-tree.ts +107 -0
  62. package/src/scheduler-slots.test.ts +53 -0
  63. package/src/scheduler-slots.ts +94 -0
  64. package/src/scheduler-summary.test.ts +47 -0
  65. package/src/scheduler-summary.ts +81 -0
  66. package/src/sources/index.ts +1 -1
  67. package/src/sources/introspect-supabase.test.ts +13 -1
  68. package/src/sources/introspect-supabase.ts +20 -0
  69. package/src/studio/copilot-core.test.ts +45 -0
  70. package/src/studio/copilot-core.ts +65 -0
  71. package/src/studio/deploy-cli.test.ts +56 -0
  72. package/src/studio/deploy-cli.ts +100 -0
  73. package/src/studio/emit-project.test.ts +503 -18
  74. package/src/studio/emit-project.ts +829 -111
  75. package/src/studio/emit-schema.test.ts +17 -0
  76. package/src/studio/emit-schema.ts +166 -35
  77. package/src/studio/index.ts +25 -1
  78. package/src/studio/introspect-openapi.test.ts +84 -0
  79. package/src/studio/introspect-openapi.ts +252 -0
  80. package/src/studio/project.test.ts +57 -0
  81. package/src/studio/project.ts +193 -6
  82. package/src/studio/samples/crm.ts +282 -258
  83. package/src/studio/samples/fleet.ts +213 -186
  84. package/src/studio/samples/insurance.ts +223 -195
  85. package/src/studio/samples/inventory.ts +213 -182
  86. package/src/studio/samples/live-data.test.ts +99 -98
  87. package/src/studio/samples/live-data.ts +8 -10
  88. package/src/studio/samples/projects.ts +212 -190
  89. package/src/studio/samples/samples.test.ts +52 -0
  90. package/src/studio/samples/shared.ts +26 -6
  91. package/src/studio/samples/starter.ts +251 -0
  92. package/src/studio/samples/support.ts +209 -184
  93. package/src/studio/ui-components-surface.test.ts +185 -0
  94. package/src/studio/ui-components.generated.ts +5617 -0
  95. package/src/studio/ui-components.ts +641 -472
  96. package/src/sveltekit/sql-source.test.ts +13 -0
  97. package/src/sveltekit/sql-source.ts +11 -6
  98. package/src/upgrade-prompt.ts +2 -2
  99. package/src/watermark.ts +2 -2
  100. package/src/ai.test.ts +0 -522
  101. 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
+ })