sqlite-hub 0.16.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 +106 -19
- package/bin/sqlite-hub.js +1041 -224
- package/frontend/index.html +1 -0
- package/frontend/js/api.js +28 -0
- package/frontend/js/app.js +362 -6
- package/frontend/js/components/modal.js +244 -44
- package/frontend/js/components/pageHeader.js +14 -16
- package/frontend/js/components/queryHistoryPanel.js +126 -131
- package/frontend/js/components/sidebar.js +1 -0
- package/frontend/js/router.js +8 -0
- package/frontend/js/store.js +641 -0
- package/frontend/js/utils/markdownDocuments.js +248 -0
- package/frontend/js/views/documents.js +300 -0
- package/frontend/js/views/settings.js +39 -3
- package/frontend/styles/components.css +13 -0
- package/frontend/styles/tailwind.generated.css +1 -1
- package/frontend/styles/views.css +422 -0
- package/package.json +2 -1
- package/server/routes/documents.js +163 -0
- package/server/routes/settings.js +22 -6
- package/server/server.js +6 -0
- package/server/services/storage/appStateStore.js +313 -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/markdown-documents.test.js +79 -0
- package/tests/settings-metadata.test.js +16 -0
- package/tests/settings-view.test.js +32 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { escapeHtml, formatNumber, highlightSql, truncateMiddle } from "../utils/format.js";
|
|
2
2
|
import {
|
|
3
|
+
buildCopyColumnText,
|
|
3
4
|
buildCopyColumnPreviewText,
|
|
4
5
|
getCopyColumnActionLabel,
|
|
5
6
|
getCopyColumnExportMetadata,
|
|
@@ -170,7 +171,7 @@ function renderOpenConnectionForm(modal) {
|
|
|
170
171
|
text: "Open read-only",
|
|
171
172
|
})}
|
|
172
173
|
${renderError(modal.error)}
|
|
173
|
-
<div class="flex items-center justify-
|
|
174
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
174
175
|
<button
|
|
175
176
|
class="standard-button"
|
|
176
177
|
data-action="close-modal"
|
|
@@ -244,7 +245,7 @@ function renderEditConnectionForm(modal) {
|
|
|
244
245
|
text: "Open read-only",
|
|
245
246
|
})}
|
|
246
247
|
${renderError(modal.error)}
|
|
247
|
-
<div class="flex items-center justify-
|
|
248
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
248
249
|
<button
|
|
249
250
|
class="standard-button"
|
|
250
251
|
data-action="close-modal"
|
|
@@ -277,7 +278,7 @@ function renderCreateDatabaseForm(modal) {
|
|
|
277
278
|
placeholder: "Optional display name",
|
|
278
279
|
})}
|
|
279
280
|
${renderError(modal.error)}
|
|
280
|
-
<div class="flex items-center justify-
|
|
281
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
281
282
|
<button
|
|
282
283
|
class="standard-button"
|
|
283
284
|
data-action="close-modal"
|
|
@@ -363,7 +364,7 @@ function renderImportSqlForm(modal, state) {
|
|
|
363
364
|
explicit path instead of file upload.
|
|
364
365
|
</p>
|
|
365
366
|
${renderError(modal.error)}
|
|
366
|
-
<div class="flex items-center justify-
|
|
367
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
367
368
|
<button
|
|
368
369
|
class="standard-button"
|
|
369
370
|
data-action="close-modal"
|
|
@@ -423,7 +424,7 @@ function renderDeleteRowConfirmForm(modal) {
|
|
|
423
424
|
rowPreviewMarkup,
|
|
424
425
|
"</div>",
|
|
425
426
|
renderError(modal.error),
|
|
426
|
-
'<div class="flex items-center justify-
|
|
427
|
+
'<div class="flex items-center justify-between gap-3 pt-2">',
|
|
427
428
|
'<button class="standard-button" data-action="close-modal" type="button">Cancel</button>',
|
|
428
429
|
'<button class="delete-button" type="submit">',
|
|
429
430
|
modal.submitting ? "Deleting..." : "Delete Row",
|
|
@@ -513,7 +514,7 @@ function renderRowUpdatePreviewForm(modal) {
|
|
|
513
514
|
</div>
|
|
514
515
|
${paramsMarkup}
|
|
515
516
|
${renderError(modal.error)}
|
|
516
|
-
<div class="flex items-center justify-
|
|
517
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
517
518
|
<button class="standard-button" data-action="close-modal" type="button">Cancel</button>
|
|
518
519
|
<button class="signature-button" type="submit">
|
|
519
520
|
${modal.submitting ? 'Applying...' : 'Apply Changes'}
|
|
@@ -753,7 +754,7 @@ function renderChartEditorForm(modal, state) {
|
|
|
753
754
|
: ""
|
|
754
755
|
}
|
|
755
756
|
${renderError(modal.error)}
|
|
756
|
-
<div class="flex items-center justify-
|
|
757
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
757
758
|
<button
|
|
758
759
|
class="standard-button"
|
|
759
760
|
data-action="close-modal"
|
|
@@ -781,7 +782,7 @@ function renderDeleteChartForm(modal) {
|
|
|
781
782
|
'<p class="text-sm leading-7 text-on-surface-variant/65">The linked query-history entry stays intact. Only this chart definition is removed.</p>',
|
|
782
783
|
"</div>",
|
|
783
784
|
renderError(modal.error),
|
|
784
|
-
'<div class="flex items-center justify-
|
|
785
|
+
'<div class="flex items-center justify-between gap-3 pt-2">',
|
|
785
786
|
'<button class="standard-button" data-action="close-modal" type="button">Cancel</button>',
|
|
786
787
|
'<button class="delete-button" type="submit">',
|
|
787
788
|
modal.submitting ? "Deleting..." : "Delete Chart",
|
|
@@ -798,7 +799,7 @@ function renderDeleteQueryHistoryForm(modal) {
|
|
|
798
799
|
'<p class="text-sm leading-7 text-on-surface-variant/65">This removes the query-history entry and all recorded runs linked to it.</p>',
|
|
799
800
|
"</div>",
|
|
800
801
|
renderError(modal.error),
|
|
801
|
-
'<div class="flex items-center justify-
|
|
802
|
+
'<div class="flex items-center justify-between gap-3 pt-2">',
|
|
802
803
|
'<button class="standard-button" data-action="close-modal" type="button">Cancel</button>',
|
|
803
804
|
'<button class="delete-button" type="submit">',
|
|
804
805
|
modal.submitting ? "Deleting..." : "Delete Query",
|
|
@@ -806,6 +807,147 @@ function renderDeleteQueryHistoryForm(modal) {
|
|
|
806
807
|
].join("");
|
|
807
808
|
}
|
|
808
809
|
|
|
810
|
+
function renderDeleteDocumentForm(modal) {
|
|
811
|
+
return [
|
|
812
|
+
'<form class="space-y-5" data-form="delete-document-confirm"><div class="space-y-3">',
|
|
813
|
+
'<p class="text-sm leading-7 text-on-surface">Delete document <span class="font-bold text-primary-container">',
|
|
814
|
+
escapeHtml(modal.filename ?? "document"),
|
|
815
|
+
"</span>?</p>",
|
|
816
|
+
'<p class="text-sm leading-7 text-on-surface-variant/65">This removes the Markdown document from the active database document folder.</p>',
|
|
817
|
+
'<div class="border border-outline-variant/10 bg-surface-container-lowest px-4 py-3 text-[10px] font-mono uppercase tracking-[0.18em] text-on-surface-variant/55">',
|
|
818
|
+
formatNumber(modal.contentLength ?? 0),
|
|
819
|
+
" chars</div>",
|
|
820
|
+
"</div>",
|
|
821
|
+
renderError(modal.error),
|
|
822
|
+
'<div class="flex items-center justify-between gap-3 pt-2">',
|
|
823
|
+
'<button class="standard-button" data-action="close-modal" type="button">Cancel</button>',
|
|
824
|
+
'<button class="delete-button" type="submit">',
|
|
825
|
+
modal.submitting ? "Deleting..." : "Delete Document",
|
|
826
|
+
"</button></div></form>",
|
|
827
|
+
].join("");
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function getDocumentInsertQueryTitle(query) {
|
|
831
|
+
return query?.displayTitle || query?.title || query?.previewSql || query?.rawSql || "Saved query";
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
function getSelectedDocumentInsertQuery(modal) {
|
|
835
|
+
const selectedHistoryId = String(modal.selectedHistoryId ?? "");
|
|
836
|
+
|
|
837
|
+
return (modal.queries ?? []).find((query) => String(query.id) === selectedHistoryId) ?? null;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function renderDocumentInsertQuerySelect(modal, emptyText) {
|
|
841
|
+
const queries = modal.queries ?? [];
|
|
842
|
+
|
|
843
|
+
if (modal.loading) {
|
|
844
|
+
return '<div class="border border-outline-variant/10 bg-surface-container-lowest px-4 py-3 text-sm text-on-surface-variant/65">Loading saved queries...</div>';
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (!queries.length) {
|
|
848
|
+
return `<div class="border border-outline-variant/10 bg-surface-container-lowest px-4 py-3 text-sm text-on-surface-variant/65">${escapeHtml(emptyText)}</div>`;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
return `
|
|
852
|
+
<label class="block space-y-2">
|
|
853
|
+
<span class="text-[10px] font-mono uppercase tracking-[0.22em] text-on-surface-variant/60">
|
|
854
|
+
Saved Query
|
|
855
|
+
</span>
|
|
856
|
+
<select
|
|
857
|
+
class="control-select w-full border border-outline-variant/20 bg-surface-container-lowest text-sm text-on-surface outline-none transition-colors focus:border-primary-container"
|
|
858
|
+
data-bind="document-insert-query-select"
|
|
859
|
+
name="historyId"
|
|
860
|
+
>
|
|
861
|
+
${queries
|
|
862
|
+
.map(
|
|
863
|
+
(query) => `
|
|
864
|
+
<option
|
|
865
|
+
value="${escapeHtml(query.id)}"
|
|
866
|
+
${String(query.id) === String(modal.selectedHistoryId) ? "selected" : ""}
|
|
867
|
+
>
|
|
868
|
+
${escapeHtml(getDocumentInsertQueryTitle(query))}
|
|
869
|
+
</option>
|
|
870
|
+
`
|
|
871
|
+
)
|
|
872
|
+
.join("")}
|
|
873
|
+
</select>
|
|
874
|
+
</label>
|
|
875
|
+
`;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
function renderDocumentInsertQueryPreview(query) {
|
|
879
|
+
if (!query) {
|
|
880
|
+
return "";
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
return `
|
|
884
|
+
<div class="space-y-2">
|
|
885
|
+
<div class="text-[10px] font-mono uppercase tracking-[0.22em] text-on-surface-variant/60">
|
|
886
|
+
Query Preview
|
|
887
|
+
</div>
|
|
888
|
+
<pre class="max-h-44 overflow-auto border border-outline-variant/10 bg-surface-container-lowest px-4 py-3 font-mono text-xs leading-6 text-on-surface-variant/75 custom-scrollbar">${escapeHtml(
|
|
889
|
+
query.rawSql || query.previewSql || ""
|
|
890
|
+
)}</pre>
|
|
891
|
+
</div>
|
|
892
|
+
`;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
function renderDocumentInsertTableForm(modal) {
|
|
896
|
+
const selectedQuery = getSelectedDocumentInsertQuery(modal);
|
|
897
|
+
const disabledAttribute = modal.loading || modal.submitting || !(modal.queries ?? []).length
|
|
898
|
+
? 'disabled aria-disabled="true"'
|
|
899
|
+
: "";
|
|
900
|
+
|
|
901
|
+
return `
|
|
902
|
+
<form class="space-y-5" data-form="document-insert-table">
|
|
903
|
+
${renderDocumentInsertQuerySelect(modal, "No saved queries are available for this database.")}
|
|
904
|
+
${renderDocumentInsertQueryPreview(selectedQuery)}
|
|
905
|
+
${renderError(modal.error)}
|
|
906
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
907
|
+
<button class="standard-button" data-action="close-modal" type="button">Cancel</button>
|
|
908
|
+
<button class="signature-button" type="submit" ${disabledAttribute}>
|
|
909
|
+
${modal.submitting ? "Inserting..." : "Insert Table"}
|
|
910
|
+
</button>
|
|
911
|
+
</div>
|
|
912
|
+
</form>
|
|
913
|
+
`;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
function renderDocumentInsertNoteForm(modal) {
|
|
917
|
+
const selectedQuery = getSelectedDocumentInsertQuery(modal);
|
|
918
|
+
const note = String(selectedQuery?.notes ?? "").trim();
|
|
919
|
+
const disabledAttribute = modal.loading || modal.submitting || !(modal.queries ?? []).length
|
|
920
|
+
? 'disabled aria-disabled="true"'
|
|
921
|
+
: "";
|
|
922
|
+
|
|
923
|
+
return `
|
|
924
|
+
<form class="space-y-5" data-form="document-insert-note">
|
|
925
|
+
${renderDocumentInsertQuerySelect(modal, "No saved queries with notes are available for this database.")}
|
|
926
|
+
${
|
|
927
|
+
note
|
|
928
|
+
? `
|
|
929
|
+
<div class="space-y-2">
|
|
930
|
+
<div class="text-[10px] font-mono uppercase tracking-[0.22em] text-on-surface-variant/60">
|
|
931
|
+
Note Preview
|
|
932
|
+
</div>
|
|
933
|
+
<pre class="max-h-64 overflow-auto whitespace-pre-wrap border border-outline-variant/10 bg-surface-container-lowest px-4 py-3 text-sm leading-6 text-on-surface custom-scrollbar">${escapeHtml(
|
|
934
|
+
note
|
|
935
|
+
)}</pre>
|
|
936
|
+
</div>
|
|
937
|
+
`
|
|
938
|
+
: ""
|
|
939
|
+
}
|
|
940
|
+
${renderError(modal.error)}
|
|
941
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
942
|
+
<button class="standard-button" data-action="close-modal" type="button">Cancel</button>
|
|
943
|
+
<button class="signature-button" type="submit" ${disabledAttribute}>
|
|
944
|
+
${modal.submitting ? "Inserting..." : "Insert Note"}
|
|
945
|
+
</button>
|
|
946
|
+
</div>
|
|
947
|
+
</form>
|
|
948
|
+
`;
|
|
949
|
+
}
|
|
950
|
+
|
|
809
951
|
function renderQueryExportPreview(lines = []) {
|
|
810
952
|
return lines.map((line) => `<span class="block whitespace-pre">${escapeHtml(line)}</span>`).join("");
|
|
811
953
|
}
|
|
@@ -888,7 +1030,7 @@ function renderTextExportModal(modal, action) {
|
|
|
888
1030
|
.join("")}
|
|
889
1031
|
</div>
|
|
890
1032
|
${renderError(modal.error)}
|
|
891
|
-
<div class="flex justify-
|
|
1033
|
+
<div class="flex justify-start">
|
|
892
1034
|
<button class="standard-button" data-action="close-modal" type="button">
|
|
893
1035
|
Cancel
|
|
894
1036
|
</button>
|
|
@@ -911,23 +1053,47 @@ function getCopyColumnResult(state, modal) {
|
|
|
911
1053
|
|
|
912
1054
|
function renderCopyColumnPreview(modal, state) {
|
|
913
1055
|
const result = getCopyColumnResult(state, modal);
|
|
1056
|
+
const isMarkdownTodo = isMarkdownTodoCopyColumnMode(modal.copyMode);
|
|
914
1057
|
const separator = Boolean(modal.lineBreaks) && !isMarkdownTodoCopyColumnMode(modal.copyMode)
|
|
915
1058
|
? "\n"
|
|
916
1059
|
: String(modal.separator ?? ",");
|
|
917
1060
|
const wrapper = String(modal.wrapper ?? '"');
|
|
918
|
-
const preview =
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1061
|
+
const preview = isMarkdownTodo
|
|
1062
|
+
? modal.editedText ?? buildCopyColumnText({
|
|
1063
|
+
result,
|
|
1064
|
+
columnName: modal.columnName,
|
|
1065
|
+
copyMode: modal.copyMode,
|
|
1066
|
+
separator: "\n",
|
|
1067
|
+
wrapper,
|
|
1068
|
+
}).text
|
|
1069
|
+
: buildCopyColumnPreviewText({
|
|
1070
|
+
result,
|
|
1071
|
+
columnName: modal.columnName,
|
|
1072
|
+
copyMode: modal.copyMode,
|
|
1073
|
+
separator,
|
|
1074
|
+
wrapper,
|
|
1075
|
+
maxRows: 4,
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
if (!preview && !isMarkdownTodo) {
|
|
928
1079
|
return "";
|
|
929
1080
|
}
|
|
930
1081
|
|
|
1082
|
+
if (isMarkdownTodo) {
|
|
1083
|
+
return `
|
|
1084
|
+
<label class="block space-y-2">
|
|
1085
|
+
<span class="text-[10px] font-mono uppercase tracking-[0.22em] text-on-surface-variant/60">
|
|
1086
|
+
Editable Preview
|
|
1087
|
+
</span>
|
|
1088
|
+
<textarea
|
|
1089
|
+
class="copy-column-preview copy-column-preview--editable custom-scrollbar"
|
|
1090
|
+
name="editedText"
|
|
1091
|
+
spellcheck="true"
|
|
1092
|
+
>${escapeHtml(preview)}</textarea>
|
|
1093
|
+
</label>
|
|
1094
|
+
`;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
931
1097
|
return `
|
|
932
1098
|
<div class="space-y-2">
|
|
933
1099
|
<div class="text-[10px] font-mono uppercase tracking-[0.22em] text-on-surface-variant/60">
|
|
@@ -977,7 +1143,7 @@ function renderCopyColumnFormatField({ label, name, value = "" }) {
|
|
|
977
1143
|
`;
|
|
978
1144
|
}
|
|
979
1145
|
|
|
980
|
-
function renderCopyColumnModal(modal, state) {
|
|
1146
|
+
export function renderCopyColumnModal(modal, state) {
|
|
981
1147
|
const result = getCopyColumnResult(state, modal);
|
|
982
1148
|
const rows = result?.rows ?? [];
|
|
983
1149
|
const valueCount = modal.copyMode === "first-10" ? Math.min(rows.length, 10) : rows.length;
|
|
@@ -1029,7 +1195,7 @@ function renderCopyColumnModal(modal, state) {
|
|
|
1029
1195
|
${formatFieldsMarkup}
|
|
1030
1196
|
${renderCopyColumnPreview(modal, state)}
|
|
1031
1197
|
${renderError(modal.error)}
|
|
1032
|
-
<div class="flex flex-wrap items-center justify-
|
|
1198
|
+
<div class="flex flex-wrap items-center justify-between gap-3 pt-2">
|
|
1033
1199
|
<button
|
|
1034
1200
|
class="standard-button"
|
|
1035
1201
|
data-action="close-modal"
|
|
@@ -1038,24 +1204,41 @@ function renderCopyColumnModal(modal, state) {
|
|
|
1038
1204
|
>
|
|
1039
1205
|
Cancel
|
|
1040
1206
|
</button>
|
|
1041
|
-
<
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1207
|
+
<div class="flex flex-wrap items-center justify-end gap-3">
|
|
1208
|
+
<button
|
|
1209
|
+
class="standard-button"
|
|
1210
|
+
name="intent"
|
|
1211
|
+
type="submit"
|
|
1212
|
+
value="export"
|
|
1213
|
+
${disabledAttribute}
|
|
1214
|
+
>
|
|
1215
|
+
${modal.submitting ? "Working..." : `Export as ${exportMetadata.extension.toUpperCase()}`}
|
|
1216
|
+
</button>
|
|
1217
|
+
${
|
|
1218
|
+
isMarkdownTodo
|
|
1219
|
+
? `
|
|
1220
|
+
<button
|
|
1221
|
+
class="standard-button"
|
|
1222
|
+
name="intent"
|
|
1223
|
+
type="submit"
|
|
1224
|
+
value="document"
|
|
1225
|
+
${disabledAttribute}
|
|
1226
|
+
>
|
|
1227
|
+
${modal.submitting ? "Working..." : "Export to document folder"}
|
|
1228
|
+
</button>
|
|
1229
|
+
`
|
|
1230
|
+
: ""
|
|
1231
|
+
}
|
|
1232
|
+
<button
|
|
1233
|
+
class="signature-button"
|
|
1234
|
+
name="intent"
|
|
1235
|
+
type="submit"
|
|
1236
|
+
value="copy"
|
|
1237
|
+
${disabledAttribute}
|
|
1238
|
+
>
|
|
1239
|
+
${modal.submitting ? "Working..." : "Copy"}
|
|
1240
|
+
</button>
|
|
1241
|
+
</div>
|
|
1059
1242
|
</div>
|
|
1060
1243
|
</form>
|
|
1061
1244
|
`;
|
|
@@ -1230,7 +1413,7 @@ function renderTableDesignerConstraintsModal(modal, state) {
|
|
|
1230
1413
|
<div class="table-designer-constraints-modal__empty">
|
|
1231
1414
|
No active table designer draft.
|
|
1232
1415
|
</div>
|
|
1233
|
-
<div class="flex items-center justify-
|
|
1416
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
1234
1417
|
<button class="standard-button" data-action="close-modal" type="button">Close</button>
|
|
1235
1418
|
</div>
|
|
1236
1419
|
`;
|
|
@@ -1291,7 +1474,7 @@ function renderTableDesignerConstraintsModal(modal, state) {
|
|
|
1291
1474
|
: "No multi-column or partial unique constraints detected.",
|
|
1292
1475
|
body: uniqueConstraints.map(renderTableDesignerUniqueConstraintEditor).join(""),
|
|
1293
1476
|
})}
|
|
1294
|
-
<div class="flex items-center justify-
|
|
1477
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
1295
1478
|
<button class="standard-button" data-action="close-modal" type="button">Close</button>
|
|
1296
1479
|
</div>
|
|
1297
1480
|
</div>
|
|
@@ -1336,7 +1519,7 @@ function renderCreateMediaTaggingMappingTableForm(modal, state) {
|
|
|
1336
1519
|
${renderSqlPreviewField(MEDIA_TAGGING_DEFAULT_MAPPING_TABLE_SQL)}
|
|
1337
1520
|
</div>
|
|
1338
1521
|
${renderError(modal.error)}
|
|
1339
|
-
<div class="flex items-center justify-
|
|
1522
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
1340
1523
|
<button
|
|
1341
1524
|
class="standard-button"
|
|
1342
1525
|
data-action="close-modal"
|
|
@@ -1400,7 +1583,7 @@ function renderCreateMediaTaggingTagTableForm(modal, state) {
|
|
|
1400
1583
|
${renderSqlPreviewField(MEDIA_TAGGING_DEFAULT_TAG_TABLE_SQL)}
|
|
1401
1584
|
</div>
|
|
1402
1585
|
${renderError(modal.error)}
|
|
1403
|
-
<div class="flex items-center justify-
|
|
1586
|
+
<div class="flex items-center justify-between gap-3 pt-2">
|
|
1404
1587
|
<button
|
|
1405
1588
|
class="standard-button"
|
|
1406
1589
|
data-action="close-modal"
|
|
@@ -1479,6 +1662,21 @@ export function renderModal(state) {
|
|
|
1479
1662
|
title: "Delete Query",
|
|
1480
1663
|
body: renderDeleteQueryHistoryForm(modal),
|
|
1481
1664
|
},
|
|
1665
|
+
"delete-document": {
|
|
1666
|
+
eyebrow: "Documents // Confirm deletion",
|
|
1667
|
+
title: "Delete Document",
|
|
1668
|
+
body: renderDeleteDocumentForm(modal),
|
|
1669
|
+
},
|
|
1670
|
+
"document-insert-table": {
|
|
1671
|
+
eyebrow: "Documents // Saved query output",
|
|
1672
|
+
title: "Insert Table",
|
|
1673
|
+
body: renderDocumentInsertTableForm(modal),
|
|
1674
|
+
},
|
|
1675
|
+
"document-insert-note": {
|
|
1676
|
+
eyebrow: "Documents // Saved query notes",
|
|
1677
|
+
title: "Insert Note",
|
|
1678
|
+
body: renderDocumentInsertNoteForm(modal),
|
|
1679
|
+
},
|
|
1482
1680
|
"query-export": {
|
|
1483
1681
|
eyebrow: "SQL Editor // Export query result",
|
|
1484
1682
|
title: "Export Query",
|
|
@@ -1521,6 +1719,8 @@ export function renderModal(state) {
|
|
|
1521
1719
|
<div class="fixed inset-0 z-50 flex items-center justify-center bg-background/85 px-4 backdrop-blur-sm">
|
|
1522
1720
|
<div class="w-full ${
|
|
1523
1721
|
modal.kind === "chart-editor" ||
|
|
1722
|
+
modal.kind === "document-insert-table" ||
|
|
1723
|
+
modal.kind === "document-insert-note" ||
|
|
1524
1724
|
modal.kind === "row-update-preview" ||
|
|
1525
1725
|
modal.kind === "table-designer-constraints"
|
|
1526
1726
|
? "max-w-3xl"
|
|
@@ -1,33 +1,31 @@
|
|
|
1
|
-
import { escapeHtml } from
|
|
1
|
+
import { escapeHtml } from '../utils/format.js';
|
|
2
2
|
|
|
3
|
-
export function renderPageHeader({ eyebrow =
|
|
4
|
-
|
|
3
|
+
export function renderPageHeader({ eyebrow = '', title, subtitle = '', actions = '' }) {
|
|
4
|
+
return `
|
|
5
5
|
<div class="mb-10 flex flex-wrap items-end justify-between gap-6">
|
|
6
6
|
<div>
|
|
7
7
|
${
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
eyebrow
|
|
9
|
+
? `
|
|
10
10
|
<div class="page-eyebrow">
|
|
11
11
|
<span class="text-[#FCE300] text-xs font-mono font-bold tracking-widest uppercase">${escapeHtml(
|
|
12
|
-
|
|
12
|
+
eyebrow,
|
|
13
13
|
)}</span>
|
|
14
14
|
<div class="page-eyebrow-line"></div>
|
|
15
15
|
</div>
|
|
16
16
|
`
|
|
17
|
-
|
|
17
|
+
: ''
|
|
18
18
|
}
|
|
19
|
-
<h1 class="text-5xl font-headline font-bold text-[#FCE300] tracking-tighter uppercase">${escapeHtml(
|
|
20
|
-
title
|
|
21
|
-
)}</h1>
|
|
19
|
+
<h1 class="text-5xl font-headline font-bold text-[#FCE300] tracking-tighter uppercase">${escapeHtml(title)}</h1>
|
|
22
20
|
${
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
subtitle
|
|
22
|
+
? `<p class="text-xs font-mono text-on-surface/40 mt-1 uppercase tracking-widest">${escapeHtml(
|
|
23
|
+
subtitle,
|
|
24
|
+
)}</p>`
|
|
25
|
+
: ''
|
|
28
26
|
}
|
|
29
27
|
</div>
|
|
30
|
-
${actions ? `<div class="flex gap-3">${actions}</div>` :
|
|
28
|
+
${actions ? `<div class="flex gap-3">${actions}</div>` : ''}
|
|
31
29
|
</div>
|
|
32
30
|
`;
|
|
33
31
|
}
|