sqlite-hub 0.9.4 → 0.9.8
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/frontend/js/app.js +149 -22
- package/frontend/js/components/structureGraph.js +10 -9
- package/frontend/js/components/tableDesignerEditor.js +57 -36
- package/frontend/js/store.js +10 -4
- package/frontend/js/utils/dom.js +28 -0
- package/frontend/styles/base.css +1 -0
- package/frontend/styles/structure-graph.css +215 -213
- package/frontend/styles/tailwind.css +2 -3
- package/frontend/styles/tailwind.generated.css +2 -1
- package/package.json +11 -10
package/frontend/js/app.js
CHANGED
|
@@ -4,6 +4,11 @@ import { renderQueryHistoryDetail } from './components/queryHistoryDetail.js';
|
|
|
4
4
|
import { renderQueryHistoryListItem } from './components/queryHistoryPanel.js';
|
|
5
5
|
import { renderSidebar } from './components/sidebar.js';
|
|
6
6
|
import { renderStatusBar } from './components/statusBar.js';
|
|
7
|
+
import {
|
|
8
|
+
renderTableDesignerFeedback,
|
|
9
|
+
renderTableDesignerReferenceColumnOptions,
|
|
10
|
+
} from './components/tableDesignerEditor.js';
|
|
11
|
+
import { renderTableDesignerSqlPreview } from './components/tableDesignerSqlPreview.js';
|
|
7
12
|
import {
|
|
8
13
|
mountStructureGraph,
|
|
9
14
|
teardownStructureGraph,
|
|
@@ -122,11 +127,15 @@ import { renderOverviewView } from './views/overview.js';
|
|
|
122
127
|
import { renderSettingsView } from './views/settings.js';
|
|
123
128
|
import { renderStructureView } from './views/structure.js';
|
|
124
129
|
import { renderTableDesignerView } from './views/tableDesigner.js';
|
|
130
|
+
import {
|
|
131
|
+
replaceChildrenFromRenderedMarkup,
|
|
132
|
+
replaceElementFromRenderedMarkup,
|
|
133
|
+
} from './utils/dom.js';
|
|
125
134
|
import { highlightSql } from './utils/format.js';
|
|
126
135
|
|
|
127
136
|
const appRoot = document.querySelector('#app');
|
|
128
137
|
|
|
129
|
-
appRoot
|
|
138
|
+
replaceChildrenFromRenderedMarkup(appRoot, renderAppShell());
|
|
130
139
|
|
|
131
140
|
const shellRefs = {
|
|
132
141
|
shell: document.querySelector('.app-shell'),
|
|
@@ -186,7 +195,7 @@ function syncQueryEditorHighlight(textarea) {
|
|
|
186
195
|
return;
|
|
187
196
|
}
|
|
188
197
|
|
|
189
|
-
highlightNode
|
|
198
|
+
replaceChildrenFromRenderedMarkup(highlightNode, renderQueryHighlightMarkup(textarea.value));
|
|
190
199
|
}
|
|
191
200
|
|
|
192
201
|
function syncQueryEditorScroll(textarea) {
|
|
@@ -258,12 +267,20 @@ function syncMediaTaggingCurrentMediaUi(button, detailsVisible) {
|
|
|
258
267
|
const nextVisible = Boolean(detailsVisible);
|
|
259
268
|
const expandedLabel = button.dataset.expandedLabel || 'Shrink Media Viewer';
|
|
260
269
|
const collapsedLabel = button.dataset.collapsedLabel || 'Show Media Viewer';
|
|
261
|
-
const expandedMarkup = `<span class="material-symbols-outlined">visibility_off</span> ${expandedLabel}`;
|
|
262
|
-
|
|
263
270
|
preview.classList.toggle('media-tagging-preview--meta-hidden', !nextVisible);
|
|
264
271
|
button.dataset.nextValue = nextVisible ? 'false' : 'true';
|
|
265
272
|
button.setAttribute('aria-expanded', nextVisible ? 'true' : 'false');
|
|
266
|
-
|
|
273
|
+
|
|
274
|
+
if (nextVisible) {
|
|
275
|
+
const icon = document.createElement('span');
|
|
276
|
+
|
|
277
|
+
icon.className = 'material-symbols-outlined';
|
|
278
|
+
icon.textContent = 'visibility_off';
|
|
279
|
+
button.replaceChildren(icon, document.createTextNode(` ${expandedLabel}`));
|
|
280
|
+
} else {
|
|
281
|
+
button.textContent = collapsedLabel;
|
|
282
|
+
}
|
|
283
|
+
|
|
267
284
|
return true;
|
|
268
285
|
}
|
|
269
286
|
|
|
@@ -332,6 +349,84 @@ function syncMediaTaggingTagSearchUi(input) {
|
|
|
332
349
|
return true;
|
|
333
350
|
}
|
|
334
351
|
|
|
352
|
+
function syncTableDesignerReferenceColumnOptions(sourceNode, state) {
|
|
353
|
+
if (
|
|
354
|
+
!(sourceNode instanceof HTMLSelectElement) ||
|
|
355
|
+
sourceNode.dataset.bind !== 'table-designer-column-field' ||
|
|
356
|
+
sourceNode.dataset.field !== 'referencesTable'
|
|
357
|
+
) {
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const rowNode = sourceNode.closest('.table-designer-grid__row');
|
|
362
|
+
const referenceColumnSelect = rowNode?.querySelector(
|
|
363
|
+
'[data-bind="table-designer-column-field"][data-field="referencesColumn"]',
|
|
364
|
+
);
|
|
365
|
+
const column = state.tableDesigner.draft?.columns.find(item => item.id === sourceNode.dataset.columnId);
|
|
366
|
+
|
|
367
|
+
if (!(referenceColumnSelect instanceof HTMLSelectElement) || !column) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
replaceChildrenFromRenderedMarkup(
|
|
372
|
+
referenceColumnSelect,
|
|
373
|
+
renderTableDesignerReferenceColumnOptions(
|
|
374
|
+
state.tableDesigner.draft,
|
|
375
|
+
state.tableDesigner.tables ?? [],
|
|
376
|
+
column.referencesTable,
|
|
377
|
+
column.referencesColumn,
|
|
378
|
+
),
|
|
379
|
+
);
|
|
380
|
+
referenceColumnSelect.value = column.referencesColumn ?? '';
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function syncTableDesignerDraftUi(sourceNode) {
|
|
385
|
+
const state = getState();
|
|
386
|
+
const draft = state.tableDesigner.draft;
|
|
387
|
+
|
|
388
|
+
if (state.route.name !== 'tableDesigner' || !draft) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
let synced = syncTableDesignerReferenceColumnOptions(sourceNode, state);
|
|
393
|
+
|
|
394
|
+
const saveButton = shellRefs.view.querySelector('[data-table-designer-save-button]');
|
|
395
|
+
if (saveButton instanceof HTMLButtonElement) {
|
|
396
|
+
saveButton.disabled = !draft.canSave;
|
|
397
|
+
} else {
|
|
398
|
+
synced = false;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const feedbackNode = shellRefs.view.querySelector('[data-table-designer-feedback]');
|
|
402
|
+
if (feedbackNode instanceof HTMLElement) {
|
|
403
|
+
replaceChildrenFromRenderedMarkup(
|
|
404
|
+
feedbackNode,
|
|
405
|
+
renderTableDesignerFeedback(draft, state.tableDesigner.saveError),
|
|
406
|
+
);
|
|
407
|
+
} else {
|
|
408
|
+
synced = false;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const previewNode = shellRefs.view.querySelector('.table-designer-workspace__bottom');
|
|
412
|
+
if (previewNode instanceof HTMLElement) {
|
|
413
|
+
previewNode.classList.toggle('is-collapsed', !state.tableDesigner.sqlPreviewVisible);
|
|
414
|
+
replaceChildrenFromRenderedMarkup(
|
|
415
|
+
previewNode,
|
|
416
|
+
renderTableDesignerSqlPreview(draft, state.tableDesigner.sqlPreviewVisible),
|
|
417
|
+
);
|
|
418
|
+
} else {
|
|
419
|
+
synced = false;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (synced) {
|
|
423
|
+
lastRenderedMainMarkup = renderTableDesignerView(state).main;
|
|
424
|
+
lastRenderedPanelMarkup = '';
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return synced;
|
|
428
|
+
}
|
|
429
|
+
|
|
335
430
|
function syncDataRowSelectionUi(selectedRowIndex = null) {
|
|
336
431
|
if (getState().route.name !== 'data') {
|
|
337
432
|
return false;
|
|
@@ -350,7 +445,7 @@ function syncDataRowSelectionUi(selectedRowIndex = null) {
|
|
|
350
445
|
const panelMarkup = renderDataRowEditorPanel(getState());
|
|
351
446
|
const panelOpen = Boolean(panelMarkup);
|
|
352
447
|
|
|
353
|
-
shellRefs.panel
|
|
448
|
+
replaceChildrenFromRenderedMarkup(shellRefs.panel, panelMarkup);
|
|
354
449
|
shellRefs.shell.classList.toggle('panel-open', panelOpen);
|
|
355
450
|
lastRenderedPanelMarkup = panelMarkup;
|
|
356
451
|
lastRenderedPanelOpen = panelOpen;
|
|
@@ -375,10 +470,13 @@ function syncQueryHistoryUi(historyId) {
|
|
|
375
470
|
)?.closest('.query-history-item');
|
|
376
471
|
|
|
377
472
|
if (historyItem && listItemNode instanceof HTMLElement) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
473
|
+
replaceElementFromRenderedMarkup(
|
|
474
|
+
listItemNode,
|
|
475
|
+
renderQueryHistoryListItem(
|
|
476
|
+
historyItem,
|
|
477
|
+
state.editor.historyActiveId,
|
|
478
|
+
state.editor.historySelectedId,
|
|
479
|
+
),
|
|
382
480
|
);
|
|
383
481
|
}
|
|
384
482
|
|
|
@@ -391,7 +489,7 @@ function syncQueryHistoryUi(historyId) {
|
|
|
391
489
|
});
|
|
392
490
|
const panelOpen = Boolean(panelMarkup);
|
|
393
491
|
|
|
394
|
-
shellRefs.panel
|
|
492
|
+
replaceChildrenFromRenderedMarkup(shellRefs.panel, panelMarkup);
|
|
395
493
|
shellRefs.shell.classList.toggle('panel-open', panelOpen);
|
|
396
494
|
lastRenderedPanelMarkup = panelMarkup;
|
|
397
495
|
lastRenderedPanelOpen = panelOpen;
|
|
@@ -414,7 +512,7 @@ function syncQueryHistorySelectionUi(selectedHistoryId = null) {
|
|
|
414
512
|
}
|
|
415
513
|
|
|
416
514
|
if (selectedHistoryId === null) {
|
|
417
|
-
shellRefs.panel.
|
|
515
|
+
shellRefs.panel.replaceChildren();
|
|
418
516
|
shellRefs.shell.classList.remove('panel-open');
|
|
419
517
|
lastRenderedPanelMarkup = '';
|
|
420
518
|
lastRenderedPanelOpen = false;
|
|
@@ -600,7 +698,7 @@ function patchChartsDetailUi(state) {
|
|
|
600
698
|
return false;
|
|
601
699
|
}
|
|
602
700
|
|
|
603
|
-
detailNode
|
|
701
|
+
replaceChildrenFromRenderedMarkup(detailNode, renderChartsDetail(state));
|
|
604
702
|
syncChartsHistorySelectionUi(state);
|
|
605
703
|
return true;
|
|
606
704
|
}
|
|
@@ -976,7 +1074,7 @@ function renderApp(state) {
|
|
|
976
1074
|
!lockedRouteChanged;
|
|
977
1075
|
|
|
978
1076
|
if (shellMarkupUnchanged && toastMarkup !== lastRenderedToastMarkup) {
|
|
979
|
-
shellRefs.toast
|
|
1077
|
+
replaceChildrenFromRenderedMarkup(shellRefs.toast, toastMarkup);
|
|
980
1078
|
lastRenderedToastMarkup = toastMarkup;
|
|
981
1079
|
return;
|
|
982
1080
|
}
|
|
@@ -1013,7 +1111,7 @@ function renderApp(state) {
|
|
|
1013
1111
|
}
|
|
1014
1112
|
|
|
1015
1113
|
if (topNavChanged) {
|
|
1016
|
-
shellRefs.topNav
|
|
1114
|
+
replaceChildrenFromRenderedMarkup(shellRefs.topNav, topNavMarkup);
|
|
1017
1115
|
}
|
|
1018
1116
|
|
|
1019
1117
|
if (sidebarChanged) {
|
|
@@ -1023,16 +1121,16 @@ function renderApp(state) {
|
|
|
1023
1121
|
syncSidebarActiveRoute(state.route.name);
|
|
1024
1122
|
|
|
1025
1123
|
if (!sidebarSynced) {
|
|
1026
|
-
shellRefs.sidebar
|
|
1124
|
+
replaceChildrenFromRenderedMarkup(shellRefs.sidebar, sidebarMarkup);
|
|
1027
1125
|
}
|
|
1028
1126
|
}
|
|
1029
1127
|
|
|
1030
1128
|
if (statusBarChanged) {
|
|
1031
|
-
shellRefs.statusBar
|
|
1129
|
+
replaceChildrenFromRenderedMarkup(shellRefs.statusBar, statusBarMarkup);
|
|
1032
1130
|
}
|
|
1033
1131
|
|
|
1034
1132
|
if (mainChanged && !mainPatched) {
|
|
1035
|
-
shellRefs.view
|
|
1133
|
+
replaceChildrenFromRenderedMarkup(shellRefs.view, main);
|
|
1036
1134
|
}
|
|
1037
1135
|
|
|
1038
1136
|
if (mainChanged || lockedRouteChanged) {
|
|
@@ -1040,15 +1138,15 @@ function renderApp(state) {
|
|
|
1040
1138
|
}
|
|
1041
1139
|
|
|
1042
1140
|
if (panelChanged) {
|
|
1043
|
-
shellRefs.panel
|
|
1141
|
+
replaceChildrenFromRenderedMarkup(shellRefs.panel, panel);
|
|
1044
1142
|
}
|
|
1045
1143
|
|
|
1046
1144
|
if (modalChanged) {
|
|
1047
|
-
shellRefs.modal
|
|
1145
|
+
replaceChildrenFromRenderedMarkup(shellRefs.modal, modalMarkup);
|
|
1048
1146
|
}
|
|
1049
1147
|
|
|
1050
1148
|
if (toastMarkup !== lastRenderedToastMarkup) {
|
|
1051
|
-
shellRefs.toast
|
|
1149
|
+
replaceChildrenFromRenderedMarkup(shellRefs.toast, toastMarkup);
|
|
1052
1150
|
}
|
|
1053
1151
|
|
|
1054
1152
|
if (panelChanged || panelOpenChanged) {
|
|
@@ -1640,7 +1738,10 @@ document.addEventListener('input', event => {
|
|
|
1640
1738
|
}
|
|
1641
1739
|
|
|
1642
1740
|
if (bindNode.dataset.bind === 'table-designer-field') {
|
|
1643
|
-
if (
|
|
1741
|
+
if (
|
|
1742
|
+
(bindNode instanceof HTMLInputElement && bindNode.type === 'checkbox') ||
|
|
1743
|
+
bindNode instanceof HTMLSelectElement
|
|
1744
|
+
) {
|
|
1644
1745
|
return;
|
|
1645
1746
|
}
|
|
1646
1747
|
|
|
@@ -1649,6 +1750,10 @@ document.addEventListener('input', event => {
|
|
|
1649
1750
|
}
|
|
1650
1751
|
|
|
1651
1752
|
if (bindNode.dataset.bind === 'table-designer-column-field') {
|
|
1753
|
+
if (bindNode instanceof HTMLSelectElement) {
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1652
1757
|
updateCurrentTableDesignerColumnField(bindNode.dataset.columnId, bindNode.dataset.field, bindNode.value);
|
|
1653
1758
|
return;
|
|
1654
1759
|
}
|
|
@@ -1753,11 +1858,33 @@ document.addEventListener('change', event => {
|
|
|
1753
1858
|
return;
|
|
1754
1859
|
}
|
|
1755
1860
|
|
|
1861
|
+
if (bindNode instanceof HTMLSelectElement) {
|
|
1862
|
+
updateCurrentTableDesignerField(bindNode.dataset.field, bindNode.value, { notify: false });
|
|
1863
|
+
|
|
1864
|
+
if (!syncTableDesignerDraftUi(bindNode)) {
|
|
1865
|
+
renderApp(getState());
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1756
1871
|
updateCurrentTableDesignerField(bindNode.dataset.field, bindNode.value);
|
|
1757
1872
|
return;
|
|
1758
1873
|
}
|
|
1759
1874
|
|
|
1760
1875
|
if (bindNode.dataset.bind === 'table-designer-column-field') {
|
|
1876
|
+
if (bindNode instanceof HTMLSelectElement) {
|
|
1877
|
+
updateCurrentTableDesignerColumnField(bindNode.dataset.columnId, bindNode.dataset.field, bindNode.value, {
|
|
1878
|
+
notify: false,
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1881
|
+
if (!syncTableDesignerDraftUi(bindNode)) {
|
|
1882
|
+
renderApp(getState());
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1761
1888
|
updateCurrentTableDesignerColumnField(bindNode.dataset.columnId, bindNode.dataset.field, bindNode.value);
|
|
1762
1889
|
return;
|
|
1763
1890
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { showToast } from '../store.js';
|
|
2
|
+
import { replaceChildrenFromRenderedMarkup } from '../utils/dom.js';
|
|
2
3
|
import { escapeHtml, formatNumber } from '../utils/format.js';
|
|
3
4
|
|
|
4
5
|
let cytoscapeFactory = null;
|
|
@@ -530,12 +531,12 @@ function updateInspectorToggleButton() {
|
|
|
530
531
|
}
|
|
531
532
|
|
|
532
533
|
currentGraph.inspectorToggleButton.classList.toggle('is-active', currentGraph.inspectorHidden);
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
534
|
+
const icon = document.createElement('span');
|
|
535
|
+
const label = currentGraph.inspectorHidden ? 'Show Inspector' : 'Hide Inspector';
|
|
536
|
+
|
|
537
|
+
icon.className = 'material-symbols-outlined text-sm';
|
|
538
|
+
icon.textContent = currentGraph.inspectorHidden ? 'right_panel_open' : 'right_panel_close';
|
|
539
|
+
currentGraph.inspectorToggleButton.replaceChildren(icon, document.createTextNode(` ${label}`));
|
|
539
540
|
}
|
|
540
541
|
|
|
541
542
|
function clearSelection() {
|
|
@@ -546,7 +547,7 @@ function clearSelection() {
|
|
|
546
547
|
currentGraph.selectedTableName = null;
|
|
547
548
|
resetHighlights(currentGraph.cy);
|
|
548
549
|
syncEntryHighlights();
|
|
549
|
-
currentGraph.inspector
|
|
550
|
+
replaceChildrenFromRenderedMarkup(currentGraph.inspector, getDefaultInspectorMarkup());
|
|
550
551
|
updateOpenDataButton();
|
|
551
552
|
}
|
|
552
553
|
|
|
@@ -557,7 +558,7 @@ function applyTableSelection(node, { focus = true } = {}) {
|
|
|
557
558
|
|
|
558
559
|
const tableData = node.data('table');
|
|
559
560
|
currentGraph.selectedTableName = tableData.name;
|
|
560
|
-
currentGraph.inspector
|
|
561
|
+
replaceChildrenFromRenderedMarkup(currentGraph.inspector, renderInspector(tableData));
|
|
561
562
|
highlightConnectedElements(currentGraph.cy, node);
|
|
562
563
|
syncEntryHighlights([tableData.name]);
|
|
563
564
|
updateOpenDataButton();
|
|
@@ -742,7 +743,7 @@ export async function mountStructureGraph(snapshot) {
|
|
|
742
743
|
|
|
743
744
|
if (!schema.tables?.length) {
|
|
744
745
|
empty?.removeAttribute('hidden');
|
|
745
|
-
inspector
|
|
746
|
+
replaceChildrenFromRenderedMarkup(inspector, clearInspector());
|
|
746
747
|
return;
|
|
747
748
|
}
|
|
748
749
|
|
|
@@ -55,8 +55,33 @@ function getReferencedColumns(draft, catalogTables, referencesTable) {
|
|
|
55
55
|
);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
export function renderTableDesignerReferenceColumnOptions(
|
|
59
|
+
draft,
|
|
60
|
+
catalogTables,
|
|
61
|
+
referencesTable,
|
|
62
|
+
selectedValue
|
|
63
|
+
) {
|
|
64
|
+
const referenceColumns = getReferencedColumns(draft, catalogTables, referencesTable);
|
|
65
|
+
|
|
66
|
+
return [
|
|
67
|
+
'<option value="">No FK column</option>',
|
|
68
|
+
referenceColumns
|
|
69
|
+
.map((name) =>
|
|
70
|
+
[
|
|
71
|
+
'<option value="',
|
|
72
|
+
escapeHtml(name),
|
|
73
|
+
'" ',
|
|
74
|
+
name === selectedValue ? "selected" : "",
|
|
75
|
+
">",
|
|
76
|
+
escapeHtml(name),
|
|
77
|
+
"</option>",
|
|
78
|
+
].join("")
|
|
79
|
+
)
|
|
80
|
+
.join(""),
|
|
81
|
+
].join("");
|
|
82
|
+
}
|
|
83
|
+
|
|
58
84
|
function renderColumnRow(column, draft, catalogTables) {
|
|
59
|
-
const referenceColumns = getReferencedColumns(draft, catalogTables, column.referencesTable);
|
|
60
85
|
const typeOptions = draft.supportedTypes
|
|
61
86
|
.map((type) =>
|
|
62
87
|
[
|
|
@@ -83,19 +108,12 @@ function renderColumnRow(column, draft, catalogTables) {
|
|
|
83
108
|
].join("")
|
|
84
109
|
)
|
|
85
110
|
.join("");
|
|
86
|
-
const referenceColumnOptions =
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
name === column.referencesColumn ? "selected" : "",
|
|
93
|
-
">",
|
|
94
|
-
escapeHtml(name),
|
|
95
|
-
"</option>",
|
|
96
|
-
].join("")
|
|
97
|
-
)
|
|
98
|
-
.join("");
|
|
111
|
+
const referenceColumnOptions = renderTableDesignerReferenceColumnOptions(
|
|
112
|
+
draft,
|
|
113
|
+
catalogTables,
|
|
114
|
+
column.referencesTable,
|
|
115
|
+
column.referencesColumn
|
|
116
|
+
);
|
|
99
117
|
|
|
100
118
|
const columnId = escapeHtml(column.id);
|
|
101
119
|
|
|
@@ -141,7 +159,7 @@ function renderColumnRow(column, draft, catalogTables) {
|
|
|
141
159
|
"</select>",
|
|
142
160
|
'<select class="table-designer-field" data-bind="table-designer-column-field" data-column-id="',
|
|
143
161
|
columnId,
|
|
144
|
-
'" data-field="referencesColumn"
|
|
162
|
+
'" data-field="referencesColumn">',
|
|
145
163
|
referenceColumnOptions,
|
|
146
164
|
"</select>",
|
|
147
165
|
'<button class="delete-button" data-action="remove-table-designer-column" data-column-id="',
|
|
@@ -202,6 +220,26 @@ function renderFillToggle(draft) {
|
|
|
202
220
|
`;
|
|
203
221
|
}
|
|
204
222
|
|
|
223
|
+
export function renderTableDesignerFeedback(draft, saveError) {
|
|
224
|
+
const validationItems = (draft?.validationErrors ?? []).map((message) => ({
|
|
225
|
+
title: message,
|
|
226
|
+
}));
|
|
227
|
+
const warningItems = draft?.warnings ?? [];
|
|
228
|
+
|
|
229
|
+
return [
|
|
230
|
+
saveError
|
|
231
|
+
? `
|
|
232
|
+
<div class="table-designer-main__error">
|
|
233
|
+
<div class="table-designer-main__error-code">${escapeHtml(saveError.code)}</div>
|
|
234
|
+
<div class="table-designer-main__error-text">${escapeHtml(saveError.message)}</div>
|
|
235
|
+
</div>
|
|
236
|
+
`
|
|
237
|
+
: "",
|
|
238
|
+
renderWarningList(validationItems, "table-designer-banner is-validation", "Validation", "alert"),
|
|
239
|
+
renderWarningList(warningItems, "table-designer-banner is-warning", "Warnings", "alert"),
|
|
240
|
+
].join("");
|
|
241
|
+
}
|
|
242
|
+
|
|
205
243
|
export function renderTableDesignerEditor(state) {
|
|
206
244
|
const draft = state.tableDesigner.draft;
|
|
207
245
|
|
|
@@ -228,10 +266,6 @@ export function renderTableDesignerEditor(state) {
|
|
|
228
266
|
`;
|
|
229
267
|
}
|
|
230
268
|
|
|
231
|
-
const validationItems = (draft.validationErrors ?? []).map((message) => ({
|
|
232
|
-
title: message,
|
|
233
|
-
}));
|
|
234
|
-
const warningItems = draft.warnings ?? [];
|
|
235
269
|
const catalogTables = state.tableDesigner.tables ?? [];
|
|
236
270
|
const visibleColumns = draft.columns.filter((column) => !column.deleted);
|
|
237
271
|
const saveLabel =
|
|
@@ -286,6 +320,7 @@ export function renderTableDesignerEditor(state) {
|
|
|
286
320
|
<button
|
|
287
321
|
class="standard-button"
|
|
288
322
|
data-action="save-table-designer"
|
|
323
|
+
data-table-designer-save-button
|
|
289
324
|
${draft.canSave ? "" : "disabled"}
|
|
290
325
|
type="button"
|
|
291
326
|
>
|
|
@@ -294,23 +329,9 @@ export function renderTableDesignerEditor(state) {
|
|
|
294
329
|
</div>
|
|
295
330
|
</header>
|
|
296
331
|
|
|
297
|
-
|
|
298
|
-
state.tableDesigner.saveError
|
|
299
|
-
|
|
300
|
-
<div class="table-designer-main__error">
|
|
301
|
-
<div class="table-designer-main__error-code">${escapeHtml(
|
|
302
|
-
state.tableDesigner.saveError.code
|
|
303
|
-
)}</div>
|
|
304
|
-
<div class="table-designer-main__error-text">${escapeHtml(
|
|
305
|
-
state.tableDesigner.saveError.message
|
|
306
|
-
)}</div>
|
|
307
|
-
</div>
|
|
308
|
-
`
|
|
309
|
-
: ""
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
${renderWarningList(validationItems, "table-designer-banner is-validation", "Validation", "alert")}
|
|
313
|
-
${renderWarningList(warningItems, "table-designer-banner is-warning", "Warnings", "alert")}
|
|
332
|
+
<div data-table-designer-feedback>
|
|
333
|
+
${renderTableDesignerFeedback(draft, state.tableDesigner.saveError)}
|
|
334
|
+
</div>
|
|
314
335
|
|
|
315
336
|
<section class="table-designer-main__section">
|
|
316
337
|
<div class="table-designer-main__section-header">
|
package/frontend/js/store.js
CHANGED
|
@@ -2856,7 +2856,7 @@ export function setTableDesignerSqlPreviewVisibility(visible) {
|
|
|
2856
2856
|
emitChange();
|
|
2857
2857
|
}
|
|
2858
2858
|
|
|
2859
|
-
export function updateCurrentTableDesignerField(field, value) {
|
|
2859
|
+
export function updateCurrentTableDesignerField(field, value, options = {}) {
|
|
2860
2860
|
if (!state.tableDesigner.draft) {
|
|
2861
2861
|
return;
|
|
2862
2862
|
}
|
|
@@ -2868,10 +2868,13 @@ export function updateCurrentTableDesignerField(field, value) {
|
|
|
2868
2868
|
getTableDesignerContext(),
|
|
2869
2869
|
);
|
|
2870
2870
|
state.tableDesigner.saveError = null;
|
|
2871
|
-
|
|
2871
|
+
|
|
2872
|
+
if (options.notify !== false) {
|
|
2873
|
+
emitChange();
|
|
2874
|
+
}
|
|
2872
2875
|
}
|
|
2873
2876
|
|
|
2874
|
-
export function updateCurrentTableDesignerColumnField(columnId, field, value) {
|
|
2877
|
+
export function updateCurrentTableDesignerColumnField(columnId, field, value, options = {}) {
|
|
2875
2878
|
if (!state.tableDesigner.draft) {
|
|
2876
2879
|
return;
|
|
2877
2880
|
}
|
|
@@ -2884,7 +2887,10 @@ export function updateCurrentTableDesignerColumnField(columnId, field, value) {
|
|
|
2884
2887
|
getTableDesignerContext(),
|
|
2885
2888
|
);
|
|
2886
2889
|
state.tableDesigner.saveError = null;
|
|
2887
|
-
|
|
2890
|
+
|
|
2891
|
+
if (options.notify !== false) {
|
|
2892
|
+
emitChange();
|
|
2893
|
+
}
|
|
2888
2894
|
}
|
|
2889
2895
|
|
|
2890
2896
|
export function addCurrentTableDesignerColumn() {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
function createRenderedMarkupFragment(contextNode, markup) {
|
|
2
|
+
const range = document.createRange();
|
|
3
|
+
|
|
4
|
+
range.selectNodeContents(contextNode);
|
|
5
|
+
return range.createContextualFragment(String(markup ?? ''));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Renderers must escape user-controlled values before markup reaches this DOM boundary.
|
|
9
|
+
export function replaceChildrenFromRenderedMarkup(target, markup) {
|
|
10
|
+
if (!(target instanceof Element)) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
target.replaceChildren(createRenderedMarkupFragment(target, markup));
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function replaceElementFromRenderedMarkup(target, markup) {
|
|
19
|
+
if (!(target instanceof Element)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const range = document.createRange();
|
|
24
|
+
|
|
25
|
+
range.selectNode(target);
|
|
26
|
+
target.replaceWith(range.createContextualFragment(String(markup ?? '')));
|
|
27
|
+
return true;
|
|
28
|
+
}
|