sqlite-hub 0.10.0 → 0.12.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 +44 -13
- package/database.sqlite +0 -0
- package/fill.js +526 -0
- package/frontend/js/api.js +70 -11
- package/frontend/js/app.js +104 -32
- package/frontend/js/components/emptyState.js +42 -46
- package/frontend/js/components/modal.js +95 -0
- package/frontend/js/components/queryEditor.js +3 -2
- package/frontend/js/components/rowEditorPanel.js +145 -6
- package/frontend/js/components/sidebar.js +5 -5
- package/frontend/js/store.js +303 -34
- package/frontend/js/views/data.js +94 -70
- package/frontend/js/views/editor.js +2 -0
- package/frontend/js/views/settings.js +1 -1
- package/frontend/styles/tailwind.generated.css +1 -1
- package/frontend/styles/tokens.css +95 -95
- package/package.json +1 -1
- package/server/routes/data.js +3 -0
- package/server/routes/export.js +97 -12
- package/server/services/sqlite/dataBrowserService.js +25 -4
- package/server/services/sqlite/exportService.js +74 -15
- package/server/services/sqlite/introspection.js +199 -1
- package/server/services/sqlite/sqlExecutor.js +2 -0
- package/server/services/sqlite/tableFilter.js +75 -0
- package/server/utils/csv.js +30 -4
- package/tests/check-constraint-options.test.js +76 -0
- package/tests/sql-identifier-safety.test.js +59 -0
package/frontend/js/store.js
CHANGED
|
@@ -30,7 +30,8 @@ const DEFAULT_SETTINGS = {
|
|
|
30
30
|
csvDelimiter: ',',
|
|
31
31
|
};
|
|
32
32
|
const DEFAULT_DATA_PAGE_SIZE = 50;
|
|
33
|
-
const DATA_PAGE_SIZES = [25, 50, 100];
|
|
33
|
+
const DATA_PAGE_SIZES = [25, 50, 100, 250];
|
|
34
|
+
const DATA_FILTER_OPERATORS = new Set(['=', '!=', '<', '>', '<=', '>=', 'equals']);
|
|
34
35
|
const DATA_ROW_SIZE_STORAGE_KEY = 'data_row_size';
|
|
35
36
|
const CHARTS_HISTORY_TAB_STORAGE_KEY = 'charts_history_tab';
|
|
36
37
|
const QUERY_HISTORY_TAB_STORAGE_KEY = 'query_history_tab';
|
|
@@ -49,6 +50,11 @@ const QUERY_HISTORY_PAGE_SIZE = 30;
|
|
|
49
50
|
const QUERY_HISTORY_RUN_LIMIT = 8;
|
|
50
51
|
const CHART_HEIGHT_PRESETS = new Set(['small', 'medium', 'large']);
|
|
51
52
|
const EDITOR_RESULT_TABS = new Set(['results', 'performance', 'messages']);
|
|
53
|
+
const TEXT_EXPORT_FORMAT_LABELS = {
|
|
54
|
+
csv: 'CSV',
|
|
55
|
+
tsv: 'TSV',
|
|
56
|
+
md: 'Markdown',
|
|
57
|
+
};
|
|
52
58
|
const MISSING_DATABASE_ERROR = {
|
|
53
59
|
code: 'ACTIVE_DATABASE_REQUIRED',
|
|
54
60
|
message: 'No active SQLite database selected.',
|
|
@@ -213,6 +219,7 @@ const state = {
|
|
|
213
219
|
searchQuery: '',
|
|
214
220
|
tableSearchQuery: '',
|
|
215
221
|
searchColumn: '',
|
|
222
|
+
filterOperator: '=',
|
|
216
223
|
selectedRowIndex: null,
|
|
217
224
|
selectedRow: null,
|
|
218
225
|
pendingOpenRow: null,
|
|
@@ -545,6 +552,23 @@ function canEditQueryResult(snapshot = state) {
|
|
|
545
552
|
function resetDataBrowserSearch() {
|
|
546
553
|
state.dataBrowser.searchQuery = '';
|
|
547
554
|
state.dataBrowser.searchColumn = '';
|
|
555
|
+
state.dataBrowser.filterOperator = '=';
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function isDataBrowserTextColumn(columnName) {
|
|
559
|
+
const column = (state.dataBrowser.table?.columnMeta ?? []).find(item => item.name === columnName);
|
|
560
|
+
|
|
561
|
+
return String(column?.affinity ?? '').toUpperCase() === 'TEXT';
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function normalizeDataFilterOperatorForColumn(operator, columnName) {
|
|
565
|
+
const normalizedOperator = DATA_FILTER_OPERATORS.has(operator) ? operator : '=';
|
|
566
|
+
|
|
567
|
+
if (normalizedOperator === 'equals' && !isDataBrowserTextColumn(columnName)) {
|
|
568
|
+
return '=';
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
return normalizedOperator;
|
|
548
572
|
}
|
|
549
573
|
|
|
550
574
|
function resetDataBrowserTableSearch() {
|
|
@@ -1512,6 +1536,9 @@ async function loadDataTable(version) {
|
|
|
1512
1536
|
offset: (page - 1) * pageSize,
|
|
1513
1537
|
sortColumn,
|
|
1514
1538
|
sortDirection,
|
|
1539
|
+
filterColumn: state.dataBrowser.searchColumn,
|
|
1540
|
+
filterOperator: state.dataBrowser.filterOperator,
|
|
1541
|
+
filterValue: state.dataBrowser.searchQuery,
|
|
1515
1542
|
});
|
|
1516
1543
|
|
|
1517
1544
|
if (version !== routeLoadVersion) {
|
|
@@ -1523,9 +1550,22 @@ async function loadDataTable(version) {
|
|
|
1523
1550
|
state.dataBrowser.page = response.data?.page ?? page;
|
|
1524
1551
|
state.dataBrowser.sortColumn = response.data?.sort?.column ?? null;
|
|
1525
1552
|
state.dataBrowser.sortDirection = response.data?.sort?.direction ?? null;
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1553
|
+
const responseColumns = response.data?.columns ?? [];
|
|
1554
|
+
const responseFilter = response.data?.filter ?? null;
|
|
1555
|
+
|
|
1556
|
+
state.dataBrowser.searchColumn =
|
|
1557
|
+
responseFilter?.column ??
|
|
1558
|
+
(responseColumns.includes(state.dataBrowser.searchColumn)
|
|
1559
|
+
? state.dataBrowser.searchColumn
|
|
1560
|
+
: (responseColumns[0] ?? ''));
|
|
1561
|
+
const responseOperator = DATA_FILTER_OPERATORS.has(responseFilter?.operator)
|
|
1562
|
+
? responseFilter.operator
|
|
1563
|
+
: state.dataBrowser.filterOperator;
|
|
1564
|
+
|
|
1565
|
+
state.dataBrowser.filterOperator = normalizeDataFilterOperatorForColumn(
|
|
1566
|
+
responseOperator,
|
|
1567
|
+
state.dataBrowser.searchColumn,
|
|
1568
|
+
);
|
|
1529
1569
|
clearDataBrowserRowSelectionState();
|
|
1530
1570
|
await resolvePendingDataBrowserRow(version);
|
|
1531
1571
|
} catch (error) {
|
|
@@ -1943,14 +1983,20 @@ async function previewMediaTaggingDraft(options = {}) {
|
|
|
1943
1983
|
}
|
|
1944
1984
|
}
|
|
1945
1985
|
|
|
1946
|
-
function invalidateDatabaseCaches() {
|
|
1986
|
+
function invalidateDatabaseCaches(options = {}) {
|
|
1987
|
+
const preserveDataBrowserState = options.preserveDataBrowserState === true;
|
|
1988
|
+
|
|
1947
1989
|
state.overview.data = null;
|
|
1948
1990
|
state.dataBrowser.tables = [];
|
|
1949
|
-
|
|
1991
|
+
if (!preserveDataBrowserState) {
|
|
1992
|
+
state.dataBrowser.selectedTable = null;
|
|
1993
|
+
}
|
|
1950
1994
|
state.dataBrowser.table = null;
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1995
|
+
if (!preserveDataBrowserState) {
|
|
1996
|
+
state.dataBrowser.page = 1;
|
|
1997
|
+
resetDataBrowserTableSearch();
|
|
1998
|
+
resetDataBrowserSearch();
|
|
1999
|
+
}
|
|
1954
2000
|
clearDataBrowserRowSelectionState();
|
|
1955
2001
|
state.dataBrowser.pendingOpenRow = null;
|
|
1956
2002
|
state.dataBrowser.exportLoading = false;
|
|
@@ -2218,6 +2264,34 @@ export function openModal(kind) {
|
|
|
2218
2264
|
emitChange();
|
|
2219
2265
|
}
|
|
2220
2266
|
|
|
2267
|
+
export function openQueryExportModal() {
|
|
2268
|
+
if (!String(state.editor.sqlText ?? '').trim()) {
|
|
2269
|
+
pushToast('Enter a query before exporting.', 'alert');
|
|
2270
|
+
return;
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
state.modal = {
|
|
2274
|
+
kind: 'query-export',
|
|
2275
|
+
error: null,
|
|
2276
|
+
submitting: false,
|
|
2277
|
+
};
|
|
2278
|
+
emitChange();
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
export function openDataExportModal() {
|
|
2282
|
+
if (!state.dataBrowser.selectedTable) {
|
|
2283
|
+
pushToast('No table selected for export.', 'alert');
|
|
2284
|
+
return;
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
state.modal = {
|
|
2288
|
+
kind: 'data-export',
|
|
2289
|
+
error: null,
|
|
2290
|
+
submitting: false,
|
|
2291
|
+
};
|
|
2292
|
+
emitChange();
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2221
2295
|
export function openEditConnectionModal(id) {
|
|
2222
2296
|
const connection = state.connections.recent.find(entry => entry.id === id);
|
|
2223
2297
|
|
|
@@ -2810,7 +2884,7 @@ export async function executeCurrentQuery() {
|
|
|
2810
2884
|
state.editor.result = response.data;
|
|
2811
2885
|
resetEditorResultSort();
|
|
2812
2886
|
state.editor.error = null;
|
|
2813
|
-
invalidateDatabaseCaches();
|
|
2887
|
+
invalidateDatabaseCaches({ preserveDataBrowserState: true });
|
|
2814
2888
|
await refreshQueryHistoryState();
|
|
2815
2889
|
pushToast(response.message || `Executed ${response.data.statementCount} SQL statement(s).`, 'success');
|
|
2816
2890
|
return true;
|
|
@@ -3123,9 +3197,15 @@ export function addCurrentTableDesignerColumn() {
|
|
|
3123
3197
|
return nextColumn?.id ?? null;
|
|
3124
3198
|
}
|
|
3125
3199
|
|
|
3126
|
-
export function queueTableDesignerCsvImport(fileName, csvText) {
|
|
3200
|
+
export function queueTableDesignerCsvImport(fileName, csvText, options = {}) {
|
|
3127
3201
|
try {
|
|
3128
|
-
const imported = createTableDesignerDraftFromCsvImport(
|
|
3202
|
+
const imported = createTableDesignerDraftFromCsvImport(
|
|
3203
|
+
{ fileName, csvText },
|
|
3204
|
+
{
|
|
3205
|
+
...getTableDesignerContext(),
|
|
3206
|
+
...(options.context ?? {}),
|
|
3207
|
+
},
|
|
3208
|
+
);
|
|
3129
3209
|
|
|
3130
3210
|
state.tableDesigner.pendingImportedDraft = imported.draft;
|
|
3131
3211
|
state.tableDesigner.selectedTableName = null;
|
|
@@ -3134,6 +3214,10 @@ export function queueTableDesignerCsvImport(fileName, csvText) {
|
|
|
3134
3214
|
emitChange();
|
|
3135
3215
|
return imported;
|
|
3136
3216
|
} catch (error) {
|
|
3217
|
+
if (options.throwOnError) {
|
|
3218
|
+
throw error;
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3137
3221
|
pushToast(error?.message || 'CSV import failed.', 'alert');
|
|
3138
3222
|
return null;
|
|
3139
3223
|
}
|
|
@@ -3627,18 +3711,59 @@ export function clearDataRowSelection(options = {}) {
|
|
|
3627
3711
|
}
|
|
3628
3712
|
}
|
|
3629
3713
|
|
|
3630
|
-
|
|
3631
|
-
state.
|
|
3714
|
+
async function reloadDataTableForFilterChange() {
|
|
3715
|
+
if (state.route.name === 'data' && state.dataBrowser.selectedTable) {
|
|
3716
|
+
await loadDataTable(++routeLoadVersion);
|
|
3717
|
+
}
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3720
|
+
export async function setDataSearchQuery(query) {
|
|
3721
|
+
const nextQuery = String(query ?? '');
|
|
3722
|
+
|
|
3723
|
+
if (state.dataBrowser.searchQuery === nextQuery) {
|
|
3724
|
+
return;
|
|
3725
|
+
}
|
|
3726
|
+
|
|
3727
|
+
state.dataBrowser.searchQuery = nextQuery;
|
|
3728
|
+
state.dataBrowser.page = 1;
|
|
3729
|
+
clearDataBrowserRowSelectionState();
|
|
3730
|
+
state.dataBrowser.saveError = null;
|
|
3731
|
+
emitChange();
|
|
3732
|
+
await reloadDataTableForFilterChange();
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
export async function setDataSearchColumn(columnName) {
|
|
3736
|
+
const nextColumnName = String(columnName ?? '');
|
|
3737
|
+
|
|
3738
|
+
if (state.dataBrowser.searchColumn === nextColumnName) {
|
|
3739
|
+
return;
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3742
|
+
state.dataBrowser.searchColumn = nextColumnName;
|
|
3743
|
+
state.dataBrowser.filterOperator = normalizeDataFilterOperatorForColumn(
|
|
3744
|
+
state.dataBrowser.filterOperator,
|
|
3745
|
+
nextColumnName,
|
|
3746
|
+
);
|
|
3747
|
+
state.dataBrowser.page = 1;
|
|
3632
3748
|
clearDataBrowserRowSelectionState();
|
|
3633
3749
|
state.dataBrowser.saveError = null;
|
|
3634
3750
|
emitChange();
|
|
3751
|
+
await reloadDataTableForFilterChange();
|
|
3635
3752
|
}
|
|
3636
3753
|
|
|
3637
|
-
export function
|
|
3638
|
-
|
|
3754
|
+
export async function setDataFilterOperator(operator) {
|
|
3755
|
+
const nextOperator = String(operator ?? '=').trim();
|
|
3756
|
+
|
|
3757
|
+
if (!DATA_FILTER_OPERATORS.has(nextOperator) || state.dataBrowser.filterOperator === nextOperator) {
|
|
3758
|
+
return;
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3761
|
+
state.dataBrowser.filterOperator = nextOperator;
|
|
3762
|
+
state.dataBrowser.page = 1;
|
|
3639
3763
|
clearDataBrowserRowSelectionState();
|
|
3640
3764
|
state.dataBrowser.saveError = null;
|
|
3641
3765
|
emitChange();
|
|
3766
|
+
await reloadDataTableForFilterChange();
|
|
3642
3767
|
}
|
|
3643
3768
|
|
|
3644
3769
|
export function toggleDataTablesPanel() {
|
|
@@ -4056,25 +4181,127 @@ export async function submitDeleteQueryHistoryConfirmation() {
|
|
|
4056
4181
|
return deleted;
|
|
4057
4182
|
}
|
|
4058
4183
|
|
|
4059
|
-
|
|
4184
|
+
function beginCurrentQueryExport() {
|
|
4060
4185
|
state.editor.exportLoading = true;
|
|
4186
|
+
if (state.modal?.kind === 'query-export') {
|
|
4187
|
+
state.modal.submitting = true;
|
|
4188
|
+
state.modal.error = null;
|
|
4189
|
+
}
|
|
4061
4190
|
emitChange();
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
function reportCurrentQueryExportError(error) {
|
|
4194
|
+
if (state.modal?.kind === 'query-export') {
|
|
4195
|
+
withModalError(error);
|
|
4196
|
+
return;
|
|
4197
|
+
}
|
|
4198
|
+
|
|
4199
|
+
state.editor.error = normalizeError(error);
|
|
4200
|
+
emitChange();
|
|
4201
|
+
}
|
|
4202
|
+
|
|
4203
|
+
function finishCurrentQueryExport() {
|
|
4204
|
+
state.editor.exportLoading = false;
|
|
4205
|
+
if (state.modal?.kind === 'query-export') {
|
|
4206
|
+
state.modal.submitting = false;
|
|
4207
|
+
}
|
|
4208
|
+
emitChange();
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
export async function exportCurrentQueryFormat(format = 'csv') {
|
|
4212
|
+
const normalizedFormat = String(format ?? 'csv').toLowerCase();
|
|
4213
|
+
const label = TEXT_EXPORT_FORMAT_LABELS[normalizedFormat] ?? TEXT_EXPORT_FORMAT_LABELS.csv;
|
|
4214
|
+
|
|
4215
|
+
beginCurrentQueryExport();
|
|
4062
4216
|
|
|
4063
4217
|
try {
|
|
4064
|
-
await api.
|
|
4065
|
-
|
|
4218
|
+
await api.downloadQueryExport(state.editor.sqlText, normalizedFormat);
|
|
4219
|
+
closeModalInternal();
|
|
4220
|
+
pushToast(`${label} export started.`, 'success');
|
|
4066
4221
|
return true;
|
|
4067
4222
|
} catch (error) {
|
|
4068
|
-
|
|
4069
|
-
emitChange();
|
|
4223
|
+
reportCurrentQueryExportError(error);
|
|
4070
4224
|
return false;
|
|
4071
4225
|
} finally {
|
|
4072
|
-
|
|
4226
|
+
finishCurrentQueryExport();
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4229
|
+
|
|
4230
|
+
export async function duplicateCurrentQueryAsTable() {
|
|
4231
|
+
beginCurrentQueryExport();
|
|
4232
|
+
|
|
4233
|
+
try {
|
|
4234
|
+
const response = await api.getQueryExport(state.editor.sqlText, 'csv');
|
|
4235
|
+
const exportData = response?.data ?? {};
|
|
4236
|
+
const imported = queueTableDesignerCsvImport(
|
|
4237
|
+
exportData.filename || 'query-results.csv',
|
|
4238
|
+
exportData.content || '',
|
|
4239
|
+
{ throwOnError: true },
|
|
4240
|
+
);
|
|
4241
|
+
|
|
4242
|
+
closeModalInternal();
|
|
4243
|
+
pushToast(
|
|
4244
|
+
`Table draft created from ${imported.importedRowCount} row${imported.importedRowCount === 1 ? '' : 's'}.`,
|
|
4245
|
+
'success',
|
|
4246
|
+
);
|
|
4247
|
+
return imported;
|
|
4248
|
+
} catch (error) {
|
|
4249
|
+
reportCurrentQueryExportError(error);
|
|
4250
|
+
return null;
|
|
4251
|
+
} finally {
|
|
4252
|
+
finishCurrentQueryExport();
|
|
4253
|
+
}
|
|
4254
|
+
}
|
|
4255
|
+
|
|
4256
|
+
export async function exportCurrentQueryCsv() {
|
|
4257
|
+
try {
|
|
4258
|
+
return await exportCurrentQueryFormat('csv');
|
|
4259
|
+
} catch (error) {
|
|
4260
|
+
state.editor.error = normalizeError(error);
|
|
4073
4261
|
emitChange();
|
|
4262
|
+
return false;
|
|
4074
4263
|
}
|
|
4075
4264
|
}
|
|
4076
4265
|
|
|
4077
|
-
|
|
4266
|
+
function getCurrentDataTableExportOptions(format = 'csv') {
|
|
4267
|
+
return {
|
|
4268
|
+
sortColumn: state.dataBrowser.sortColumn,
|
|
4269
|
+
sortDirection: state.dataBrowser.sortDirection,
|
|
4270
|
+
filterColumn: state.dataBrowser.searchColumn,
|
|
4271
|
+
filterOperator: state.dataBrowser.filterOperator,
|
|
4272
|
+
filterValue: state.dataBrowser.searchQuery,
|
|
4273
|
+
format,
|
|
4274
|
+
};
|
|
4275
|
+
}
|
|
4276
|
+
|
|
4277
|
+
function beginCurrentDataTableExport() {
|
|
4278
|
+
state.dataBrowser.exportLoading = true;
|
|
4279
|
+
if (state.modal?.kind === 'data-export') {
|
|
4280
|
+
state.modal.submitting = true;
|
|
4281
|
+
state.modal.error = null;
|
|
4282
|
+
}
|
|
4283
|
+
emitChange();
|
|
4284
|
+
}
|
|
4285
|
+
|
|
4286
|
+
function reportCurrentDataTableExportError(error) {
|
|
4287
|
+
if (state.modal?.kind === 'data-export') {
|
|
4288
|
+
withModalError(error);
|
|
4289
|
+
return;
|
|
4290
|
+
}
|
|
4291
|
+
|
|
4292
|
+
state.dataBrowser.error = normalizeError(error);
|
|
4293
|
+
emitChange();
|
|
4294
|
+
}
|
|
4295
|
+
|
|
4296
|
+
function finishCurrentDataTableExport() {
|
|
4297
|
+
state.dataBrowser.exportLoading = false;
|
|
4298
|
+
if (state.modal?.kind === 'data-export') {
|
|
4299
|
+
state.modal.submitting = false;
|
|
4300
|
+
}
|
|
4301
|
+
emitChange();
|
|
4302
|
+
}
|
|
4303
|
+
|
|
4304
|
+
export async function exportCurrentDataTableFormat(format = 'csv') {
|
|
4078
4305
|
const tableName = state.dataBrowser.selectedTable;
|
|
4079
4306
|
|
|
4080
4307
|
if (!tableName) {
|
|
@@ -4082,26 +4309,68 @@ export async function exportCurrentDataTableCsv() {
|
|
|
4082
4309
|
return false;
|
|
4083
4310
|
}
|
|
4084
4311
|
|
|
4085
|
-
|
|
4086
|
-
|
|
4312
|
+
const normalizedFormat = String(format ?? 'csv').toLowerCase();
|
|
4313
|
+
const label = TEXT_EXPORT_FORMAT_LABELS[normalizedFormat] ?? TEXT_EXPORT_FORMAT_LABELS.csv;
|
|
4314
|
+
|
|
4315
|
+
beginCurrentDataTableExport();
|
|
4087
4316
|
|
|
4088
4317
|
try {
|
|
4089
|
-
await api.
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
});
|
|
4093
|
-
pushToast(`CSV export started for ${tableName}.`, 'success');
|
|
4318
|
+
await api.downloadTableExport(tableName, getCurrentDataTableExportOptions(normalizedFormat));
|
|
4319
|
+
closeModalInternal();
|
|
4320
|
+
pushToast(`${label} export started for ${tableName}.`, 'success');
|
|
4094
4321
|
return true;
|
|
4095
4322
|
} catch (error) {
|
|
4096
|
-
|
|
4097
|
-
emitChange();
|
|
4323
|
+
reportCurrentDataTableExportError(error);
|
|
4098
4324
|
return false;
|
|
4099
4325
|
} finally {
|
|
4100
|
-
|
|
4101
|
-
emitChange();
|
|
4326
|
+
finishCurrentDataTableExport();
|
|
4102
4327
|
}
|
|
4103
4328
|
}
|
|
4104
4329
|
|
|
4330
|
+
export async function duplicateCurrentDataTableAsTable() {
|
|
4331
|
+
const tableName = state.dataBrowser.selectedTable;
|
|
4332
|
+
|
|
4333
|
+
if (!tableName) {
|
|
4334
|
+
pushToast('No table selected for export.', 'alert');
|
|
4335
|
+
return null;
|
|
4336
|
+
}
|
|
4337
|
+
|
|
4338
|
+
beginCurrentDataTableExport();
|
|
4339
|
+
|
|
4340
|
+
try {
|
|
4341
|
+
const response = await api.getTableExport(tableName, getCurrentDataTableExportOptions('csv'));
|
|
4342
|
+
const exportData = response?.data ?? {};
|
|
4343
|
+
const imported = queueTableDesignerCsvImport(
|
|
4344
|
+
exportData.filename || `${tableName}.csv`,
|
|
4345
|
+
exportData.content || '',
|
|
4346
|
+
{
|
|
4347
|
+
throwOnError: true,
|
|
4348
|
+
context: {
|
|
4349
|
+
catalogTables: state.tableDesigner.tables?.length
|
|
4350
|
+
? state.tableDesigner.tables
|
|
4351
|
+
: state.dataBrowser.tables,
|
|
4352
|
+
},
|
|
4353
|
+
},
|
|
4354
|
+
);
|
|
4355
|
+
|
|
4356
|
+
closeModalInternal();
|
|
4357
|
+
pushToast(
|
|
4358
|
+
`Table draft created from ${imported.importedRowCount} row${imported.importedRowCount === 1 ? '' : 's'}.`,
|
|
4359
|
+
'success',
|
|
4360
|
+
);
|
|
4361
|
+
return imported;
|
|
4362
|
+
} catch (error) {
|
|
4363
|
+
reportCurrentDataTableExportError(error);
|
|
4364
|
+
return null;
|
|
4365
|
+
} finally {
|
|
4366
|
+
finishCurrentDataTableExport();
|
|
4367
|
+
}
|
|
4368
|
+
}
|
|
4369
|
+
|
|
4370
|
+
export async function exportCurrentDataTableCsv() {
|
|
4371
|
+
return exportCurrentDataTableFormat('csv');
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4105
4374
|
export function sortEditorResultsByColumn(columnName) {
|
|
4106
4375
|
const normalizedColumn = String(columnName ?? '').trim();
|
|
4107
4376
|
const result = state.editor.result;
|