@protobase/ui 0.19.5 → 0.19.7
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/dist/account/account-section.js +2 -2
- package/dist/account/account-security-page.js +2 -2
- package/dist/account/backup-codes.js +1 -1
- package/dist/account/passkeys-section.js +2 -2
- package/dist/account/password-dialog.js +1 -1
- package/dist/account/sign-in-policy-form.js +2 -2
- package/dist/account/sign-in-policy-page.js +2 -2
- package/dist/account/sign-in-providers-section.js +1 -1
- package/dist/account/staff-sign-in-log.js +3 -3
- package/dist/account/two-factor-setup.js +6 -6
- package/dist/action-card/action-card.js +1 -1
- package/dist/activity-chart/activity-chart.js +2 -2
- package/dist/app/delete/dialogs.js +3 -3
- package/dist/app/displays/display-controls.js +1 -1
- package/dist/app/displays/display-frame.js +1 -1
- package/dist/app/displays/list-cards.js +1 -1
- package/dist/app/displays/map-display.js +1 -1
- package/dist/app/displays/record-card.js +1 -1
- package/dist/app/embedded-list/embedded-list.js +2 -2
- package/dist/app/error-banner.js +1 -1
- package/dist/app/export/builder-port.js +54 -0
- package/dist/app/export/builder.js +61 -0
- package/dist/app/export/cells.js +93 -0
- package/dist/app/export/csv.js +17 -0
- package/dist/app/export/export-dialog.js +235 -0
- package/dist/app/export/export-options.js +49 -0
- package/dist/app/export/export-worker.d.ts +1 -0
- package/dist/app/export/export-worker.js +9 -0
- package/dist/app/export/run-export.js +62 -0
- package/dist/app/export/sink.js +91 -0
- package/dist/app/export/use-export-flow.js +139 -0
- package/dist/app/export/xlsx.js +91 -0
- package/dist/app/field-editor.js +6 -12
- package/dist/app/file-field.js +4 -4
- package/dist/app/gallery/lightbox.js +2 -2
- package/dist/app/gallery/photo-details.js +1 -1
- package/dist/app/import/import-check-step.js +2 -2
- package/dist/app/import/import-file-step.js +2 -2
- package/dist/app/import/import-mapping-step.js +1 -1
- package/dist/app/import/import-result-step.js +2 -2
- package/dist/app/import/import-select.js +2 -2
- package/dist/app/list-page.js +28 -3
- package/dist/app/meta-gate.js +3 -3
- package/dist/app/pages/blocks/card-frame.js +4 -4
- package/dist/app/pages/blocks/field.js +2 -5
- package/dist/app/pages/blocks/stat.js +2 -2
- package/dist/app/pages/problem.js +1 -1
- package/dist/app/pages/render-node.js +1 -1
- package/dist/app/record-page.js +2 -2
- package/dist/app/record-row/record-row-body.js +3 -3
- package/dist/app/record-row/saved-record-row.js +1 -1
- package/dist/app/related-section.js +1 -1
- package/dist/app/relation-picker.js +1 -1
- package/dist/app/runtime/runtime-update.js +3 -3
- package/dist/app/saved/saved-list.js +1 -1
- package/dist/app/searches/saved-search-rows.js +2 -2
- package/dist/app/searches/saved-search-section.js +1 -1
- package/dist/app/searches/saved-searches.js +1 -1
- package/dist/app/searches/search-controls.js +2 -2
- package/dist/app/searches/search-name-dialog.js +1 -1
- package/dist/app/searches/update-search-dialog.js +16 -19
- package/dist/app/sensitive-field.js +1 -1
- package/dist/app/source-notice.js +3 -3
- package/dist/app/staff-banner.js +1 -1
- package/dist/app-shell/breadcrumb.js +1 -1
- package/dist/app-shell/global-search.js +1 -1
- package/dist/app-shell/page-header.js +1 -1
- package/dist/app-shell/profile-menu.js +3 -3
- package/dist/app-shell/sidebar-group.js +1 -1
- package/dist/app-shell/sidebar-item.js +1 -1
- package/dist/app-shell/sidebar.js +2 -2
- package/dist/assistant-dock/part-view.js +1 -4
- package/dist/assistant-dock/widget-view.js +1 -4
- package/dist/auth/auth-gate.js +2 -2
- package/dist/auth/auth-layout.js +1 -1
- package/dist/auth/code-form.js +2 -2
- package/dist/auth/first-run-page.js +1 -1
- package/dist/auth/forgot-password-form.js +2 -2
- package/dist/auth/provider-sign-in-page.js +1 -1
- package/dist/auth/reset-password-form.js +3 -3
- package/dist/auth/setup-required-form.js +2 -2
- package/dist/auth/setup-required-page.js +1 -1
- package/dist/auth/sign-in-form.js +5 -5
- package/dist/auth/sign-in-prompt.js +2 -2
- package/dist/auth/sign-up-details-form.js +3 -3
- package/dist/auth/sign-up-email-form.js +4 -4
- package/dist/auth/staff-sign-in-form.js +3 -3
- package/dist/auth/two-factor-form.js +5 -5
- package/dist/chat/chat-message.js +1 -1
- package/dist/chat/chat-thread.js +1 -1
- package/dist/data/query-keys.js +7 -0
- package/dist/data-grid/grid-row.js +1 -1
- package/dist/data-grid/header-menu.js +1 -1
- package/dist/data-grid/row-menu.js +1 -1
- package/dist/filter-panel/facet-combobox.js +1 -1
- package/dist/filter-panel/filter-menu.js +1 -1
- package/dist/filter-panel/filter-panel.js +2 -2
- package/dist/inline-child-table/line-menu.js +1 -1
- package/dist/inline-child-table/line-row.js +4 -4
- package/dist/inline-child-table/number-cell.js +1 -1
- package/dist/inline-child-table/totals-footer.js +2 -2
- package/dist/organizations/app-roles-picker.js +1 -1
- package/dist/organizations/invitation-page.js +3 -3
- package/dist/organizations/invitations-page.js +2 -2
- package/dist/organizations/members-page.js +2 -2
- package/dist/organizations/organization-page.js +1 -1
- package/dist/organizations/organizations-page.js +2 -2
- package/dist/package.js +1 -1
- package/dist/plugins/before-sign-in.js +1 -1
- package/dist/plugins/plugin-gate.js +1 -1
- package/dist/plugins/plugin-notice.js +1 -1
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/dialog.js +2 -2
- package/dist/primitives/input.js +1 -1
- package/dist/primitives/menu-select.js +2 -2
- package/dist/primitives/responsive-dialog.js +1 -1
- package/dist/primitives/segmented.js +1 -1
- package/dist/primitives/sheet.js +1 -1
- package/dist/primitives/textarea.js +1 -1
- package/dist/record-view/action-rail.js +1 -1
- package/dist/record-view/field.js +1 -1
- package/dist/record-view/key-facts.js +2 -2
- package/dist/record-view/record-sidebar.js +2 -2
- package/dist/record-view/section.js +2 -2
- package/dist/record-view/spec-table.js +1 -1
- package/dist/shell/assets/app-BRVJlz_E.js +68 -0
- package/dist/shell/assets/export-worker-CVd5saLq.js +2 -0
- package/dist/shell/assets/{index-BzCCIfII.js → index-CafsxSWx.js} +1 -1
- package/dist/shell/assets/index-Cuulz26c.css +2 -0
- package/dist/shell/assets/maplibre-Cb7ks8SG.js +814 -0
- package/dist/shell/assets/{record-map-BK_02Lmk.js → record-map-dXyPrmGg.js} +1 -1
- package/dist/shell/assets/{records-map-Dn72A_l-.js → records-map-bGH18FRn.js} +1 -1
- package/dist/shell/assets/{shared-protobase-ui-B6lrj7eA.js → shared-protobase-ui-e-G14mxb.js} +1 -1
- package/dist/shell/index.html +4 -4
- package/dist/shell/protobase.shell.json +1 -1
- package/dist/side-panel/side-panel.js +1 -1
- package/dist/step-list/step-list.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme.css +2 -0
- package/dist/toasts/toast.js +2 -2
- package/package.json +5 -4
- package/dist/shell/assets/app-CZ4drn7G.js +0 -67
- package/dist/shell/assets/index-BoeKjvo8.css +0 -2
- package/dist/shell/assets/maplibre-BOsAtlAo.js +0 -814
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Zip, ZipDeflate } from "fflate";
|
|
2
|
+
//#region src/app/export/xlsx.ts
|
|
3
|
+
/** The most data rows a sheet holds: Excel's 1,048,576 rows, less the header. */
|
|
4
|
+
const xlsxMaxRows = 1048575;
|
|
5
|
+
const maxCellText = 32767;
|
|
6
|
+
const invalidXml = /[\u0000-\u0008\u000b\u000c\u000e-\u001f]/g;
|
|
7
|
+
const escapeXml = (text) => text.replace(invalidXml, "").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
8
|
+
/** A column's letters: 0 is A, 25 is Z, 26 is AA. */
|
|
9
|
+
const columnLetters = (index) => {
|
|
10
|
+
const letter = String.fromCharCode(65 + index % 26);
|
|
11
|
+
return index < 26 ? letter : columnLetters(Math.floor(index / 26) - 1) + letter;
|
|
12
|
+
};
|
|
13
|
+
const textCell = (ref, text, style = "") => `<c r="${ref}"${style} t="inlineStr"><is><t xml:space="preserve">${escapeXml(text.slice(0, maxCellText))}</t></is></c>`;
|
|
14
|
+
const xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
|
15
|
+
const mainNs = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
16
|
+
const relNs = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
17
|
+
const packageRelNs = "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
18
|
+
const contentTypes = `${xml}<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/></Types>`;
|
|
19
|
+
const rootRels = `${xml}<Relationships xmlns="${packageRelNs}"><Relationship Id="rId1" Type="${relNs}/officeDocument" Target="xl/workbook.xml"/></Relationships>`;
|
|
20
|
+
const workbookRels = `${xml}<Relationships xmlns="${packageRelNs}"><Relationship Id="rId1" Type="${relNs}/worksheet" Target="worksheets/sheet1.xml"/><Relationship Id="rId2" Type="${relNs}/styles" Target="styles.xml"/></Relationships>`;
|
|
21
|
+
const sheetName = (name) => name.replace(/[:\\/?*[\]]/g, " ").slice(0, 31).trim() || "Sheet1";
|
|
22
|
+
const workbook = (name) => `${xml}<workbook xmlns="${mainNs}" xmlns:r="${relNs}"><sheets><sheet name="${escapeXml(sheetName(name))}" sheetId="1" r:id="rId1"/></sheets></workbook>`;
|
|
23
|
+
const styles = (formats) => {
|
|
24
|
+
const numFmts = formats.map((code, index) => `<numFmt numFmtId="${164 + index}" formatCode="${escapeXml(code)}"/>`).join("");
|
|
25
|
+
const xfs = formats.map((_, index) => `<xf numFmtId="${164 + index}" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/>`).join("");
|
|
26
|
+
return `${xml}<styleSheet xmlns="${mainNs}">${formats.length > 0 ? `<numFmts count="${formats.length}">${numFmts}</numFmts>` : ""}<fonts count="2"><font><sz val="11"/><name val="Calibri"/></font><font><b/><sz val="11"/><name val="Calibri"/></font></fonts><fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills><borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="${2 + formats.length}"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/><xf numFmtId="0" fontId="1" fillId="0" borderId="0" xfId="0" applyFont="1"/>${xfs}</cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`;
|
|
27
|
+
};
|
|
28
|
+
const encoder = new TextEncoder();
|
|
29
|
+
/**
|
|
30
|
+
* Writes a one-sheet .xlsx file as it goes, handing each compressed piece to `onChunk`: a bold, frozen header row, then
|
|
31
|
+
* `rows` as often as they come, and `finish` once. Text is written inline in its cell rather than in a table of shared
|
|
32
|
+
* strings, so the writer holds no more than the rows it is given.
|
|
33
|
+
*/
|
|
34
|
+
const createXlsxWriter = (sheet, onChunk) => {
|
|
35
|
+
const zip = new Zip((error, chunk, final) => {
|
|
36
|
+
if (error) throw error;
|
|
37
|
+
onChunk(chunk, final);
|
|
38
|
+
});
|
|
39
|
+
const add = (path, text) => {
|
|
40
|
+
const file = new ZipDeflate(path, { level: 6 });
|
|
41
|
+
zip.add(file);
|
|
42
|
+
file.push(encoder.encode(text), true);
|
|
43
|
+
};
|
|
44
|
+
add("[Content_Types].xml", contentTypes);
|
|
45
|
+
add("_rels/.rels", rootRels);
|
|
46
|
+
add("xl/workbook.xml", workbook(sheet.name));
|
|
47
|
+
add("xl/_rels/workbook.xml.rels", workbookRels);
|
|
48
|
+
const worksheet = new ZipDeflate("xl/worksheets/sheet1.xml", { level: 6 });
|
|
49
|
+
zip.add(worksheet);
|
|
50
|
+
const cols = sheet.widths.map((width, index) => `<col min="${index + 1}" max="${index + 1}" width="${width}" customWidth="1"/>`).join("");
|
|
51
|
+
const frozen = "<sheetViews><sheetView workbookViewId=\"0\"><pane ySplit=\"1\" topLeftCell=\"A2\" activePane=\"bottomLeft\" state=\"frozen\"/></sheetView></sheetViews>";
|
|
52
|
+
const header = `<row r="1">${sheet.headers.map((text, index) => textCell(`${columnLetters(index)}1`, text, " s=\"1\"")).join("")}</row>`;
|
|
53
|
+
worksheet.push(encoder.encode(`${xml}<worksheet xmlns="${mainNs}">${frozen}${cols ? `<cols>${cols}</cols>` : ""}<sheetData>${header}`));
|
|
54
|
+
const letters = sheet.headers.map((_, index) => columnLetters(index));
|
|
55
|
+
const formats = [];
|
|
56
|
+
const styleOf = (format) => {
|
|
57
|
+
const index = formats.indexOf(format);
|
|
58
|
+
if (index >= 0) return index + 2;
|
|
59
|
+
formats.push(format);
|
|
60
|
+
return formats.length + 1;
|
|
61
|
+
};
|
|
62
|
+
const cellXml = (cell, ref) => {
|
|
63
|
+
switch (cell.kind) {
|
|
64
|
+
case "empty": return "";
|
|
65
|
+
case "text": return textCell(ref, cell.value);
|
|
66
|
+
case "boolean": return `<c r="${ref}" t="b"><v>${cell.value ? 1 : 0}</v></c>`;
|
|
67
|
+
case "number": return `<c r="${ref}"${cell.format ? ` s="${styleOf(cell.format)}"` : ""}><v>${cell.value}</v></c>`;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
let rowNumber = 1;
|
|
71
|
+
const rows = (cells) => {
|
|
72
|
+
let text = "";
|
|
73
|
+
for (const row of cells) {
|
|
74
|
+
rowNumber += 1;
|
|
75
|
+
if (rowNumber > 1048576) throw new Error(`A sheet holds at most ${xlsxMaxRows} rows`);
|
|
76
|
+
text += `<row r="${rowNumber}">${row.map((cell, index) => cellXml(cell, `${letters[index]}${rowNumber}`)).join("")}</row>`;
|
|
77
|
+
}
|
|
78
|
+
worksheet.push(encoder.encode(text));
|
|
79
|
+
};
|
|
80
|
+
const finish = () => {
|
|
81
|
+
worksheet.push(encoder.encode("</sheetData></worksheet>"), true);
|
|
82
|
+
add("xl/styles.xml", styles(formats));
|
|
83
|
+
zip.end();
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
rows,
|
|
87
|
+
finish
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
//#endregion
|
|
91
|
+
export { columnLetters, createXlsxWriter, xlsxMaxRows };
|
package/dist/app/field-editor.js
CHANGED
|
@@ -50,7 +50,7 @@ const BuiltInEditor = ({ field, hints, value, stored, relationLabel, relationTo,
|
|
|
50
50
|
})
|
|
51
51
|
});
|
|
52
52
|
if (field.type === "boolean" && locked) return /* @__PURE__ */ jsx("div", {
|
|
53
|
-
className: "py-1.5 text-
|
|
53
|
+
className: "py-1.5 text-muted-foreground",
|
|
54
54
|
children: displayValue(field, stored, hints)
|
|
55
55
|
});
|
|
56
56
|
if (field.type === "boolean") return /* @__PURE__ */ jsx(Switch, {
|
|
@@ -61,7 +61,7 @@ const BuiltInEditor = ({ field, hints, value, stored, relationLabel, relationTo,
|
|
|
61
61
|
if (field.type === "relation") {
|
|
62
62
|
const label = relationLabel ?? String(stored ?? "—");
|
|
63
63
|
return /* @__PURE__ */ jsx("div", {
|
|
64
|
-
className: "py-1.5
|
|
64
|
+
className: "py-1.5",
|
|
65
65
|
children: relationTo ? /* @__PURE__ */ jsx(AppLink, {
|
|
66
66
|
to: relationTo,
|
|
67
67
|
className: "font-medium text-primary-text hover:underline",
|
|
@@ -71,13 +71,13 @@ const BuiltInEditor = ({ field, hints, value, stored, relationLabel, relationTo,
|
|
|
71
71
|
}
|
|
72
72
|
const multiline = Boolean(hints?.multiline) && field.type === "text";
|
|
73
73
|
if (!isEditable(field) || locked) return /* @__PURE__ */ jsx("div", {
|
|
74
|
-
className: cn("py-1.5
|
|
74
|
+
className: cn("py-1.5 tabular-nums", field.type === "decimal" || field.type === "integer" ? "font-medium" : "text-muted-foreground", multiline && "whitespace-pre-line break-words"),
|
|
75
75
|
children: displayValue(field, stored, hints)
|
|
76
76
|
});
|
|
77
77
|
if (field.type === "enum") return /* @__PURE__ */ jsxs("select", {
|
|
78
78
|
value: String(value),
|
|
79
79
|
onChange: (event) => onChange(event.target.value),
|
|
80
|
-
className: "h-8 w-full rounded-md border border-border-strong bg-background px-2
|
|
80
|
+
className: "h-8 w-full rounded-md border border-border-strong bg-background px-2 shadow-sm focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20",
|
|
81
81
|
children: [value === "" && /* @__PURE__ */ jsx("option", {
|
|
82
82
|
value: "",
|
|
83
83
|
children: "Choose..."
|
|
@@ -94,14 +94,8 @@ const BuiltInEditor = ({ field, hints, value, stored, relationLabel, relationTo,
|
|
|
94
94
|
});
|
|
95
95
|
return /* @__PURE__ */ jsx(Input, {
|
|
96
96
|
invalid,
|
|
97
|
-
leading: hints?.prefix ? /* @__PURE__ */ jsx("span", {
|
|
98
|
-
|
|
99
|
-
children: hints.prefix
|
|
100
|
-
}) : void 0,
|
|
101
|
-
trailing: hints?.suffix ? /* @__PURE__ */ jsx("span", {
|
|
102
|
-
className: "text-[13px]",
|
|
103
|
-
children: hints.suffix.trim()
|
|
104
|
-
}) : void 0,
|
|
97
|
+
leading: hints?.prefix ? /* @__PURE__ */ jsx("span", { children: hints.prefix }) : void 0,
|
|
98
|
+
trailing: hints?.suffix ? /* @__PURE__ */ jsx("span", { children: hints.suffix.trim() }) : void 0,
|
|
105
99
|
placeholder,
|
|
106
100
|
className: cn(numeric.has(field.type) && "text-right tabular-nums"),
|
|
107
101
|
value: String(value),
|
package/dist/app/file-field.js
CHANGED
|
@@ -27,11 +27,11 @@ const Thumbnail = ({ value }) => {
|
|
|
27
27
|
const FileSummary = ({ value }) => {
|
|
28
28
|
const shown = fileShown(value);
|
|
29
29
|
if (!shown) return /* @__PURE__ */ jsx("div", {
|
|
30
|
-
className: "py-1.5 text-
|
|
30
|
+
className: "py-1.5 text-muted-foreground",
|
|
31
31
|
children: "—"
|
|
32
32
|
});
|
|
33
33
|
if ("missing" in shown) return /* @__PURE__ */ jsx("div", {
|
|
34
|
-
className: "py-1.5 text-
|
|
34
|
+
className: "py-1.5 text-danger-text",
|
|
35
35
|
children: "The file is missing from storage"
|
|
36
36
|
});
|
|
37
37
|
const url = "url" in shown ? shown.url : void 0;
|
|
@@ -39,7 +39,7 @@ const FileSummary = ({ value }) => {
|
|
|
39
39
|
return /* @__PURE__ */ jsxs("div", {
|
|
40
40
|
className: "flex min-w-0 items-center gap-3 py-1",
|
|
41
41
|
children: [/* @__PURE__ */ jsx(Thumbnail, { value }), /* @__PURE__ */ jsxs("div", {
|
|
42
|
-
className: "min-w-0
|
|
42
|
+
className: "min-w-0",
|
|
43
43
|
children: [url && !url.startsWith("blob:") ? /* @__PURE__ */ jsx("a", {
|
|
44
44
|
href: url,
|
|
45
45
|
target: "_blank",
|
|
@@ -158,7 +158,7 @@ const FileField = ({ field, hints, resource, value, locked, invalid, onChange })
|
|
|
158
158
|
},
|
|
159
159
|
onDragLeave: () => setDragging(false),
|
|
160
160
|
onDrop: drop,
|
|
161
|
-
className: cn("flex items-center gap-3 rounded-md border border-dashed px-3 py-2.5 text-
|
|
161
|
+
className: cn("flex items-center gap-3 rounded-md border border-dashed px-3 py-2.5 text-muted-foreground", dragging ? "border-primary bg-primary/5" : invalid ? "border-danger" : "border-border-strong"),
|
|
162
162
|
children: [
|
|
163
163
|
/* @__PURE__ */ jsx(Upload, { className: "size-4 shrink-0" }),
|
|
164
164
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -77,7 +77,7 @@ const Lightbox = ({ title, photos, index, onIndex, onClose, details, detailsTitl
|
|
|
77
77
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
78
78
|
className: "flex shrink-0 items-center justify-between gap-2 p-3",
|
|
79
79
|
children: [/* @__PURE__ */ jsx("span", {
|
|
80
|
-
className: "rounded-full bg-background/85 px-3 py-1
|
|
80
|
+
className: "rounded-full bg-background/85 px-3 py-1 font-medium tabular-nums text-foreground",
|
|
81
81
|
"aria-live": "polite",
|
|
82
82
|
children: `${index + 1} / ${count}`
|
|
83
83
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -141,7 +141,7 @@ const Lightbox = ({ title, photos, index, onIndex, onClose, details, detailsTitl
|
|
|
141
141
|
"aria-label": detailsTitle,
|
|
142
142
|
className: "min-h-dvh w-[360px] shrink-0 border-l border-border bg-background p-5 text-foreground",
|
|
143
143
|
children: [/* @__PURE__ */ jsx("h2", {
|
|
144
|
-
className: "mb-3 text-[
|
|
144
|
+
className: "mb-3 text-[16px] font-semibold",
|
|
145
145
|
children: detailsTitle
|
|
146
146
|
}), shownDetails]
|
|
147
147
|
}),
|
|
@@ -34,7 +34,7 @@ const PhotoDetails = ({ model, view, photoKey, fields }) => {
|
|
|
34
34
|
resource: model.name,
|
|
35
35
|
key: photoKey
|
|
36
36
|
},
|
|
37
|
-
className: "mt-3 inline-block
|
|
37
|
+
className: "mt-3 inline-block font-medium text-primary-text hover:underline",
|
|
38
38
|
children: `Open ${singular}`
|
|
39
39
|
})] });
|
|
40
40
|
};
|
|
@@ -37,7 +37,7 @@ const ProblemList = ({ rows }) => /* @__PURE__ */ jsxs("ul", {
|
|
|
37
37
|
})]
|
|
38
38
|
});
|
|
39
39
|
const ImportChecking = ({ rows }) => /* @__PURE__ */ jsxs("p", {
|
|
40
|
-
className: "flex items-center gap-2 text-
|
|
40
|
+
className: "flex items-center gap-2 text-muted-foreground",
|
|
41
41
|
role: "status",
|
|
42
42
|
children: [
|
|
43
43
|
/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }),
|
|
@@ -54,7 +54,7 @@ const ImportCheckStep = ({ check, model, resources, views, columns, headers, fil
|
|
|
54
54
|
const view = views[model.name];
|
|
55
55
|
const shown = columns.map((column) => model.fields[column.field]);
|
|
56
56
|
return /* @__PURE__ */ jsxs("div", {
|
|
57
|
-
className: "flex flex-col gap-4
|
|
57
|
+
className: "flex flex-col gap-4",
|
|
58
58
|
children: [
|
|
59
59
|
/* @__PURE__ */ jsx(ImportCounts, {
|
|
60
60
|
label: "Check",
|
|
@@ -8,7 +8,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
8
8
|
const ImportFileStep = ({ file, sheets, sheet, reading, onChoose, onSheet }) => {
|
|
9
9
|
const id = useId();
|
|
10
10
|
return /* @__PURE__ */ jsxs("div", {
|
|
11
|
-
className: "flex flex-col gap-4
|
|
11
|
+
className: "flex flex-col gap-4",
|
|
12
12
|
children: [
|
|
13
13
|
/* @__PURE__ */ jsxs("div", {
|
|
14
14
|
className: "flex flex-col gap-1.5",
|
|
@@ -27,7 +27,7 @@ const ImportFileStep = ({ file, sheets, sheet, reading, onChoose, onSheet }) =>
|
|
|
27
27
|
const chosen = event.target.files?.[0];
|
|
28
28
|
if (chosen) onChoose(chosen);
|
|
29
29
|
},
|
|
30
|
-
className: "
|
|
30
|
+
className: "file:mr-3 file:h-8 file:rounded-md file:border file:border-border-strong file:bg-background file:px-3 file:font-medium file:text-foreground max-sm:file:min-h-11"
|
|
31
31
|
}),
|
|
32
32
|
/* @__PURE__ */ jsx("p", {
|
|
33
33
|
className: "text-xs text-muted-foreground",
|
|
@@ -48,7 +48,7 @@ const ImportMappingStep = ({ flow, model, resources, views, canUpdate }) => {
|
|
|
48
48
|
}));
|
|
49
49
|
const keys = matchFields(model);
|
|
50
50
|
return /* @__PURE__ */ jsxs("div", {
|
|
51
|
-
className: "flex flex-col gap-5
|
|
51
|
+
className: "flex flex-col gap-5",
|
|
52
52
|
children: [
|
|
53
53
|
canUpdate && /* @__PURE__ */ jsxs("div", {
|
|
54
54
|
className: "flex flex-col gap-1.5",
|
|
@@ -10,7 +10,7 @@ const count = (value) => value.toLocaleString("en-IE");
|
|
|
10
10
|
const ImportProgressStep = ({ progress, total, cancelling }) => {
|
|
11
11
|
const done = progress.created + progress.updated + progress.failed;
|
|
12
12
|
return /* @__PURE__ */ jsxs("div", {
|
|
13
|
-
className: "flex flex-col gap-2
|
|
13
|
+
className: "flex flex-col gap-2",
|
|
14
14
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
15
15
|
className: "flex items-baseline justify-between gap-2 text-xs",
|
|
16
16
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -40,7 +40,7 @@ const ImportProgressStep = ({ progress, total, cancelling }) => {
|
|
|
40
40
|
};
|
|
41
41
|
/** What the import did: created, updated, skipped and failed rows, and the rows it did not write with the reasons, to download. */
|
|
42
42
|
const ImportSummary = ({ result, stopped, headers, fileName }) => /* @__PURE__ */ jsxs("div", {
|
|
43
|
-
className: "flex flex-col gap-4
|
|
43
|
+
className: "flex flex-col gap-4",
|
|
44
44
|
children: [
|
|
45
45
|
stopped !== void 0 && /* @__PURE__ */ jsx(ErrorBanner, {
|
|
46
46
|
title: "The import stopped. The rows counted below were saved.",
|
|
@@ -10,7 +10,7 @@ const ImportSelect = ({ label, name, value, options, onChange, help, className }
|
|
|
10
10
|
children: [
|
|
11
11
|
/* @__PURE__ */ jsx("label", {
|
|
12
12
|
htmlFor: id,
|
|
13
|
-
className: "
|
|
13
|
+
className: "font-medium",
|
|
14
14
|
children: label
|
|
15
15
|
}),
|
|
16
16
|
/* @__PURE__ */ jsx("select", {
|
|
@@ -18,7 +18,7 @@ const ImportSelect = ({ label, name, value, options, onChange, help, className }
|
|
|
18
18
|
"aria-label": name,
|
|
19
19
|
value,
|
|
20
20
|
onChange: (event) => onChange(event.target.value),
|
|
21
|
-
className: "h-8 w-full min-w-0 rounded-md border border-border-strong bg-background px-2
|
|
21
|
+
className: "h-8 w-full min-w-0 rounded-md border border-border-strong bg-background px-2 shadow-sm focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20 max-sm:min-h-11",
|
|
22
22
|
children: options.map((option) => /* @__PURE__ */ jsx("option", {
|
|
23
23
|
value: option.value,
|
|
24
24
|
children: option.label
|
package/dist/app/list-page.js
CHANGED
|
@@ -29,6 +29,8 @@ import { Sheet } from "../primitives/sheet.js";
|
|
|
29
29
|
import { useDeleteFlow } from "./delete/use-delete-flow.js";
|
|
30
30
|
import { useRestore } from "./delete/use-restore.js";
|
|
31
31
|
import { ImportButton } from "./import/import-button.js";
|
|
32
|
+
import { exportOffered, exportsSelection } from "./export/export-options.js";
|
|
33
|
+
import { useExportFlow } from "./export/use-export-flow.js";
|
|
32
34
|
import { SignInPrompt } from "../auth/sign-in-prompt.js";
|
|
33
35
|
import { ListCards } from "./displays/list-cards.js";
|
|
34
36
|
import { MapDisplay } from "./displays/map-display.js";
|
|
@@ -44,7 +46,7 @@ import { facetNames, filterChips } from "./searches/saved-search.js";
|
|
|
44
46
|
import { SaveSearchButton } from "./searches/save-search-button.js";
|
|
45
47
|
import { SavedSearches } from "./searches/saved-searches.js";
|
|
46
48
|
import { useMemo, useState } from "react";
|
|
47
|
-
import { Plus, SlidersHorizontal } from "lucide-react";
|
|
49
|
+
import { Download, Plus, SlidersHorizontal } from "lucide-react";
|
|
48
50
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
49
51
|
import { createWhere } from "@protobase/schema";
|
|
50
52
|
import { tableDisplay } from "@protobase/schema/internal";
|
|
@@ -272,6 +274,23 @@ const LoadedList = ({ model, address, scope, heading }) => {
|
|
|
272
274
|
chips: filterChips(model, view, filterText, facetNames(config))
|
|
273
275
|
});
|
|
274
276
|
const importButton = !scope && /* @__PURE__ */ jsx(ImportButton, { model });
|
|
277
|
+
const exportFlow = useExportFlow({
|
|
278
|
+
model,
|
|
279
|
+
view,
|
|
280
|
+
resources: meta.resources,
|
|
281
|
+
views: meta.views,
|
|
282
|
+
plural,
|
|
283
|
+
filter: loadFilter,
|
|
284
|
+
orderBy
|
|
285
|
+
});
|
|
286
|
+
const exportButton = exportOffered(view) && /* @__PURE__ */ jsxs(Button, {
|
|
287
|
+
onClick: () => exportFlow.open(),
|
|
288
|
+
...!desktop && {
|
|
289
|
+
"aria-label": "Export",
|
|
290
|
+
title: "Export"
|
|
291
|
+
},
|
|
292
|
+
children: [/* @__PURE__ */ jsx(Download, { className: "size-3.5" }), desktop && "Export"]
|
|
293
|
+
});
|
|
275
294
|
const displaySwitch = (menu) => /* @__PURE__ */ jsx(DisplaySwitch, {
|
|
276
295
|
view,
|
|
277
296
|
value: display?.name ?? tableDisplay,
|
|
@@ -300,11 +319,14 @@ const LoadedList = ({ model, address, scope, heading }) => {
|
|
|
300
319
|
available: (row) => rowAllows(row, "delete"),
|
|
301
320
|
onSelect: (row) => void remove.start(target(row))
|
|
302
321
|
}] : []],
|
|
303
|
-
bulkActions:
|
|
322
|
+
bulkActions: [...exportOffered(view) && exportsSelection(model) ? [{
|
|
323
|
+
label: (count) => `Export ${count}`,
|
|
324
|
+
onRun: (rows) => exportFlow.open(rows)
|
|
325
|
+
}] : [], ...can(permissions, "delete") ? [{
|
|
304
326
|
label: (count) => `Delete ${count}`,
|
|
305
327
|
destructive: true,
|
|
306
328
|
onRun: (rows) => remove.startBulk(rows.map(target))
|
|
307
|
-
}] : [],
|
|
329
|
+
}] : []],
|
|
308
330
|
rowNumbers: false,
|
|
309
331
|
pinKey: auth.kind === "signed-in" ? pinnedStorageKey(auth.user.id, resource) : void 0,
|
|
310
332
|
scroll: "parent",
|
|
@@ -344,6 +366,7 @@ const LoadedList = ({ model, address, scope, heading }) => {
|
|
|
344
366
|
className: "flex min-h-0 flex-1 flex-col gap-3 px-5 py-4",
|
|
345
367
|
children: [
|
|
346
368
|
remove.dialogs,
|
|
369
|
+
exportFlow.dialogs,
|
|
347
370
|
/* @__PURE__ */ jsx(PageHeader, {
|
|
348
371
|
title: heading?.title ?? plural,
|
|
349
372
|
subtitle: heading ? heading.subtitle : view?.help,
|
|
@@ -352,10 +375,12 @@ const LoadedList = ({ model, address, scope, heading }) => {
|
|
|
352
375
|
displaySwitch(false),
|
|
353
376
|
saveSearch,
|
|
354
377
|
importButton,
|
|
378
|
+
exportButton,
|
|
355
379
|
createButton
|
|
356
380
|
] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
357
381
|
saveSearch,
|
|
358
382
|
importButton,
|
|
383
|
+
exportButton,
|
|
359
384
|
createButton
|
|
360
385
|
] })
|
|
361
386
|
}),
|
package/dist/app/meta-gate.js
CHANGED
|
@@ -19,10 +19,10 @@ const Notice = ({ title, children }) => /* @__PURE__ */ jsx("div", {
|
|
|
19
19
|
children: /* @__PURE__ */ jsxs("div", {
|
|
20
20
|
className: "max-w-md text-center",
|
|
21
21
|
children: [/* @__PURE__ */ jsx("h1", {
|
|
22
|
-
className: "text-[
|
|
22
|
+
className: "text-[16px] font-semibold",
|
|
23
23
|
children: title
|
|
24
24
|
}), /* @__PURE__ */ jsx("p", {
|
|
25
|
-
className: "mt-1 text-
|
|
25
|
+
className: "mt-1 text-muted-foreground",
|
|
26
26
|
children
|
|
27
27
|
})]
|
|
28
28
|
})
|
|
@@ -69,7 +69,7 @@ const WithSources = ({ meta, children }) => {
|
|
|
69
69
|
const MetaGate = ({ children }) => {
|
|
70
70
|
const meta = useMeta();
|
|
71
71
|
if (meta.isPending) return /* @__PURE__ */ jsxs("div", {
|
|
72
|
-
className: "flex h-full min-h-48 items-center justify-center gap-2 text-
|
|
72
|
+
className: "flex h-full min-h-48 items-center justify-center gap-2 text-muted-foreground",
|
|
73
73
|
children: [/* @__PURE__ */ jsx(Spinner, {}), " Loading"]
|
|
74
74
|
});
|
|
75
75
|
if (meta.error) return /* @__PURE__ */ jsx(Notice, {
|
|
@@ -10,10 +10,10 @@ const CardFrame = ({ title, description, actions, className, bodyClassName, chil
|
|
|
10
10
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
11
11
|
className: "min-w-0",
|
|
12
12
|
children: [title && /* @__PURE__ */ jsx("h2", {
|
|
13
|
-
className: "text-[
|
|
13
|
+
className: "text-[16px] font-semibold tracking-tight",
|
|
14
14
|
children: title
|
|
15
15
|
}), description && /* @__PURE__ */ jsx("p", {
|
|
16
|
-
className: "mt-0.5 text-
|
|
16
|
+
className: "mt-0.5 text-muted-foreground",
|
|
17
17
|
children: description
|
|
18
18
|
})]
|
|
19
19
|
}), actions && /* @__PURE__ */ jsx("div", {
|
|
@@ -21,13 +21,13 @@ const CardFrame = ({ title, description, actions, className, bodyClassName, chil
|
|
|
21
21
|
children: actions
|
|
22
22
|
})]
|
|
23
23
|
}), /* @__PURE__ */ jsx("div", {
|
|
24
|
-
className: cn("min-w-0 flex-1 p-4
|
|
24
|
+
className: cn("min-w-0 flex-1 p-4", bodyClassName),
|
|
25
25
|
children
|
|
26
26
|
})]
|
|
27
27
|
});
|
|
28
28
|
/** A short line in place of content: nothing to show, or not loaded yet. */
|
|
29
29
|
const Quiet = ({ children }) => /* @__PURE__ */ jsx("p", {
|
|
30
|
-
className: "text-
|
|
30
|
+
className: "text-muted-foreground",
|
|
31
31
|
children
|
|
32
32
|
});
|
|
33
33
|
//#endregion
|
|
@@ -25,10 +25,7 @@ const FieldBlock = ({ node }) => {
|
|
|
25
25
|
value: value.value,
|
|
26
26
|
format
|
|
27
27
|
});
|
|
28
|
-
if (label === false) return /* @__PURE__ */ jsx("div", {
|
|
29
|
-
className: "text-[13px]",
|
|
30
|
-
children: shown
|
|
31
|
-
});
|
|
28
|
+
if (label === false) return /* @__PURE__ */ jsx("div", { children: shown });
|
|
32
29
|
const text = label ?? fieldLabel(name, value.state === "ready" ? views[value.model.name]?.fields[value.field.name]?.label : void 0);
|
|
33
30
|
return /* @__PURE__ */ jsxs("div", {
|
|
34
31
|
className: "min-w-0",
|
|
@@ -36,7 +33,7 @@ const FieldBlock = ({ node }) => {
|
|
|
36
33
|
className: "text-xs text-muted-foreground",
|
|
37
34
|
children: text
|
|
38
35
|
}), /* @__PURE__ */ jsx("div", {
|
|
39
|
-
className: "mt-0.5 truncate
|
|
36
|
+
className: "mt-0.5 truncate",
|
|
40
37
|
children: shown
|
|
41
38
|
})]
|
|
42
39
|
});
|
|
@@ -14,7 +14,7 @@ const Count = ({ model, filter }) => {
|
|
|
14
14
|
const count = useCount(model, filter);
|
|
15
15
|
if (count.isPending) return /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-16" });
|
|
16
16
|
if (count.error) return /* @__PURE__ */ jsx("span", {
|
|
17
|
-
className: "text-
|
|
17
|
+
className: "text-danger-text",
|
|
18
18
|
children: "Could not count"
|
|
19
19
|
});
|
|
20
20
|
return /* @__PURE__ */ jsx(AppLink, {
|
|
@@ -54,7 +54,7 @@ const StatBlock = ({ node }) => {
|
|
|
54
54
|
bodyClassName: "flex flex-col",
|
|
55
55
|
children: [
|
|
56
56
|
/* @__PURE__ */ jsx("p", {
|
|
57
|
-
className: "text-
|
|
57
|
+
className: "text-muted-foreground break-words",
|
|
58
58
|
children: label
|
|
59
59
|
}),
|
|
60
60
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -3,7 +3,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
3
3
|
/** A warning in place of something the app cannot draw, such as a component no one registered. */
|
|
4
4
|
const Problem = ({ children }) => /* @__PURE__ */ jsx("div", {
|
|
5
5
|
role: "alert",
|
|
6
|
-
className: "rounded-lg border border-dashed border-warning bg-warning-soft p-3 text-
|
|
6
|
+
className: "rounded-lg border border-dashed border-warning bg-warning-soft p-3 text-warning-text",
|
|
7
7
|
children
|
|
8
8
|
});
|
|
9
9
|
//#endregion
|
|
@@ -49,7 +49,7 @@ const renderChildren = (children) => {
|
|
|
49
49
|
const [first] = run;
|
|
50
50
|
if (!isInline(first)) return /* @__PURE__ */ jsx(RenderNode, { node: first }, index);
|
|
51
51
|
return /* @__PURE__ */ jsx("p", {
|
|
52
|
-
className: "
|
|
52
|
+
className: "leading-6",
|
|
53
53
|
children: run.map((child, position) => typeof child === "string" ? /* @__PURE__ */ jsx(Fragment, { children: child }, position) : /* @__PURE__ */ jsx(RenderNode, { node: child }, position))
|
|
54
54
|
}, index);
|
|
55
55
|
});
|
package/dist/app/record-page.js
CHANGED
|
@@ -323,7 +323,7 @@ const LoadedRecord = ({ model, recordKey, stored }) => {
|
|
|
323
323
|
})
|
|
324
324
|
}),
|
|
325
325
|
shown !== "form" && offersEdit && editor.dirty && /* @__PURE__ */ jsxs("div", {
|
|
326
|
-
className: "mt-4 flex items-center justify-between gap-3 rounded-lg border bg-surface px-3 py-2
|
|
326
|
+
className: "mt-4 flex items-center justify-between gap-3 rounded-lg border bg-surface px-3 py-2",
|
|
327
327
|
role: "status",
|
|
328
328
|
children: [/* @__PURE__ */ jsx("span", { children: "You have unsaved changes to this record." }), /* @__PURE__ */ jsxs("span", {
|
|
329
329
|
className: "flex gap-2",
|
|
@@ -339,7 +339,7 @@ const LoadedRecord = ({ model, recordKey, stored }) => {
|
|
|
339
339
|
})]
|
|
340
340
|
}),
|
|
341
341
|
shown === "form" && editor.restored && /* @__PURE__ */ jsxs("div", {
|
|
342
|
-
className: "mt-4 flex items-center justify-between gap-3 rounded-lg border bg-surface px-3 py-2
|
|
342
|
+
className: "mt-4 flex items-center justify-between gap-3 rounded-lg border bg-surface px-3 py-2",
|
|
343
343
|
role: "status",
|
|
344
344
|
children: [/* @__PURE__ */ jsx("span", { children: "Your unsaved changes were restored." }), /* @__PURE__ */ jsxs("span", {
|
|
345
345
|
className: "flex gap-2",
|
|
@@ -68,7 +68,7 @@ const RecordRowBody = ({ model, view, filter, sort = "", display: named, limit,
|
|
|
68
68
|
showChips && chips.length > 0 || total !== void 0 || note ? /* @__PURE__ */ jsxs("div", {
|
|
69
69
|
className: "flex flex-wrap items-center justify-between gap-2",
|
|
70
70
|
children: [showChips && chips.length > 0 ? /* @__PURE__ */ jsx(FilterChipList, { chips }) : /* @__PURE__ */ jsx("span", {}), /* @__PURE__ */ jsxs("p", {
|
|
71
|
-
className: "flex flex-wrap gap-x-3 text-
|
|
71
|
+
className: "flex flex-wrap gap-x-3 text-muted-foreground",
|
|
72
72
|
children: [note && /* @__PURE__ */ jsx("span", { children: note }), total !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
73
73
|
className: "tabular-nums",
|
|
74
74
|
children: `${total.toLocaleString("en-GB")} ${total === 1 ? singular : plural.toLowerCase()}`
|
|
@@ -79,7 +79,7 @@ const RecordRowBody = ({ model, view, filter, sort = "", display: named, limit,
|
|
|
79
79
|
title: "Could not load",
|
|
80
80
|
error: rows.error
|
|
81
81
|
}) : !source || source.total === 0 ? /* @__PURE__ */ jsx("p", {
|
|
82
|
-
className: "text-
|
|
82
|
+
className: "text-muted-foreground",
|
|
83
83
|
children: empty ?? `No ${plural.toLowerCase()} match.`
|
|
84
84
|
}) : /* @__PURE__ */ jsx(RecordRow, {
|
|
85
85
|
model,
|
|
@@ -98,7 +98,7 @@ const RecordRowBody = ({ model, view, filter, sort = "", display: named, limit,
|
|
|
98
98
|
resource: list
|
|
99
99
|
}),
|
|
100
100
|
onClick: viewAll?.onOpen,
|
|
101
|
-
className: "flex items-center gap-1 self-end
|
|
101
|
+
className: "flex items-center gap-1 self-end font-medium text-primary-text hover:underline",
|
|
102
102
|
children: [viewAll?.label ?? /* @__PURE__ */ jsxs(Fragment$1, { children: ["View all ", /* @__PURE__ */ jsx("span", {
|
|
103
103
|
className: "sr-only",
|
|
104
104
|
children: plural.toLowerCase()
|
|
@@ -25,7 +25,7 @@ const SavedRecordRow = ({ model, view, empty, ...props }) => {
|
|
|
25
25
|
if (!saved.data) return /* @__PURE__ */ jsx(Skeleton, { className: "h-24" });
|
|
26
26
|
const scope = savedScope(listed.model, saved.data);
|
|
27
27
|
if (!scope) return /* @__PURE__ */ jsx("p", {
|
|
28
|
-
className: "text-
|
|
28
|
+
className: "text-muted-foreground",
|
|
29
29
|
children: empty ?? `No ${plural} yet.`
|
|
30
30
|
});
|
|
31
31
|
return /* @__PURE__ */ jsx(RecordRowBody, {
|
|
@@ -62,7 +62,7 @@ const Loading = () => /* @__PURE__ */ jsx("div", {
|
|
|
62
62
|
children: Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }, index))
|
|
63
63
|
});
|
|
64
64
|
const Empty = ({ text }) => /* @__PURE__ */ jsx("p", {
|
|
65
|
-
className: "text-
|
|
65
|
+
className: "text-muted-foreground",
|
|
66
66
|
children: text ?? "Nothing here yet."
|
|
67
67
|
});
|
|
68
68
|
/**
|
|
@@ -38,7 +38,7 @@ const RelationPicker = ({ target, view, value, label, invalid, onChange }) => {
|
|
|
38
38
|
onChange: (event) => setText(event.target.value)
|
|
39
39
|
}), open && /* @__PURE__ */ jsxs("ul", {
|
|
40
40
|
role: "listbox",
|
|
41
|
-
className: "absolute z-30 mt-1 max-h-60 w-full overflow-y-auto rounded-md border bg-background py-1
|
|
41
|
+
className: "absolute z-30 mt-1 max-h-60 w-full overflow-y-auto rounded-md border bg-background py-1 shadow-pop",
|
|
42
42
|
children: [
|
|
43
43
|
options.data?.items.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
|
|
44
44
|
type: "button",
|
|
@@ -7,7 +7,7 @@ import { ArrowUpCircle } from "lucide-react";
|
|
|
7
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
//#region src/app/runtime/runtime-update.tsx
|
|
9
9
|
const Row = ({ label, value }) => /* @__PURE__ */ jsxs("div", {
|
|
10
|
-
className: "flex justify-between gap-4 py-1
|
|
10
|
+
className: "flex justify-between gap-4 py-1",
|
|
11
11
|
children: [/* @__PURE__ */ jsx("span", {
|
|
12
12
|
className: "text-muted-foreground",
|
|
13
13
|
children: label
|
|
@@ -60,11 +60,11 @@ const RuntimeUpdate = ({ client }) => {
|
|
|
60
60
|
}),
|
|
61
61
|
error !== void 0 && /* @__PURE__ */ jsx("p", {
|
|
62
62
|
role: "alert",
|
|
63
|
-
className: "mt-3 text-
|
|
63
|
+
className: "mt-3 text-danger-text",
|
|
64
64
|
children: updateErrorText(error)
|
|
65
65
|
}),
|
|
66
66
|
checkError !== void 0 && /* @__PURE__ */ jsx("p", {
|
|
67
|
-
className: "mt-3 text-
|
|
67
|
+
className: "mt-3 text-muted-foreground",
|
|
68
68
|
children: "The status could not be checked again; this is the last one read."
|
|
69
69
|
})
|
|
70
70
|
]
|
|
@@ -30,7 +30,7 @@ const SavedList = ({ model, view, target, children }) => {
|
|
|
30
30
|
}));
|
|
31
31
|
const scope = savedScope(target, saved.data);
|
|
32
32
|
if (!scope) return frame(/* @__PURE__ */ jsxs("p", {
|
|
33
|
-
className: "py-8 text-center text-
|
|
33
|
+
className: "py-8 text-center text-muted-foreground",
|
|
34
34
|
children: [
|
|
35
35
|
"No ",
|
|
36
36
|
plural.toLowerCase(),
|
|
@@ -25,7 +25,7 @@ const SearchRowItem = ({ model, view, target, targetView, row }) => {
|
|
|
25
25
|
"aria-label": title,
|
|
26
26
|
className: "flex flex-col gap-3 py-4 first:pt-0 last:pb-0",
|
|
27
27
|
children: [/* @__PURE__ */ jsx("h3", {
|
|
28
|
-
className: "text-[
|
|
28
|
+
className: "text-[15px] font-semibold",
|
|
29
29
|
children: /* @__PURE__ */ jsx(AppLink, {
|
|
30
30
|
to: {
|
|
31
31
|
kind: "record",
|
|
@@ -55,7 +55,7 @@ const SavedSearchRows = ({ model, view, empty }) => {
|
|
|
55
55
|
});
|
|
56
56
|
if (!saved.data) return /* @__PURE__ */ jsx(Skeleton, { className: "h-40" });
|
|
57
57
|
if (saved.data.length === 0) return /* @__PURE__ */ jsx("p", {
|
|
58
|
-
className: "text-
|
|
58
|
+
className: "text-muted-foreground",
|
|
59
59
|
children: empty ?? `No ${plural} yet.`
|
|
60
60
|
});
|
|
61
61
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -53,7 +53,7 @@ const SavedSearchSection = ({ model, view, of, target, targetView, row, recordKe
|
|
|
53
53
|
children: [/* @__PURE__ */ jsx("div", {
|
|
54
54
|
className: "flex min-w-0 flex-col gap-2",
|
|
55
55
|
children: /* @__PURE__ */ jsx("h2", {
|
|
56
|
-
className: "text-[
|
|
56
|
+
className: "text-[16px] font-semibold",
|
|
57
57
|
children: /* @__PURE__ */ jsx(AppLink, {
|
|
58
58
|
to: {
|
|
59
59
|
kind: "record",
|
|
@@ -58,7 +58,7 @@ const SavedSearches = ({ model, view }) => {
|
|
|
58
58
|
if (saved.data.length === 0) {
|
|
59
59
|
const searched = (targetView?.names?.plural ?? humanize(target.name)).toLowerCase();
|
|
60
60
|
return frame(/* @__PURE__ */ jsxs("p", {
|
|
61
|
-
className: "py-8 text-center text-
|
|
61
|
+
className: "py-8 text-center text-muted-foreground",
|
|
62
62
|
children: [
|
|
63
63
|
"No ",
|
|
64
64
|
plural.toLowerCase(),
|