sqlite-hub 0.7.0 → 0.9.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/changelog.md +25 -0
- package/docs/DESIGN_GUIDELINES.md +36 -0
- package/frontend/index.html +79 -0
- package/frontend/js/api.js +67 -0
- package/frontend/js/app.js +1401 -921
- package/frontend/js/components/connectionCard.js +3 -4
- package/frontend/js/components/emptyState.js +4 -4
- package/frontend/js/components/modal.js +239 -30
- package/frontend/js/components/queryEditor.js +11 -8
- package/frontend/js/components/queryHistoryDetail.js +27 -8
- package/frontend/js/components/queryHistoryPanel.js +6 -5
- package/frontend/js/components/rowEditorPanel.js +84 -58
- package/frontend/js/components/sidebar.js +76 -33
- package/frontend/js/components/structureGraph.js +629 -715
- package/frontend/js/components/tableDesignerEditor.js +9 -8
- package/frontend/js/components/tableDesignerSidebar.js +11 -10
- package/frontend/js/components/tableDesignerSqlPreview.js +61 -30
- package/frontend/js/lib/mediaTaggingDefaults.js +27 -0
- package/frontend/js/router.js +81 -71
- package/frontend/js/store.js +3095 -2165
- package/frontend/js/views/charts.js +68 -40
- package/frontend/js/views/connections.js +5 -17
- package/frontend/js/views/data.js +40 -27
- package/frontend/js/views/editor.js +172 -177
- package/frontend/js/views/mediaTagging.js +861 -0
- package/frontend/js/views/overview.js +149 -10
- package/frontend/js/views/settings.js +2 -2
- package/frontend/js/views/structure.js +74 -70
- package/frontend/js/views/tableDesigner.js +7 -2
- package/frontend/styles/base.css +73 -1
- package/frontend/styles/components.css +105 -105
- package/frontend/styles/structure-graph.css +19 -82
- package/frontend/styles/tokens.css +2 -0
- package/frontend/styles/views.css +823 -30
- package/package.json +1 -1
- package/server/routes/charts.js +4 -1
- package/server/routes/data.js +14 -0
- package/server/routes/mediaTagging.js +166 -0
- package/server/routes/sql.js +1 -0
- package/server/server.js +4 -0
- package/server/services/sqlite/dataBrowserService.js +25 -0
- package/server/services/sqlite/exportService.js +31 -1
- package/server/services/sqlite/mediaTaggingService.js +1689 -0
- package/server/services/sqlite/overviewService.js +68 -0
- package/server/services/storage/appStateStore.js +321 -2
|
@@ -50,10 +50,10 @@ function renderChartsList(state) {
|
|
|
50
50
|
<div>
|
|
51
51
|
<span class="material-symbols-outlined mb-3 text-4xl text-on-surface-variant/25">query_stats</span>
|
|
52
52
|
<p class="font-headline text-lg font-black uppercase tracking-tight text-on-surface">
|
|
53
|
-
No
|
|
53
|
+
No Chartable Queries
|
|
54
54
|
</p>
|
|
55
55
|
<p class="mt-2 max-w-xs text-sm leading-6 text-on-surface-variant/60">
|
|
56
|
-
Run
|
|
56
|
+
Run SELECT queries in the SQL Editor first. They will appear here automatically.
|
|
57
57
|
</p>
|
|
58
58
|
</div>
|
|
59
59
|
</div>
|
|
@@ -157,7 +157,7 @@ function renderQuerySqlSection(state, rawSql) {
|
|
|
157
157
|
return `
|
|
158
158
|
<section class="mt-5 border border-outline-variant/10 bg-surface-container-lowest">
|
|
159
159
|
<button
|
|
160
|
-
class="flex w-full
|
|
160
|
+
class="standard-button flex w-full justify-between border-b border-outline-variant/10 px-4 text-left"
|
|
161
161
|
data-action="toggle-charts-sql-panel"
|
|
162
162
|
type="button"
|
|
163
163
|
>
|
|
@@ -192,10 +192,13 @@ function renderQueryResultsSection(state) {
|
|
|
192
192
|
Results
|
|
193
193
|
</span>
|
|
194
194
|
<button
|
|
195
|
-
class="
|
|
195
|
+
class="standard-button"
|
|
196
196
|
data-action="toggle-charts-results-panel"
|
|
197
197
|
type="button"
|
|
198
198
|
>
|
|
199
|
+
<span class="material-symbols-outlined text-sm">
|
|
200
|
+
${isVisible ? 'table_rows_narrow' : 'table_rows'}
|
|
201
|
+
</span>
|
|
199
202
|
${isVisible ? 'Hide Results' : 'Show Results'}
|
|
200
203
|
</button>
|
|
201
204
|
</div>
|
|
@@ -244,7 +247,7 @@ function renderChartHeightPresetToggle(state) {
|
|
|
244
247
|
.map(
|
|
245
248
|
preset => `
|
|
246
249
|
<button
|
|
247
|
-
class="
|
|
250
|
+
class="standard-button charts-height-toggle__button ${activePreset === preset.value ? 'is-active' : ''}"
|
|
248
251
|
data-action="set-charts-height-preset"
|
|
249
252
|
data-preset="${preset.value}"
|
|
250
253
|
type="button"
|
|
@@ -312,7 +315,7 @@ function renderChartCard(chart, state, analysis) {
|
|
|
312
315
|
</div>
|
|
313
316
|
<div class="flex flex-wrap items-center gap-2">
|
|
314
317
|
<button
|
|
315
|
-
class="
|
|
318
|
+
class="standard-button"
|
|
316
319
|
data-action="open-edit-query-chart-modal"
|
|
317
320
|
data-chart-id="${escapeHtml(chart.id)}"
|
|
318
321
|
type="button"
|
|
@@ -320,7 +323,7 @@ function renderChartCard(chart, state, analysis) {
|
|
|
320
323
|
Edit
|
|
321
324
|
</button>
|
|
322
325
|
<button
|
|
323
|
-
class="
|
|
326
|
+
class="delete-button"
|
|
324
327
|
data-action="open-delete-query-chart-modal"
|
|
325
328
|
data-chart-id="${escapeHtml(chart.id)}"
|
|
326
329
|
type="button"
|
|
@@ -328,7 +331,7 @@ function renderChartCard(chart, state, analysis) {
|
|
|
328
331
|
Delete
|
|
329
332
|
</button>
|
|
330
333
|
<button
|
|
331
|
-
class="
|
|
334
|
+
class="standard-button"
|
|
332
335
|
data-action="export-query-chart-png"
|
|
333
336
|
data-chart-id="${escapeHtml(chart.id)}"
|
|
334
337
|
type="button"
|
|
@@ -347,6 +350,7 @@ function renderChartCard(chart, state, analysis) {
|
|
|
347
350
|
function renderChartsDetail(state) {
|
|
348
351
|
const detail = state.charts.detail;
|
|
349
352
|
const selectedHistoryId = state.charts.selectedHistoryId;
|
|
353
|
+
const historyVisible = state.editor.historyPanelVisible !== false;
|
|
350
354
|
|
|
351
355
|
if (!selectedHistoryId) {
|
|
352
356
|
return renderEmptyChartDetail();
|
|
@@ -384,32 +388,48 @@ function renderChartsDetail(state) {
|
|
|
384
388
|
<div class="custom-scrollbar flex-1 overflow-auto">
|
|
385
389
|
<div class="charts-detail-shell">
|
|
386
390
|
<header class="charts-detail-shell__header">
|
|
387
|
-
<div class="
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
+
<div class="text-[10px] font-mono uppercase tracking-[0.18em] text-primary-container/70">
|
|
392
|
+
Charts
|
|
393
|
+
</div>
|
|
394
|
+
<div class="charts-detail-shell__title">
|
|
391
395
|
<h1 class="mt-2 truncate font-headline text-4xl font-black uppercase tracking-tight text-primary-container">
|
|
392
396
|
${escapeHtml(detail.item.displayTitle)}
|
|
393
397
|
</h1>
|
|
394
398
|
</div>
|
|
395
399
|
<div class="charts-detail-shell__controls">
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
>
|
|
411
|
-
|
|
412
|
-
|
|
400
|
+
<div class="charts-detail-shell__controls-group">
|
|
401
|
+
${renderChartHeightPresetToggle(state)}
|
|
402
|
+
<button
|
|
403
|
+
class="standard-button"
|
|
404
|
+
data-action="toggle-query-history-panel"
|
|
405
|
+
data-next-value="${historyVisible ? 'false' : 'true'}"
|
|
406
|
+
type="button"
|
|
407
|
+
>
|
|
408
|
+
<span class="material-symbols-outlined text-sm">${
|
|
409
|
+
historyVisible ? 'visibility_off' : 'history'
|
|
410
|
+
}</span>
|
|
411
|
+
${historyVisible ? 'Hide Query History' : 'Show Query History'}
|
|
412
|
+
</button>
|
|
413
|
+
</div>
|
|
414
|
+
<div class="charts-detail-shell__controls-group charts-detail-shell__controls-group--end">
|
|
415
|
+
<button
|
|
416
|
+
class="standard-button"
|
|
417
|
+
data-action="open-query-history"
|
|
418
|
+
data-history-id="${escapeHtml(detail.item.id)}"
|
|
419
|
+
type="button"
|
|
420
|
+
>
|
|
421
|
+
<span class="material-symbols-outlined text-sm">terminal</span>
|
|
422
|
+
Open In Editor
|
|
423
|
+
</button>
|
|
424
|
+
<button
|
|
425
|
+
class="signature-button"
|
|
426
|
+
data-action="open-create-query-chart-modal"
|
|
427
|
+
type="button"
|
|
428
|
+
${state.charts.resultError || !state.charts.result ? 'disabled' : ''}
|
|
429
|
+
>
|
|
430
|
+
New Chart
|
|
431
|
+
</button>
|
|
432
|
+
</div>
|
|
413
433
|
</div>
|
|
414
434
|
</header>
|
|
415
435
|
|
|
@@ -442,6 +462,8 @@ function renderChartsDetail(state) {
|
|
|
442
462
|
}
|
|
443
463
|
|
|
444
464
|
export function renderChartsView(state) {
|
|
465
|
+
const historyVisible = state.editor.historyPanelVisible !== false || !state.charts.selectedHistoryId;
|
|
466
|
+
|
|
445
467
|
if (!state.connections.active && state.charts.error?.code === 'ACTIVE_DATABASE_REQUIRED') {
|
|
446
468
|
return {
|
|
447
469
|
main: `<section class="view-surface flex min-h-full">${renderMissingDatabase()}</section>`,
|
|
@@ -452,17 +474,23 @@ export function renderChartsView(state) {
|
|
|
452
474
|
return {
|
|
453
475
|
main: `
|
|
454
476
|
<section class="charts-view">
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
477
|
+
${
|
|
478
|
+
historyVisible
|
|
479
|
+
? `
|
|
480
|
+
<aside class="charts-view__sidebar">
|
|
481
|
+
<div class="charts-view__sidebar-header">
|
|
482
|
+
<div class="text-[10px] font-bold uppercase tracking-[0.2em] text-primary-container">
|
|
483
|
+
Query History
|
|
484
|
+
</div>
|
|
485
|
+
<h2 class="mt-2 text-[10px] font-mono uppercase tracking-[0.16em] text-on-surface-variant/55">
|
|
486
|
+
Charts
|
|
487
|
+
</h2>
|
|
488
|
+
</div>
|
|
489
|
+
${renderChartsList(state)}
|
|
490
|
+
</aside>
|
|
491
|
+
`
|
|
492
|
+
: ''
|
|
493
|
+
}
|
|
466
494
|
<div class="charts-view__detail">${renderChartsDetail(state)}</div>
|
|
467
495
|
</section>
|
|
468
496
|
`,
|
|
@@ -8,32 +8,25 @@ function renderConnectionsActionButton({
|
|
|
8
8
|
action = "open-modal",
|
|
9
9
|
modal,
|
|
10
10
|
tone = "secondary",
|
|
11
|
-
className = "",
|
|
12
11
|
disabled = false,
|
|
13
12
|
}) {
|
|
14
|
-
const clipPath = "polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 0 100%)";
|
|
15
13
|
const toneClassName =
|
|
16
14
|
tone === "primary"
|
|
17
|
-
? "
|
|
18
|
-
: "
|
|
19
|
-
const iconClassName =
|
|
20
|
-
tone === "primary"
|
|
21
|
-
? "text-base text-on-primary"
|
|
22
|
-
: "text-base text-primary-container/90";
|
|
23
|
-
const clipStyle = `style="--clip-path: ${clipPath};"`;
|
|
15
|
+
? "signature-button"
|
|
16
|
+
: "standard-button";
|
|
17
|
+
const iconClassName = "";
|
|
24
18
|
const modalAttribute = modal ? `data-modal="${modal}"` : "";
|
|
25
19
|
|
|
26
20
|
return `
|
|
27
21
|
<button
|
|
28
|
-
class="
|
|
22
|
+
class="${toneClassName}"
|
|
29
23
|
data-action="${escapeHtml(action)}"
|
|
30
24
|
${modalAttribute}
|
|
31
|
-
${clipStyle}
|
|
32
25
|
type="button"
|
|
33
26
|
${disabled ? "disabled" : ""}
|
|
34
27
|
>
|
|
35
28
|
<span>${label}</span>
|
|
36
|
-
<span class="material-symbols-outlined ${iconClassName}">${icon}</span>
|
|
29
|
+
<span class="material-symbols-outlined${iconClassName ? ` ${iconClassName}` : ""}">${icon}</span>
|
|
37
30
|
</button>
|
|
38
31
|
`;
|
|
39
32
|
}
|
|
@@ -77,13 +70,11 @@ function renderConnectionsBody(state) {
|
|
|
77
70
|
icon: "folder_open",
|
|
78
71
|
modal: "open-connection",
|
|
79
72
|
tone: "primary",
|
|
80
|
-
className: "min-w-[17rem] px-8 py-6 text-sm",
|
|
81
73
|
})}
|
|
82
74
|
${renderConnectionsActionButton({
|
|
83
75
|
label: "Create Database",
|
|
84
76
|
icon: "note_add",
|
|
85
77
|
modal: "create-connection",
|
|
86
|
-
className: "min-w-[17rem] px-8 py-6 text-sm",
|
|
87
78
|
})}
|
|
88
79
|
</div>
|
|
89
80
|
</div>
|
|
@@ -108,13 +99,11 @@ export function renderConnectionsView(state) {
|
|
|
108
99
|
icon: "folder_open",
|
|
109
100
|
modal: "open-connection",
|
|
110
101
|
tone: "primary",
|
|
111
|
-
className: "min-w-[13rem]",
|
|
112
102
|
})}
|
|
113
103
|
${renderConnectionsActionButton({
|
|
114
104
|
label: "Create Database",
|
|
115
105
|
icon: "note_add",
|
|
116
106
|
modal: "create-connection",
|
|
117
|
-
className: "min-w-[13rem]",
|
|
118
107
|
})}
|
|
119
108
|
${
|
|
120
109
|
state.connections.active
|
|
@@ -122,7 +111,6 @@ export function renderConnectionsView(state) {
|
|
|
122
111
|
label: state.connections.backupLoading ? "Creating Backup..." : "Create Backup",
|
|
123
112
|
icon: "inventory_2",
|
|
124
113
|
action: "create-backup",
|
|
125
|
-
className: "min-w-[13rem]",
|
|
126
114
|
disabled: state.connections.backupLoading,
|
|
127
115
|
})
|
|
128
116
|
: ""
|
|
@@ -3,6 +3,10 @@ import { renderRowEditorPanel } from '../components/rowEditorPanel.js';
|
|
|
3
3
|
import { escapeHtml, formatCellValue, formatNumber, isBlobPreview, truncateMiddle } from '../utils/format.js';
|
|
4
4
|
|
|
5
5
|
function getSelectedRow(state) {
|
|
6
|
+
if (state.dataBrowser.selectedRow) {
|
|
7
|
+
return state.dataBrowser.selectedRow;
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
const rowIndex = state.dataBrowser.selectedRowIndex;
|
|
7
11
|
|
|
8
12
|
if (typeof rowIndex !== 'number') {
|
|
@@ -93,14 +97,14 @@ function renderWorkspaceHeader(state) {
|
|
|
93
97
|
${
|
|
94
98
|
table
|
|
95
99
|
? `<button
|
|
96
|
-
class="
|
|
100
|
+
class="standard-button"
|
|
97
101
|
data-action="toggle-data-tables"
|
|
98
102
|
type="button"
|
|
99
103
|
>
|
|
100
104
|
${tablesVisible ? '<span class="material-symbols-outlined text-sm">visibility_off</span> Hide Tables' : 'Show Tables'}
|
|
101
105
|
</button>
|
|
102
106
|
<button
|
|
103
|
-
class="
|
|
107
|
+
class="standard-button"
|
|
104
108
|
data-action="export-data-csv"
|
|
105
109
|
type="button"
|
|
106
110
|
>
|
|
@@ -109,7 +113,7 @@ function renderWorkspaceHeader(state) {
|
|
|
109
113
|
: ''
|
|
110
114
|
}
|
|
111
115
|
<button
|
|
112
|
-
class="
|
|
116
|
+
class="standard-button"
|
|
113
117
|
data-action="refresh-view"
|
|
114
118
|
type="button"
|
|
115
119
|
>
|
|
@@ -119,11 +123,12 @@ function renderWorkspaceHeader(state) {
|
|
|
119
123
|
table
|
|
120
124
|
? `
|
|
121
125
|
<button
|
|
122
|
-
class="
|
|
126
|
+
class="standard-button"
|
|
123
127
|
data-action="navigate"
|
|
124
|
-
data-to="/structure"
|
|
128
|
+
data-to="/structure/${encodeURIComponent(table.name)}"
|
|
125
129
|
type="button"
|
|
126
130
|
>
|
|
131
|
+
<span class="material-symbols-outlined">account_tree</span>
|
|
127
132
|
Open Structure
|
|
128
133
|
</button>
|
|
129
134
|
`
|
|
@@ -239,10 +244,10 @@ function renderTableSearchBar(table, state, activeColumn, filteredRowCount) {
|
|
|
239
244
|
|
|
240
245
|
return `
|
|
241
246
|
<div class="flex flex-wrap items-center gap-3 border-b border-outline-variant/10 bg-surface-container-low px-6 py-4">
|
|
242
|
-
<label class="flex min-w-[18rem] flex-1 items-center gap-3 border border-outline-variant/20 bg-surface-container-lowest px-
|
|
247
|
+
<label class="control-shell flex min-w-[18rem] flex-1 items-center gap-3 border border-outline-variant/20 bg-surface-container-lowest px-3">
|
|
243
248
|
<span class="material-symbols-outlined text-base text-on-surface-variant/55">search</span>
|
|
244
249
|
<input
|
|
245
|
-
class="min-w-0 flex-1
|
|
250
|
+
class="control-input control-input--ghost min-w-0 flex-1 text-sm text-on-surface outline-none placeholder:text-on-surface-variant/40"
|
|
246
251
|
data-bind="data-search-query"
|
|
247
252
|
placeholder="Filter current page..."
|
|
248
253
|
type="search"
|
|
@@ -250,7 +255,7 @@ function renderTableSearchBar(table, state, activeColumn, filteredRowCount) {
|
|
|
250
255
|
/>
|
|
251
256
|
</label>
|
|
252
257
|
<select
|
|
253
|
-
class="min-w-[14rem] border border-outline-variant/20 bg-surface-container-lowest
|
|
258
|
+
class="control-select min-w-[14rem] border border-outline-variant/20 bg-surface-container-lowest font-mono text-xs tracking-[0.04em] text-on-surface outline-none"
|
|
254
259
|
data-bind="data-search-column"
|
|
255
260
|
>
|
|
256
261
|
${columns
|
|
@@ -340,13 +345,9 @@ function renderTableSurface(state) {
|
|
|
340
345
|
getRowClass: (_, filteredIndex) => {
|
|
341
346
|
const rowIndex = filteredRows[filteredIndex]?.index ?? filteredIndex;
|
|
342
347
|
|
|
343
|
-
return
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
: filteredIndex % 2 === 0
|
|
347
|
-
? 'bg-surface-container-low'
|
|
348
|
-
: 'bg-surface-container-lowest'
|
|
349
|
-
} cursor-pointer transition-colors hover:bg-surface-container-high`;
|
|
348
|
+
return `data-browser-row ${
|
|
349
|
+
filteredIndex % 2 === 0 ? 'data-browser-row--even' : 'data-browser-row--odd'
|
|
350
|
+
} ${state.dataBrowser.selectedRowIndex === rowIndex ? 'is-selected' : ''} cursor-pointer transition-colors`;
|
|
350
351
|
},
|
|
351
352
|
getRowAttrs: (_, filteredIndex) => {
|
|
352
353
|
const rowIndex = filteredRows[filteredIndex]?.index ?? filteredIndex;
|
|
@@ -390,10 +391,8 @@ function renderTableSurface(state) {
|
|
|
390
391
|
.map(
|
|
391
392
|
pageSize => `
|
|
392
393
|
<button
|
|
393
|
-
class="
|
|
394
|
-
pageSize === (table.limit ?? state.dataBrowser.pageSize)
|
|
395
|
-
? 'border-primary-container/30 bg-surface-container-high text-primary-container'
|
|
396
|
-
: 'border-outline-variant/20 text-on-surface hover:bg-surface-container-highest'
|
|
394
|
+
class="standard-button ${
|
|
395
|
+
pageSize === (table.limit ?? state.dataBrowser.pageSize) ? 'is-active' : ''
|
|
397
396
|
}"
|
|
398
397
|
data-action="set-data-page-size"
|
|
399
398
|
data-page-size="${pageSize}"
|
|
@@ -408,7 +407,7 @@ function renderTableSurface(state) {
|
|
|
408
407
|
</div>
|
|
409
408
|
<div class="flex items-center gap-2">
|
|
410
409
|
<button
|
|
411
|
-
class="
|
|
410
|
+
class="standard-button"
|
|
412
411
|
data-action="set-data-page"
|
|
413
412
|
data-page="${page - 1}"
|
|
414
413
|
type="button"
|
|
@@ -420,7 +419,7 @@ function renderTableSurface(state) {
|
|
|
420
419
|
page ${escapeHtml(formatNumber(page))} / ${escapeHtml(formatNumber(pageCount))}
|
|
421
420
|
</div>
|
|
422
421
|
<button
|
|
423
|
-
class="
|
|
422
|
+
class="standard-button"
|
|
424
423
|
data-action="set-data-page"
|
|
425
424
|
data-page="${page + 1}"
|
|
426
425
|
type="button"
|
|
@@ -435,15 +434,23 @@ function renderTableSurface(state) {
|
|
|
435
434
|
`;
|
|
436
435
|
}
|
|
437
436
|
|
|
438
|
-
function renderDataRowEditorPanel(state) {
|
|
437
|
+
export function renderDataRowEditorPanel(state) {
|
|
439
438
|
const table = state.dataBrowser.table;
|
|
440
439
|
const rowIndex = state.dataBrowser.selectedRowIndex;
|
|
441
440
|
const row = getSelectedRow(state);
|
|
441
|
+
const isIndexedRow = typeof rowIndex === 'number';
|
|
442
442
|
|
|
443
|
-
if (!table || !row
|
|
443
|
+
if (!table || !row) {
|
|
444
444
|
return '';
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
+
const foreignKeyColumnNames = new Set(
|
|
448
|
+
(table.foreignKeys ?? []).flatMap(foreignKey =>
|
|
449
|
+
(foreignKey.mappings ?? []).map(mapping => String(mapping.from ?? '').trim()).filter(Boolean),
|
|
450
|
+
),
|
|
451
|
+
);
|
|
452
|
+
const getColumnBadges = column => (foreignKeyColumnNames.has(column.name) ? ['FK'] : []);
|
|
453
|
+
|
|
447
454
|
const identityColumns = table.identityStrategy?.type === 'primaryKey' ? (table.identityStrategy.columns ?? []) : [];
|
|
448
455
|
const editableColumns = (table.columnMeta ?? []).filter(column => {
|
|
449
456
|
if (!column.visible || column.generated) {
|
|
@@ -477,10 +484,12 @@ function renderDataRowEditorPanel(state) {
|
|
|
477
484
|
return renderRowEditorPanel({
|
|
478
485
|
title: table.name,
|
|
479
486
|
sectionLabel: 'Row Editor',
|
|
480
|
-
subtitle: `row ${rowIndex + 1}
|
|
487
|
+
subtitle: isIndexedRow ? `row ${rowIndex + 1}` : 'targeted row',
|
|
481
488
|
closeAction: 'clear-data-row-selection',
|
|
482
489
|
formName: 'save-data-row',
|
|
483
|
-
hiddenFields:
|
|
490
|
+
hiddenFields: isIndexedRow
|
|
491
|
+
? [{ name: 'rowIndex', value: String(rowIndex) }]
|
|
492
|
+
: [{ name: 'rowIdentity', value: JSON.stringify(row.__identity ?? null) }],
|
|
484
493
|
disabledMessage: state.connections.active?.readOnly
|
|
485
494
|
? 'The active database is opened read-only, so row editing is disabled.'
|
|
486
495
|
: table.notSafelyUpdatable
|
|
@@ -492,19 +501,23 @@ function renderDataRowEditorPanel(state) {
|
|
|
492
501
|
return {
|
|
493
502
|
name: column.name,
|
|
494
503
|
label: column.name,
|
|
504
|
+
badges: getColumnBadges(column),
|
|
495
505
|
value: value === null || value === undefined ? '' : String(value),
|
|
496
506
|
};
|
|
497
507
|
}),
|
|
498
508
|
readonlyFields: readonlyColumns.map(column => ({
|
|
499
509
|
name: column.name,
|
|
500
|
-
label:
|
|
510
|
+
label: {
|
|
511
|
+
label: column.name,
|
|
512
|
+
badges: getColumnBadges(column),
|
|
513
|
+
},
|
|
501
514
|
value: formatCellValue(row[column.name]),
|
|
502
515
|
})),
|
|
503
516
|
saveError: state.dataBrowser.saveError,
|
|
504
517
|
saving: state.dataBrowser.saving,
|
|
505
518
|
deleting: state.dataBrowser.deleting,
|
|
506
519
|
deleteAction: 'delete-data-row',
|
|
507
|
-
deleteRowIndex: rowIndex,
|
|
520
|
+
deleteRowIndex: isIndexedRow ? rowIndex : null,
|
|
508
521
|
deleteEnabled: Boolean(row.__identity),
|
|
509
522
|
reloadAction: 'reload-data-route',
|
|
510
523
|
});
|