sqlite-hub 0.12.0 → 0.17.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 +118 -23
- package/bin/sqlite-hub.js +1041 -224
- package/frontend/index.html +1 -0
- package/frontend/js/api.js +32 -2
- package/frontend/js/app.js +989 -13
- package/frontend/js/components/modal.js +644 -15
- package/frontend/js/components/pageHeader.js +14 -16
- package/frontend/js/components/queryEditor.js +9 -1
- package/frontend/js/components/queryHistoryPanel.js +126 -131
- package/frontend/js/components/queryResults.js +79 -17
- package/frontend/js/components/rowEditorPanel.js +204 -10
- package/frontend/js/components/sidebar.js +102 -18
- package/frontend/js/components/tableDesignerEditor.js +69 -11
- package/frontend/js/router.js +8 -0
- package/frontend/js/store.js +868 -9
- package/frontend/js/utils/copyColumnExport.js +117 -0
- package/frontend/js/utils/exportFilenames.js +32 -0
- package/frontend/js/utils/filePathPreview.js +315 -0
- package/frontend/js/utils/format.js +1 -1
- package/frontend/js/utils/markdownDocuments.js +248 -0
- package/frontend/js/utils/rowEditorJson.js +65 -0
- package/frontend/js/utils/sqlFormatter.js +691 -0
- package/frontend/js/utils/tableDesigner.js +178 -6
- package/frontend/js/utils/textCellStats.js +20 -0
- package/frontend/js/utils/timestampPreview.js +264 -0
- package/frontend/js/views/charts.js +3 -1
- package/frontend/js/views/data.js +34 -2
- package/frontend/js/views/documents.js +300 -0
- package/frontend/js/views/editor.js +48 -1
- package/frontend/js/views/settings.js +39 -6
- package/frontend/js/views/structure.js +154 -212
- package/frontend/styles/base.css +6 -0
- package/frontend/styles/components.css +476 -2
- package/frontend/styles/structure-graph.css +0 -3
- package/frontend/styles/tailwind.generated.css +1 -1
- package/frontend/styles/tokens.css +1 -1
- package/frontend/styles/views.css +422 -0
- package/package.json +3 -3
- package/server/routes/documents.js +163 -0
- package/server/routes/settings.js +22 -6
- package/server/server.js +6 -0
- package/server/services/sqlite/introspection.js +10 -0
- package/server/services/sqlite/sqlExecutor.js +29 -0
- package/server/services/sqlite/tableDesigner/changeAnalysis.js +25 -1
- package/server/services/sqlite/tableDesigner/schemaMapping.js +105 -10
- package/server/services/sqlite/tableDesigner/validation.js +60 -2
- package/server/services/sqlite/tableDesignerService.js +1 -1
- package/server/services/storage/appStateStore.js +313 -0
- package/tests/check-constraint-options.test.js +14 -0
- package/tests/cli-args.test.js +100 -0
- package/tests/copy-column-modal.test.js +83 -0
- package/tests/database-documents.test.js +85 -0
- package/tests/export-filenames.test.js +34 -0
- package/tests/file-path-preview.test.js +165 -0
- package/tests/markdown-documents.test.js +79 -0
- package/tests/row-editor-json.test.js +82 -0
- package/tests/row-editor-timestamp-preview.test.js +192 -0
- package/tests/settings-metadata.test.js +16 -0
- package/tests/settings-view.test.js +32 -0
- package/tests/sql-formatter.test.js +173 -0
- package/tests/sql-highlight.test.js +38 -0
- package/tests/table-designer-v2-unique-constraints.test.js +78 -0
- package/tests/text-cell-stats.test.js +38 -0
- package/fill.js +0 -526
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { escapeHtml, formatCompactDateTime, formatNumber } from '../utils/format.js';
|
|
2
|
+
import { renderMarkdownPreview } from '../utils/markdownDocuments.js';
|
|
3
|
+
|
|
4
|
+
function renderMissingDatabase() {
|
|
5
|
+
return `
|
|
6
|
+
<section class="view-surface">
|
|
7
|
+
<div class="view-frame flex min-h-full items-center justify-center">
|
|
8
|
+
<div class="text-center">
|
|
9
|
+
<span class="material-symbols-outlined mb-3 text-5xl text-on-surface-variant/25">database_off</span>
|
|
10
|
+
<p class="font-headline text-xl font-black uppercase tracking-tight text-primary-container">
|
|
11
|
+
No Active SQLite Database
|
|
12
|
+
</p>
|
|
13
|
+
<p class="mt-3 max-w-xl text-sm leading-7 text-on-surface-variant/65">
|
|
14
|
+
Select a database before opening its document folder.
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</section>
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function renderDocumentListItem(item, selectedId) {
|
|
23
|
+
const isSelected = String(item.id) === String(selectedId);
|
|
24
|
+
|
|
25
|
+
return `
|
|
26
|
+
<button
|
|
27
|
+
class="documents-list-item ${isSelected ? 'is-selected' : ''}"
|
|
28
|
+
data-action="select-document"
|
|
29
|
+
data-document-id="${escapeHtml(item.id)}"
|
|
30
|
+
type="button"
|
|
31
|
+
>
|
|
32
|
+
<span class="material-symbols-outlined documents-list-item__icon">description</span>
|
|
33
|
+
<span class="documents-list-item__body">
|
|
34
|
+
<span class="documents-list-item__title" title="${escapeHtml(item.filename)}">
|
|
35
|
+
${escapeHtml(item.filename)}
|
|
36
|
+
</span>
|
|
37
|
+
<span class="documents-list-item__meta">
|
|
38
|
+
${escapeHtml(formatCompactDateTime(item.updatedAt))} // ${formatNumber(item.contentLength ?? 0)} chars
|
|
39
|
+
</span>
|
|
40
|
+
</span>
|
|
41
|
+
</button>
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function renderDocumentsSidebar(documents) {
|
|
46
|
+
const items = documents.items ?? [];
|
|
47
|
+
|
|
48
|
+
return `
|
|
49
|
+
<aside class="documents-view__sidebar">
|
|
50
|
+
<div class="documents-view__sidebar-header">
|
|
51
|
+
<div>
|
|
52
|
+
<div class="text-[10px] font-mono uppercase tracking-[0.22em] text-on-surface-variant/50">
|
|
53
|
+
Documents
|
|
54
|
+
</div>
|
|
55
|
+
<div class="mt-1 font-mono text-xs text-primary-container">${formatNumber(items.length)} files</div>
|
|
56
|
+
</div>
|
|
57
|
+
<button
|
|
58
|
+
class="icon-button"
|
|
59
|
+
data-action="create-document"
|
|
60
|
+
title="New document"
|
|
61
|
+
type="button"
|
|
62
|
+
${documents.saving ? 'disabled aria-disabled="true"' : ''}
|
|
63
|
+
>
|
|
64
|
+
<span class="material-symbols-outlined">add</span>
|
|
65
|
+
</button>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="documents-view__sidebar-body custom-scrollbar">
|
|
68
|
+
${
|
|
69
|
+
items.length
|
|
70
|
+
? items.map(item => renderDocumentListItem(item, documents.selectedId)).join('')
|
|
71
|
+
: `<div class="documents-list-empty">No documents yet</div>`
|
|
72
|
+
}
|
|
73
|
+
</div>
|
|
74
|
+
</aside>
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function renderDocumentToolbar(documents) {
|
|
79
|
+
const disabled = documents.saving || documents.detailLoading || !documents.selectedId;
|
|
80
|
+
|
|
81
|
+
return ` <label class="documents-filename-field">
|
|
82
|
+
<input
|
|
83
|
+
class="control-input"
|
|
84
|
+
data-bind="document-field"
|
|
85
|
+
data-field="filename"
|
|
86
|
+
name="filename"
|
|
87
|
+
spellcheck="false"
|
|
88
|
+
type="text"
|
|
89
|
+
value="${escapeHtml(documents.draftFilename)}"
|
|
90
|
+
${!documents.selectedId ? 'disabled' : ''}
|
|
91
|
+
/>
|
|
92
|
+
</label>
|
|
93
|
+
<div class="documents-toolbar">
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
<div class="documents-toolbar__actions">
|
|
98
|
+
<button
|
|
99
|
+
class="standard-button"
|
|
100
|
+
data-action="toggle-document-pane"
|
|
101
|
+
data-pane="editor"
|
|
102
|
+
type="button"
|
|
103
|
+
>
|
|
104
|
+
<span class="material-symbols-outlined">${documents.editorVisible ? 'visibility_off' : 'edit_note'}</span>
|
|
105
|
+
${documents.editorVisible ? 'Hide Editor' : 'Show Editor'}
|
|
106
|
+
</button>
|
|
107
|
+
<button
|
|
108
|
+
class="standard-button"
|
|
109
|
+
data-action="toggle-document-pane"
|
|
110
|
+
data-pane="preview"
|
|
111
|
+
type="button"
|
|
112
|
+
>
|
|
113
|
+
<span class="material-symbols-outlined">${documents.previewVisible ? 'visibility_off' : 'visibility'}</span>
|
|
114
|
+
${documents.previewVisible ? 'Hide Preview' : 'Show Preview'}
|
|
115
|
+
</button>
|
|
116
|
+
<input
|
|
117
|
+
accept=".md,.markdown,text/markdown,text/plain"
|
|
118
|
+
data-bind="document-import-file"
|
|
119
|
+
hidden
|
|
120
|
+
type="file"
|
|
121
|
+
/>
|
|
122
|
+
</div>
|
|
123
|
+
<div class="documents-toolbar__actions">
|
|
124
|
+
<button
|
|
125
|
+
class="standard-button"
|
|
126
|
+
data-action="open-document-insert-table-modal"
|
|
127
|
+
type="button"
|
|
128
|
+
${disabled ? 'disabled aria-disabled="true"' : ''}
|
|
129
|
+
>
|
|
130
|
+
<span class="material-symbols-outlined">table_chart</span>
|
|
131
|
+
Insert Table
|
|
132
|
+
</button>
|
|
133
|
+
<button
|
|
134
|
+
class="standard-button"
|
|
135
|
+
data-action="open-document-insert-note-modal"
|
|
136
|
+
type="button"
|
|
137
|
+
${disabled ? 'disabled aria-disabled="true"' : ''}
|
|
138
|
+
>
|
|
139
|
+
<span class="material-symbols-outlined">note_add</span>
|
|
140
|
+
Insert Note
|
|
141
|
+
</button>
|
|
142
|
+
<button
|
|
143
|
+
class="standard-button"
|
|
144
|
+
data-action="export-document-markdown"
|
|
145
|
+
type="button"
|
|
146
|
+
${disabled ? 'disabled aria-disabled="true"' : ''}
|
|
147
|
+
>
|
|
148
|
+
<span class="material-symbols-outlined">download</span>
|
|
149
|
+
Export .md
|
|
150
|
+
</button>
|
|
151
|
+
<button
|
|
152
|
+
class="standard-button"
|
|
153
|
+
data-action="import-document-markdown"
|
|
154
|
+
type="button"
|
|
155
|
+
${documents.saving ? 'disabled aria-disabled="true"' : ''}
|
|
156
|
+
>
|
|
157
|
+
<span class="material-symbols-outlined">upload_file</span>
|
|
158
|
+
Import .md
|
|
159
|
+
</button>
|
|
160
|
+
</div>
|
|
161
|
+
<div class="documents-toolbar__actions">
|
|
162
|
+
<button
|
|
163
|
+
class="standard-button"
|
|
164
|
+
data-action="delete-document"
|
|
165
|
+
type="button"
|
|
166
|
+
${disabled || documents.deleting ? 'disabled aria-disabled="true"' : ''}
|
|
167
|
+
>
|
|
168
|
+
<span class="material-symbols-outlined">delete</span>
|
|
169
|
+
Delete
|
|
170
|
+
</button>
|
|
171
|
+
<button
|
|
172
|
+
class="signature-button"
|
|
173
|
+
data-action="save-document"
|
|
174
|
+
type="button"
|
|
175
|
+
${disabled || !documents.dirty ? 'disabled aria-disabled="true"' : ''}
|
|
176
|
+
>
|
|
177
|
+
<span class="material-symbols-outlined">save</span>
|
|
178
|
+
${documents.saving ? 'Saving...' : 'Save'}
|
|
179
|
+
</button>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function renderDocumentEditor(documents) {
|
|
186
|
+
if (!documents.editorVisible) {
|
|
187
|
+
return '';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return `
|
|
191
|
+
<section class="documents-pane documents-pane--editor">
|
|
192
|
+
<div class="documents-pane__header">
|
|
193
|
+
<span>Editor</span>
|
|
194
|
+
<span>${formatNumber(documents.draftContent.length)} chars</span>
|
|
195
|
+
</div>
|
|
196
|
+
<textarea
|
|
197
|
+
class="documents-editor-input custom-scrollbar"
|
|
198
|
+
data-bind="document-field"
|
|
199
|
+
data-field="content"
|
|
200
|
+
name="content"
|
|
201
|
+
spellcheck="true"
|
|
202
|
+
${!documents.selectedId ? 'disabled' : ''}
|
|
203
|
+
>${escapeHtml(documents.draftContent)}</textarea>
|
|
204
|
+
</section>
|
|
205
|
+
`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function renderDocumentPreview(documents) {
|
|
209
|
+
if (!documents.previewVisible) {
|
|
210
|
+
return '';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return `
|
|
214
|
+
<section class="documents-pane documents-pane--preview">
|
|
215
|
+
<div class="documents-pane__header">
|
|
216
|
+
<span>Preview</span>
|
|
217
|
+
<span>${escapeHtml(documents.dirty ? 'unsaved' : 'saved')}</span>
|
|
218
|
+
</div>
|
|
219
|
+
<div class="document-markdown-preview custom-scrollbar" data-document-preview>
|
|
220
|
+
${renderMarkdownPreview(documents.draftContent)}
|
|
221
|
+
</div>
|
|
222
|
+
</section>
|
|
223
|
+
`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function renderEmptyDocumentsState(documents) {
|
|
227
|
+
return `
|
|
228
|
+
<div class="documents-empty-state">
|
|
229
|
+
<span class="material-symbols-outlined">description</span>
|
|
230
|
+
<p class="font-headline text-2xl font-black uppercase tracking-tight text-primary-container">
|
|
231
|
+
No Documents
|
|
232
|
+
</p>
|
|
233
|
+
<button
|
|
234
|
+
class="signature-button mt-4"
|
|
235
|
+
data-action="create-document"
|
|
236
|
+
type="button"
|
|
237
|
+
${documents.saving ? 'disabled aria-disabled="true"' : ''}
|
|
238
|
+
>
|
|
239
|
+
<span class="material-symbols-outlined">add</span>
|
|
240
|
+
New Document
|
|
241
|
+
</button>
|
|
242
|
+
</div>
|
|
243
|
+
`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function renderDocumentDetail(documents) {
|
|
247
|
+
if (documents.loading && !documents.items.length) {
|
|
248
|
+
return `
|
|
249
|
+
<main class="documents-view__detail">
|
|
250
|
+
<div class="documents-empty-state">
|
|
251
|
+
<span class="material-symbols-outlined">sync</span>
|
|
252
|
+
<p class="font-headline text-2xl font-black uppercase tracking-tight text-primary-container">
|
|
253
|
+
Loading Documents
|
|
254
|
+
</p>
|
|
255
|
+
</div>
|
|
256
|
+
</main>
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (!documents.selectedId) {
|
|
261
|
+
return `
|
|
262
|
+
<main class="documents-view__detail">
|
|
263
|
+
${renderEmptyDocumentsState(documents)}
|
|
264
|
+
</main>
|
|
265
|
+
`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const paneCount = Number(documents.editorVisible) + Number(documents.previewVisible);
|
|
269
|
+
|
|
270
|
+
return `
|
|
271
|
+
<main class="documents-view__detail">
|
|
272
|
+
${renderDocumentToolbar(documents)}
|
|
273
|
+
${documents.saveError ? `<div class="documents-error">${escapeHtml(documents.saveError.message)}</div>` : ''}
|
|
274
|
+
<div class="documents-workspace ${paneCount > 1 ? 'documents-workspace--split' : ''}">
|
|
275
|
+
${renderDocumentEditor(documents)}
|
|
276
|
+
${renderDocumentPreview(documents)}
|
|
277
|
+
</div>
|
|
278
|
+
</main>
|
|
279
|
+
`;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function renderDocumentsView(state) {
|
|
283
|
+
if (!state.connections.active) {
|
|
284
|
+
return {
|
|
285
|
+
main: renderMissingDatabase(),
|
|
286
|
+
panel: '',
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const documents = state.documents;
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
main: `<div class="documents-view">
|
|
294
|
+
${renderDocumentsSidebar(documents)}
|
|
295
|
+
${renderDocumentDetail(documents)}
|
|
296
|
+
</div>
|
|
297
|
+
</div>`,
|
|
298
|
+
panel: '',
|
|
299
|
+
};
|
|
300
|
+
}
|
|
@@ -143,6 +143,35 @@ function getUniqueResultColumns(columns = []) {
|
|
|
143
143
|
return uniqueColumns;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
function getEditorColumnTypeBadge(column) {
|
|
147
|
+
if (column.sourceColumn === 'rowid') {
|
|
148
|
+
return 'ROWID';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return String(column.declaredType || column.affinity || 'BLOB')
|
|
152
|
+
.trim()
|
|
153
|
+
.toUpperCase();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function getEditorColumnBadges(column) {
|
|
157
|
+
const badges = [{ label: getEditorColumnTypeBadge(column), tone: 'type' }];
|
|
158
|
+
|
|
159
|
+
if (Number(column.primaryKeyPosition ?? 0) > 0) {
|
|
160
|
+
badges.push({
|
|
161
|
+
label: Number(column.primaryKeyPosition) > 1 ? `PK ${column.primaryKeyPosition}` : 'PK',
|
|
162
|
+
tone: 'primary-key',
|
|
163
|
+
});
|
|
164
|
+
} else if (column.identity && column.sourceColumn === 'rowid') {
|
|
165
|
+
badges.push({ label: 'ROWID', tone: 'primary-key' });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (column.foreignKey) {
|
|
169
|
+
badges.push({ label: 'FK', tone: 'foreign-key' });
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return badges;
|
|
173
|
+
}
|
|
174
|
+
|
|
146
175
|
function renderEditorRowPanel(state) {
|
|
147
176
|
const result = state.editor.result;
|
|
148
177
|
const rowIndex = state.editor.selectedRowIndex;
|
|
@@ -153,6 +182,15 @@ function renderEditorRowPanel(state) {
|
|
|
153
182
|
}
|
|
154
183
|
|
|
155
184
|
const uniqueColumns = getUniqueResultColumns(result.editing?.columns ?? []);
|
|
185
|
+
const tableMeta =
|
|
186
|
+
result.editing?.tableMeta ?? {
|
|
187
|
+
columns: uniqueColumns.map(column => ({
|
|
188
|
+
name: column.sourceColumn,
|
|
189
|
+
primaryKeyPosition: Number(column.primaryKeyPosition ?? 0),
|
|
190
|
+
foreignKey: Boolean(column.foreignKey),
|
|
191
|
+
})),
|
|
192
|
+
foreignKeys: [],
|
|
193
|
+
};
|
|
156
194
|
const editableColumns = uniqueColumns.filter(column => {
|
|
157
195
|
if (column.identity || column.generated || !column.visible) {
|
|
158
196
|
return false;
|
|
@@ -193,6 +231,7 @@ function renderEditorRowPanel(state) {
|
|
|
193
231
|
return {
|
|
194
232
|
name: column.sourceColumn,
|
|
195
233
|
label: column.sourceColumn,
|
|
234
|
+
badges: getEditorColumnBadges(column),
|
|
196
235
|
allowedValues: column.allowedValues ?? [],
|
|
197
236
|
notNull: Boolean(column.notNull),
|
|
198
237
|
value: value === null || value === undefined ? '' : String(value),
|
|
@@ -200,15 +239,21 @@ function renderEditorRowPanel(state) {
|
|
|
200
239
|
}),
|
|
201
240
|
readonlyFields: readonlyColumns.map(column => ({
|
|
202
241
|
name: column.sourceColumn,
|
|
203
|
-
label:
|
|
242
|
+
label: {
|
|
243
|
+
label: column.sourceColumn,
|
|
244
|
+
badges: getEditorColumnBadges(column),
|
|
245
|
+
},
|
|
246
|
+
rawValue: row[column.resultName],
|
|
204
247
|
value: formatCellValue(row[column.resultName]),
|
|
205
248
|
})),
|
|
249
|
+
tableMeta,
|
|
206
250
|
saveError: state.editor.saveError,
|
|
207
251
|
saving: state.editor.saving,
|
|
208
252
|
deleting: state.editor.deleting,
|
|
209
253
|
deleteAction: 'delete-editor-row',
|
|
210
254
|
deleteRowIndex: rowIndex,
|
|
211
255
|
deleteEnabled: editingState.enabled && Boolean(row.__identity),
|
|
256
|
+
jsonActionsEnabled: true,
|
|
212
257
|
});
|
|
213
258
|
}
|
|
214
259
|
|
|
@@ -233,6 +278,8 @@ function renderResultsSurface(state, isResultsRoute) {
|
|
|
233
278
|
editable: editingState.enabled,
|
|
234
279
|
sortColumn: state.editor.resultSortColumn,
|
|
235
280
|
sortDirection: state.editor.resultSortDirection,
|
|
281
|
+
resultScope: 'editor',
|
|
282
|
+
sortAction: 'sort-editor-results-column',
|
|
236
283
|
})
|
|
237
284
|
: renderMissingDatabase();
|
|
238
285
|
}
|
|
@@ -24,6 +24,9 @@ function renderSettingsContent(state) {
|
|
|
24
24
|
`;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
const appVersion = escapeHtml(state.settings.appVersion ?? '0.0.0');
|
|
28
|
+
const sqliteVersion = escapeHtml(state.settings.sqliteVersion ?? 'unknown');
|
|
29
|
+
|
|
27
30
|
return `
|
|
28
31
|
<div class="grid grid-cols-1 gap-6 xl:grid-cols-2">
|
|
29
32
|
<section class="shell-section overflow-hidden">
|
|
@@ -32,17 +35,47 @@ function renderSettingsContent(state) {
|
|
|
32
35
|
<span class="material-symbols-outlined text-xs text-primary-container">deployed_code</span>
|
|
33
36
|
</div>
|
|
34
37
|
<div class="space-y-5 p-6">
|
|
38
|
+
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
|
39
|
+
<div>
|
|
40
|
+
<div class="text-[10px] font-mono uppercase tracking-[0.2em] text-on-surface-variant/60">
|
|
41
|
+
Current_Version
|
|
42
|
+
</div>
|
|
43
|
+
<div class="mt-2 font-headline text-4xl font-black uppercase tracking-tight text-primary-container">
|
|
44
|
+
v${appVersion}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<div>
|
|
48
|
+
<div class="text-[10px] font-mono uppercase tracking-[0.2em] text-on-surface-variant/60">
|
|
49
|
+
SQLite_Runtime
|
|
50
|
+
</div>
|
|
51
|
+
<div class="mt-2 font-headline text-4xl font-black uppercase tracking-tight text-primary-container">
|
|
52
|
+
${sqliteVersion}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="border-t border-outline-variant/10 py-4 text-sm leading-6 text-on-surface-variant">
|
|
57
|
+
SQL functions and syntax are evaluated with this SQLite runtime.
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</section>
|
|
61
|
+
|
|
62
|
+
<section class="shell-section overflow-hidden">
|
|
63
|
+
<div class="flex items-center justify-between border-b border-outline-variant/10 bg-surface-container-highest px-4 py-2">
|
|
64
|
+
<span class="text-[10px] font-bold uppercase tracking-[0.25em]">CLI</span>
|
|
65
|
+
<span class="material-symbols-outlined text-xs text-primary-container">terminal</span>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="space-y-4 p-6">
|
|
35
68
|
<div>
|
|
36
69
|
<div class="text-[10px] font-mono uppercase tracking-[0.2em] text-on-surface-variant/60">
|
|
37
|
-
|
|
38
|
-
</div>
|
|
39
|
-
<div class="mt-2 font-headline text-4xl font-black uppercase tracking-tight text-primary-container">
|
|
40
|
-
v${escapeHtml(state.settings.appVersion ?? '0.0.0')}
|
|
70
|
+
Custom_Port
|
|
41
71
|
</div>
|
|
42
|
-
<div class="mt-
|
|
43
|
-
|
|
72
|
+
<div class="mt-3 border border-outline-variant/10 bg-surface-container-high px-4 py-3 font-mono text-sm text-primary-container">
|
|
73
|
+
sqlite-hub --port:PORT
|
|
44
74
|
</div>
|
|
45
75
|
</div>
|
|
76
|
+
<div class="text-sm leading-6 text-on-surface-variant">
|
|
77
|
+
Start SQLite Hub with a different local port when the default port is already in use.
|
|
78
|
+
</div>
|
|
46
79
|
</div>
|
|
47
80
|
</section>
|
|
48
81
|
|