sqlite-hub 2.0.1 → 2.2.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 +21 -9
- package/docs/MCP.md +8 -0
- package/docs/changelog.md +16 -0
- package/docs/guidelines/DESIGN.md +64 -0
- package/docs/todo.md +2 -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 +18 -0
- package/frontend/js/app.js +567 -15
- package/frontend/js/components/badges.js +16 -0
- package/frontend/js/components/connectionCard.js +35 -0
- package/frontend/js/components/modal.js +268 -247
- 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 +1847 -190
- package/frontend/js/utils/connectionRegistry.js +76 -0
- package/frontend/js/utils/markdownDocuments.js +21 -4
- 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 +101 -6
- package/frontend/js/views/data.js +52 -9
- package/frontend/js/views/documents.js +153 -59
- 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/base.css +9 -0
- package/frontend/styles/components.css +676 -79
- package/frontend/styles/structure-graph.css +49 -0
- package/frontend/styles/tailwind.generated.css +1 -1
- package/frontend/styles/views.css +12 -0
- package/package.json +1 -1
- package/server/routes/backups.js +37 -1
- package/server/routes/charts.js +28 -0
- package/server/routes/connections.js +12 -0
- package/server/routes/data.js +30 -2
- package/server/routes/documents.js +61 -5
- package/server/routes/settings.js +32 -0
- package/server/routes/tableDesigner.js +35 -2
- package/server/server.js +3 -3
- package/server/services/mcpToolService.js +30 -0
- package/server/services/sqlite/connectionManager.js +25 -2
- package/server/services/sqlite/dataBrowserService.js +21 -0
- package/server/services/sqlite/introspection.js +39 -1
- package/server/services/sqlite/overviewService.js +1 -0
- 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 +590 -10
- package/server/utils/fileValidation.js +5 -0
- package/server/utils/userActionLog.js +49 -0
- 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,
|
|
@@ -46,6 +47,9 @@ import {
|
|
|
46
47
|
exportCurrentQueryFormat,
|
|
47
48
|
getState,
|
|
48
49
|
initializeApp,
|
|
50
|
+
insertCurrentDocumentDatabaseInfo,
|
|
51
|
+
insertCurrentDocumentSavedQueries,
|
|
52
|
+
insertCurrentDocumentTimeMetadata,
|
|
49
53
|
insertMarkdownIntoLastOpenDocument,
|
|
50
54
|
loadMoreQueryHistory,
|
|
51
55
|
loadMoreLogs,
|
|
@@ -66,6 +70,7 @@ import {
|
|
|
66
70
|
openDeleteQueryChartModal,
|
|
67
71
|
openDataExportModal,
|
|
68
72
|
openGenerateDataModal,
|
|
73
|
+
openCreateDocumentFolderModal,
|
|
69
74
|
openDeleteDocumentModal,
|
|
70
75
|
openQueryExportModal,
|
|
71
76
|
openDataRowByIdentity,
|
|
@@ -75,6 +80,7 @@ import {
|
|
|
75
80
|
openEditQueryChartModal,
|
|
76
81
|
openDocumentInsertNoteModal,
|
|
77
82
|
openDocumentInsertTableModal,
|
|
83
|
+
openDocumentInsertTableDefinitionModal,
|
|
78
84
|
preserveCurrentDataRowSelectionForReload,
|
|
79
85
|
openDataRowUpdatePreview,
|
|
80
86
|
openEditorRowUpdatePreview,
|
|
@@ -97,12 +103,21 @@ import {
|
|
|
97
103
|
selectQueryHistoryItem,
|
|
98
104
|
selectStructureEntry,
|
|
99
105
|
setDocumentsSearchQuery,
|
|
106
|
+
setConnectionSearchQuery,
|
|
100
107
|
setLogFilter,
|
|
101
108
|
setLogSearchInput,
|
|
102
109
|
applyLogSearch,
|
|
103
110
|
setTableDesignerSearchQuery,
|
|
104
111
|
setTableDesignerSqlPreviewVisibility,
|
|
105
112
|
toggleTableDesignerTablesPanel,
|
|
113
|
+
openTableDesignerConstraintsDrawer,
|
|
114
|
+
closeTableDesignerConstraintsDrawer,
|
|
115
|
+
startTableDesignerCheckEditor,
|
|
116
|
+
cancelTableDesignerCheckEditor,
|
|
117
|
+
applyTableDesignerCheckPreset,
|
|
118
|
+
updateTableDesignerCheckEditorField,
|
|
119
|
+
saveTableDesignerCheckEditor,
|
|
120
|
+
removeCurrentTableDesignerCheckConstraint,
|
|
106
121
|
setDataTableSearchQuery,
|
|
107
122
|
setStructureTableSearchQuery,
|
|
108
123
|
toggleStructureTablesPanel,
|
|
@@ -125,6 +140,8 @@ import {
|
|
|
125
140
|
submitDeleteDocumentConfirmation,
|
|
126
141
|
submitDocumentInsertNote,
|
|
127
142
|
submitDocumentInsertTable,
|
|
143
|
+
submitDocumentInsertTableDefinition,
|
|
144
|
+
submitCreateDocumentFolder,
|
|
128
145
|
submitCreateMediaTaggingTagTable,
|
|
129
146
|
submitCreateMediaTaggingMappingTable,
|
|
130
147
|
submitDeleteQueryHistoryConfirmation,
|
|
@@ -156,22 +173,28 @@ import {
|
|
|
156
173
|
toggleDocumentsPane,
|
|
157
174
|
setMediaTaggingWorkflowMediaDetailsVisible,
|
|
158
175
|
setMediaTaggingWorkflowMediaRotationDegrees,
|
|
159
|
-
|
|
176
|
+
queueTableDesignerImport,
|
|
160
177
|
showToast,
|
|
161
178
|
storeCopyColumnPreferences,
|
|
162
179
|
submitCreateConnection,
|
|
163
180
|
createCurrentMediaTag,
|
|
181
|
+
moveCurrentDocumentToFolder,
|
|
164
182
|
submitDeleteRowConfirmation,
|
|
165
183
|
submitEditConnection,
|
|
166
184
|
submitImportSql,
|
|
167
185
|
submitOpenConnection,
|
|
168
186
|
subscribe,
|
|
169
187
|
toggleCurrentMediaTagSelection,
|
|
188
|
+
toggleConnectionTagFilter,
|
|
170
189
|
toggleQueryHistorySavedState,
|
|
190
|
+
addEditConnectionTag,
|
|
171
191
|
updateCurrentMediaTaggingField,
|
|
172
192
|
updateCurrentMediaTaggingTagFormField,
|
|
173
193
|
updateCopyColumnModalFormatField,
|
|
174
194
|
updateCurrentDocumentDraftField,
|
|
195
|
+
updateDocumentTableDefinitionOption,
|
|
196
|
+
updateDocumentTableDefinitionSampleRowCount,
|
|
197
|
+
updateDocumentTableDefinitionSelection,
|
|
175
198
|
updateDocumentInsertQuerySelection,
|
|
176
199
|
updateCurrentQueryChartDraftConfigField,
|
|
177
200
|
updateCurrentQueryChartDraftField,
|
|
@@ -181,6 +204,8 @@ import {
|
|
|
181
204
|
updateGenerateDataMapping,
|
|
182
205
|
updateGenerateDataModal,
|
|
183
206
|
updateGenerateTypesModal,
|
|
207
|
+
updateEditConnectionTagQuery,
|
|
208
|
+
removeEditConnectionTag,
|
|
184
209
|
addCurrentTableDesignerColumn,
|
|
185
210
|
applyCurrentMediaTaggingSelection,
|
|
186
211
|
removeCurrentTableDesignerColumn,
|
|
@@ -188,7 +213,7 @@ import {
|
|
|
188
213
|
import { renderChartsDetail, renderChartsView } from './views/charts.js';
|
|
189
214
|
import { renderBackupsView } from './views/backups.js';
|
|
190
215
|
import { renderConnectionsView } from './views/connections.js';
|
|
191
|
-
import { renderDataRowEditorPanel, renderDataView } from './views/data.js';
|
|
216
|
+
import { buildDataSidebarSignature, renderDataRowEditorPanel, renderDataView } from './views/data.js';
|
|
192
217
|
import { renderDocumentsView } from './views/documents.js';
|
|
193
218
|
import { renderEditorView } from './views/editor.js';
|
|
194
219
|
import { renderLandingView } from './views/landing.js';
|
|
@@ -260,6 +285,7 @@ let lastRenderedToastMarkup = '';
|
|
|
260
285
|
let lastRenderedChartsHistorySignature = '';
|
|
261
286
|
let lastRenderedChartsDetailSignature = '';
|
|
262
287
|
let lastRenderedChartsCardSignature = '';
|
|
288
|
+
let lastRenderedDataSidebarSignature = '';
|
|
263
289
|
let lastRenderedPanelOpen = false;
|
|
264
290
|
let lastRenderedLockedRoute = false;
|
|
265
291
|
let pendingNewTableDesignerAutofocus = false;
|
|
@@ -267,10 +293,25 @@ let pendingQueryEditorFocus = false;
|
|
|
267
293
|
let pendingMediaTaggingTagSearchFocus = false;
|
|
268
294
|
let documentAutosaveTimer = null;
|
|
269
295
|
let pendingDocumentAutosaveId = null;
|
|
296
|
+
let lastDocumentEditorInsertionRange = null;
|
|
270
297
|
|
|
271
|
-
const DOCUMENT_AUTOSAVE_DELAY_MS =
|
|
298
|
+
const DOCUMENT_AUTOSAVE_DELAY_MS = 2000;
|
|
272
299
|
|
|
273
300
|
const APP_TITLE = 'SQLite Hub';
|
|
301
|
+
const TABLE_DESIGNER_IMPORT_FORMATS = {
|
|
302
|
+
csv: {
|
|
303
|
+
accept: '.csv,text/csv',
|
|
304
|
+
label: 'CSV',
|
|
305
|
+
},
|
|
306
|
+
tsv: {
|
|
307
|
+
accept: '.tsv,text/tab-separated-values',
|
|
308
|
+
label: 'TSV',
|
|
309
|
+
},
|
|
310
|
+
json: {
|
|
311
|
+
accept: '.json,application/json',
|
|
312
|
+
label: 'JSON',
|
|
313
|
+
},
|
|
314
|
+
};
|
|
274
315
|
const ROUTE_TITLE_SEGMENTS = {
|
|
275
316
|
connections: 'Connections',
|
|
276
317
|
backups: 'Backups',
|
|
@@ -575,6 +616,28 @@ function syncTableDesignerDraftUi(sourceNode) {
|
|
|
575
616
|
return synced;
|
|
576
617
|
}
|
|
577
618
|
|
|
619
|
+
function normalizeCheckExpressionPreview(expression) {
|
|
620
|
+
const normalized = String(expression ?? '').trim();
|
|
621
|
+
|
|
622
|
+
if (!normalized) {
|
|
623
|
+
return 'CHECK (...)';
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return /^CHECK\s*\(/i.test(normalized) ? normalized : `CHECK (${normalized})`;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function syncTableDesignerCheckEditorPreview(sourceNode) {
|
|
630
|
+
const drawerNode = sourceNode.closest('.table-designer-check-drawer');
|
|
631
|
+
const previewNode = drawerNode?.querySelector('[data-table-designer-check-preview]');
|
|
632
|
+
|
|
633
|
+
if (!(previewNode instanceof HTMLElement)) {
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
replaceChildrenFromRenderedMarkup(previewNode, highlightSql(normalizeCheckExpressionPreview(sourceNode.value)));
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
|
|
578
641
|
function syncDataRowSelectionUi(selectedRowIndex = null) {
|
|
579
642
|
if (getState().route.name !== 'data') {
|
|
580
643
|
return false;
|
|
@@ -600,6 +663,81 @@ function syncDataRowSelectionUi(selectedRowIndex = null) {
|
|
|
600
663
|
return true;
|
|
601
664
|
}
|
|
602
665
|
|
|
666
|
+
function syncDataSidebarActiveTable(state) {
|
|
667
|
+
if (state.route.name !== 'data') {
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const sidebarNode = shellRefs.view.querySelector('[data-data-sidebar]');
|
|
672
|
+
|
|
673
|
+
if (!(sidebarNode instanceof HTMLElement)) {
|
|
674
|
+
return state.dataBrowser.tablesVisible === false;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const selectedTableName = String(state.dataBrowser.selectedTable ?? '');
|
|
678
|
+
|
|
679
|
+
for (const itemNode of sidebarNode.querySelectorAll('[data-data-table-item]')) {
|
|
680
|
+
if (!(itemNode instanceof HTMLElement)) {
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const isActive = itemNode.dataset.dataTableName === selectedTableName;
|
|
685
|
+
|
|
686
|
+
itemNode.classList.toggle('is-active', isActive);
|
|
687
|
+
itemNode.classList.toggle('border-primary-container/30', isActive);
|
|
688
|
+
itemNode.classList.toggle('bg-surface-container-high', isActive);
|
|
689
|
+
itemNode.classList.toggle('border-outline-variant/10', !isActive);
|
|
690
|
+
itemNode.classList.toggle('bg-surface-container-lowest', !isActive);
|
|
691
|
+
itemNode.classList.toggle('hover:bg-surface-container-high', !isActive);
|
|
692
|
+
|
|
693
|
+
const labelNode = itemNode.querySelector('[data-data-table-name-label]');
|
|
694
|
+
|
|
695
|
+
if (labelNode instanceof HTMLElement) {
|
|
696
|
+
labelNode.classList.toggle('is-active', isActive);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
function renderDataMainIntoScratch(state) {
|
|
704
|
+
const scratch = document.createElement('div');
|
|
705
|
+
|
|
706
|
+
replaceChildrenFromRenderedMarkup(scratch, renderDataView(state).main);
|
|
707
|
+
return scratch;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function patchDataMainUi(state, { tableHorizontalScrollState = null } = {}) {
|
|
711
|
+
const dataView = shellRefs.view.querySelector('[data-data-view]');
|
|
712
|
+
|
|
713
|
+
if (!(dataView instanceof HTMLElement)) {
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const currentWorkspace = dataView.querySelector('[data-data-workspace]');
|
|
718
|
+
const currentSidebar = dataView.querySelector('[data-data-sidebar]');
|
|
719
|
+
const scratch = renderDataMainIntoScratch(state);
|
|
720
|
+
const nextWorkspace = scratch.querySelector('[data-data-workspace]');
|
|
721
|
+
const nextSidebar = scratch.querySelector('[data-data-sidebar]');
|
|
722
|
+
|
|
723
|
+
if (
|
|
724
|
+
!(currentWorkspace instanceof HTMLElement) ||
|
|
725
|
+
!(nextWorkspace instanceof HTMLElement) ||
|
|
726
|
+
Boolean(currentSidebar) !== Boolean(nextSidebar)
|
|
727
|
+
) {
|
|
728
|
+
return false;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
currentWorkspace.replaceWith(nextWorkspace);
|
|
732
|
+
restoreTableHorizontalScrollState({
|
|
733
|
+
snapshot: tableHorizontalScrollState,
|
|
734
|
+
routeName: state.route.name,
|
|
735
|
+
scrollNodes: nextWorkspace.querySelectorAll('[data-table-horizontal-scroll]'),
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
return syncDataSidebarActiveTable(state);
|
|
739
|
+
}
|
|
740
|
+
|
|
603
741
|
function syncQueryHistoryUi(historyId) {
|
|
604
742
|
const state = getState();
|
|
605
743
|
const numericId = Number(historyId);
|
|
@@ -1074,6 +1212,71 @@ function patchLogsTableUi(state) {
|
|
|
1074
1212
|
return true;
|
|
1075
1213
|
}
|
|
1076
1214
|
|
|
1215
|
+
function normalizeDocumentsTextPatchMarkup(markup) {
|
|
1216
|
+
return String(markup ?? '')
|
|
1217
|
+
.replace(
|
|
1218
|
+
/(<span\b[^>]*data-document-save-state=")(?:saved|unsaved)("[^>]*>)[\s\S]*?(<\/span>)/g,
|
|
1219
|
+
'$1__document_save_state__$2__document_save_state__$3',
|
|
1220
|
+
)
|
|
1221
|
+
.replace(
|
|
1222
|
+
/(<span\b[^>]*data-document-list-meta\b[^>]*>)[\s\S]*?(<\/span>)/g,
|
|
1223
|
+
'$1__document_list_meta__$2',
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
function renderDocumentsMainIntoScratch(state) {
|
|
1228
|
+
const scratch = document.createElement('div');
|
|
1229
|
+
|
|
1230
|
+
replaceChildrenFromRenderedMarkup(scratch, renderDocumentsView(state).main);
|
|
1231
|
+
return scratch;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
function patchDocumentsTextNodes(selector, scratch) {
|
|
1235
|
+
const currentNodes = shellRefs.view.querySelectorAll(selector);
|
|
1236
|
+
const nextNodes = scratch.querySelectorAll(selector);
|
|
1237
|
+
|
|
1238
|
+
if (currentNodes.length !== nextNodes.length) {
|
|
1239
|
+
return false;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
for (let index = 0; index < currentNodes.length; index += 1) {
|
|
1243
|
+
const currentNode = currentNodes[index];
|
|
1244
|
+
const nextNode = nextNodes[index];
|
|
1245
|
+
|
|
1246
|
+
if (!(currentNode instanceof HTMLElement) || !(nextNode instanceof HTMLElement)) {
|
|
1247
|
+
return false;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
currentNode.textContent = nextNode.textContent;
|
|
1251
|
+
|
|
1252
|
+
if (selector === '[data-document-save-state]') {
|
|
1253
|
+
currentNode.dataset.documentSaveState = nextNode.dataset.documentSaveState ?? '';
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
return true;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
function patchDocumentsTextOnlyUi(state, nextMainMarkup) {
|
|
1261
|
+
if (lastRenderedRouteName !== 'documents' || state.route.name !== 'documents') {
|
|
1262
|
+
return false;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
const previousComparable = normalizeDocumentsTextPatchMarkup(lastRenderedMainMarkup);
|
|
1266
|
+
const nextComparable = normalizeDocumentsTextPatchMarkup(nextMainMarkup);
|
|
1267
|
+
|
|
1268
|
+
if (previousComparable !== nextComparable) {
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
const scratch = renderDocumentsMainIntoScratch(state);
|
|
1273
|
+
|
|
1274
|
+
return (
|
|
1275
|
+
patchDocumentsTextNodes('[data-document-save-state]', scratch) &&
|
|
1276
|
+
patchDocumentsTextNodes('[data-document-list-meta]', scratch)
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1077
1280
|
function readFileAsBase64(file) {
|
|
1078
1281
|
return new Promise((resolve, reject) => {
|
|
1079
1282
|
const reader = new FileReader();
|
|
@@ -1383,6 +1586,29 @@ function focusMediaTaggingTagSearchInput() {
|
|
|
1383
1586
|
return true;
|
|
1384
1587
|
}
|
|
1385
1588
|
|
|
1589
|
+
function focusModalAutofocusElement() {
|
|
1590
|
+
const element = shellRefs.modal.querySelector('[autofocus]');
|
|
1591
|
+
|
|
1592
|
+
if (
|
|
1593
|
+
!(
|
|
1594
|
+
element instanceof HTMLInputElement ||
|
|
1595
|
+
element instanceof HTMLTextAreaElement ||
|
|
1596
|
+
element instanceof HTMLSelectElement ||
|
|
1597
|
+
element instanceof HTMLButtonElement
|
|
1598
|
+
)
|
|
1599
|
+
) {
|
|
1600
|
+
return false;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
element.focus({ preventScroll: true });
|
|
1604
|
+
|
|
1605
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
|
|
1606
|
+
element.setSelectionRange(element.value.length, element.value.length);
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
return true;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1386
1612
|
function syncSidebarActiveRoute(routeName) {
|
|
1387
1613
|
if (!isMediaTaggingRouteName(routeName)) {
|
|
1388
1614
|
return false;
|
|
@@ -1417,11 +1643,18 @@ async function applyMediaTaggingAndFocusSearch() {
|
|
|
1417
1643
|
return result;
|
|
1418
1644
|
}
|
|
1419
1645
|
|
|
1420
|
-
|
|
1646
|
+
function normalizeTableDesignerImportFormat(value) {
|
|
1647
|
+
const normalized = String(value ?? '').trim().toLowerCase();
|
|
1648
|
+
return Object.prototype.hasOwnProperty.call(TABLE_DESIGNER_IMPORT_FORMATS, normalized) ? normalized : 'csv';
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
async function handleTableDesignerImport(fileInput) {
|
|
1421
1652
|
if (!(fileInput instanceof HTMLInputElement)) {
|
|
1422
1653
|
return;
|
|
1423
1654
|
}
|
|
1424
1655
|
|
|
1656
|
+
const format = normalizeTableDesignerImportFormat(fileInput.dataset.importFormat);
|
|
1657
|
+
const formatLabel = TABLE_DESIGNER_IMPORT_FORMATS[format].label;
|
|
1425
1658
|
const file = fileInput.files?.[0];
|
|
1426
1659
|
|
|
1427
1660
|
if (!(file instanceof File)) {
|
|
@@ -1429,14 +1662,14 @@ async function handleTableDesignerCsvImport(fileInput) {
|
|
|
1429
1662
|
}
|
|
1430
1663
|
|
|
1431
1664
|
if (!file.size) {
|
|
1432
|
-
showToast(
|
|
1665
|
+
showToast(`The selected ${formatLabel} file is empty.`, 'alert');
|
|
1433
1666
|
fileInput.value = '';
|
|
1434
1667
|
return;
|
|
1435
1668
|
}
|
|
1436
1669
|
|
|
1437
1670
|
try {
|
|
1438
|
-
const
|
|
1439
|
-
const imported =
|
|
1671
|
+
const text = await readFileAsText(file);
|
|
1672
|
+
const imported = queueTableDesignerImport(file.name, text, { format });
|
|
1440
1673
|
|
|
1441
1674
|
if (!imported) {
|
|
1442
1675
|
return;
|
|
@@ -1450,7 +1683,7 @@ async function handleTableDesignerCsvImport(fileInput) {
|
|
|
1450
1683
|
'success',
|
|
1451
1684
|
);
|
|
1452
1685
|
} catch (error) {
|
|
1453
|
-
showToast(error?.message ||
|
|
1686
|
+
showToast(error?.message || `${formatLabel} import failed.`, 'alert');
|
|
1454
1687
|
} finally {
|
|
1455
1688
|
fileInput.value = '';
|
|
1456
1689
|
}
|
|
@@ -1503,6 +1736,7 @@ function renderApp(state) {
|
|
|
1503
1736
|
const chartsHistorySignature = buildChartsHistorySignature(state);
|
|
1504
1737
|
const chartsDetailSignature = buildChartsDetailSignature(state);
|
|
1505
1738
|
const chartsCardSignature = buildChartsCardSignature(state);
|
|
1739
|
+
const dataSidebarSignature = buildDataSidebarSignature(state);
|
|
1506
1740
|
const isLockedRoute = [
|
|
1507
1741
|
'editor',
|
|
1508
1742
|
'editorResults',
|
|
@@ -1526,6 +1760,7 @@ function renderApp(state) {
|
|
|
1526
1760
|
const chartsHistoryChanged = chartsHistorySignature !== lastRenderedChartsHistorySignature;
|
|
1527
1761
|
const chartsDetailChanged = chartsDetailSignature !== lastRenderedChartsDetailSignature;
|
|
1528
1762
|
const chartsCardsChanged = chartsCardSignature !== lastRenderedChartsCardSignature;
|
|
1763
|
+
const dataSidebarChanged = dataSidebarSignature !== lastRenderedDataSidebarSignature;
|
|
1529
1764
|
const panelOpenChanged = panelOpen !== lastRenderedPanelOpen;
|
|
1530
1765
|
const lockedRouteChanged = isLockedRoute !== lastRenderedLockedRoute;
|
|
1531
1766
|
const shellMarkupUnchanged =
|
|
@@ -1566,9 +1801,16 @@ function renderApp(state) {
|
|
|
1566
1801
|
|
|
1567
1802
|
const canPatchChartsMain = mainChanged && previousRouteName === 'charts' && state.route.name === 'charts';
|
|
1568
1803
|
const canPatchLogsMain = mainChanged && previousRouteName === 'logs' && state.route.name === 'logs';
|
|
1804
|
+
const canPatchDocumentsMain = mainChanged && previousRouteName === 'documents' && state.route.name === 'documents';
|
|
1805
|
+
const canPatchDataMain =
|
|
1806
|
+
mainChanged && previousRouteName === 'data' && state.route.name === 'data' && !dataSidebarChanged;
|
|
1569
1807
|
let mainPatched = false;
|
|
1570
1808
|
let preservedChartsDom = false;
|
|
1571
1809
|
|
|
1810
|
+
if (canPatchDataMain) {
|
|
1811
|
+
mainPatched = patchDataMainUi(state, { tableHorizontalScrollState });
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1572
1814
|
if (canPatchChartsMain) {
|
|
1573
1815
|
const historyPatched = !chartsHistoryChanged || patchChartsHistoryUi(state);
|
|
1574
1816
|
|
|
@@ -1595,6 +1837,10 @@ function renderApp(state) {
|
|
|
1595
1837
|
mainPatched = patchLogsTableUi(state);
|
|
1596
1838
|
}
|
|
1597
1839
|
|
|
1840
|
+
if (!mainPatched && canPatchDocumentsMain) {
|
|
1841
|
+
mainPatched = patchDocumentsTextOnlyUi(state, main);
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1598
1844
|
if (mainChanged) {
|
|
1599
1845
|
if (!mainPatched) {
|
|
1600
1846
|
teardownStructureGraph();
|
|
@@ -1674,6 +1920,8 @@ function renderApp(state) {
|
|
|
1674
1920
|
if (focusNewTableDesignerNameField()) {
|
|
1675
1921
|
pendingNewTableDesignerAutofocus = false;
|
|
1676
1922
|
}
|
|
1923
|
+
} else if (modalChanged && state.modal && focusModalAutofocusElement()) {
|
|
1924
|
+
// Modal content is inserted dynamically, so native autofocus is not reliable.
|
|
1677
1925
|
} else {
|
|
1678
1926
|
restoreFocusedInputState(focusedInput);
|
|
1679
1927
|
}
|
|
@@ -1690,6 +1938,7 @@ function renderApp(state) {
|
|
|
1690
1938
|
lastRenderedChartsHistorySignature = chartsHistorySignature;
|
|
1691
1939
|
lastRenderedChartsDetailSignature = chartsDetailSignature;
|
|
1692
1940
|
lastRenderedChartsCardSignature = chartsCardSignature;
|
|
1941
|
+
lastRenderedDataSidebarSignature = dataSidebarSignature;
|
|
1693
1942
|
lastRenderedPanelOpen = panelOpen;
|
|
1694
1943
|
lastRenderedLockedRoute = isLockedRoute;
|
|
1695
1944
|
|
|
@@ -2379,16 +2628,60 @@ function exportCurrentDocumentMarkdown() {
|
|
|
2379
2628
|
showToast(`Document "${filename}" exported.`, 'success');
|
|
2380
2629
|
}
|
|
2381
2630
|
|
|
2631
|
+
function isDocumentEditorInput(node) {
|
|
2632
|
+
return (
|
|
2633
|
+
node instanceof HTMLTextAreaElement &&
|
|
2634
|
+
node.classList.contains('documents-editor-input') &&
|
|
2635
|
+
node.dataset.bind === 'document-field' &&
|
|
2636
|
+
node.dataset.field === 'content'
|
|
2637
|
+
);
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
function rememberDocumentEditorInsertionRange(textarea) {
|
|
2641
|
+
if (!isDocumentEditorInput(textarea)) {
|
|
2642
|
+
return null;
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
const documents = getState().documents;
|
|
2646
|
+
const range = {
|
|
2647
|
+
documentId: String(documents.selectedId ?? ''),
|
|
2648
|
+
start: textarea.selectionStart,
|
|
2649
|
+
end: textarea.selectionEnd,
|
|
2650
|
+
};
|
|
2651
|
+
|
|
2652
|
+
lastDocumentEditorInsertionRange = range;
|
|
2653
|
+
return range;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
function rememberDocumentEditorInsertionRangeFromTarget(target) {
|
|
2657
|
+
if (isDocumentEditorInput(target)) {
|
|
2658
|
+
rememberDocumentEditorInsertionRange(target);
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2382
2662
|
function getCurrentDocumentEditorInsertionRange() {
|
|
2383
2663
|
const textarea = document.querySelector('.documents-editor-input');
|
|
2384
2664
|
|
|
2385
|
-
if (
|
|
2665
|
+
if (isDocumentEditorInput(textarea)) {
|
|
2666
|
+
const range = rememberDocumentEditorInsertionRange(textarea);
|
|
2667
|
+
|
|
2668
|
+
return range
|
|
2669
|
+
? {
|
|
2670
|
+
start: range.start,
|
|
2671
|
+
end: range.end,
|
|
2672
|
+
}
|
|
2673
|
+
: null;
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
const documents = getState().documents;
|
|
2677
|
+
|
|
2678
|
+
if (String(lastDocumentEditorInsertionRange?.documentId ?? '') !== String(documents.selectedId ?? '')) {
|
|
2386
2679
|
return null;
|
|
2387
2680
|
}
|
|
2388
2681
|
|
|
2389
2682
|
return {
|
|
2390
|
-
start:
|
|
2391
|
-
end:
|
|
2683
|
+
start: lastDocumentEditorInsertionRange.start,
|
|
2684
|
+
end: lastDocumentEditorInsertionRange.end,
|
|
2392
2685
|
};
|
|
2393
2686
|
}
|
|
2394
2687
|
|
|
@@ -2621,6 +2914,12 @@ async function handleAction(actionNode) {
|
|
|
2621
2914
|
}
|
|
2622
2915
|
return;
|
|
2623
2916
|
}
|
|
2917
|
+
case 'open-create-document-folder-modal':
|
|
2918
|
+
openCreateDocumentFolderModal();
|
|
2919
|
+
return;
|
|
2920
|
+
case 'move-document-to-folder':
|
|
2921
|
+
await moveCurrentDocumentToFolder(actionNode.dataset.folderId || null);
|
|
2922
|
+
return;
|
|
2624
2923
|
case 'select-document': {
|
|
2625
2924
|
const documentId = String(actionNode.dataset.documentId ?? '').trim();
|
|
2626
2925
|
|
|
@@ -2643,6 +2942,33 @@ async function handleAction(actionNode) {
|
|
|
2643
2942
|
case 'open-document-insert-note-modal':
|
|
2644
2943
|
await openDocumentInsertNoteModal(getCurrentDocumentEditorInsertionRange());
|
|
2645
2944
|
return;
|
|
2945
|
+
case 'open-document-insert-table-definition-modal':
|
|
2946
|
+
await openDocumentInsertTableDefinitionModal(getCurrentDocumentEditorInsertionRange());
|
|
2947
|
+
return;
|
|
2948
|
+
case 'insert-document-saved-queries': {
|
|
2949
|
+
const inserted = await insertCurrentDocumentSavedQueries(getCurrentDocumentEditorInsertionRange());
|
|
2950
|
+
|
|
2951
|
+
if (inserted) {
|
|
2952
|
+
scheduleDocumentAutosave(getState().documents.selectedId);
|
|
2953
|
+
}
|
|
2954
|
+
return;
|
|
2955
|
+
}
|
|
2956
|
+
case 'insert-document-time-metadata': {
|
|
2957
|
+
const inserted = await insertCurrentDocumentTimeMetadata(getCurrentDocumentEditorInsertionRange());
|
|
2958
|
+
|
|
2959
|
+
if (inserted) {
|
|
2960
|
+
scheduleDocumentAutosave(getState().documents.selectedId);
|
|
2961
|
+
}
|
|
2962
|
+
return;
|
|
2963
|
+
}
|
|
2964
|
+
case 'insert-document-database-info': {
|
|
2965
|
+
const inserted = await insertCurrentDocumentDatabaseInfo(getCurrentDocumentEditorInsertionRange());
|
|
2966
|
+
|
|
2967
|
+
if (inserted) {
|
|
2968
|
+
scheduleDocumentAutosave(getState().documents.selectedId);
|
|
2969
|
+
}
|
|
2970
|
+
return;
|
|
2971
|
+
}
|
|
2646
2972
|
case 'import-document-markdown': {
|
|
2647
2973
|
const fileInput = document.querySelector('[data-bind="document-import-file"]');
|
|
2648
2974
|
|
|
@@ -2662,8 +2988,9 @@ async function handleAction(actionNode) {
|
|
|
2662
2988
|
toggleDocumentsPane(actionNode.dataset.pane);
|
|
2663
2989
|
return;
|
|
2664
2990
|
case 'toggle-document-todo':
|
|
2665
|
-
|
|
2666
|
-
|
|
2991
|
+
if (toggleCurrentDocumentTodo(actionNode.dataset.lineIndex)) {
|
|
2992
|
+
scheduleDocumentAutosave(getState().documents.selectedId);
|
|
2993
|
+
}
|
|
2667
2994
|
return;
|
|
2668
2995
|
case 'open-create-query-chart-modal':
|
|
2669
2996
|
openCreateQueryChartModal();
|
|
@@ -2680,6 +3007,16 @@ async function handleAction(actionNode) {
|
|
|
2680
3007
|
case 'edit-connection':
|
|
2681
3008
|
openEditConnectionModal(actionNode.dataset.connectionId);
|
|
2682
3009
|
return;
|
|
3010
|
+
case 'clear-connection-tag-filters':
|
|
3011
|
+
clearConnectionTagFilters();
|
|
3012
|
+
return;
|
|
3013
|
+
case 'add-edit-connection-tag':
|
|
3014
|
+
case 'create-edit-connection-tag':
|
|
3015
|
+
addEditConnectionTag(actionNode.dataset.tagName);
|
|
3016
|
+
return;
|
|
3017
|
+
case 'remove-edit-connection-tag':
|
|
3018
|
+
removeEditConnectionTag(actionNode.dataset.tagName);
|
|
3019
|
+
return;
|
|
2683
3020
|
case 'choose-open-database-path': {
|
|
2684
3021
|
const labelNode = actionNode.querySelector('[data-open-database-path-button-label]');
|
|
2685
3022
|
|
|
@@ -3063,6 +3400,30 @@ async function handleAction(actionNode) {
|
|
|
3063
3400
|
removeCurrentTableDesignerColumn(actionNode.dataset.columnId);
|
|
3064
3401
|
}
|
|
3065
3402
|
return;
|
|
3403
|
+
case 'open-table-designer-constraints':
|
|
3404
|
+
openTableDesignerConstraintsDrawer(actionNode.dataset.columnId, actionNode.dataset.columnName);
|
|
3405
|
+
return;
|
|
3406
|
+
case 'close-table-designer-constraints':
|
|
3407
|
+
closeTableDesignerConstraintsDrawer();
|
|
3408
|
+
return;
|
|
3409
|
+
case 'start-table-designer-check-editor':
|
|
3410
|
+
startTableDesignerCheckEditor();
|
|
3411
|
+
return;
|
|
3412
|
+
case 'edit-table-designer-check':
|
|
3413
|
+
startTableDesignerCheckEditor(actionNode.dataset.constraintId);
|
|
3414
|
+
return;
|
|
3415
|
+
case 'cancel-table-designer-check-editor':
|
|
3416
|
+
cancelTableDesignerCheckEditor();
|
|
3417
|
+
return;
|
|
3418
|
+
case 'apply-table-designer-check-preset':
|
|
3419
|
+
applyTableDesignerCheckPreset(actionNode.dataset.presetId);
|
|
3420
|
+
return;
|
|
3421
|
+
case 'save-table-designer-check':
|
|
3422
|
+
await saveTableDesignerCheckEditor();
|
|
3423
|
+
return;
|
|
3424
|
+
case 'remove-table-designer-check':
|
|
3425
|
+
removeCurrentTableDesignerCheckConstraint(actionNode.dataset.constraintId);
|
|
3426
|
+
return;
|
|
3066
3427
|
case 'save-table-designer': {
|
|
3067
3428
|
const savedTableName = await saveCurrentTableDesignerDraft();
|
|
3068
3429
|
if (savedTableName) {
|
|
@@ -3186,14 +3547,20 @@ async function handleAction(actionNode) {
|
|
|
3186
3547
|
router.navigate(`/structure/${encodeURIComponent(mediaTableName)}`);
|
|
3187
3548
|
return;
|
|
3188
3549
|
}
|
|
3189
|
-
case 'import-table-designer-
|
|
3550
|
+
case 'import-table-designer-data': {
|
|
3190
3551
|
const fileInput = document.querySelector('[data-bind="table-designer-import-file"]');
|
|
3191
3552
|
|
|
3192
3553
|
if (!(fileInput instanceof HTMLInputElement)) {
|
|
3193
3554
|
return;
|
|
3194
3555
|
}
|
|
3195
3556
|
|
|
3557
|
+
const format = normalizeTableDesignerImportFormat(actionNode.dataset.importFormat);
|
|
3558
|
+
const formatOptions = TABLE_DESIGNER_IMPORT_FORMATS[format];
|
|
3559
|
+
|
|
3560
|
+
fileInput.dataset.importFormat = format;
|
|
3561
|
+
fileInput.accept = actionNode.dataset.importAccept || formatOptions.accept;
|
|
3196
3562
|
fileInput.value = '';
|
|
3563
|
+
actionNode.closest('[data-dropdown-button]')?.removeAttribute('open');
|
|
3197
3564
|
fileInput.click();
|
|
3198
3565
|
return;
|
|
3199
3566
|
}
|
|
@@ -3256,6 +3623,35 @@ function canApplyMediaTaggingShortcut(state) {
|
|
|
3256
3623
|
);
|
|
3257
3624
|
}
|
|
3258
3625
|
|
|
3626
|
+
function isEditableShortcutTarget(target) {
|
|
3627
|
+
if (!(target instanceof HTMLElement)) {
|
|
3628
|
+
return false;
|
|
3629
|
+
}
|
|
3630
|
+
|
|
3631
|
+
if (
|
|
3632
|
+
target instanceof HTMLInputElement ||
|
|
3633
|
+
target instanceof HTMLTextAreaElement ||
|
|
3634
|
+
target instanceof HTMLSelectElement
|
|
3635
|
+
) {
|
|
3636
|
+
return true;
|
|
3637
|
+
}
|
|
3638
|
+
|
|
3639
|
+
if (target.isContentEditable) {
|
|
3640
|
+
return true;
|
|
3641
|
+
}
|
|
3642
|
+
|
|
3643
|
+
if (
|
|
3644
|
+
target.closest(
|
|
3645
|
+
'[contenteditable="true"], [data-bind="current-query"], [data-sql-highlight="true"], .query-editor-input',
|
|
3646
|
+
)
|
|
3647
|
+
) {
|
|
3648
|
+
return true;
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
const role = String(target.getAttribute('role') ?? '').trim().toLowerCase();
|
|
3652
|
+
return role === 'textbox' || role === 'searchbox' || role === 'combobox';
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3259
3655
|
document.addEventListener('click', event => {
|
|
3260
3656
|
const target = event.target instanceof Element ? event.target : null;
|
|
3261
3657
|
|
|
@@ -3322,6 +3718,30 @@ document.addEventListener('contextmenu', event => {
|
|
|
3322
3718
|
openCopyColumnMenu(headerNode);
|
|
3323
3719
|
});
|
|
3324
3720
|
|
|
3721
|
+
document.addEventListener('focusin', event => {
|
|
3722
|
+
rememberDocumentEditorInsertionRangeFromTarget(event.target);
|
|
3723
|
+
});
|
|
3724
|
+
|
|
3725
|
+
document.addEventListener('keyup', event => {
|
|
3726
|
+
rememberDocumentEditorInsertionRangeFromTarget(event.target);
|
|
3727
|
+
});
|
|
3728
|
+
|
|
3729
|
+
document.addEventListener('pointerup', event => {
|
|
3730
|
+
rememberDocumentEditorInsertionRangeFromTarget(event.target);
|
|
3731
|
+
});
|
|
3732
|
+
|
|
3733
|
+
document.addEventListener(
|
|
3734
|
+
'select',
|
|
3735
|
+
event => {
|
|
3736
|
+
rememberDocumentEditorInsertionRangeFromTarget(event.target);
|
|
3737
|
+
},
|
|
3738
|
+
true,
|
|
3739
|
+
);
|
|
3740
|
+
|
|
3741
|
+
document.addEventListener('selectionchange', () => {
|
|
3742
|
+
rememberDocumentEditorInsertionRangeFromTarget(document.activeElement);
|
|
3743
|
+
});
|
|
3744
|
+
|
|
3325
3745
|
document.addEventListener('keydown', event => {
|
|
3326
3746
|
const target = event.target;
|
|
3327
3747
|
const state = getState();
|
|
@@ -3340,6 +3760,27 @@ document.addEventListener('keydown', event => {
|
|
|
3340
3760
|
return;
|
|
3341
3761
|
}
|
|
3342
3762
|
|
|
3763
|
+
if (
|
|
3764
|
+
event.key === '/' &&
|
|
3765
|
+
!event.shiftKey &&
|
|
3766
|
+
!event.altKey &&
|
|
3767
|
+
!event.ctrlKey &&
|
|
3768
|
+
!event.metaKey &&
|
|
3769
|
+
!event.defaultPrevented &&
|
|
3770
|
+
state.route.name === 'connections' &&
|
|
3771
|
+
!isEditableShortcutTarget(target)
|
|
3772
|
+
) {
|
|
3773
|
+
const searchInput = document.querySelector('[data-connections-search-input]');
|
|
3774
|
+
|
|
3775
|
+
if (searchInput instanceof HTMLInputElement) {
|
|
3776
|
+
event.preventDefault();
|
|
3777
|
+
searchInput.focus({ preventScroll: true });
|
|
3778
|
+
searchInput.select();
|
|
3779
|
+
}
|
|
3780
|
+
|
|
3781
|
+
return;
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3343
3784
|
// Handle Enter key in tag form fields to trigger create tag
|
|
3344
3785
|
if (
|
|
3345
3786
|
event.key === 'Enter' &&
|
|
@@ -3359,6 +3800,34 @@ document.addEventListener('keydown', event => {
|
|
|
3359
3800
|
return;
|
|
3360
3801
|
}
|
|
3361
3802
|
|
|
3803
|
+
if (
|
|
3804
|
+
event.key === 'Enter' &&
|
|
3805
|
+
!event.shiftKey &&
|
|
3806
|
+
!event.altKey &&
|
|
3807
|
+
!event.ctrlKey &&
|
|
3808
|
+
!event.metaKey &&
|
|
3809
|
+
!event.defaultPrevented &&
|
|
3810
|
+
target instanceof HTMLElement &&
|
|
3811
|
+
target.dataset.bind === 'edit-connection-tag-query'
|
|
3812
|
+
) {
|
|
3813
|
+
event.preventDefault();
|
|
3814
|
+
const tagQuery = target instanceof HTMLInputElement ? target.value.trim() : '';
|
|
3815
|
+
|
|
3816
|
+
if (!tagQuery) {
|
|
3817
|
+
return;
|
|
3818
|
+
}
|
|
3819
|
+
|
|
3820
|
+
const primaryTagAction =
|
|
3821
|
+
document.querySelector('[data-edit-connection-tag-primary]') ??
|
|
3822
|
+
document.querySelector('[data-action="add-edit-connection-tag"]');
|
|
3823
|
+
|
|
3824
|
+
if (primaryTagAction instanceof HTMLElement) {
|
|
3825
|
+
primaryTagAction.click();
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3828
|
+
return;
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3362
3831
|
if (
|
|
3363
3832
|
(event.key === 'Enter' || event.code === 'Enter' || event.code === 'NumpadEnter') &&
|
|
3364
3833
|
event.shiftKey &&
|
|
@@ -3396,6 +3865,16 @@ document.addEventListener('keydown', event => {
|
|
|
3396
3865
|
return;
|
|
3397
3866
|
}
|
|
3398
3867
|
|
|
3868
|
+
if (target instanceof HTMLInputElement && target.dataset.bind === 'connections-search') {
|
|
3869
|
+
event.preventDefault();
|
|
3870
|
+
|
|
3871
|
+
if (!clearInputForEscape(target)) {
|
|
3872
|
+
target.blur();
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
return;
|
|
3876
|
+
}
|
|
3877
|
+
|
|
3399
3878
|
if (target instanceof HTMLInputElement && clearInputForEscape(target)) {
|
|
3400
3879
|
event.preventDefault();
|
|
3401
3880
|
return;
|
|
@@ -3425,6 +3904,12 @@ document.addEventListener('keydown', event => {
|
|
|
3425
3904
|
return;
|
|
3426
3905
|
}
|
|
3427
3906
|
|
|
3907
|
+
if (state.route.name === 'tableDesigner' && state.tableDesigner.constraintsDrawer?.visible) {
|
|
3908
|
+
event.preventDefault();
|
|
3909
|
+
closeTableDesignerConstraintsDrawer();
|
|
3910
|
+
return;
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3428
3913
|
if (state.route.name === 'charts' && state.charts.detailPanelVisible) {
|
|
3429
3914
|
event.preventDefault();
|
|
3430
3915
|
setChartsDetailPanelVisibility(false);
|
|
@@ -3523,6 +4008,7 @@ document.addEventListener('input', event => {
|
|
|
3523
4008
|
}
|
|
3524
4009
|
|
|
3525
4010
|
if (bindNode.dataset.bind === 'document-field') {
|
|
4011
|
+
rememberDocumentEditorInsertionRangeFromTarget(bindNode);
|
|
3526
4012
|
updateCurrentDocumentDraftField(bindNode.dataset.field, bindNode.value);
|
|
3527
4013
|
scheduleDocumentAutosave(getState().documents.selectedId);
|
|
3528
4014
|
return;
|
|
@@ -3538,6 +4024,16 @@ document.addEventListener('input', event => {
|
|
|
3538
4024
|
return;
|
|
3539
4025
|
}
|
|
3540
4026
|
|
|
4027
|
+
if (bindNode.dataset.bind === 'connections-search') {
|
|
4028
|
+
setConnectionSearchQuery(bindNode.value);
|
|
4029
|
+
return;
|
|
4030
|
+
}
|
|
4031
|
+
|
|
4032
|
+
if (bindNode.dataset.bind === 'edit-connection-tag-query') {
|
|
4033
|
+
updateEditConnectionTagQuery(bindNode.value);
|
|
4034
|
+
return;
|
|
4035
|
+
}
|
|
4036
|
+
|
|
3541
4037
|
if (bindNode.dataset.bind === 'data-search-query') {
|
|
3542
4038
|
void setDataSearchQuery(bindNode.value);
|
|
3543
4039
|
return;
|
|
@@ -3563,6 +4059,20 @@ document.addEventListener('input', event => {
|
|
|
3563
4059
|
return;
|
|
3564
4060
|
}
|
|
3565
4061
|
|
|
4062
|
+
if (bindNode.dataset.bind === 'table-designer-check-editor-field') {
|
|
4063
|
+
const field = bindNode.dataset.field;
|
|
4064
|
+
const value = bindNode instanceof HTMLInputElement || bindNode instanceof HTMLTextAreaElement ? bindNode.value : '';
|
|
4065
|
+
const isCustomExpression = field === 'expression';
|
|
4066
|
+
|
|
4067
|
+
updateTableDesignerCheckEditorField(field, value, { notify: !isCustomExpression });
|
|
4068
|
+
|
|
4069
|
+
if (isCustomExpression) {
|
|
4070
|
+
syncTableDesignerCheckEditorPreview(bindNode);
|
|
4071
|
+
}
|
|
4072
|
+
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
|
|
3566
4076
|
if (bindNode.dataset.bind === 'table-designer-field') {
|
|
3567
4077
|
if (
|
|
3568
4078
|
(bindNode instanceof HTMLInputElement && bindNode.type === 'checkbox') ||
|
|
@@ -3709,6 +4219,12 @@ document.addEventListener('change', event => {
|
|
|
3709
4219
|
return;
|
|
3710
4220
|
}
|
|
3711
4221
|
|
|
4222
|
+
if (bindNode.dataset.bind === 'connection-tag-filter') {
|
|
4223
|
+
const nextValue = bindNode instanceof HTMLInputElement && bindNode.type === 'checkbox' ? bindNode.checked : false;
|
|
4224
|
+
toggleConnectionTagFilter(bindNode.dataset.tagId, nextValue);
|
|
4225
|
+
return;
|
|
4226
|
+
}
|
|
4227
|
+
|
|
3712
4228
|
if (bindNode.dataset.bind === 'media-tagging-field') {
|
|
3713
4229
|
updateCurrentMediaTaggingField(bindNode.dataset.field, bindNode.value);
|
|
3714
4230
|
void refreshMediaTaggingPreview();
|
|
@@ -3731,7 +4247,15 @@ document.addEventListener('change', event => {
|
|
|
3731
4247
|
}
|
|
3732
4248
|
|
|
3733
4249
|
if (bindNode.dataset.bind === 'table-designer-import-file') {
|
|
3734
|
-
void
|
|
4250
|
+
void handleTableDesignerImport(bindNode);
|
|
4251
|
+
return;
|
|
4252
|
+
}
|
|
4253
|
+
|
|
4254
|
+
if (bindNode.dataset.bind === 'table-designer-check-editor-field') {
|
|
4255
|
+
const value = bindNode instanceof HTMLInputElement || bindNode instanceof HTMLTextAreaElement ? bindNode.value : '';
|
|
4256
|
+
|
|
4257
|
+
updateTableDesignerCheckEditorField(bindNode.dataset.field, value, { notify: false });
|
|
4258
|
+
syncTableDesignerCheckEditorPreview(bindNode);
|
|
3735
4259
|
return;
|
|
3736
4260
|
}
|
|
3737
4261
|
|
|
@@ -3745,6 +4269,21 @@ document.addEventListener('change', event => {
|
|
|
3745
4269
|
return;
|
|
3746
4270
|
}
|
|
3747
4271
|
|
|
4272
|
+
if (bindNode.dataset.bind === 'document-table-definition-select') {
|
|
4273
|
+
updateDocumentTableDefinitionSelection(bindNode.value);
|
|
4274
|
+
return;
|
|
4275
|
+
}
|
|
4276
|
+
|
|
4277
|
+
if (bindNode.dataset.bind === 'document-table-definition-option') {
|
|
4278
|
+
updateDocumentTableDefinitionOption(bindNode.dataset.option, bindNode.checked);
|
|
4279
|
+
return;
|
|
4280
|
+
}
|
|
4281
|
+
|
|
4282
|
+
if (bindNode.dataset.bind === 'document-table-definition-row-count') {
|
|
4283
|
+
updateDocumentTableDefinitionSampleRowCount(bindNode.value);
|
|
4284
|
+
return;
|
|
4285
|
+
}
|
|
4286
|
+
|
|
3748
4287
|
if (bindNode.dataset.bind === 'table-designer-field') {
|
|
3749
4288
|
if (bindNode instanceof HTMLInputElement && bindNode.type === 'checkbox') {
|
|
3750
4289
|
updateCurrentTableDesignerField(bindNode.dataset.field, bindNode.checked);
|
|
@@ -3913,6 +4452,7 @@ document.addEventListener('submit', async event => {
|
|
|
3913
4452
|
readOnly: formData.get('readOnly') === 'on',
|
|
3914
4453
|
clearLogo: formData.get('clearLogo') === 'on' && !logoUpload,
|
|
3915
4454
|
logoUpload,
|
|
4455
|
+
tags: formData.getAll('tags').map(value => String(value ?? '')),
|
|
3916
4456
|
});
|
|
3917
4457
|
|
|
3918
4458
|
return;
|
|
@@ -3958,6 +4498,10 @@ document.addEventListener('submit', async event => {
|
|
|
3958
4498
|
case 'delete-api-token-confirm':
|
|
3959
4499
|
await submitDeleteSettingsApiTokenConfirmation();
|
|
3960
4500
|
return;
|
|
4501
|
+
case 'create-document-folder': {
|
|
4502
|
+
await submitCreateDocumentFolder(String(formData.get('name') ?? ''));
|
|
4503
|
+
return;
|
|
4504
|
+
}
|
|
3961
4505
|
case 'document-insert-table': {
|
|
3962
4506
|
const inserted = await submitDocumentInsertTable();
|
|
3963
4507
|
|
|
@@ -3966,6 +4510,14 @@ document.addEventListener('submit', async event => {
|
|
|
3966
4510
|
}
|
|
3967
4511
|
return;
|
|
3968
4512
|
}
|
|
4513
|
+
case 'document-insert-table-definition': {
|
|
4514
|
+
const inserted = await submitDocumentInsertTableDefinition();
|
|
4515
|
+
|
|
4516
|
+
if (inserted) {
|
|
4517
|
+
scheduleDocumentAutosave(getState().documents.selectedId);
|
|
4518
|
+
}
|
|
4519
|
+
return;
|
|
4520
|
+
}
|
|
3969
4521
|
case 'document-insert-note': {
|
|
3970
4522
|
const inserted = submitDocumentInsertNote();
|
|
3971
4523
|
|