@jxsuite/studio 0.37.1 → 1.1.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 (113) hide show
  1. package/dist/iframe-entry.js +622 -49
  2. package/dist/iframe-entry.js.map +15 -12
  3. package/dist/studio.css +1333 -0
  4. package/dist/studio.js +103709 -81001
  5. package/dist/studio.js.map +201 -157
  6. package/package.json +47 -45
  7. package/src/account-status.ts +39 -0
  8. package/src/browse/browse.ts +10 -14
  9. package/src/canvas/canvas-live-render.ts +21 -2
  10. package/src/canvas/canvas-render.ts +35 -16
  11. package/src/canvas/canvas-utils.ts +118 -72
  12. package/src/canvas/iframe-entry.ts +20 -0
  13. package/src/canvas/iframe-eval.ts +155 -0
  14. package/src/canvas/iframe-host.ts +132 -6
  15. package/src/canvas/iframe-inline-edit.ts +107 -1
  16. package/src/canvas/iframe-protocol.ts +43 -3
  17. package/src/canvas/iframe-render.ts +18 -0
  18. package/src/collab/collab-session.ts +23 -8
  19. package/src/collab/collab-state.ts +6 -3
  20. package/src/component-props.ts +104 -0
  21. package/src/editor/context-menu.ts +1 -1
  22. package/src/editor/inline-edit-apply.ts +36 -1
  23. package/src/editor/inline-edit.ts +58 -1
  24. package/src/editor/repeater-scope.ts +8 -13
  25. package/src/editor/shortcuts.ts +41 -12
  26. package/src/files/file-ops.ts +14 -0
  27. package/src/files/files.ts +56 -1
  28. package/src/format/format-host.ts +63 -1
  29. package/src/grid/cell-editors.ts +288 -0
  30. package/src/grid/cell-popovers.ts +108 -0
  31. package/src/grid/csv-codec.ts +122 -0
  32. package/src/grid/edit-buffer.ts +490 -0
  33. package/src/grid/grid-controller.ts +417 -0
  34. package/src/grid/grid-layout.ts +83 -0
  35. package/src/grid/grid-open.ts +167 -0
  36. package/src/grid/grid-panel.ts +302 -0
  37. package/src/grid/grid-source.ts +210 -0
  38. package/src/grid/grid-view.ts +367 -0
  39. package/src/grid/schema-columns.ts +261 -0
  40. package/src/grid/sources/connector-source.ts +217 -0
  41. package/src/grid/sources/content-source.ts +542 -0
  42. package/src/grid/sources/csv-file-source.ts +247 -0
  43. package/src/grid/tabulator-tables.d.ts +120 -0
  44. package/src/new-project/add-repo-modal.ts +183 -0
  45. package/src/new-project/new-project-modal.ts +22 -3
  46. package/src/page-params.ts +34 -8
  47. package/src/panels/ai-chat/chat-markdown.ts +2 -2
  48. package/src/panels/ai-panel.ts +61 -4
  49. package/src/panels/block-action-bar.ts +8 -3
  50. package/src/panels/chat-panel.ts +98 -0
  51. package/src/panels/data-grid.ts +241 -0
  52. package/src/panels/editors.ts +43 -17
  53. package/src/panels/events-panel.ts +137 -44
  54. package/src/panels/formula-workspace.ts +379 -0
  55. package/src/panels/frontmatter-fields.ts +231 -0
  56. package/src/panels/frontmatter-panel.ts +132 -0
  57. package/src/panels/git-panel.ts +1 -1
  58. package/src/panels/head-panel.ts +11 -175
  59. package/src/panels/properties-panel.ts +154 -144
  60. package/src/panels/right-panel.ts +9 -47
  61. package/src/panels/signals-panel.ts +217 -460
  62. package/src/panels/statement-editor.ts +710 -0
  63. package/src/panels/statusbar.ts +1 -1
  64. package/src/panels/style-panel.ts +25 -1
  65. package/src/panels/stylebook-panel.ts +0 -2
  66. package/src/panels/tab-bar.ts +175 -6
  67. package/src/panels/tab-strip.ts +62 -6
  68. package/src/panels/toolbar.ts +37 -3
  69. package/src/panels/welcome-screen.ts +50 -0
  70. package/src/platform-errors.ts +30 -0
  71. package/src/platforms/cloud.ts +172 -89
  72. package/src/platforms/devserver.ts +172 -0
  73. package/src/services/ai-project-tools.ts +541 -0
  74. package/src/services/ai-session-store.ts +28 -0
  75. package/src/services/ai-system-prompt.ts +194 -24
  76. package/src/services/ai-tools.ts +88 -21
  77. package/src/services/automation.ts +16 -0
  78. package/src/services/context-resolver.ts +73 -0
  79. package/src/services/data-service.ts +155 -0
  80. package/src/services/document-assistant.ts +81 -11
  81. package/src/services/gated-registry.ts +72 -0
  82. package/src/services/live-preview.ts +0 -0
  83. package/src/services/monaco-setup.ts +75 -26
  84. package/src/services/preview-eval.ts +68 -0
  85. package/src/services/project-adoption.ts +31 -0
  86. package/src/settings/contributed-section.ts +406 -0
  87. package/src/settings/extension-sections.ts +145 -0
  88. package/src/settings/schema-field-ui.ts +4 -2
  89. package/src/settings/settings-modal.ts +101 -42
  90. package/src/site-context.ts +12 -1
  91. package/src/store.ts +4 -0
  92. package/src/studio.ts +107 -52
  93. package/src/tabs/patch-ops.ts +25 -0
  94. package/src/tabs/tab.ts +39 -1
  95. package/src/tabs/transact.ts +61 -14
  96. package/src/types.ts +132 -1
  97. package/src/ui/dynamic-slot.ts +272 -0
  98. package/src/ui/expression-editor.ts +423 -125
  99. package/src/ui/field-row.ts +5 -0
  100. package/src/ui/form-controls.ts +322 -0
  101. package/src/ui/formula-catalog.ts +557 -0
  102. package/src/ui/formula-chips.ts +216 -0
  103. package/src/ui/formula-palette.ts +211 -0
  104. package/src/ui/layers.ts +40 -0
  105. package/src/ui/media-picker.ts +1 -1
  106. package/src/ui/panel-resize.ts +15 -1
  107. package/src/ui/progress-modal.ts +2 -2
  108. package/src/ui/schema-form.ts +524 -0
  109. package/src/utils/preview-format.ts +26 -0
  110. package/src/utils/studio-utils.ts +4 -3
  111. package/src/view.ts +4 -4
  112. package/src/workspace/workspace.ts +14 -0
  113. package/src/settings/content-types-editor.ts +0 -599
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Connector-table grid source — SQL rows through the platform data surface.
3
+ *
4
+ * Columns come from backend introspection (DataColumnMeta); the primary key and the
5
+ * created_at/updated_at system columns are read-only (matching the old modal grid's rules). Paging
6
+ * and ordering are remote — rows(query) maps straight onto DataRowsQuery — so the grid shows a
7
+ * pager instead of loading whole tables. Commit flushes the batch as per-row API calls: one
8
+ * dataUpdateRow per edited row (fields merged), dataInsertRow per new row, dataDeleteRow per
9
+ * deletion. The server is authoritative — there are no file fingerprints; conflicts surface as
10
+ * per-row API errors.
11
+ */
12
+ import { deleteRow, fetchRows, insertRow, updateRow } from "../../services/data-service";
13
+ import { makeGridTabId } from "../grid-source";
14
+ import type { DataColumnMeta, DataRowsQuery } from "../../types";
15
+ import type {
16
+ CommitResult,
17
+ GridCellValue,
18
+ GridColumn,
19
+ GridColumnKind,
20
+ GridEditBatch,
21
+ GridQuery,
22
+ GridRow,
23
+ GridRowsResult,
24
+ GridSource,
25
+ } from "../grid-source";
26
+
27
+ /** Page size when the query does not specify one (matches the old modal grid). */
28
+ export const DATA_PAGE_SIZE = 50;
29
+
30
+ /** SQL type → column kind (best-effort across sqlite/postgres type names). */
31
+ export function kindForSqlType(type: string): GridColumnKind {
32
+ const t = type.toLowerCase();
33
+ if (/(int|real|floa|doub|num|dec)/.test(t)) {
34
+ return "number";
35
+ }
36
+ if (t.includes("bool")) {
37
+ return "boolean";
38
+ }
39
+ if (/(timestamp|datetime|date)/.test(t)) {
40
+ return "date";
41
+ }
42
+ return "string";
43
+ }
44
+
45
+ /** System-managed columns are display-only (same rule as the old modal grid). */
46
+ function editableColumn(column: DataColumnMeta): boolean {
47
+ return !column.pk && column.name !== "created_at" && column.name !== "updated_at";
48
+ }
49
+
50
+ /** DB value → grid cell value (JSON-ish values surface as text). */
51
+ function toCellValue(value: unknown): GridCellValue {
52
+ if (value === null || value === undefined) {
53
+ return null;
54
+ }
55
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
56
+ return value;
57
+ }
58
+ return JSON.stringify(value);
59
+ }
60
+
61
+ /** Create the grid source for one connector table. */
62
+ export function createConnectorSource(connection: string | undefined, table: string): GridSource {
63
+ let columnsMeta: DataColumnMeta[] = [];
64
+ let pkName = "id";
65
+ /** Map of rowKey → the pk value as the backend returned it (numeric pks stay numeric). */
66
+ const pkValues = new Map<string, string | number>();
67
+
68
+ const applyMeta = (columns: DataColumnMeta[]) => {
69
+ if (columns.length > 0) {
70
+ columnsMeta = columns;
71
+ pkName = columns.find((c) => c.pk)?.name ?? "id";
72
+ }
73
+ };
74
+
75
+ const toQuery = (query?: GridQuery): DataRowsQuery => ({
76
+ table,
77
+ ...(connection ? { connection } : {}),
78
+ limit: query?.limit ?? DATA_PAGE_SIZE,
79
+ offset: query?.offset ?? 0,
80
+ ...(query?.orderBy ? { dir: query.dir ?? "asc", orderBy: query.orderBy } : {}),
81
+ });
82
+
83
+ const rowKeyOf = (row: Record<string, unknown>, index: number): string => {
84
+ const pk = row[pkName];
85
+ if (typeof pk === "string" || typeof pk === "number") {
86
+ pkValues.set(String(pk), pk);
87
+ return String(pk);
88
+ }
89
+ return `row-${index}`;
90
+ };
91
+
92
+ return {
93
+ capabilities: { delete: true, insert: true, remotePaging: true, remoteSort: true },
94
+
95
+ async columns(): Promise<GridColumn[]> {
96
+ if (columnsMeta.length === 0) {
97
+ const result = await fetchRows(toQuery({ limit: 1, offset: 0 }));
98
+ applyMeta(result.columns);
99
+ }
100
+ return columnsMeta.map((meta): GridColumn => {
101
+ const kind = editableColumn(meta) ? kindForSqlType(meta.type) : "readonly";
102
+ return {
103
+ editable: kind !== "readonly",
104
+ field: meta.name,
105
+ kind,
106
+ pk: meta.pk === true,
107
+ title: meta.name,
108
+ widthHint: meta.pk ? 80 : undefined,
109
+ };
110
+ });
111
+ },
112
+
113
+ async commit(batch: GridEditBatch): Promise<CommitResult> {
114
+ const result: CommitResult = { cells: [], deletes: [], inserts: [] };
115
+
116
+ // Cell edits merge into one dataUpdateRow per row.
117
+ const byRow = new Map<string, { field: string; value: GridCellValue }[]>();
118
+ for (const cell of batch.cells) {
119
+ const list = byRow.get(cell.rowKey) ?? [];
120
+ list.push({ field: cell.field, value: cell.value });
121
+ byRow.set(cell.rowKey, list);
122
+ }
123
+ for (const [rowKey, patches] of byRow) {
124
+ const pk = pkValues.get(rowKey);
125
+ const outcome = (ok: boolean, error?: string) => {
126
+ for (const patch of patches) {
127
+ result.cells.push({ error, field: patch.field, ok, rowKey });
128
+ }
129
+ };
130
+ if (pk === undefined) {
131
+ outcome(false, "Row has no primary key — refresh the grid");
132
+ continue;
133
+ }
134
+ try {
135
+ const set: Record<string, unknown> = {};
136
+ for (const patch of patches) {
137
+ set[patch.field] = patch.value;
138
+ }
139
+ await updateRow({ pk, set, table, ...(connection ? { connection } : {}) });
140
+ outcome(true);
141
+ } catch (error) {
142
+ outcome(false, error instanceof Error ? error.message : String(error));
143
+ }
144
+ }
145
+
146
+ for (const insert of batch.inserts) {
147
+ try {
148
+ const values: Record<string, unknown> = {};
149
+ for (const [field, value] of Object.entries(insert.cells)) {
150
+ if (value !== null) {
151
+ values[field] = value;
152
+ }
153
+ }
154
+ const { row } = await insertRow({ table, values, ...(connection ? { connection } : {}) });
155
+ const pk = row[pkName];
156
+ const newKey = typeof pk === "string" || typeof pk === "number" ? String(pk) : undefined;
157
+ if (newKey !== undefined && (typeof pk === "string" || typeof pk === "number")) {
158
+ pkValues.set(newKey, pk);
159
+ }
160
+ result.inserts.push({ newKey, ok: true, tempKey: insert.tempKey });
161
+ } catch (error) {
162
+ result.inserts.push({
163
+ error: error instanceof Error ? error.message : String(error),
164
+ ok: false,
165
+ tempKey: insert.tempKey,
166
+ });
167
+ }
168
+ }
169
+
170
+ for (const del of batch.deletes) {
171
+ const pk = pkValues.get(del.rowKey);
172
+ if (pk === undefined) {
173
+ result.deletes.push({
174
+ error: "Row has no primary key — refresh the grid",
175
+ ok: false,
176
+ rowKey: del.rowKey,
177
+ });
178
+ continue;
179
+ }
180
+ try {
181
+ await deleteRow({ pk, table, ...(connection ? { connection } : {}) });
182
+ result.deletes.push({ ok: true, rowKey: del.rowKey });
183
+ } catch (error) {
184
+ result.deletes.push({
185
+ error: error instanceof Error ? error.message : String(error),
186
+ ok: false,
187
+ rowKey: del.rowKey,
188
+ });
189
+ }
190
+ }
191
+
192
+ return result;
193
+ },
194
+
195
+ id: makeGridTabId({ connection: connection ?? "default", kind: "data", table }),
196
+ label: table,
197
+
198
+ async refresh(): Promise<void> {
199
+ columnsMeta = [];
200
+ pkValues.clear();
201
+ },
202
+
203
+ async rows(query?: GridQuery): Promise<GridRowsResult> {
204
+ const result = await fetchRows(toQuery(query));
205
+ applyMeta(result.columns);
206
+ const rows: GridRow[] = result.rows.map((row, index) => {
207
+ const key = rowKeyOf(row, index);
208
+ const cells: Record<string, GridCellValue> = {};
209
+ for (const meta of columnsMeta) {
210
+ cells[meta.name] = toCellValue(row[meta.name]);
211
+ }
212
+ return { cells, key };
213
+ });
214
+ return { rows, total: result.total };
215
+ },
216
+ };
217
+ }