sqlite-hub 2.0.0 → 2.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.
- package/README.md +15 -10
- package/docs/MCP.md +36 -4
- package/docs/changelog.md +11 -0
- package/docs/guidelines/DESIGN.md +64 -0
- package/frontend/assets/mockups/backups_1_1920.webp +0 -0
- package/frontend/assets/mockups/backups_2_compare_drawer_1920.webp +0 -0
- package/frontend/assets/mockups/backups_3_create_backup_modal_1920.webp +0 -0
- package/frontend/assets/mockups/backups_4_edit_backup_modal_1920.webp +0 -0
- package/frontend/assets/mockups/backups_5_restore_backup_modal_1920.webp +0 -0
- package/frontend/assets/mockups/backups_6_delete_backup_modal_1920.webp +0 -0
- package/frontend/assets/mockups/charts_1_1920.webp +0 -0
- package/frontend/assets/mockups/charts_2_query_detail_1920.webp +0 -0
- package/frontend/assets/mockups/charts_3_create_query_chart_modal_1920.webp +0 -0
- package/frontend/assets/mockups/charts_4_edit_query_chart_modal_1920.webp +0 -0
- package/frontend/assets/mockups/charts_5_delete_query_chart_modal_1920.webp +0 -0
- package/frontend/assets/mockups/charts_6_copy_column_modal_1920.webp +0 -0
- package/frontend/assets/mockups/connections_1_1920.webp +0 -0
- package/frontend/assets/mockups/connections_2_create_connection_modal_1920.webp +0 -0
- package/frontend/assets/mockups/connections_3_open_connection_modal_1920.webp +0 -0
- package/frontend/assets/mockups/data_1_1920.webp +0 -0
- package/frontend/assets/mockups/data_2_roweditor_1920.webp +0 -0
- package/frontend/assets/mockups/data_3_generate_data_modal_1920.webp +0 -0
- package/frontend/assets/mockups/data_4_data_export_modal_1920.webp +0 -0
- package/frontend/assets/mockups/documents_1_1920.webp +0 -0
- package/frontend/assets/mockups/documents_2_document_insert_table_modal_1920.webp +0 -0
- package/frontend/assets/mockups/documents_3_document_insert_note_modal_1920.webp +0 -0
- package/frontend/assets/mockups/logs_1_1920.webp +0 -0
- package/frontend/assets/mockups/media_tagging_queue_1_1920.webp +0 -0
- package/frontend/assets/mockups/media_tagging_setup_1_1920.webp +0 -0
- package/frontend/assets/mockups/media_tagging_setup_2_create_media_tagging_tag_table_modal_1920.webp +0 -0
- package/frontend/assets/mockups/media_tagging_setup_3_create_media_tagging_mapping_table_modal_1920.webp +0 -0
- package/frontend/assets/mockups/overview_1_1920.webp +0 -0
- package/frontend/assets/mockups/settings_1_1920.webp +0 -0
- package/frontend/assets/mockups/sql_editor_1_1920.webp +0 -0
- package/frontend/assets/mockups/sql_editor_2_query_detail_1920.webp +0 -0
- package/frontend/assets/mockups/sql_editor_3_query_export_modal_1920.webp +0 -0
- package/frontend/assets/mockups/structure_1_1920.webp +0 -0
- package/frontend/assets/mockups/structure_2_generate_types_modal_1920.webp +0 -0
- package/frontend/assets/mockups/structure_3_generate_types_modal_1920.webp +0 -0
- package/frontend/assets/mockups/table_designer_1_1920.webp +0 -0
- package/frontend/assets/mockups/table_designer_2_table_designer_constraints_modal_1920.webp +0 -0
- package/frontend/js/api.js +11 -0
- package/frontend/js/app.js +238 -8
- package/frontend/js/components/badges.js +16 -0
- package/frontend/js/components/connectionCard.js +35 -0
- package/frontend/js/components/modal.js +116 -245
- package/frontend/js/components/queryHistoryDetail.js +25 -45
- package/frontend/js/components/rowEditorPanel.js +7 -60
- package/frontend/js/components/structureGraph.js +292 -13
- package/frontend/js/components/tableDesignerConstraintsDrawer.js +400 -0
- package/frontend/js/components/tableDesignerEditor.js +51 -16
- package/frontend/js/components/tableDesignerSidebar.js +9 -5
- package/frontend/js/store.js +551 -7
- package/frontend/js/utils/connectionRegistry.js +76 -0
- package/frontend/js/utils/tableDesigner.js +431 -62
- package/frontend/js/views/backups.js +2 -5
- package/frontend/js/views/charts.js +20 -10
- package/frontend/js/views/connections.js +103 -3
- package/frontend/js/views/data.js +19 -5
- package/frontend/js/views/settings.js +2 -2
- package/frontend/js/views/structure.js +28 -5
- package/frontend/js/views/tableAdvisor.js +14 -6
- package/frontend/js/views/tableDesigner.js +44 -9
- package/frontend/styles/components.css +676 -79
- package/frontend/styles/structure-graph.css +49 -0
- package/frontend/styles/tailwind.generated.css +1 -1
- package/package.json +1 -1
- package/server/mcp/httpRouter.js +95 -0
- package/server/routes/connections.js +12 -0
- package/server/routes/data.js +1 -1
- package/server/routes/settings.js +29 -7
- package/server/routes/tableDesigner.js +15 -1
- package/server/server.js +15 -0
- package/server/services/mcpToolService.js +28 -0
- package/server/services/sqlite/connectionManager.js +23 -2
- package/server/services/sqlite/dataBrowserService.js +21 -0
- package/server/services/sqlite/introspection.js +39 -1
- package/server/services/sqlite/structureService.js +66 -11
- package/server/services/sqlite/tableAdvisor.js +6 -0
- package/server/services/sqlite/tableDesigner/schemaMapping.js +7 -1
- package/server/services/sqlite/tableDesigner/sql.js +31 -2
- package/server/services/sqlite/tableDesigner/validation.js +69 -9
- package/server/services/sqlite/tableDesignerService.js +110 -5
- package/server/services/storage/appStateStore.js +303 -4
- package/frontend/assets/mockups/backups_2_create_backup_modal_1920.webp +0 -0
- package/frontend/assets/mockups/backups_3_edit_backup_modal_1920.webp +0 -0
- package/frontend/assets/mockups/backups_4_restore_backup_modal_1920.webp +0 -0
- package/frontend/assets/mockups/backups_5_delete_backup_modal_1920.webp +0 -0
- package/frontend/assets/mockups/data_3_data_export_modal_1920.webp +0 -0
package/frontend/js/app.js
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
clearEditorRowSelection,
|
|
36
36
|
clearEditorResults,
|
|
37
37
|
clearQueryHistorySelection,
|
|
38
|
+
clearConnectionTagFilters,
|
|
38
39
|
closeModal,
|
|
39
40
|
checkSettingsAppVersion,
|
|
40
41
|
dismissMediaTaggingIssue,
|
|
@@ -97,12 +98,21 @@ import {
|
|
|
97
98
|
selectQueryHistoryItem,
|
|
98
99
|
selectStructureEntry,
|
|
99
100
|
setDocumentsSearchQuery,
|
|
101
|
+
setConnectionSearchQuery,
|
|
100
102
|
setLogFilter,
|
|
101
103
|
setLogSearchInput,
|
|
102
104
|
applyLogSearch,
|
|
103
105
|
setTableDesignerSearchQuery,
|
|
104
106
|
setTableDesignerSqlPreviewVisibility,
|
|
105
107
|
toggleTableDesignerTablesPanel,
|
|
108
|
+
openTableDesignerConstraintsDrawer,
|
|
109
|
+
closeTableDesignerConstraintsDrawer,
|
|
110
|
+
startTableDesignerCheckEditor,
|
|
111
|
+
cancelTableDesignerCheckEditor,
|
|
112
|
+
applyTableDesignerCheckPreset,
|
|
113
|
+
updateTableDesignerCheckEditorField,
|
|
114
|
+
saveTableDesignerCheckEditor,
|
|
115
|
+
removeCurrentTableDesignerCheckConstraint,
|
|
106
116
|
setDataTableSearchQuery,
|
|
107
117
|
setStructureTableSearchQuery,
|
|
108
118
|
toggleStructureTablesPanel,
|
|
@@ -156,7 +166,7 @@ import {
|
|
|
156
166
|
toggleDocumentsPane,
|
|
157
167
|
setMediaTaggingWorkflowMediaDetailsVisible,
|
|
158
168
|
setMediaTaggingWorkflowMediaRotationDegrees,
|
|
159
|
-
|
|
169
|
+
queueTableDesignerImport,
|
|
160
170
|
showToast,
|
|
161
171
|
storeCopyColumnPreferences,
|
|
162
172
|
submitCreateConnection,
|
|
@@ -167,7 +177,9 @@ import {
|
|
|
167
177
|
submitOpenConnection,
|
|
168
178
|
subscribe,
|
|
169
179
|
toggleCurrentMediaTagSelection,
|
|
180
|
+
toggleConnectionTagFilter,
|
|
170
181
|
toggleQueryHistorySavedState,
|
|
182
|
+
addEditConnectionTag,
|
|
171
183
|
updateCurrentMediaTaggingField,
|
|
172
184
|
updateCurrentMediaTaggingTagFormField,
|
|
173
185
|
updateCopyColumnModalFormatField,
|
|
@@ -181,6 +193,8 @@ import {
|
|
|
181
193
|
updateGenerateDataMapping,
|
|
182
194
|
updateGenerateDataModal,
|
|
183
195
|
updateGenerateTypesModal,
|
|
196
|
+
updateEditConnectionTagQuery,
|
|
197
|
+
removeEditConnectionTag,
|
|
184
198
|
addCurrentTableDesignerColumn,
|
|
185
199
|
applyCurrentMediaTaggingSelection,
|
|
186
200
|
removeCurrentTableDesignerColumn,
|
|
@@ -271,6 +285,20 @@ let pendingDocumentAutosaveId = null;
|
|
|
271
285
|
const DOCUMENT_AUTOSAVE_DELAY_MS = 5000;
|
|
272
286
|
|
|
273
287
|
const APP_TITLE = 'SQLite Hub';
|
|
288
|
+
const TABLE_DESIGNER_IMPORT_FORMATS = {
|
|
289
|
+
csv: {
|
|
290
|
+
accept: '.csv,text/csv',
|
|
291
|
+
label: 'CSV',
|
|
292
|
+
},
|
|
293
|
+
tsv: {
|
|
294
|
+
accept: '.tsv,text/tab-separated-values',
|
|
295
|
+
label: 'TSV',
|
|
296
|
+
},
|
|
297
|
+
json: {
|
|
298
|
+
accept: '.json,application/json',
|
|
299
|
+
label: 'JSON',
|
|
300
|
+
},
|
|
301
|
+
};
|
|
274
302
|
const ROUTE_TITLE_SEGMENTS = {
|
|
275
303
|
connections: 'Connections',
|
|
276
304
|
backups: 'Backups',
|
|
@@ -575,6 +603,28 @@ function syncTableDesignerDraftUi(sourceNode) {
|
|
|
575
603
|
return synced;
|
|
576
604
|
}
|
|
577
605
|
|
|
606
|
+
function normalizeCheckExpressionPreview(expression) {
|
|
607
|
+
const normalized = String(expression ?? '').trim();
|
|
608
|
+
|
|
609
|
+
if (!normalized) {
|
|
610
|
+
return 'CHECK (...)';
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return /^CHECK\s*\(/i.test(normalized) ? normalized : `CHECK (${normalized})`;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function syncTableDesignerCheckEditorPreview(sourceNode) {
|
|
617
|
+
const drawerNode = sourceNode.closest('.table-designer-check-drawer');
|
|
618
|
+
const previewNode = drawerNode?.querySelector('[data-table-designer-check-preview]');
|
|
619
|
+
|
|
620
|
+
if (!(previewNode instanceof HTMLElement)) {
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
replaceChildrenFromRenderedMarkup(previewNode, highlightSql(normalizeCheckExpressionPreview(sourceNode.value)));
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
|
|
578
628
|
function syncDataRowSelectionUi(selectedRowIndex = null) {
|
|
579
629
|
if (getState().route.name !== 'data') {
|
|
580
630
|
return false;
|
|
@@ -1417,11 +1467,18 @@ async function applyMediaTaggingAndFocusSearch() {
|
|
|
1417
1467
|
return result;
|
|
1418
1468
|
}
|
|
1419
1469
|
|
|
1420
|
-
|
|
1470
|
+
function normalizeTableDesignerImportFormat(value) {
|
|
1471
|
+
const normalized = String(value ?? '').trim().toLowerCase();
|
|
1472
|
+
return Object.prototype.hasOwnProperty.call(TABLE_DESIGNER_IMPORT_FORMATS, normalized) ? normalized : 'csv';
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
async function handleTableDesignerImport(fileInput) {
|
|
1421
1476
|
if (!(fileInput instanceof HTMLInputElement)) {
|
|
1422
1477
|
return;
|
|
1423
1478
|
}
|
|
1424
1479
|
|
|
1480
|
+
const format = normalizeTableDesignerImportFormat(fileInput.dataset.importFormat);
|
|
1481
|
+
const formatLabel = TABLE_DESIGNER_IMPORT_FORMATS[format].label;
|
|
1425
1482
|
const file = fileInput.files?.[0];
|
|
1426
1483
|
|
|
1427
1484
|
if (!(file instanceof File)) {
|
|
@@ -1429,14 +1486,14 @@ async function handleTableDesignerCsvImport(fileInput) {
|
|
|
1429
1486
|
}
|
|
1430
1487
|
|
|
1431
1488
|
if (!file.size) {
|
|
1432
|
-
showToast(
|
|
1489
|
+
showToast(`The selected ${formatLabel} file is empty.`, 'alert');
|
|
1433
1490
|
fileInput.value = '';
|
|
1434
1491
|
return;
|
|
1435
1492
|
}
|
|
1436
1493
|
|
|
1437
1494
|
try {
|
|
1438
|
-
const
|
|
1439
|
-
const imported =
|
|
1495
|
+
const text = await readFileAsText(file);
|
|
1496
|
+
const imported = queueTableDesignerImport(file.name, text, { format });
|
|
1440
1497
|
|
|
1441
1498
|
if (!imported) {
|
|
1442
1499
|
return;
|
|
@@ -1450,7 +1507,7 @@ async function handleTableDesignerCsvImport(fileInput) {
|
|
|
1450
1507
|
'success',
|
|
1451
1508
|
);
|
|
1452
1509
|
} catch (error) {
|
|
1453
|
-
showToast(error?.message ||
|
|
1510
|
+
showToast(error?.message || `${formatLabel} import failed.`, 'alert');
|
|
1454
1511
|
} finally {
|
|
1455
1512
|
fileInput.value = '';
|
|
1456
1513
|
}
|
|
@@ -2680,6 +2737,16 @@ async function handleAction(actionNode) {
|
|
|
2680
2737
|
case 'edit-connection':
|
|
2681
2738
|
openEditConnectionModal(actionNode.dataset.connectionId);
|
|
2682
2739
|
return;
|
|
2740
|
+
case 'clear-connection-tag-filters':
|
|
2741
|
+
clearConnectionTagFilters();
|
|
2742
|
+
return;
|
|
2743
|
+
case 'add-edit-connection-tag':
|
|
2744
|
+
case 'create-edit-connection-tag':
|
|
2745
|
+
addEditConnectionTag(actionNode.dataset.tagName);
|
|
2746
|
+
return;
|
|
2747
|
+
case 'remove-edit-connection-tag':
|
|
2748
|
+
removeEditConnectionTag(actionNode.dataset.tagName);
|
|
2749
|
+
return;
|
|
2683
2750
|
case 'choose-open-database-path': {
|
|
2684
2751
|
const labelNode = actionNode.querySelector('[data-open-database-path-button-label]');
|
|
2685
2752
|
|
|
@@ -3063,6 +3130,30 @@ async function handleAction(actionNode) {
|
|
|
3063
3130
|
removeCurrentTableDesignerColumn(actionNode.dataset.columnId);
|
|
3064
3131
|
}
|
|
3065
3132
|
return;
|
|
3133
|
+
case 'open-table-designer-constraints':
|
|
3134
|
+
openTableDesignerConstraintsDrawer(actionNode.dataset.columnId, actionNode.dataset.columnName);
|
|
3135
|
+
return;
|
|
3136
|
+
case 'close-table-designer-constraints':
|
|
3137
|
+
closeTableDesignerConstraintsDrawer();
|
|
3138
|
+
return;
|
|
3139
|
+
case 'start-table-designer-check-editor':
|
|
3140
|
+
startTableDesignerCheckEditor();
|
|
3141
|
+
return;
|
|
3142
|
+
case 'edit-table-designer-check':
|
|
3143
|
+
startTableDesignerCheckEditor(actionNode.dataset.constraintId);
|
|
3144
|
+
return;
|
|
3145
|
+
case 'cancel-table-designer-check-editor':
|
|
3146
|
+
cancelTableDesignerCheckEditor();
|
|
3147
|
+
return;
|
|
3148
|
+
case 'apply-table-designer-check-preset':
|
|
3149
|
+
applyTableDesignerCheckPreset(actionNode.dataset.presetId);
|
|
3150
|
+
return;
|
|
3151
|
+
case 'save-table-designer-check':
|
|
3152
|
+
await saveTableDesignerCheckEditor();
|
|
3153
|
+
return;
|
|
3154
|
+
case 'remove-table-designer-check':
|
|
3155
|
+
removeCurrentTableDesignerCheckConstraint(actionNode.dataset.constraintId);
|
|
3156
|
+
return;
|
|
3066
3157
|
case 'save-table-designer': {
|
|
3067
3158
|
const savedTableName = await saveCurrentTableDesignerDraft();
|
|
3068
3159
|
if (savedTableName) {
|
|
@@ -3186,14 +3277,20 @@ async function handleAction(actionNode) {
|
|
|
3186
3277
|
router.navigate(`/structure/${encodeURIComponent(mediaTableName)}`);
|
|
3187
3278
|
return;
|
|
3188
3279
|
}
|
|
3189
|
-
case 'import-table-designer-
|
|
3280
|
+
case 'import-table-designer-data': {
|
|
3190
3281
|
const fileInput = document.querySelector('[data-bind="table-designer-import-file"]');
|
|
3191
3282
|
|
|
3192
3283
|
if (!(fileInput instanceof HTMLInputElement)) {
|
|
3193
3284
|
return;
|
|
3194
3285
|
}
|
|
3195
3286
|
|
|
3287
|
+
const format = normalizeTableDesignerImportFormat(actionNode.dataset.importFormat);
|
|
3288
|
+
const formatOptions = TABLE_DESIGNER_IMPORT_FORMATS[format];
|
|
3289
|
+
|
|
3290
|
+
fileInput.dataset.importFormat = format;
|
|
3291
|
+
fileInput.accept = actionNode.dataset.importAccept || formatOptions.accept;
|
|
3196
3292
|
fileInput.value = '';
|
|
3293
|
+
actionNode.closest('[data-dropdown-button]')?.removeAttribute('open');
|
|
3197
3294
|
fileInput.click();
|
|
3198
3295
|
return;
|
|
3199
3296
|
}
|
|
@@ -3256,6 +3353,35 @@ function canApplyMediaTaggingShortcut(state) {
|
|
|
3256
3353
|
);
|
|
3257
3354
|
}
|
|
3258
3355
|
|
|
3356
|
+
function isEditableShortcutTarget(target) {
|
|
3357
|
+
if (!(target instanceof HTMLElement)) {
|
|
3358
|
+
return false;
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
if (
|
|
3362
|
+
target instanceof HTMLInputElement ||
|
|
3363
|
+
target instanceof HTMLTextAreaElement ||
|
|
3364
|
+
target instanceof HTMLSelectElement
|
|
3365
|
+
) {
|
|
3366
|
+
return true;
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3369
|
+
if (target.isContentEditable) {
|
|
3370
|
+
return true;
|
|
3371
|
+
}
|
|
3372
|
+
|
|
3373
|
+
if (
|
|
3374
|
+
target.closest(
|
|
3375
|
+
'[contenteditable="true"], [data-bind="current-query"], [data-sql-highlight="true"], .query-editor-input',
|
|
3376
|
+
)
|
|
3377
|
+
) {
|
|
3378
|
+
return true;
|
|
3379
|
+
}
|
|
3380
|
+
|
|
3381
|
+
const role = String(target.getAttribute('role') ?? '').trim().toLowerCase();
|
|
3382
|
+
return role === 'textbox' || role === 'searchbox' || role === 'combobox';
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3259
3385
|
document.addEventListener('click', event => {
|
|
3260
3386
|
const target = event.target instanceof Element ? event.target : null;
|
|
3261
3387
|
|
|
@@ -3340,6 +3466,27 @@ document.addEventListener('keydown', event => {
|
|
|
3340
3466
|
return;
|
|
3341
3467
|
}
|
|
3342
3468
|
|
|
3469
|
+
if (
|
|
3470
|
+
event.key === '/' &&
|
|
3471
|
+
!event.shiftKey &&
|
|
3472
|
+
!event.altKey &&
|
|
3473
|
+
!event.ctrlKey &&
|
|
3474
|
+
!event.metaKey &&
|
|
3475
|
+
!event.defaultPrevented &&
|
|
3476
|
+
state.route.name === 'connections' &&
|
|
3477
|
+
!isEditableShortcutTarget(target)
|
|
3478
|
+
) {
|
|
3479
|
+
const searchInput = document.querySelector('[data-connections-search-input]');
|
|
3480
|
+
|
|
3481
|
+
if (searchInput instanceof HTMLInputElement) {
|
|
3482
|
+
event.preventDefault();
|
|
3483
|
+
searchInput.focus({ preventScroll: true });
|
|
3484
|
+
searchInput.select();
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3487
|
+
return;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3343
3490
|
// Handle Enter key in tag form fields to trigger create tag
|
|
3344
3491
|
if (
|
|
3345
3492
|
event.key === 'Enter' &&
|
|
@@ -3359,6 +3506,34 @@ document.addEventListener('keydown', event => {
|
|
|
3359
3506
|
return;
|
|
3360
3507
|
}
|
|
3361
3508
|
|
|
3509
|
+
if (
|
|
3510
|
+
event.key === 'Enter' &&
|
|
3511
|
+
!event.shiftKey &&
|
|
3512
|
+
!event.altKey &&
|
|
3513
|
+
!event.ctrlKey &&
|
|
3514
|
+
!event.metaKey &&
|
|
3515
|
+
!event.defaultPrevented &&
|
|
3516
|
+
target instanceof HTMLElement &&
|
|
3517
|
+
target.dataset.bind === 'edit-connection-tag-query'
|
|
3518
|
+
) {
|
|
3519
|
+
event.preventDefault();
|
|
3520
|
+
const tagQuery = target instanceof HTMLInputElement ? target.value.trim() : '';
|
|
3521
|
+
|
|
3522
|
+
if (!tagQuery) {
|
|
3523
|
+
return;
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3526
|
+
const primaryTagAction =
|
|
3527
|
+
document.querySelector('[data-edit-connection-tag-primary]') ??
|
|
3528
|
+
document.querySelector('[data-action="add-edit-connection-tag"]');
|
|
3529
|
+
|
|
3530
|
+
if (primaryTagAction instanceof HTMLElement) {
|
|
3531
|
+
primaryTagAction.click();
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
return;
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3362
3537
|
if (
|
|
3363
3538
|
(event.key === 'Enter' || event.code === 'Enter' || event.code === 'NumpadEnter') &&
|
|
3364
3539
|
event.shiftKey &&
|
|
@@ -3396,6 +3571,16 @@ document.addEventListener('keydown', event => {
|
|
|
3396
3571
|
return;
|
|
3397
3572
|
}
|
|
3398
3573
|
|
|
3574
|
+
if (target instanceof HTMLInputElement && target.dataset.bind === 'connections-search') {
|
|
3575
|
+
event.preventDefault();
|
|
3576
|
+
|
|
3577
|
+
if (!clearInputForEscape(target)) {
|
|
3578
|
+
target.blur();
|
|
3579
|
+
}
|
|
3580
|
+
|
|
3581
|
+
return;
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3399
3584
|
if (target instanceof HTMLInputElement && clearInputForEscape(target)) {
|
|
3400
3585
|
event.preventDefault();
|
|
3401
3586
|
return;
|
|
@@ -3425,6 +3610,12 @@ document.addEventListener('keydown', event => {
|
|
|
3425
3610
|
return;
|
|
3426
3611
|
}
|
|
3427
3612
|
|
|
3613
|
+
if (state.route.name === 'tableDesigner' && state.tableDesigner.constraintsDrawer?.visible) {
|
|
3614
|
+
event.preventDefault();
|
|
3615
|
+
closeTableDesignerConstraintsDrawer();
|
|
3616
|
+
return;
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3428
3619
|
if (state.route.name === 'charts' && state.charts.detailPanelVisible) {
|
|
3429
3620
|
event.preventDefault();
|
|
3430
3621
|
setChartsDetailPanelVisibility(false);
|
|
@@ -3538,6 +3729,16 @@ document.addEventListener('input', event => {
|
|
|
3538
3729
|
return;
|
|
3539
3730
|
}
|
|
3540
3731
|
|
|
3732
|
+
if (bindNode.dataset.bind === 'connections-search') {
|
|
3733
|
+
setConnectionSearchQuery(bindNode.value);
|
|
3734
|
+
return;
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3737
|
+
if (bindNode.dataset.bind === 'edit-connection-tag-query') {
|
|
3738
|
+
updateEditConnectionTagQuery(bindNode.value);
|
|
3739
|
+
return;
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3541
3742
|
if (bindNode.dataset.bind === 'data-search-query') {
|
|
3542
3743
|
void setDataSearchQuery(bindNode.value);
|
|
3543
3744
|
return;
|
|
@@ -3563,6 +3764,20 @@ document.addEventListener('input', event => {
|
|
|
3563
3764
|
return;
|
|
3564
3765
|
}
|
|
3565
3766
|
|
|
3767
|
+
if (bindNode.dataset.bind === 'table-designer-check-editor-field') {
|
|
3768
|
+
const field = bindNode.dataset.field;
|
|
3769
|
+
const value = bindNode instanceof HTMLInputElement || bindNode instanceof HTMLTextAreaElement ? bindNode.value : '';
|
|
3770
|
+
const isCustomExpression = field === 'expression';
|
|
3771
|
+
|
|
3772
|
+
updateTableDesignerCheckEditorField(field, value, { notify: !isCustomExpression });
|
|
3773
|
+
|
|
3774
|
+
if (isCustomExpression) {
|
|
3775
|
+
syncTableDesignerCheckEditorPreview(bindNode);
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3778
|
+
return;
|
|
3779
|
+
}
|
|
3780
|
+
|
|
3566
3781
|
if (bindNode.dataset.bind === 'table-designer-field') {
|
|
3567
3782
|
if (
|
|
3568
3783
|
(bindNode instanceof HTMLInputElement && bindNode.type === 'checkbox') ||
|
|
@@ -3709,6 +3924,12 @@ document.addEventListener('change', event => {
|
|
|
3709
3924
|
return;
|
|
3710
3925
|
}
|
|
3711
3926
|
|
|
3927
|
+
if (bindNode.dataset.bind === 'connection-tag-filter') {
|
|
3928
|
+
const nextValue = bindNode instanceof HTMLInputElement && bindNode.type === 'checkbox' ? bindNode.checked : false;
|
|
3929
|
+
toggleConnectionTagFilter(bindNode.dataset.tagId, nextValue);
|
|
3930
|
+
return;
|
|
3931
|
+
}
|
|
3932
|
+
|
|
3712
3933
|
if (bindNode.dataset.bind === 'media-tagging-field') {
|
|
3713
3934
|
updateCurrentMediaTaggingField(bindNode.dataset.field, bindNode.value);
|
|
3714
3935
|
void refreshMediaTaggingPreview();
|
|
@@ -3731,7 +3952,15 @@ document.addEventListener('change', event => {
|
|
|
3731
3952
|
}
|
|
3732
3953
|
|
|
3733
3954
|
if (bindNode.dataset.bind === 'table-designer-import-file') {
|
|
3734
|
-
void
|
|
3955
|
+
void handleTableDesignerImport(bindNode);
|
|
3956
|
+
return;
|
|
3957
|
+
}
|
|
3958
|
+
|
|
3959
|
+
if (bindNode.dataset.bind === 'table-designer-check-editor-field') {
|
|
3960
|
+
const value = bindNode instanceof HTMLInputElement || bindNode instanceof HTMLTextAreaElement ? bindNode.value : '';
|
|
3961
|
+
|
|
3962
|
+
updateTableDesignerCheckEditorField(bindNode.dataset.field, value, { notify: false });
|
|
3963
|
+
syncTableDesignerCheckEditorPreview(bindNode);
|
|
3735
3964
|
return;
|
|
3736
3965
|
}
|
|
3737
3966
|
|
|
@@ -3913,6 +4142,7 @@ document.addEventListener('submit', async event => {
|
|
|
3913
4142
|
readOnly: formData.get('readOnly') === 'on',
|
|
3914
4143
|
clearLogo: formData.get('clearLogo') === 'on' && !logoUpload,
|
|
3915
4144
|
logoUpload,
|
|
4145
|
+
tags: formData.getAll('tags').map(value => String(value ?? '')),
|
|
3916
4146
|
});
|
|
3917
4147
|
|
|
3918
4148
|
return;
|
|
@@ -3,3 +3,19 @@ import { escapeHtml } from "../utils/format.js";
|
|
|
3
3
|
export function renderStatusBadge(label, tone = "muted") {
|
|
4
4
|
return `<span class="status-badge status-badge--${tone}">${escapeHtml(label)}</span>`;
|
|
5
5
|
}
|
|
6
|
+
|
|
7
|
+
export function renderTableKindBadge(table) {
|
|
8
|
+
if (table?.isVirtual) {
|
|
9
|
+
return `<span class="status-badge status-badge--primary shrink-0" title="Virtual table">Virtual</span>`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (table?.isShadow) {
|
|
13
|
+
return `<span class="status-badge status-badge--muted shrink-0" title="Shadow table">Shadow</span>`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function renderVirtualTableBadge(table) {
|
|
20
|
+
return renderTableKindBadge(table);
|
|
21
|
+
}
|
|
@@ -7,6 +7,40 @@ import {
|
|
|
7
7
|
import { renderStatusBadge } from "./badges.js";
|
|
8
8
|
import { renderConnectionLogo } from "./connectionLogo.js";
|
|
9
9
|
|
|
10
|
+
function renderConnectionTags(tags = []) {
|
|
11
|
+
const normalizedTags = Array.isArray(tags)
|
|
12
|
+
? tags.filter((tag) => String(tag?.name ?? "").trim())
|
|
13
|
+
: [];
|
|
14
|
+
|
|
15
|
+
if (!normalizedTags.length) {
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const visibleTags = normalizedTags.slice(0, 2);
|
|
20
|
+
const hiddenCount = Math.max(0, normalizedTags.length - visibleTags.length);
|
|
21
|
+
const title = normalizedTags.map((tag) => tag.name).join(", ");
|
|
22
|
+
|
|
23
|
+
return [
|
|
24
|
+
'<div class="connection-user-tags" title="',
|
|
25
|
+
escapeHtml(title),
|
|
26
|
+
'">',
|
|
27
|
+
visibleTags
|
|
28
|
+
.map(
|
|
29
|
+
(tag) =>
|
|
30
|
+
'<span class="connection-user-tag">' +
|
|
31
|
+
escapeHtml(tag.name) +
|
|
32
|
+
"</span>"
|
|
33
|
+
)
|
|
34
|
+
.join(""),
|
|
35
|
+
hiddenCount
|
|
36
|
+
? '<span class="connection-user-tag connection-user-tag--more">+' +
|
|
37
|
+
escapeHtml(String(hiddenCount)) +
|
|
38
|
+
"</span>"
|
|
39
|
+
: "",
|
|
40
|
+
"</div>",
|
|
41
|
+
].join("");
|
|
42
|
+
}
|
|
43
|
+
|
|
10
44
|
export function renderConnectionCard(connection, activeConnectionId) {
|
|
11
45
|
const isActive = activeConnectionId
|
|
12
46
|
? connection.id === activeConnectionId
|
|
@@ -46,6 +80,7 @@ export function renderConnectionCard(connection, activeConnectionId) {
|
|
|
46
80
|
'">',
|
|
47
81
|
escapeHtml(truncateMiddle(connection.path, 68)),
|
|
48
82
|
"</p>",
|
|
83
|
+
renderConnectionTags(connection.tags),
|
|
49
84
|
'<div class="mt-8 grid grid-cols-2 gap-4">',
|
|
50
85
|
'<div><div class="mb-1 text-[9px] font-mono uppercase text-outline-variant">Allocation</div><div class="text-xs font-bold text-on-surface">',
|
|
51
86
|
escapeHtml(formatBytes(connection.sizeBytes)),
|