@svgrid/enterprise 3.1.16 → 3.1.18

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 (57) hide show
  1. package/dist/SvGridEditPanel.svelte +14 -1
  2. package/dist/SvGridScheduler.svelte +15 -6
  3. package/dist/SvSheet.svelte +2 -0
  4. package/dist/cdn/svgrid-enterprise.svelte-external.js +6582 -6501
  5. package/dist/designer/assets/{index-C0GDyyFs.js → index-DKudY-XD.js} +357 -346
  6. package/dist/designer/assets/index-WCxj6WfJ.css +1 -0
  7. package/dist/designer/index.html +2 -2
  8. package/dist/fields/SvBase.svelte +36 -33
  9. package/dist/fields/base-connect.js +50 -9
  10. package/dist/fields/base-sql.d.ts +8 -0
  11. package/dist/fields/base-sql.js +12 -3
  12. package/dist/install.js +3 -3
  13. package/dist/node/studio.js +205 -60
  14. package/dist/sheet-enable.d.ts +8 -2
  15. package/dist/sheet-enable.js +21 -9
  16. package/dist/sources/introspect-supabase.d.ts +6 -3
  17. package/dist/sources/introspect-supabase.js +29 -11
  18. package/dist/sources/supabase.d.ts +10 -0
  19. package/dist/sources/supabase.js +11 -2
  20. package/dist/studio/cli.d.ts +9 -0
  21. package/dist/studio/cli.js +41 -7
  22. package/dist/studio/emit-project.d.ts +3 -1
  23. package/dist/studio/emit-project.js +84 -33
  24. package/dist/studio/emit-schema.js +9 -2
  25. package/dist/studio/index.d.ts +1 -1
  26. package/dist/studio/init-flow.d.ts +7 -0
  27. package/dist/studio/init-flow.js +23 -2
  28. package/dist/studio/introspect-db.d.ts +15 -1
  29. package/dist/studio/introspect-db.js +29 -5
  30. package/dist/sveltekit/sql-source.d.ts +24 -0
  31. package/dist/sveltekit/sql-source.js +34 -1
  32. package/dist/sveltekit/sql.js +14 -2
  33. package/dist/version.d.ts +2 -2
  34. package/dist/version.js +2 -2
  35. package/dist/wc/GridFooter-BgoA77TJ.js +145 -0
  36. package/dist/wc/{GridMenus-q9qYpzKh.js → GridMenus-DVGuqp2l.js} +430 -430
  37. package/dist/wc/{PinSplitter-D-qtDhSM.js → PinSplitter-Btco0txr.js} +24 -24
  38. package/dist/wc/{SvChartMenu-CQNrQGT2.js → SvChartMenu-Ue-HFR5c.js} +58 -58
  39. package/dist/wc/{SvDateRangeInput-BYNOfYxD.js → SvDateRangeInput-CJZohgBe.js} +43 -43
  40. package/dist/wc/{SvDateTimePicker-Bq9N0Oiy.js → SvDateTimePicker-DmK_QkkU.js} +241 -241
  41. package/dist/wc/{SvField-B_kurx_P.js → SvField-C-OodMMv.js} +71 -71
  42. package/dist/wc/SvGridCellEditor-C7ios4i_.js +582 -0
  43. package/dist/wc/{SvGridChart-DrmqEen2.js → SvGridChart-DWRqlhCV.js} +549 -549
  44. package/dist/wc/{SvGridChartBuilder-XFvW1BdT.js → SvGridChartBuilder-BXW3yUR0.js} +337 -337
  45. package/dist/wc/{SvGridChartPanel-oJJtUKG6.js → SvGridChartPanel-28n4tomx.js} +354 -354
  46. package/dist/wc/{SvGridChartView-Cetuj70H.js → SvGridChartView-CbG_WrU-.js} +7 -7
  47. package/dist/wc/{SvGridDropdown-45WsObLL.js → SvGridDropdown-BVnpNU_I.js} +130 -130
  48. package/dist/wc/{SvModal-DrfOYYyX.js → SvModal-DLppAQED.js} +91 -91
  49. package/dist/wc/{client-DQIzjDBG.js → client-GWAV79ON.js} +479 -476
  50. package/dist/wc/{date-format-DS-z_h9v.js → date-format-4_QoS4zZ.js} +393 -393
  51. package/dist/wc/{grid-extension.svelte-Bufq4B4C.js → grid-extension.svelte-CucBS4FL.js} +1 -1
  52. package/dist/wc/sv-sheet-element.js +10475 -10461
  53. package/dist/wc/{svelte-virtualizer.svelte-CkZaFakp.js → svelte-virtualizer.svelte-BDcouWqw.js} +3 -3
  54. package/package.json +17 -4
  55. package/dist/designer/assets/index-BdL--HXH.css +0 -1
  56. package/dist/wc/GridFooter-4T29pfok.js +0 -145
  57. package/dist/wc/SvGridCellEditor-Nnl8C3Yj.js +0 -582
