@svgrid/enterprise 1.2.0 → 2.0.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 (159) hide show
  1. package/dist/cdn/svgrid-enterprise.svelte-external.js +26039 -805
  2. package/dist/designer/assets/index-Dp44bTid.js +939 -0
  3. package/dist/designer/assets/index-RJp6x8tw.css +1 -0
  4. package/dist/designer/assets/jszip.min-CjMo-QGg.js +2 -0
  5. package/dist/designer/index.html +13 -0
  6. package/dist/node/studio.js +22554 -0
  7. package/package.json +10 -3
  8. package/src/SvAuthGate.svelte +115 -0
  9. package/src/SvBoard.dom.test.ts +67 -0
  10. package/src/SvBoard.svelte +192 -0
  11. package/src/SvExportMenu.svelte +553 -0
  12. package/src/SvFileInput.svelte +113 -0
  13. package/src/SvGridEditPanel.dom.test.ts +146 -0
  14. package/src/SvGridEditPanel.svelte +793 -0
  15. package/src/SvGridMasterDetail.svelte +95 -0
  16. package/src/SvImportDialog.svelte +1020 -0
  17. package/src/SvLookupInput.svelte +180 -0
  18. package/src/SvRecordDetail.dom.test.ts +137 -0
  19. package/src/SvRecordDetail.svelte +288 -0
  20. package/src/SvSchedule.dom.test.ts +57 -0
  21. package/src/SvSchedule.svelte +156 -0
  22. package/src/SvSchemaChart.svelte +233 -0
  23. package/src/SvSchemaDashboard.svelte +130 -0
  24. package/src/ai-export-pdf.test.ts +74 -0
  25. package/src/ai-export-xlsx.test.ts +87 -0
  26. package/src/ai-export.test.ts +110 -0
  27. package/src/ai.ts +1188 -782
  28. package/src/edit-panel.test.ts +213 -0
  29. package/src/edit-panel.ts +228 -0
  30. package/src/export-conditional.test.ts +60 -0
  31. package/src/export-conditional.ts +94 -0
  32. package/src/export-ooxml.test.ts +152 -0
  33. package/src/export-ooxml.ts +485 -0
  34. package/src/export-pdf.test.ts +138 -0
  35. package/src/export-pdf.ts +245 -0
  36. package/src/export-print.test.ts +66 -0
  37. package/src/export-print.ts +132 -0
  38. package/src/export-serialize.test.ts +56 -0
  39. package/src/export-serialize.ts +24 -0
  40. package/src/export-xls.ts +196 -0
  41. package/src/export-xlsx-roundtrip.test.ts +120 -0
  42. package/src/export-xlsx.test.ts +150 -0
  43. package/src/export.test.ts +349 -0
  44. package/src/export.ts +1452 -549
  45. package/src/import-automap.test.ts +131 -0
  46. package/src/import-hardening.test.ts +158 -0
  47. package/src/import.ts +1042 -648
  48. package/src/index.ts +282 -0
  49. package/src/install.ts +134 -114
  50. package/src/license-core.test.ts +23 -0
  51. package/src/license-core.ts +35 -0
  52. package/src/license.ts +103 -90
  53. package/src/master-detail.test.ts +61 -0
  54. package/src/master-detail.ts +42 -0
  55. package/src/print.ts +107 -127
  56. package/src/schema-designer.test.ts +121 -0
  57. package/src/schema-designer.ts +142 -0
  58. package/src/schema.test.ts +268 -0
  59. package/src/schema.ts +499 -0
  60. package/src/smart-shim.ts +107 -105
  61. package/src/sources/aggregate.test.ts +79 -0
  62. package/src/sources/aggregate.ts +102 -0
  63. package/src/sources/auth-supabase.test.ts +80 -0
  64. package/src/sources/auth-supabase.ts +87 -0
  65. package/src/sources/dashboard.kpi.test.ts +50 -0
  66. package/src/sources/dashboard.test.ts +61 -0
  67. package/src/sources/dashboard.ts +136 -0
  68. package/src/sources/field-inference.test.ts +60 -0
  69. package/src/sources/field-inference.ts +63 -0
  70. package/src/sources/filters.test.ts +58 -0
  71. package/src/sources/filters.ts +64 -0
  72. package/src/sources/index.ts +67 -0
  73. package/src/sources/introspect-supabase.test.ts +100 -0
  74. package/src/sources/introspect-supabase.ts +119 -0
  75. package/src/sources/realtime-supabase.test.ts +93 -0
  76. package/src/sources/realtime-supabase.ts +99 -0
  77. package/src/sources/relation-lookup.test.ts +99 -0
  78. package/src/sources/relation-lookup.ts +128 -0
  79. package/src/sources/rest-adapters.test.ts +95 -0
  80. package/src/sources/rest-adapters.ts +120 -0
  81. package/src/sources/rest.test.ts +104 -0
  82. package/src/sources/rest.ts +129 -0
  83. package/src/sources/schema-from-columns.test.ts +106 -0
  84. package/src/sources/schema-from-columns.ts +88 -0
  85. package/src/sources/supabase.test.ts +110 -0
  86. package/src/sources/supabase.ts +99 -0
  87. package/src/sources/with-entity-rules.test.ts +104 -0
  88. package/src/sources/with-entity-rules.ts +78 -0
  89. package/src/sources/with-relation-labels.test.ts +75 -0
  90. package/src/sources/with-relation-labels.ts +73 -0
  91. package/src/studio/bug-report.test.ts +101 -0
  92. package/src/studio/bug-report.ts +165 -0
  93. package/src/studio/cli.test.ts +187 -0
  94. package/src/studio/cli.ts +112 -0
  95. package/src/studio/csv.test.ts +90 -0
  96. package/src/studio/csv.ts +165 -0
  97. package/src/studio/db-connect-string.test.ts +94 -0
  98. package/src/studio/db-connect-string.ts +128 -0
  99. package/src/studio/emit-project.test.ts +923 -0
  100. package/src/studio/emit-project.ts +1273 -0
  101. package/src/studio/emit-schema.test.ts +94 -0
  102. package/src/studio/emit-schema.ts +920 -0
  103. package/src/studio/index.ts +195 -0
  104. package/src/studio/introspect-db.test.ts +186 -0
  105. package/src/studio/introspect-db.ts +312 -0
  106. package/src/studio/introspect-prisma.test.ts +99 -0
  107. package/src/studio/introspect-prisma.ts +175 -0
  108. package/src/studio/introspect.test.ts +172 -0
  109. package/src/studio/introspect.ts +310 -0
  110. package/src/studio/pipeline.test.ts +42 -0
  111. package/src/studio/project-robust.test.ts +157 -0
  112. package/src/studio/project.test.ts +473 -0
  113. package/src/studio/project.ts +916 -0
  114. package/src/studio/sample-data.test.ts +58 -0
  115. package/src/studio/sample-data.ts +200 -0
  116. package/src/studio/samples/ats.ts +202 -0
  117. package/src/studio/samples/clinic.ts +177 -0
  118. package/src/studio/samples/crm.ts +250 -0
  119. package/src/studio/samples/ecommerce.ts +187 -0
  120. package/src/studio/samples/events.ts +199 -0
  121. package/src/studio/samples/fleet.ts +184 -0
  122. package/src/studio/samples/gym.ts +213 -0
  123. package/src/studio/samples/hr.ts +193 -0
  124. package/src/studio/samples/index.ts +55 -0
  125. package/src/studio/samples/insurance.ts +195 -0
  126. package/src/studio/samples/inventory.ts +182 -0
  127. package/src/studio/samples/invoicing.ts +162 -0
  128. package/src/studio/samples/library.ts +180 -0
  129. package/src/studio/samples/live-data.test.ts +98 -0
  130. package/src/studio/samples/live-data.ts +308 -0
  131. package/src/studio/samples/projects.ts +190 -0
  132. package/src/studio/samples/realestate.ts +196 -0
  133. package/src/studio/samples/restaurant.ts +187 -0
  134. package/src/studio/samples/samples.test.ts +208 -0
  135. package/src/studio/samples/school.ts +197 -0
  136. package/src/studio/samples/seed-floor.test.ts +25 -0
  137. package/src/studio/samples/shared.ts +305 -0
  138. package/src/studio/samples/subscriptions.ts +183 -0
  139. package/src/studio/samples/support.ts +182 -0
  140. package/src/studio/scaffold-app.test.ts +91 -0
  141. package/src/studio/scaffold-app.ts +161 -0
  142. package/src/studio/scaffold.test.ts +178 -0
  143. package/src/studio/scaffold.ts +374 -0
  144. package/src/studio/themes.ts +172 -0
  145. package/src/studio/verify.test.ts +47 -0
  146. package/src/studio/verify.ts +79 -0
  147. package/src/sveltekit/in-memory.test.ts +104 -0
  148. package/src/sveltekit/in-memory.ts +129 -0
  149. package/src/sveltekit/index.ts +23 -0
  150. package/src/sveltekit/query-plan.test.ts +109 -0
  151. package/src/sveltekit/query-plan.ts +125 -0
  152. package/src/sveltekit/sql-source.test.ts +185 -0
  153. package/src/sveltekit/sql-source.ts +166 -0
  154. package/src/sveltekit/sql.test.ts +80 -0
  155. package/src/sveltekit/sql.ts +131 -0
  156. package/src/sveltekit/transport.test.ts +175 -0
  157. package/src/sveltekit/transport.ts +254 -0
  158. package/src/sveltekit/types.ts +11 -0
  159. package/src/upgrade-prompt.ts +149 -148