@@ -4,7 +4,7 @@
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-C0GDyyFs.js"></script>
7
+ <script type="module" crossorigin src="./assets/index-DKudY-XD.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">
@@ -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-BdL--HXH.css">
48
+ <link rel="stylesheet" crossorigin href="./assets/index-WCxj6WfJ.css">
49
49
  </head>
50
50
  <body>
51
51
  <div id="app"></div>
@@ -525,11 +525,12 @@
525
525
  })
526
526
  </script>
527
527
 
528
- {#if tables && current}
528
+ <!-- An empty list still gets the tabs, so "Add table" is there. -->
529
+ {#if tables}
529
530
  <div class="sv-fbase-tables" style:height>
530
531
  <BaseTabs
531
532
  {tables}
532
- activeId={current.id}
533
+ activeId={current?.id ?? ''}
533
534
  onSwitch={switchTo}
534
535
  onAdd={addTable}
535
536
  onRename={renameTable}
@@ -539,37 +540,39 @@
539
540
  status={syncLine}
540
541
  />
541
542
  <div class="sv-fbase-slot">
542
- {#key current.id}
543
- <BaseTableView
544
- {...gridProps}
545
- bare
546
- data={gridData}
547
- columns={current.columns}
548
- views={current.views ?? GRID_ONLY}
549
- bind:activeView={viewOf[current.id]}
550
- onViewsChange={(v: FieldView[]) => commit(pulled({ views: v }))}
551
- table={current}
552
- tables={() => pulled()}
553
- runner={automations ? runner : undefined}
554
- {serverRuns}
555
- onAutomationsChange={(list: BaseAutomation[]) => commit(pulled({ automations: list }))}
556
- onFormSubmit={(row: Row, viewId: string) => void runner.handle({ type: 'form', table: current!.id, record: row, view: viewId })}
557
- newRecord={() => ({ id: newRecordId() })}
558
- {viewTypes}
559
- {rowHeights}
560
- containerHeight="100%"
561
- onApiReady={(a: any) => {
562
- api = a
563
- onApiReady?.(a)
564
- const rowId = pendingOpen
565
- pendingOpen = null
566
- if (rowId) queueMicrotask(() => {
567
- const ctrl = gridOf(a)
568
- if (ctrl) openRecord({ ctrl, rowId })
569
- })
570
- }}
571
- />
572
- {/key}
543
+ {#if current}
544
+ {#key current.id}
545
+ <BaseTableView
546
+ {...gridProps}
547
+ bare
548
+ data={gridData}
549
+ columns={current.columns}
550
+ views={current.views ?? GRID_ONLY}
551
+ bind:activeView={viewOf[current.id]}
552
+ onViewsChange={(v: FieldView[]) => commit(pulled({ views: v }))}
553
+ table={current}
554
+ tables={() => pulled()}
555
+ runner={automations ? runner : undefined}
556
+ {serverRuns}
557
+ onAutomationsChange={(list: BaseAutomation[]) => commit(pulled({ automations: list }))}
558
+ onFormSubmit={(row: Row, viewId: string) => void runner.handle({ type: 'form', table: current!.id, record: row, view: viewId })}
559
+ newRecord={() => ({ id: newRecordId() })}
560
+ {viewTypes}
561
+ {rowHeights}
562
+ containerHeight="100%"
563
+ onApiReady={(a: any) => {
564
+ api = a
565
+ onApiReady?.(a)
566
+ const rowId = pendingOpen
567
+ pendingOpen = null
568
+ if (rowId) queueMicrotask(() => {
569
+ const ctrl = gridOf(a)
570
+ if (ctrl) openRecord({ ctrl, rowId })
571
+ })
572
+ }}
573
+ />
574
+ {/key}
575
+ {/if}
573
576
  </div>
574
577
  </div>
575
578
  {:else}
@@ -5,7 +5,7 @@ import { createSupabaseDataSource } from '../sources/supabase.js';
5
5
  import { createSupabaseRealtime } from '../sources/realtime-supabase.js';
6
6
  import { introspectSupabaseTable, listSupabaseTables } from '../sources/introspect-supabase.js';
7
7
  import { applyBaseComments, baseSpecFromSchemas, baseTablesFromSpec, withInverses } from './base-schema.js';
8
- import { SQL_COMMENT_PREFIX } from './base-sql.js';
8
+ import { BASE_ORDER_COLUMN, SQL_COMMENT_PREFIX } from './base-sql.js';
9
9
  const SQL_DIALECT = {
10
10
  postgres: { placeholders: '$', ilike: true },
11
11
  supabase: { placeholders: '$', ilike: true },
@@ -13,6 +13,41 @@ const SQL_DIALECT = {
13
13
  sqlite: { placeholders: '?' },
14
14
  mssql: { placeholders: '@' },
15
15
  };
16
+ // ---- The order column (BASE_ORDER_COLUMN) -----------------------------------
17
+ // A table made by baseToSql numbers its records in insertion order. The base
18
+ // reads in that order while nothing is sorted, but the column is not a field:
19
+ // it is left out of what the base shows and validates, out of the rows it
20
+ // gets, and out of every write (generated always, so writing it would fail).
21
+ const hasOrder = (s) => s.fields.some((f) => f.field === BASE_ORDER_COLUMN);
22
+ const ORDER = [{ field: BASE_ORDER_COLUMN }];
23
+ /** The schema the base shows: without the order column. */
24
+ function shown(s) {
25
+ return hasOrder(s) ? { ...s, fields: s.fields.filter((f) => f.field !== BASE_ORDER_COLUMN) } : s;
26
+ }
27
+ function dropOrder(row) {
28
+ if (!row || typeof row !== 'object' || !(BASE_ORDER_COLUMN in row))
29
+ return row;
30
+ const copy = { ...row };
31
+ delete copy[BASE_ORDER_COLUMN];
32
+ return copy;
33
+ }
34
+ /** A source that never hands out or writes the order column. */
35
+ function hideOrder(source) {
36
+ return {
37
+ ...source,
38
+ getRows: async (request) => {
39
+ const result = await source.getRows(request);
40
+ return { ...result, rows: result.rows.map(dropOrder) };
41
+ },
42
+ createRow: async (input) => dropOrder(await source.createRow(dropOrder(input))),
43
+ updateRow: async (id, patch) => dropOrder(await source.updateRow(id, dropOrder(patch))),
44
+ };
45
+ }
46
+ /** A table on SQL, in insertion order when it has the order column. */
47
+ function sqlSource(schema, table, dialect, execute) {
48
+ const source = createSqlDataSource({ schema, table, dialect: SQL_DIALECT[dialect], execute, ...(hasOrder(schema) ? { defaultOrder: ORDER } : {}) });
49
+ return hasOrder(schema) ? hideOrder(source) : source;
50
+ }
16
51
  const quote = (dialect, name) => dialect === 'mysql' ? `\`${name.replace(/`/g, '``')}\`` : dialect === 'mssql' ? `[${name.replace(/]/g, ']]')}]` : `"${name.replace(/"/g, '""')}"`;
17
52
  const param = (dialect, i) => (dialect === 'postgres' || dialect === 'supabase' ? `$${i}` : dialect === 'mssql' ? `@p${i}` : '?');
18
53
  /** The values each text column repeats, most used first (at most 13 per column). */
@@ -130,9 +165,10 @@ async function makesKeys(o, dialect, s) {
130
165
  async function readDatabase(o) {
131
166
  const dialect = o.dialect ?? 'postgres';
132
167
  const names = o.tables ?? (await listDatabaseTables(dialect, o.execute));
133
- const list = [];
168
+ const all = [];
134
169
  for (const table of names)
135
- list.push(await introspectDatabase({ dialect, table, execute: o.execute }));
170
+ all.push(await introspectDatabase({ dialect, table, execute: o.execute }));
171
+ const list = all.map(shown);
136
172
  // A junction table the list leaves out still carries a link to many.
137
173
  const values = o.choices === false ? {} : await readValues(o, dialect, list);
138
174
  const keys = new Map();
@@ -143,7 +179,8 @@ async function readDatabase(o) {
143
179
  let specs = baseSpecFromSchemas(list, { values, serverIds: (s) => keys.get(s.name) ?? false, order: o.tables ? 'given' : 'links', inverses: !kept });
144
180
  if (kept)
145
181
  specs = withComments(specs, comments, !!o.tables);
146
- return { specs, schemas: new Map(list.map((s) => [s.name, s])) };
182
+ // The sources read with the order column; the base never sees it.
183
+ return { specs, schemas: new Map(all.map((s) => [s.name, s])) };
147
184
  }
148
185
  /** The tables of a database, described as a base: plain JSON (what an endpoint sends). */
149
186
  export async function describeDatabase(options) {
@@ -159,7 +196,7 @@ export async function describeDatabase(options) {
159
196
  export async function baseFromDatabase(options) {
160
197
  const dialect = options.dialect ?? 'postgres';
161
198
  const { specs, schemas } = await readDatabase(options);
162
- return baseTablesFromSpec(specs, (table) => createSqlDataSource({ schema: schemas.get(table), table, dialect: SQL_DIALECT[dialect], execute: options.execute }));
199
+ return baseTablesFromSpec(specs, (table) => sqlSource(schemas.get(table), table, dialect, options.execute));
163
200
  }
164
201
  /**
165
202
  * The server half of `baseFromEndpoint`, as a SvelteKit route:
@@ -194,8 +231,8 @@ export function createBaseEndpoint(options) {
194
231
  let h = handlers.get(table);
195
232
  if (!h) {
196
233
  h = createKitHandlers({
197
- schema,
198
- source: createSqlDataSource({ schema, table, dialect: SQL_DIALECT[dialect], execute: options.execute }),
234
+ schema: shown(schema),
235
+ source: sqlSource(schema, table, dialect, options.execute),
199
236
  ...(options.authorize ? { authorize: options.authorize(table) } : {}),
200
237
  ...(options.audit ? { audit: options.audit(table) } : {}),
201
238
  });
@@ -262,10 +299,14 @@ export async function baseFromSupabase(options) {
262
299
  const comments = await readSupabaseComments(options);
263
300
  const kept = hasComments(comments);
264
301
  // Supabase makes the keys: its source inserts without the page's id.
265
- let specs = baseSpecFromSchemas(schemas, { values, serverIds: () => true, order: options.tables ? 'given' : 'links', inverses: !kept });
302
+ let specs = baseSpecFromSchemas(schemas.map(shown), { values, serverIds: () => true, order: options.tables ? 'given' : 'links', inverses: !kept });
266
303
  if (kept)
267
304
  specs = withComments(specs, comments, !!options.tables);
268
- return baseTablesFromSpec(specs, (table) => createSupabaseDataSource({ client: options.client, table, schema: byName.get(table) }), (s) => options.realtime === false
305
+ return baseTablesFromSpec(specs, (table) => {
306
+ const schema = byName.get(table);
307
+ const source = createSupabaseDataSource({ client: options.client, table, schema, ...(hasOrder(schema) ? { defaultOrder: ORDER } : {}) });
308
+ return (hasOrder(schema) ? hideOrder(source) : source);
309
+ }, (s) => options.realtime === false
269
310
  ? {}
270
311
  : { realtime: (onChange) => createSupabaseRealtime({ client: options.client, table: s.id, onChange }) });
271
312
  }
@@ -39,6 +39,14 @@ export type BaseJunctionComment = {
39
39
  };
40
40
  };
41
41
  export declare const SQL_COMMENT_PREFIX = "svgrid:";
42
+ /**
43
+ * A column baseToSql gives every table: an identity that numbers the records
44
+ * in the order they were written. Text keys (seed ids, UUIDs) do not sort that
45
+ * way, so the base reads rows in this order while nothing is sorted. It is not
46
+ * a field: baseFromDatabase, createBaseEndpoint and baseFromSupabase leave it
47
+ * out of the base and never write it.
48
+ */
49
+ export declare const BASE_ORDER_COLUMN = "svgrid_order";
42
50
  /** `fixedOn` -> `fixed_on`, `Key results` -> `key_results`. */
43
51
  export declare function sqlName(s: string): string;
44
52
  export type BaseToSqlOptions = {
@@ -14,6 +14,14 @@
14
14
  import { colId, primaryOf, rowIdOf } from './base-tables.js';
15
15
  import { fillFieldColumn } from './registry.svelte.js';
16
16
  export const SQL_COMMENT_PREFIX = 'svgrid:';
17
+ /**
18
+ * A column baseToSql gives every table: an identity that numbers the records
19
+ * in the order they were written. Text keys (seed ids, UUIDs) do not sort that
20
+ * way, so the base reads rows in this order while nothing is sorted. It is not
21
+ * a field: baseFromDatabase, createBaseEndpoint and baseFromSupabase leave it
22
+ * out of the base and never write it.
23
+ */
24
+ export const BASE_ORDER_COLUMN = 'svgrid_order';
17
25
  /** `fixedOn` -> `fixed_on`, `Key results` -> `key_results`. */
18
26
  export function sqlName(s) {
19
27
  const out = String(s)
@@ -115,7 +123,7 @@ export function baseToSql(tables, options = {}) {
115
123
  const name = nameOf.get(t.id);
116
124
  const columns = [];
117
125
  const extra = [];
118
- const taken = new Set(['id']);
126
+ const taken = new Set(['id', BASE_ORDER_COLUMN]);
119
127
  const column = (base) => {
120
128
  let c = sqlName(base);
121
129
  while (taken.has(c))
@@ -153,8 +161,9 @@ export function baseToSql(tables, options = {}) {
153
161
  columns.push({ def: d, column: column(field) });
154
162
  }
155
163
  // The database makes the key of a record added later: a Supabase insert
156
- // carries no id. The records below bring their own.
157
- const lines = [` "id" text primary key default gen_random_uuid()::text`, ...columns.map((c) => ` ${quote(c.column)} ${c.fk ? 'text' : sqlType(c.def)}`)];
164
+ // carries no id. The records below bring their own. The order column
165
+ // numbers them as they are inserted, so the records keep the order below.
166
+ const lines = [` "id" text primary key default gen_random_uuid()::text`, ` ${quote(BASE_ORDER_COLUMN)} bigint generated always as identity`, ...columns.map((c) => ` ${quote(c.column)} ${c.fk ? 'text' : sqlType(c.def)}`)];
158
167
  plans.push({ table: t, columns, extra, sql: `create table ${quote(name)} (\n${lines.join(',\n')}\n);` });
159
168
  }
160
169
  const out = [];
package/dist/install.js CHANGED
@@ -14,7 +14,7 @@ import { enableGanttView } from './gantt/gantt.js';
14
14
  import { enableSelectionBar } from './selection-bar.js';
15
15
  import { enableAdvancedFilter } from './advanced-filter-enable.js';
16
16
  import { enablePivot } from './pivot-enable.js';
17
- import { enableSheet } from './sheet-enable.js';
17
+ import { registerSheetKeymap } from './sheet-enable.js';
18
18
  import { enableServerRowModel } from './server/enable.js';
19
19
  /**
20
20
  * Augment a SvGridApi instance with Pro methods (`exportData`, `print`,
@@ -59,8 +59,8 @@ export function installEnterprise(api) {
59
59
  enableAdvancedFilter();
60
60
  // Register the Excel keymap (Ctrl+Arrow, Ctrl+D, Ctrl+A and the rest). The
61
61
  // grid interprets a key itself only when nothing claims it, so a free grid
62
- // is unaffected.
63
- enableSheet();
62
+ // is unaffected. No spreadsheet nudge: this app may only export or pivot.
63
+ registerSheetKeymap();
64
64
  // Raise the unlicensed nudge for the server-side row model. No registry to fill -
65
65
  // the model hands the grid ordinary rows - so this only nudges when unlicensed.
66
66
  enableServerRowModel();