@@ -0,0 +1,146 @@
1
+ /**
2
+ * The repo's first runtime (DOM) test: mount SvGridEditPanel in jsdom and assert
3
+ * it renders the *rich* editor suite (not bare native inputs) and round-trips a
4
+ * row's values - the path that was previously only compile-checked. Enabled by
5
+ * the svelte plugin in vite.config.ts.
6
+ */
7
+ import { describe, it, expect, afterEach, vi } from 'vitest'
8
+ import { mount, unmount, flushSync } from 'svelte'
9
+ import SvGridEditPanel from './SvGridEditPanel.svelte'
10
+ import type { EntitySchema } from './schema'
11
+ import { getSampleApp } from './studio/samples/index'
12
+
13
+ type Customer = { id: string; name: string; mrr: number; active: boolean; tier: string }
14
+
15
+ const schema: EntitySchema<Customer> = {
16
+ name: 'customers',
17
+ idField: 'id',
18
+ fields: [
19
+ { field: 'id', type: 'text', primaryKey: true, readonly: true },
20
+ { field: 'name', type: 'text', required: true },
21
+ { field: 'mrr', type: 'number' },
22
+ { field: 'active', type: 'boolean' },
23
+ { field: 'tier', type: 'enum', options: [{ value: 'free', label: 'Free' }, { value: 'pro', label: 'Pro' }] },
24
+ ],
25
+ }
26
+
27
+ let host: HTMLElement | null = null
28
+ let comp: ReturnType<typeof mount> | null = null
29
+
30
+ afterEach(() => {
31
+ if (comp) { unmount(comp); comp = null }
32
+ if (host) { host.remove(); host = null }
33
+ })
34
+
35
+ function render(props: Record<string, unknown>): HTMLElement {
36
+ host = document.createElement('div')
37
+ document.body.appendChild(host)
38
+ comp = mount(SvGridEditPanel, { target: host, props })
39
+ flushSync()
40
+ return host
41
+ }
42
+
43
+ describe('SvGridEditPanel (DOM)', () => {
44
+ it('mounts and renders each field with its rich editor, seeded from the row', () => {
45
+ const el = render({
46
+ schema,
47
+ row: { id: '1', name: 'Ada', mrr: 1200, active: true, tier: 'pro' },
48
+ presentation: 'inline',
49
+ onSubmit: vi.fn(),
50
+ onCancel: vi.fn(),
51
+ })
52
+
53
+ // Field labels are present.
54
+ expect(el.textContent).toContain('Name')
55
+ expect(el.textContent).toContain('Mrr')
56
+
57
+ // number -> SvNumberInput (its .sv-num__input), not a bare <input type="number">.
58
+ const numInput = el.querySelector<HTMLInputElement>('.sv-num__input')
59
+ expect(numInput).toBeTruthy()
60
+ expect(numInput!.value).toBe('1200') // seeded from the row
61
+
62
+ // boolean -> SvSwitchButton, on because active === true.
63
+ const sw = el.querySelector('.sv-switch')
64
+ expect(sw).toBeTruthy()
65
+ expect(sw!.classList.contains('is-on')).toBe(true)
66
+
67
+ // The primary action reads "Save" in edit mode.
68
+ const submit = el.querySelector<HTMLButtonElement>('button[type="submit"]')
69
+ expect(submit?.textContent?.trim()).toBe('Save')
70
+ })
71
+
72
+ it('is in create mode with no row (empty number, switch off, "Create" button)', () => {
73
+ const el = render({ schema, presentation: 'inline', onSubmit: vi.fn(), onCancel: vi.fn() })
74
+ expect(el.querySelector<HTMLInputElement>('.sv-num__input')!.value).toBe('') // empty, not "0"
75
+ expect(el.querySelector('.sv-switch')!.classList.contains('is-on')).toBe(false)
76
+ expect(el.querySelector('button[type="submit"]')?.textContent?.trim()).toBe('Create')
77
+ })
78
+
79
+ it('routes each editorType to its rich editor from the suite', () => {
80
+ const rich: EntitySchema = {
81
+ name: 'assets',
82
+ idField: 'id',
83
+ fields: [
84
+ { field: 'id', type: 'text', primaryKey: true, readonly: true },
85
+ { field: 'brand', type: 'text', input: { editorType: 'color' } },
86
+ { field: 'secret', type: 'text', input: { editorType: 'password' } },
87
+ { field: 'labels', type: 'text', input: { editorType: 'chips' } },
88
+ { field: 'due', type: 'date' },
89
+ { field: 'phone', type: 'text', input: { editorType: 'phone' } },
90
+ { field: 'score', type: 'number', input: { editorType: 'slider' }, min: 0, max: 10 },
91
+ ],
92
+ }
93
+ const el = render({
94
+ schema: rich,
95
+ row: { id: '1', brand: '#ff0000', secret: 'pw', labels: 'a,b', due: '2024-01-02', phone: '+14155550100', score: 7 },
96
+ presentation: 'inline',
97
+ onSubmit: vi.fn(),
98
+ onCancel: vi.fn(),
99
+ })
100
+ expect(el.querySelector('.sv-color')).toBeTruthy() // color -> SvColorInput
101
+ expect(el.querySelector('.sv-pw')).toBeTruthy() // password -> SvPasswordInput
102
+ expect(el.querySelector('.sv-tags')).toBeTruthy() // chips -> SvTagsInput
103
+ expect(el.querySelector('.sv-dtp')).toBeTruthy() // date -> SvDateTimePicker
104
+ expect(el.querySelector('.sv-phone')).toBeTruthy() // phone -> SvPhoneInput
105
+ expect(el.querySelector('.sv-slider')).toBeTruthy() // slider -> SvSlider
106
+ })
107
+
108
+ it('renders the enriched CRM sample forms with real editors (samples <-> edit panel)', () => {
109
+ const proj = getSampleApp('crm')!.build()
110
+ const entity = (name: string) => proj.entities.find((e) => e.name === name)!
111
+ const firstRow = (name: string) => (proj.dataSources?.[name] as { seed?: Record<string, unknown>[] }).seed![0]!
112
+
113
+ // Contacts: phone -> SvPhoneInput, segments (chips) -> SvTagsInput.
114
+ const contacts = render({ schema: entity('contacts'), row: firstRow('contacts'), presentation: 'inline', onSubmit: vi.fn(), onCancel: vi.fn() })
115
+ expect(contacts.querySelector('.sv-phone')).toBeTruthy()
116
+ expect(contacts.querySelector('.sv-tags')).toBeTruthy()
117
+
118
+ // Deals: probability -> SvSlider (rendered for slider editorType).
119
+ const deals = render({ schema: entity('deals'), row: firstRow('deals'), presentation: 'inline', onSubmit: vi.fn(), onCancel: vi.fn() })
120
+ expect(deals.querySelector('.sv-slider')).toBeTruthy()
121
+
122
+ // Companies: country -> SvCountryInput, health (rating) -> SvSlider.
123
+ const companies = render({ schema: entity('companies'), row: firstRow('companies'), presentation: 'inline', onSubmit: vi.fn(), onCancel: vi.fn() })
124
+ expect(companies.querySelector('.sv-country')).toBeTruthy()
125
+ expect(companies.querySelector('.sv-slider')).toBeTruthy()
126
+ })
127
+
128
+ it('submits the row values (edit mode, readonly id omitted)', async () => {
129
+ const onSubmit = vi.fn()
130
+ const el = render({
131
+ schema,
132
+ row: { id: '1', name: 'Ada', mrr: 1200, active: true, tier: 'pro' },
133
+ presentation: 'inline',
134
+ onSubmit,
135
+ onCancel: vi.fn(),
136
+ })
137
+ el.querySelector<HTMLButtonElement>('button[type="submit"]')!.click()
138
+ // Submit validates asynchronously before calling onSubmit.
139
+ await vi.waitFor(() => expect(onSubmit).toHaveBeenCalledTimes(1))
140
+ const payload = onSubmit.mock.calls[0]![0] as { mode: string; id: string | null; values: Record<string, unknown> }
141
+ expect(payload.mode).toBe('edit')
142
+ expect(payload.id).toBe('1')
143
+ expect(payload.values).toMatchObject({ name: 'Ada', mrr: 1200, active: true, tier: 'pro' })
144
+ expect(payload.values).not.toHaveProperty('id') // readonly PK is never submitted
145
+ })
146
+ })