@protobase/ui 0.25.2 → 0.25.4
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-pages.js +3 -2
- package/dist/account/account-section.js +1 -1
- package/dist/account/account-security-page.js +9 -4
- package/dist/account/backup-codes.js +7 -6
- package/dist/account/messages.js +214 -0
- package/dist/account/passkeys-section.js +23 -22
- package/dist/account/password-dialog.js +4 -3
- package/dist/account/sign-in-policy-form.js +14 -13
- package/dist/account/sign-in-policy-labels.js +30 -29
- package/dist/account/sign-in-policy-page.js +11 -6
- package/dist/account/sign-in-providers-section.js +6 -5
- package/dist/account/staff-sign-in-log.js +11 -10
- package/dist/account/totp-qr.js +2 -1
- package/dist/account/two-factor-section.js +24 -23
- package/dist/account/two-factor-setup.js +19 -18
- package/dist/action-card/action-card.js +2 -1
- package/dist/action-card/field-list.js +1 -1
- package/dist/action-card/messages.js +8 -0
- package/dist/activity-chart/activity-chart.js +3 -2
- package/dist/activity-chart/messages.js +14 -0
- package/dist/app/app.d.ts +1 -1
- package/dist/app/app.js +20 -21
- package/dist/app/assistant-shell.js +2 -1
- package/dist/app/batch-failure.js +2 -1
- package/dist/app/breadcrumb-for.js +4 -3
- package/dist/app/charts/chart-groups.js +3 -2
- package/dist/app/charts/chart-view.js +3 -2
- package/dist/app/charts/group-bars.js +2 -1
- package/dist/app/charts/messages.js +26 -0
- package/dist/app/charts/period-chart.js +3 -2
- package/dist/app/charts/split-points.js +2 -1
- package/dist/app/comments/comment-composer.js +19 -18
- package/dist/app/comments/comments-section.js +4 -3
- package/dist/app/comments/messages.js +26 -0
- package/dist/app/create/create-page.js +11 -18
- package/dist/app/custom-section.js +4 -6
- package/dist/app/displays/board-column.js +7 -6
- package/dist/app/displays/board-columns.js +3 -2
- package/dist/app/displays/board-display.js +13 -15
- package/dist/app/displays/calendar-controls.js +3 -2
- package/dist/app/displays/calendar-display.js +12 -17
- package/dist/app/displays/card-carousel.js +4 -3
- package/dist/app/displays/cards-display.js +2 -1
- package/dist/app/displays/custom-display.js +4 -6
- package/dist/app/displays/display-frame.js +3 -2
- package/dist/app/displays/list-cards.js +5 -8
- package/dist/app/displays/list-displays.js +3 -3
- package/dist/app/displays/map-display.js +15 -14
- package/dist/app/displays/messages.js +128 -2
- package/dist/app/displays/period-controls.js +4 -3
- package/dist/app/displays/record-card.js +7 -6
- package/dist/app/displays/timeline-display.js +17 -26
- package/dist/app/displays/timeline-range.js +2 -1
- package/dist/app/displays/timeline-row.js +1 -1
- package/dist/app/displays/use-board-move.js +2 -2
- package/dist/app/displays/use-calendar-move.js +2 -1
- package/dist/app/document-title.js +2 -1
- package/dist/app/error-banner.js +1 -1
- package/dist/app/export/builder-port.js +2 -1
- package/dist/app/export/export-dialog.js +39 -43
- package/dist/app/export/export-worker.js +2 -0
- package/dist/app/export/messages.js +78 -0
- package/dist/app/export/run-export.js +5 -2
- package/dist/app/export/sink.js +4 -3
- package/dist/app/export/use-export-flow.js +4 -3
- package/dist/app/field-editor.js +4 -3
- package/dist/app/field-types/messages.js +8 -0
- package/dist/app/field-types/widget-part.js +2 -1
- package/dist/app/file-field.js +11 -14
- package/dist/app/gallery/gallery-section.js +4 -3
- package/dist/app/gallery/lightbox.js +5 -4
- package/dist/app/gallery/messages.js +30 -0
- package/dist/app/gallery/photo-details.js +3 -2
- package/dist/app/hand-order/hand-sorted-list.js +3 -6
- package/dist/app/hand-order/messages.js +4 -2
- package/dist/app/history/describe-change.js +3 -8
- package/dist/app/history/messages.js +32 -0
- package/dist/app/import/convert.js +20 -19
- package/dist/app/import/failed-rows.js +3 -2
- package/dist/app/import/import-button.js +2 -1
- package/dist/app/import/import-check-step.js +21 -37
- package/dist/app/import/import-dialog.js +13 -17
- package/dist/app/import/import-file-step.js +5 -9
- package/dist/app/import/import-mapping-step.js +32 -35
- package/dist/app/import/import-result-step.js +13 -12
- package/dist/app/import/messages.js +200 -0
- package/dist/app/import/parse-worker.js +2 -0
- package/dist/app/import/prepare-rows.js +5 -4
- package/dist/app/import/sheet-cell.js +2 -1
- package/dist/app/import/sheet-file.js +3 -2
- package/dist/app/import/sheet-source.js +7 -3
- package/dist/app/import/xlsx-reader.js +4 -3
- package/dist/app/import/xlsx-xml.js +2 -1
- package/dist/app/import/zip-reader.js +4 -3
- package/dist/app/list-edit/use-list-edits.js +1 -1
- package/dist/app/list-group-chart.js +2 -1
- package/dist/app/list-page.js +1 -1
- package/dist/app/map/map-layer-switch.js +3 -2
- package/dist/app/map/messages.js +14 -0
- package/dist/app/messages.js +116 -2
- package/dist/app/meta-gate.js +1 -1
- package/dist/app/nav-from-meta.js +11 -10
- package/dist/app/pages/action-inputs/action-inputs-dialog.js +3 -2
- package/dist/app/pages/action-inputs/input-answers.js +6 -5
- package/dist/app/pages/blocks/card-row.js +3 -2
- package/dist/app/pages/blocks/field.js +1 -1
- package/dist/app/pages/blocks/modal-form.js +5 -4
- package/dist/app/pages/blocks/progress.js +1 -1
- package/dist/app/pages/blocks/record-card.js +3 -2
- package/dist/app/pages/blocks/stat.js +2 -1
- package/dist/app/pages/composed-page.js +6 -8
- package/dist/app/pages/confirm-action.js +2 -1
- package/dist/app/pages/custom-boundary.js +4 -2
- package/dist/app/pages/messages.js +64 -0
- package/dist/app/pages/render-node.js +5 -7
- package/dist/app/pages/use-run-action.js +11 -10
- package/dist/app/record-page.js +1 -1
- package/dist/app/record-row/messages.js +26 -0
- package/dist/app/record-row/record-row-body.js +12 -7
- package/dist/app/record-row/record-row.js +4 -3
- package/dist/app/record-row/saved-record-row.js +3 -2
- package/dist/app/related-dots/dots-summary.js +2 -1
- package/dist/app/related-dots/messages.js +8 -0
- package/dist/app/relation-picker.js +9 -8
- package/dist/app/router.js +5 -4
- package/dist/app/runtime/messages.js +58 -0
- package/dist/app/runtime/runtime-status.js +10 -23
- package/dist/app/runtime/runtime-update-dialog.js +7 -6
- package/dist/app/runtime/runtime-update.js +4 -3
- package/dist/app/saved/favorite-button.js +2 -1
- package/dist/app/saved/messages.js +22 -0
- package/dist/app/saved/saved-list.js +4 -7
- package/dist/app/saved/use-favorite.js +3 -2
- package/dist/app/search/messages.js +6 -2
- package/dist/app/search/navigation-hits.js +9 -7
- package/dist/app/searches/filter-chip-list.js +2 -1
- package/dist/app/searches/messages.js +96 -0
- package/dist/app/searches/save-search-button.js +5 -4
- package/dist/app/searches/saved-search-rows.js +3 -2
- package/dist/app/searches/saved-search-section.js +6 -5
- package/dist/app/searches/saved-search.js +4 -3
- package/dist/app/searches/saved-searches.js +15 -25
- package/dist/app/searches/search-controls.js +5 -4
- package/dist/app/searches/search-diff.js +4 -2
- package/dist/app/searches/search-name-dialog.js +4 -3
- package/dist/app/searches/update-search-dialog.js +15 -30
- package/dist/app/searches/use-save-search.js +8 -7
- package/dist/app/searches/use-search-row.js +4 -3
- package/dist/app/sensitive-field.js +5 -4
- package/dist/app/source-notice.js +13 -8
- package/dist/app/staff-banner.js +13 -20
- package/dist/app-shell/global-search.js +2 -2
- package/dist/app-shell/messages.js +4 -2
- package/dist/app-shell/sidebar-group.js +1 -1
- package/dist/app-shell/sidebar-item.js +1 -1
- package/dist/app-shell/sidebar.js +1 -1
- package/dist/assistant-dock/assistant-dock.js +6 -6
- package/dist/assistant-dock/messages.js +26 -0
- package/dist/assistant-dock/use-assistant.js +2 -1
- package/dist/assistant-dock/use-backend-data.js +2 -1
- package/dist/assistant-dock/widget-view.js +3 -2
- package/dist/auth/auth-gate.js +10 -5
- package/dist/auth/auth-locale.js +14 -0
- package/dist/auth/auth-messages.js +122 -43
- package/dist/auth/auth-provider.js +6 -1
- package/dist/auth/code-form.js +4 -3
- package/dist/auth/email-code-form.js +11 -13
- package/dist/auth/email-code-page.js +2 -1
- package/dist/auth/first-run-page.js +6 -5
- package/dist/auth/forgot-password-form.js +15 -17
- package/dist/auth/forgot-password-page.js +2 -1
- package/dist/auth/messages.js +200 -0
- package/dist/auth/provider-sign-in-page.js +5 -5
- package/dist/auth/resend-code-button.js +2 -1
- package/dist/auth/reset-password-form.js +12 -11
- package/dist/auth/reset-password-page.js +4 -3
- package/dist/auth/setup-required-form.js +8 -10
- package/dist/auth/setup-required-page.js +7 -2
- package/dist/auth/sign-in-form.js +18 -21
- package/dist/auth/sign-in-prompt.js +4 -3
- package/dist/auth/sign-up-code-form.js +11 -13
- package/dist/auth/sign-up-details-form.js +15 -22
- package/dist/auth/sign-up-email-form.js +9 -8
- package/dist/auth/sign-up-page.js +2 -1
- package/dist/auth/staff-sign-in-form.js +16 -19
- package/dist/auth/two-factor-form.js +19 -18
- package/dist/auth/user-to-shell.js +2 -1
- package/dist/chat/composer.js +8 -7
- package/dist/chat/messages.js +14 -0
- package/dist/compact-table/compact-table.js +4 -8
- package/dist/compact-table/messages.js +18 -0
- package/dist/data/meta-data.d.ts +1 -1
- package/dist/data/use-update-record.js +1 -1
- package/dist/data-grid/grid-header.js +1 -1
- package/dist/filter-panel/date-presets.js +1 -1
- package/dist/forms/public-form-page.js +1 -1
- package/dist/inline-child-table/inline-child-table.js +12 -12
- package/dist/inline-child-table/line-row.js +10 -9
- package/dist/inline-child-table/messages.js +52 -0
- package/dist/inline-child-table/totals-footer.js +5 -8
- package/dist/invitations/invite-form.js +3 -2
- package/dist/invitations/link-notice.js +6 -4
- package/dist/invitations/messages.js +24 -0
- package/dist/invitations/pending-invitation-row.js +4 -3
- package/dist/lists/messages.js +8 -0
- package/dist/lists/paged-search-list.js +2 -1
- package/dist/locale/slotted.js +14 -0
- package/dist/markdown/markdown-editor.js +6 -5
- package/dist/markdown/messages.js +16 -0
- package/dist/organizations/all-organizations.js +6 -5
- package/dist/organizations/app-roles-picker.js +2 -1
- package/dist/organizations/invitation-page.js +41 -51
- package/dist/organizations/invitations-page.js +11 -10
- package/dist/organizations/members-page.js +16 -11
- package/dist/organizations/messages.js +180 -0
- package/dist/organizations/organization-page.js +27 -26
- package/dist/organizations/organization-paths.js +16 -13
- package/dist/organizations/organization-row.js +3 -2
- package/dist/organizations/organizations-page.js +17 -16
- package/dist/organizations/use-organizations.js +2 -1
- package/dist/package.js +1 -1
- package/dist/plugins/before-sign-in.js +6 -1
- package/dist/plugins/load-plugin.d.ts +1 -1
- package/dist/plugins/load-plugin.js +3 -2
- package/dist/plugins/messages.js +36 -0
- package/dist/plugins/plugin-gate.js +6 -1
- package/dist/plugins/plugin-manifest.js +8 -7
- package/dist/plugins/plugin-notice.js +8 -12
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/messages.js +16 -0
- package/dist/primitives/segmented.js +1 -1
- package/dist/primitives/sheet.js +2 -1
- package/dist/primitives/spinner.js +2 -1
- package/dist/primitives/token.js +2 -1
- package/dist/record-view/field.js +2 -2
- package/dist/record-view/messages.js +4 -2
- package/dist/record-view/record-tabs.js +2 -1
- package/dist/roles/messages.js +14 -0
- package/dist/roles/use-active-role.js +3 -2
- package/dist/shell/assets/app-yCMYvqMX.js +69 -0
- package/dist/shell/assets/cn-Bi0ZEjD9.js +1 -0
- package/dist/shell/assets/export-worker-ClACk00b.js +2 -0
- package/dist/shell/assets/{index-BRkDA5KD.css → index-Bkc7w8I4.css} +1 -1
- package/dist/shell/assets/{index-xY0Mvv6V.js → index-HkjqX_O-.js} +2 -2
- package/dist/shell/assets/maplibre-DUTS_eJM.js +814 -0
- package/dist/shell/assets/{markdown-content-ukDTCu6u.js → markdown-content-CtGUP4W6.js} +1 -1
- package/dist/shell/assets/parse-worker-UhbwEjS0.js +5 -0
- package/dist/shell/assets/preload-helper-BZ3hrQDD.js +1 -0
- package/dist/shell/assets/{record-map-BJmYZ7kQ.js → record-map-DFy7sJEU.js} +1 -1
- package/dist/shell/assets/records-map-MfQEuiFB.js +1 -0
- package/dist/shell/assets/shared-protobase-ui-Bfa59vx6.js +1 -0
- package/dist/shell/index.html +6 -4
- package/dist/shell/protobase.shell.json +1 -1
- package/dist/shell/protobase.sw.js +2 -2
- package/dist/side-panel/messages.js +8 -0
- package/dist/side-panel/side-panel.js +2 -1
- package/dist/toasts/messages.js +8 -0
- package/dist/toasts/toast.js +2 -1
- package/dist/users/app-invitations.js +5 -4
- package/dist/users/create-user-form.js +9 -8
- package/dist/users/messages.js +52 -0
- package/dist/users/use-user-roles.js +2 -1
- package/dist/users/user-list.js +6 -5
- package/dist/users/user-row.js +5 -4
- package/package.json +4 -4
- package/dist/shell/assets/app-C-OLrsRR.js +0 -69
- package/dist/shell/assets/export-worker-Bz57Pf5g.js +0 -2
- package/dist/shell/assets/maplibre-Dov6nhPX.js +0 -814
- package/dist/shell/assets/parse-worker-BtcY0dQw.js +0 -5
- package/dist/shell/assets/records-map-C1_gDKHR.js +0 -1
- package/dist/shell/assets/shared-protobase-ui-CFYJAbMR.js +0 -1
package/dist/app/file-field.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cn } from "../lib/cn.js";
|
|
2
2
|
import { Button } from "../primitives/button.js";
|
|
3
3
|
import { useClient } from "../data/api-provider.js";
|
|
4
|
+
import { text } from "./messages.js";
|
|
4
5
|
import { humanize } from "../live/naming.js";
|
|
5
6
|
import { acceptOf, fileShown, formatSize, isPreviewable, shownImage } from "../live/file-values.js";
|
|
6
7
|
import { ErrorBanner } from "./error-banner.js";
|
|
@@ -32,7 +33,7 @@ const FileSummary = ({ value }) => {
|
|
|
32
33
|
});
|
|
33
34
|
if ("missing" in shown) return /* @__PURE__ */ jsx("div", {
|
|
34
35
|
className: "py-1.5 text-danger-text",
|
|
35
|
-
children: "
|
|
36
|
+
children: text("fileMissing")
|
|
36
37
|
});
|
|
37
38
|
const url = "url" in shown ? shown.url : void 0;
|
|
38
39
|
const corrected = "corrected" in shown ? shown.corrected : void 0;
|
|
@@ -97,33 +98,29 @@ const FileField = ({ field, hints, resource, value, locked, invalid, onChange })
|
|
|
97
98
|
type: "file",
|
|
98
99
|
hidden: true,
|
|
99
100
|
accept: acceptOf(field),
|
|
100
|
-
"aria-label":
|
|
101
|
+
"aria-label": text("chooseFileFor", label),
|
|
101
102
|
onChange: (event) => choose(event.target.files)
|
|
102
103
|
});
|
|
103
104
|
const error = upload.error && /* @__PURE__ */ jsx("div", {
|
|
104
105
|
className: "mt-2",
|
|
105
106
|
children: /* @__PURE__ */ jsx(ErrorBanner, {
|
|
106
|
-
title: "
|
|
107
|
+
title: text("notUploaded"),
|
|
107
108
|
error: upload.error
|
|
108
109
|
})
|
|
109
110
|
});
|
|
110
111
|
if (upload.isPending) return /* @__PURE__ */ jsxs("div", {
|
|
111
112
|
className: "py-1.5",
|
|
112
113
|
role: "status",
|
|
113
|
-
"aria-label":
|
|
114
|
+
"aria-label": text("uploadingLabel", label),
|
|
114
115
|
children: [/* @__PURE__ */ jsx("div", {
|
|
115
116
|
className: "h-1.5 overflow-hidden rounded-full bg-muted",
|
|
116
117
|
children: /* @__PURE__ */ jsx("div", {
|
|
117
118
|
className: "h-full rounded-full bg-primary transition-[width]",
|
|
118
119
|
style: { width: `${Math.round((progress ?? 0) * 100)}%` }
|
|
119
120
|
})
|
|
120
|
-
}), /* @__PURE__ */
|
|
121
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
121
122
|
className: "text-xs text-muted-foreground",
|
|
122
|
-
children:
|
|
123
|
-
"Uploading… ",
|
|
124
|
-
Math.round((progress ?? 0) * 100),
|
|
125
|
-
"%"
|
|
126
|
-
]
|
|
123
|
+
children: text("uploading", Math.round((progress ?? 0) * 100))
|
|
127
124
|
})]
|
|
128
125
|
});
|
|
129
126
|
if (fileShown(value)) return /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -137,13 +134,13 @@ const FileField = ({ field, hints, resource, value, locked, invalid, onChange })
|
|
|
137
134
|
/* @__PURE__ */ jsx(Button, {
|
|
138
135
|
size: "sm",
|
|
139
136
|
onClick: () => input.current?.click(),
|
|
140
|
-
children: "
|
|
137
|
+
children: text("replace")
|
|
141
138
|
}),
|
|
142
139
|
field.nullable && /* @__PURE__ */ jsx(Button, {
|
|
143
140
|
size: "sm",
|
|
144
141
|
variant: "ghost",
|
|
145
142
|
onClick: () => onChange(null),
|
|
146
|
-
children: "
|
|
143
|
+
children: text("remove")
|
|
147
144
|
})
|
|
148
145
|
]
|
|
149
146
|
}),
|
|
@@ -163,12 +160,12 @@ const FileField = ({ field, hints, resource, value, locked, invalid, onChange })
|
|
|
163
160
|
/* @__PURE__ */ jsx(Upload, { className: "size-4 shrink-0" }),
|
|
164
161
|
/* @__PURE__ */ jsx("span", {
|
|
165
162
|
className: "flex-1",
|
|
166
|
-
children: "
|
|
163
|
+
children: text("dropFile")
|
|
167
164
|
}),
|
|
168
165
|
/* @__PURE__ */ jsxs(Button, {
|
|
169
166
|
size: "sm",
|
|
170
167
|
onClick: () => input.current?.click(),
|
|
171
|
-
children: [/* @__PURE__ */ jsx(Paperclip, { className: "size-3.5" }), "
|
|
168
|
+
children: [/* @__PURE__ */ jsx(Paperclip, { className: "size-3.5" }), text("chooseFile")]
|
|
172
169
|
})
|
|
173
170
|
]
|
|
174
171
|
}),
|
|
@@ -7,6 +7,7 @@ import { useAdminMeta, usePermissions } from "../meta-gate.js";
|
|
|
7
7
|
import { ErrorBanner } from "../error-banner.js";
|
|
8
8
|
import { FileImage } from "../../live/file-image.js";
|
|
9
9
|
import { galleryTiles } from "./gallery-layout.js";
|
|
10
|
+
import { text } from "./messages.js";
|
|
10
11
|
import { Lightbox } from "./lightbox.js";
|
|
11
12
|
import { detailFields } from "./detail-fields.js";
|
|
12
13
|
import { PhotoDetails } from "./photo-details.js";
|
|
@@ -63,7 +64,7 @@ const GallerySection = ({ item, record, recordKey }) => {
|
|
|
63
64
|
if (photos.error) return /* @__PURE__ */ jsx(Section, {
|
|
64
65
|
title: item.title,
|
|
65
66
|
children: /* @__PURE__ */ jsx(ErrorBanner, {
|
|
66
|
-
title: "
|
|
67
|
+
title: text("couldNotLoad"),
|
|
67
68
|
error: photos.error
|
|
68
69
|
})
|
|
69
70
|
});
|
|
@@ -91,7 +92,7 @@ const GallerySection = ({ item, record, recordKey }) => {
|
|
|
91
92
|
const last = index === shown - 1 && more > 0;
|
|
92
93
|
return /* @__PURE__ */ jsxs("button", {
|
|
93
94
|
type: "button",
|
|
94
|
-
"aria-label": last ?
|
|
95
|
+
"aria-label": last ? text("showAll", count) : text("showPhoto", index + 1, count),
|
|
95
96
|
onClick: () => setOpen(index),
|
|
96
97
|
className: cn("group/tile relative overflow-hidden bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary", index === 0 ? "col-span-4 row-span-2" : "max-md:hidden", spans[shown][index]),
|
|
97
98
|
children: [
|
|
@@ -119,7 +120,7 @@ const GallerySection = ({ item, record, recordKey }) => {
|
|
|
119
120
|
onIndex: setOpen,
|
|
120
121
|
onClose: () => setOpen(void 0),
|
|
121
122
|
details,
|
|
122
|
-
detailsTitle: holder &&
|
|
123
|
+
detailsTitle: holder && text("holderDetails", holderView?.names?.singular ?? humanize(holder.name))
|
|
123
124
|
})]
|
|
124
125
|
});
|
|
125
126
|
};
|
|
@@ -6,6 +6,7 @@ import { FileImage } from "../../live/file-image.js";
|
|
|
6
6
|
import { Sheet } from "../../primitives/sheet.js";
|
|
7
7
|
import { keyStep, steppedPhoto, swipeStep, togglesDetails } from "./gallery-layout.js";
|
|
8
8
|
import { readDetailsOpen, writeDetailsOpen } from "./details-open-storage.js";
|
|
9
|
+
import { text } from "./messages.js";
|
|
9
10
|
import { useEffect, useId, useRef, useState } from "react";
|
|
10
11
|
import { ChevronLeft, ChevronRight, Info, X } from "lucide-react";
|
|
11
12
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -18,7 +19,7 @@ const control = "flex size-10 shrink-0 items-center justify-center rounded-full
|
|
|
18
19
|
* lower part of a mobile screen; this browser remembers whether they were left shown. The page does not scroll behind
|
|
19
20
|
* it, and focus returns to what opened it.
|
|
20
21
|
*/
|
|
21
|
-
const Lightbox = ({ title, photos, index, onIndex, onClose, details, detailsTitle = "
|
|
22
|
+
const Lightbox = ({ title, photos, index, onIndex, onClose, details, detailsTitle = text("details") }) => {
|
|
22
23
|
const panel = useRef(null);
|
|
23
24
|
const start = useRef(void 0);
|
|
24
25
|
const sidebarId = useId();
|
|
@@ -97,7 +98,7 @@ const Lightbox = ({ title, photos, index, onIndex, onClose, details, detailsTitl
|
|
|
97
98
|
}), /* @__PURE__ */ jsx("button", {
|
|
98
99
|
type: "button",
|
|
99
100
|
className: control,
|
|
100
|
-
"aria-label": "
|
|
101
|
+
"aria-label": text("close"),
|
|
101
102
|
onClick: onClose,
|
|
102
103
|
children: /* @__PURE__ */ jsx(X, {
|
|
103
104
|
className: "size-4",
|
|
@@ -116,7 +117,7 @@ const Lightbox = ({ title, photos, index, onIndex, onClose, details, detailsTitl
|
|
|
116
117
|
}, image.url), count > 1 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
117
118
|
type: "button",
|
|
118
119
|
className: cn(control, "absolute left-3 top-1/2 -translate-y-1/2 aria-disabled:cursor-default aria-disabled:opacity-40"),
|
|
119
|
-
"aria-label": "
|
|
120
|
+
"aria-label": text("previousPhoto"),
|
|
120
121
|
"aria-disabled": index === 0,
|
|
121
122
|
onClick: () => step(-1),
|
|
122
123
|
children: /* @__PURE__ */ jsx(ChevronLeft, {
|
|
@@ -126,7 +127,7 @@ const Lightbox = ({ title, photos, index, onIndex, onClose, details, detailsTitl
|
|
|
126
127
|
}), /* @__PURE__ */ jsx("button", {
|
|
127
128
|
type: "button",
|
|
128
129
|
className: cn(control, "absolute right-3 top-1/2 -translate-y-1/2 aria-disabled:cursor-default aria-disabled:opacity-40"),
|
|
129
|
-
"aria-label": "
|
|
130
|
+
"aria-label": text("nextPhoto"),
|
|
130
131
|
"aria-disabled": index === count - 1,
|
|
131
132
|
onClick: () => step(1),
|
|
132
133
|
children: /* @__PURE__ */ jsx(ChevronRight, {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineMessages } from "../../locale/messages.js";
|
|
2
|
+
//#region src/app/gallery/messages.ts
|
|
3
|
+
const text = defineMessages({
|
|
4
|
+
en: {
|
|
5
|
+
couldNotLoad: "Could not load the photos",
|
|
6
|
+
showAll: (count) => `Show all ${count} photos`,
|
|
7
|
+
showPhoto: (index, count) => `Show photo ${index} of ${count}`,
|
|
8
|
+
details: "Details",
|
|
9
|
+
holderDetails: (singular) => `${singular} details`,
|
|
10
|
+
close: "Close",
|
|
11
|
+
previousPhoto: "Previous photo",
|
|
12
|
+
nextPhoto: "Next photo",
|
|
13
|
+
couldNotLoadOne: (singular) => `Could not load the ${singular}`,
|
|
14
|
+
open: (singular) => `Open ${singular}`
|
|
15
|
+
},
|
|
16
|
+
nl: {
|
|
17
|
+
couldNotLoad: "Kon de foto’s niet laden",
|
|
18
|
+
showAll: (count) => `Alle ${count} foto’s tonen`,
|
|
19
|
+
showPhoto: (index, count) => `Foto ${index} van ${count} tonen`,
|
|
20
|
+
details: "Gegevens",
|
|
21
|
+
holderDetails: (singular) => `Gegevens van ${singular.toLowerCase()}`,
|
|
22
|
+
close: "Sluiten",
|
|
23
|
+
previousPhoto: "Vorige foto",
|
|
24
|
+
nextPhoto: "Volgende foto",
|
|
25
|
+
couldNotLoadOne: (singular) => `Kon ${singular} niet laden`,
|
|
26
|
+
open: (singular) => `${singular} openen`
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
//#endregion
|
|
30
|
+
export { text };
|
|
@@ -6,6 +6,7 @@ import { SpecTable } from "../../record-view/spec-table.js";
|
|
|
6
6
|
import { ErrorBanner } from "../error-banner.js";
|
|
7
7
|
import { fieldAccess } from "../permissions.js";
|
|
8
8
|
import { FieldValue } from "../pages/field-value.js";
|
|
9
|
+
import { text } from "./messages.js";
|
|
9
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
11
|
//#region src/app/gallery/photo-details.tsx
|
|
11
12
|
/**
|
|
@@ -17,7 +18,7 @@ const PhotoDetails = ({ model, view, photoKey, fields }) => {
|
|
|
17
18
|
const singular = (view?.names?.singular ?? humanize(model.name)).toLowerCase();
|
|
18
19
|
if (record.isPending) return /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" });
|
|
19
20
|
if (record.error) return /* @__PURE__ */ jsx(ErrorBanner, {
|
|
20
|
-
title:
|
|
21
|
+
title: text("couldNotLoadOne", singular),
|
|
21
22
|
error: record.error
|
|
22
23
|
});
|
|
23
24
|
const shown = fields.filter((name) => fieldAccess(record.data.permissions, name) !== "hidden");
|
|
@@ -35,7 +36,7 @@ const PhotoDetails = ({ model, view, photoKey, fields }) => {
|
|
|
35
36
|
key: photoKey
|
|
36
37
|
},
|
|
37
38
|
className: "mt-3 inline-block font-medium text-primary-text hover:underline",
|
|
38
|
-
children:
|
|
39
|
+
children: text("open", singular)
|
|
39
40
|
})] });
|
|
40
41
|
};
|
|
41
42
|
//#endregion
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Skeleton } from "../../primitives/skeleton.js";
|
|
2
|
+
import { slotted } from "../../locale/slotted.js";
|
|
2
3
|
import { Problem } from "../pages/problem.js";
|
|
3
4
|
import { recordKey, recordTitle } from "../../live/model-helpers.js";
|
|
4
5
|
import { loadedFields } from "../displays/list-displays.js";
|
|
@@ -11,7 +12,7 @@ import { embeddedColumns } from "../embedded-list/embedded-columns.js";
|
|
|
11
12
|
import { text } from "./messages.js";
|
|
12
13
|
import { useHandOrder } from "./use-hand-order.js";
|
|
13
14
|
import { useMemo } from "react";
|
|
14
|
-
import { jsx
|
|
15
|
+
import { jsx } from "react/jsx-runtime";
|
|
15
16
|
//#region src/app/hand-order/hand-sorted-list.tsx
|
|
16
17
|
/**
|
|
17
18
|
* The records in their order by hand, in the list's table with a drag handle in each row's checkbox place: dragging a
|
|
@@ -58,11 +59,7 @@ const HandSortedList = ({ model, view, field, filter, columns, sort }) => {
|
|
|
58
59
|
total: rows.length,
|
|
59
60
|
rowAt: (index) => rows[index]
|
|
60
61
|
}, [rows]);
|
|
61
|
-
if (ruleName !== void 0 && !rule) return /* @__PURE__ */
|
|
62
|
-
"No drop rule is registered as ",
|
|
63
|
-
ruleName,
|
|
64
|
-
". Give it in dropRules in protobase.ui.tsx, or load the plugin that provides it."
|
|
65
|
-
] });
|
|
62
|
+
if (ruleName !== void 0 && !rule) return /* @__PURE__ */ jsx(Problem, { children: slotted(text("noRule"), ruleName) });
|
|
66
63
|
if (order.loading) return /* @__PURE__ */ jsx("div", {
|
|
67
64
|
className: "flex flex-col gap-2",
|
|
68
65
|
children: Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }, index))
|
|
@@ -11,7 +11,8 @@ const text = defineMessages({
|
|
|
11
11
|
undo: "Undo",
|
|
12
12
|
couldNotUndo: "Could not undo",
|
|
13
13
|
movedToPlace: (place) => `Moved to place ${place}`,
|
|
14
|
-
notMoved: "Left in its place"
|
|
14
|
+
notMoved: "Left in its place",
|
|
15
|
+
noRule: "No drop rule is registered as {}. Give it in dropRules in protobase.ui.tsx, or load the plugin that provides it."
|
|
15
16
|
},
|
|
16
17
|
nl: {
|
|
17
18
|
done: "Klaar",
|
|
@@ -23,7 +24,8 @@ const text = defineMessages({
|
|
|
23
24
|
undo: "Ongedaan maken",
|
|
24
25
|
couldNotUndo: "Kon niet ongedaan maken",
|
|
25
26
|
movedToPlace: (place) => `Verplaatst naar plaats ${place}`,
|
|
26
|
-
notMoved: "Op zijn plaats gelaten"
|
|
27
|
+
notMoved: "Op zijn plaats gelaten",
|
|
28
|
+
noRule: "Er is geen sleepregel geregistreerd als {}. Geef die in dropRules in protobase.ui.tsx, of laad de plug-in die haar levert."
|
|
27
29
|
}
|
|
28
30
|
});
|
|
29
31
|
//#endregion
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { humanize } from "../../live/naming.js";
|
|
2
2
|
import { displayValue } from "../../live/display-value.js";
|
|
3
|
+
import { text } from "./messages.js";
|
|
3
4
|
//#region src/app/history/describe-change.ts
|
|
4
|
-
const verbs = {
|
|
5
|
-
create: "created this",
|
|
6
|
-
update: "changed",
|
|
7
|
-
delete: "deleted this",
|
|
8
|
-
undelete: "restored this"
|
|
9
|
-
};
|
|
10
5
|
/** Who made a change: their name, else their id; a write from outside the app names the database role. */
|
|
11
6
|
const changedBy = (change) => {
|
|
12
7
|
if (change.actor) return change.actor.name ?? change.actor.id;
|
|
13
|
-
return change.databaseRole ?
|
|
8
|
+
return change.databaseRole ? text("databaseRole", change.databaseRole) : text("database");
|
|
14
9
|
};
|
|
15
10
|
/**
|
|
16
11
|
* A change as the record page tells it: who, what they did, and for an update each changed field the model still has,
|
|
@@ -33,7 +28,7 @@ const describeChange = (change, model, view) => {
|
|
|
33
28
|
after: displayValue(field, change.after[name], hints)
|
|
34
29
|
}];
|
|
35
30
|
});
|
|
36
|
-
const verb = change.operation === "update" && fields.length === 0 ? "
|
|
31
|
+
const verb = change.operation === "update" && fields.length === 0 ? text("changedThis") : text(change.operation);
|
|
37
32
|
return {
|
|
38
33
|
who: changedBy(change),
|
|
39
34
|
verb,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineMessages } from "../../locale/messages.js";
|
|
2
|
+
//#region src/app/history/messages.ts
|
|
3
|
+
const text = defineMessages({
|
|
4
|
+
en: {
|
|
5
|
+
create: "created this",
|
|
6
|
+
update: "changed",
|
|
7
|
+
delete: "deleted this",
|
|
8
|
+
undelete: "restored this",
|
|
9
|
+
database: "Database",
|
|
10
|
+
databaseRole: (role) => `Database (${role})`,
|
|
11
|
+
changed: "changed",
|
|
12
|
+
changedThis: "changed this",
|
|
13
|
+
couldNotLoad: "Could not load the history",
|
|
14
|
+
noChanges: "No changes kept yet.",
|
|
15
|
+
showMore: "Show more"
|
|
16
|
+
},
|
|
17
|
+
nl: {
|
|
18
|
+
create: "maakte dit",
|
|
19
|
+
update: "wijzigde",
|
|
20
|
+
delete: "verwijderde dit",
|
|
21
|
+
undelete: "zette dit terug",
|
|
22
|
+
database: "Database",
|
|
23
|
+
databaseRole: (role) => `Database (${role})`,
|
|
24
|
+
changed: "gewijzigd",
|
|
25
|
+
changedThis: "wijzigde dit",
|
|
26
|
+
couldNotLoad: "Kon de geschiedenis niet laden",
|
|
27
|
+
noChanges: "Nog geen wijzigingen bewaard.",
|
|
28
|
+
showMore: "Meer tonen"
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
//#endregion
|
|
32
|
+
export { text };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseNumberText } from "../../format/number-text.js";
|
|
2
|
+
import { text } from "./messages.js";
|
|
2
3
|
import { cellText, isEmptyCell, isSheetDate } from "./sheet-cell.js";
|
|
3
4
|
import { enumLabel } from "@protobase/schema";
|
|
4
5
|
//#region src/app/import/convert.ts
|
|
@@ -16,17 +17,17 @@ const toNumberText = (cell, options) => {
|
|
|
16
17
|
if (typeof cell === "string") return parseNumberText(cell, options.decimal);
|
|
17
18
|
};
|
|
18
19
|
const integerValue = (field, cell, options) => {
|
|
19
|
-
const text = toNumberText(cell, options);
|
|
20
|
-
if (text === void 0) return problem(
|
|
21
|
-
const [whole, fraction = ""] = text.split(".");
|
|
22
|
-
if (/[1-9]/.test(fraction) || /e/i.test(text)) return problem(
|
|
20
|
+
const text$1 = toNumberText(cell, options);
|
|
21
|
+
if (text$1 === void 0) return problem(text("notNumber", quoted(cell)));
|
|
22
|
+
const [whole, fraction = ""] = text$1.split(".");
|
|
23
|
+
if (/[1-9]/.test(fraction) || /e/i.test(text$1)) return problem(text("notWholeNumber", quoted(cell)));
|
|
23
24
|
if (field.type === "bigint") return ok(String(BigInt(whole)));
|
|
24
25
|
const value = Number(whole);
|
|
25
|
-
return Number.isSafeInteger(value) ? ok(value) : problem(
|
|
26
|
+
return Number.isSafeInteger(value) ? ok(value) : problem(text("tooLarge", quoted(cell)));
|
|
26
27
|
};
|
|
27
28
|
const decimalValue = (cell, options) => {
|
|
28
|
-
const text = toNumberText(cell, options);
|
|
29
|
-
return text === void 0 ? problem(
|
|
29
|
+
const text$2 = toNumberText(cell, options);
|
|
30
|
+
return text$2 === void 0 ? problem(text("notNumber", quoted(cell))) : ok(text$2);
|
|
30
31
|
};
|
|
31
32
|
const trueWords = /* @__PURE__ */ new Set([
|
|
32
33
|
"true",
|
|
@@ -40,10 +41,10 @@ const falseWords = /* @__PURE__ */ new Set([
|
|
|
40
41
|
]);
|
|
41
42
|
const booleanValue = (cell) => {
|
|
42
43
|
if (typeof cell === "boolean") return ok(cell);
|
|
43
|
-
const text = typeof cell === "string" || typeof cell === "number" ? String(cell).trim().toLowerCase() : "";
|
|
44
|
-
if (trueWords.has(text)) return ok(true);
|
|
45
|
-
if (falseWords.has(text)) return ok(false);
|
|
46
|
-
return problem(
|
|
44
|
+
const text$3 = typeof cell === "string" || typeof cell === "number" ? String(cell).trim().toLowerCase() : "";
|
|
45
|
+
if (trueWords.has(text$3)) return ok(true);
|
|
46
|
+
if (falseWords.has(text$3)) return ok(false);
|
|
47
|
+
return problem(text("notBoolean", quoted(cell)));
|
|
47
48
|
};
|
|
48
49
|
const pad = (value) => String(value).padStart(2, "0");
|
|
49
50
|
const calendarDate = (year, month, day) => {
|
|
@@ -90,11 +91,11 @@ const wallTimeOf = (cell, options) => {
|
|
|
90
91
|
}
|
|
91
92
|
return typeof cell === "string" ? readWallTime(cell, options.dateOrder) : void 0;
|
|
92
93
|
};
|
|
93
|
-
const notDate = (cell, options) => problem(
|
|
94
|
+
const notDate = (cell, options) => problem(text("notDate", quoted(cell), options.dateOrder === "dmy"));
|
|
94
95
|
const dateValue = (cell, options) => {
|
|
95
96
|
const at = wallTimeOf(cell, options);
|
|
96
97
|
if (!at) return notDate(cell, options);
|
|
97
|
-
if (at.time && at.time !== "00:00:00") return problem(
|
|
98
|
+
if (at.time && at.time !== "00:00:00") return problem(text("hasTime", quoted(cell)));
|
|
98
99
|
return ok(at.date);
|
|
99
100
|
};
|
|
100
101
|
const timestampValue = (cell, options) => {
|
|
@@ -108,20 +109,20 @@ const timestampValue = (cell, options) => {
|
|
|
108
109
|
const normalized = (text) => text.trim().toLowerCase().replace(/\s+/g, " ");
|
|
109
110
|
const enumValue = (field, hints, cell) => {
|
|
110
111
|
const values = field.enumValues ?? [];
|
|
111
|
-
const text = normalized(cellText(cell));
|
|
112
|
-
const matches = values.filter((value) => normalized(value) === text || normalized(enumLabel(value, hints?.valueLabels)) === text);
|
|
112
|
+
const text$4 = normalized(cellText(cell));
|
|
113
|
+
const matches = values.filter((value) => normalized(value) === text$4 || normalized(enumLabel(value, hints?.valueLabels)) === text$4);
|
|
113
114
|
if (matches.length === 1) return ok(matches[0]);
|
|
114
|
-
if (matches.length > 1) return problem(
|
|
115
|
-
return problem(
|
|
115
|
+
if (matches.length > 1) return problem(text("severalValues", quoted(cell), matches.map((value) => enumLabel(value, hints?.valueLabels)).join(", ")));
|
|
116
|
+
return problem(text("notOneOf", quoted(cell), values.map((value) => enumLabel(value, hints?.valueLabels)).join(", ")));
|
|
116
117
|
};
|
|
117
|
-
const textValue = (cell) => typeof cell === "boolean" ? problem(
|
|
118
|
+
const textValue = (cell) => typeof cell === "boolean" ? problem(text("notText", quoted(cell))) : ok(cellText(cell));
|
|
118
119
|
/**
|
|
119
120
|
* The value a cell gives a field, as the API takes it, or the problem that keeps it from being one: never a guess, and an
|
|
120
121
|
* empty cell is null, never a default. A relation's cell is the value of the field its records are found by, so it
|
|
121
122
|
* converts as that field (`convertCell(targetField, ...)`).
|
|
122
123
|
*/
|
|
123
124
|
const convertCell = (field, hints, cell, options) => {
|
|
124
|
-
if (isEmptyCell(cell)) return field.nullable ? ok(null) : problem("
|
|
125
|
+
if (isEmptyCell(cell)) return field.nullable ? ok(null) : problem(text("emptyRequired"));
|
|
125
126
|
switch (field.type) {
|
|
126
127
|
case "integer":
|
|
127
128
|
case "bigint": return integerValue(field, cell, options);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { text } from "./messages.js";
|
|
1
2
|
import { cellText } from "./sheet-cell.js";
|
|
2
3
|
//#region src/app/import/failed-rows.ts
|
|
3
4
|
const csvField = (text) => /[",\r\n]/.test(text) ? `"${text.replace(/"/g, "\"\"")}"` : text;
|
|
@@ -13,8 +14,8 @@ const failedRowsCsv = (headers, rows) => {
|
|
|
13
14
|
]);
|
|
14
15
|
return `${[[
|
|
15
16
|
...headers,
|
|
16
|
-
"
|
|
17
|
-
"
|
|
17
|
+
text("line"),
|
|
18
|
+
text("problems")
|
|
18
19
|
], ...lines].map((fields) => fields.map(csvField).join(",")).join("\r\n")}\r\n`;
|
|
19
20
|
};
|
|
20
21
|
//#endregion
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Button } from "../../primitives/button.js";
|
|
2
2
|
import { useAdminMeta, usePermissions } from "../meta-gate.js";
|
|
3
3
|
import { can } from "../permissions.js";
|
|
4
|
+
import { text } from "./messages.js";
|
|
4
5
|
import { ImportDialog } from "./import-dialog.js";
|
|
5
6
|
import { useState } from "react";
|
|
6
7
|
import { Upload } from "lucide-react";
|
|
@@ -18,7 +19,7 @@ const ImportButton = ({ model }) => {
|
|
|
18
19
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Button, {
|
|
19
20
|
onClick: () => setOpen(true),
|
|
20
21
|
"aria-haspopup": "dialog",
|
|
21
|
-
children: [/* @__PURE__ */ jsx(Upload, { className: "size-3.5" }), "
|
|
22
|
+
children: [/* @__PURE__ */ jsx(Upload, { className: "size-3.5" }), text("import")]
|
|
22
23
|
}), open && /* @__PURE__ */ jsx(ImportDialog, {
|
|
23
24
|
model,
|
|
24
25
|
resources,
|
|
@@ -3,6 +3,7 @@ import { Spinner } from "../../primitives/spinner.js";
|
|
|
3
3
|
import { Button } from "../../primitives/button.js";
|
|
4
4
|
import { saveFile } from "../../lib/save-file.js";
|
|
5
5
|
import { displayValue } from "../../live/display-value.js";
|
|
6
|
+
import { text } from "./messages.js";
|
|
6
7
|
import { failedRowsCsv } from "./failed-rows.js";
|
|
7
8
|
import { ImportCounts } from "./import-counts.js";
|
|
8
9
|
import { fieldLabel, relationModel } from "./mapping.js";
|
|
@@ -12,40 +13,27 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
12
13
|
/** How many rows with problems the check lists; the file of them holds every one. */
|
|
13
14
|
const listedProblems = 50;
|
|
14
15
|
/** Saves the rows with their problems as a CSV named after the imported file. */
|
|
15
|
-
const downloadRows = (fileName, headers, rows) => saveFile(failedRowsCsv(headers, rows),
|
|
16
|
+
const downloadRows = (fileName, headers, rows) => saveFile(failedRowsCsv(headers, rows), text("notImportedFile", (fileName ?? "import").replace(/\.[^.]+$/, "")), "text/csv");
|
|
16
17
|
/** The rows with what keeps each from being imported, at most `listedProblems` of them. */
|
|
17
18
|
const ProblemList = ({ rows }) => /* @__PURE__ */ jsxs("ul", {
|
|
18
|
-
"aria-label": "
|
|
19
|
-
className: "flex flex-col gap-1 text-
|
|
19
|
+
"aria-label": text("rowsNotImported"),
|
|
20
|
+
className: "flex flex-col gap-1 text-body",
|
|
20
21
|
children: [rows.slice(0, listedProblems).map((row) => /* @__PURE__ */ jsxs("li", { children: [
|
|
21
|
-
/* @__PURE__ */
|
|
22
|
+
/* @__PURE__ */ jsx("span", {
|
|
22
23
|
className: "font-medium",
|
|
23
|
-
children:
|
|
24
|
-
"Row ",
|
|
25
|
-
row.line,
|
|
26
|
-
":"
|
|
27
|
-
]
|
|
24
|
+
children: text("rowProblems", row.line)
|
|
28
25
|
}),
|
|
29
26
|
" ",
|
|
30
27
|
row.problems.join("; ")
|
|
31
|
-
] }, row.line)), rows.length > listedProblems && /* @__PURE__ */
|
|
28
|
+
] }, row.line)), rows.length > listedProblems && /* @__PURE__ */ jsx("li", {
|
|
32
29
|
className: "text-muted-foreground",
|
|
33
|
-
children:
|
|
34
|
-
"And ",
|
|
35
|
-
(rows.length - listedProblems).toLocaleString(formatTag()),
|
|
36
|
-
" more rows, all in the file."
|
|
37
|
-
]
|
|
30
|
+
children: text("andMore", (rows.length - listedProblems).toLocaleString(formatTag()))
|
|
38
31
|
})]
|
|
39
32
|
});
|
|
40
33
|
const ImportChecking = ({ rows }) => /* @__PURE__ */ jsxs("p", {
|
|
41
34
|
className: "flex items-center gap-2 text-muted-foreground",
|
|
42
35
|
role: "status",
|
|
43
|
-
children: [
|
|
44
|
-
/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }),
|
|
45
|
-
"Checking rows… ",
|
|
46
|
-
rows.toLocaleString(formatTag()),
|
|
47
|
-
" read"
|
|
48
|
-
]
|
|
36
|
+
children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }), text("checkingRows", rows.toLocaleString(formatTag()))]
|
|
49
37
|
});
|
|
50
38
|
/**
|
|
51
39
|
* What the import would do, before it writes anything: how many rows create or update a record, the first rows as they
|
|
@@ -58,24 +46,24 @@ const ImportCheckStep = ({ check, model, resources, views, columns, headers, fil
|
|
|
58
46
|
className: "flex flex-col gap-4",
|
|
59
47
|
children: [
|
|
60
48
|
/* @__PURE__ */ jsx(ImportCounts, {
|
|
61
|
-
label: "
|
|
49
|
+
label: text("check"),
|
|
62
50
|
counts: [
|
|
63
|
-
["
|
|
64
|
-
["
|
|
65
|
-
["
|
|
66
|
-
["
|
|
51
|
+
[text("rows"), check.rows],
|
|
52
|
+
[text("toCreate"), check.creates],
|
|
53
|
+
[text("toUpdate"), check.updates],
|
|
54
|
+
[text("withProblems"), check.problems.length]
|
|
67
55
|
]
|
|
68
56
|
}),
|
|
69
57
|
check.preview.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
70
58
|
className: "overflow-x-auto rounded-lg border",
|
|
71
59
|
children: /* @__PURE__ */ jsxs("table", {
|
|
72
|
-
"aria-label": "
|
|
73
|
-
className: "w-full text-left text-
|
|
60
|
+
"aria-label": text("firstRows"),
|
|
61
|
+
className: "w-full text-left text-body",
|
|
74
62
|
children: [/* @__PURE__ */ jsx("thead", {
|
|
75
63
|
className: "bg-muted text-muted-foreground",
|
|
76
64
|
children: /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
|
|
77
65
|
className: "px-2 py-1.5 font-medium",
|
|
78
|
-
children: "
|
|
66
|
+
children: text("row")
|
|
79
67
|
}), shown.map((field) => /* @__PURE__ */ jsx("th", {
|
|
80
68
|
className: "whitespace-nowrap px-2 py-1.5 font-medium",
|
|
81
69
|
children: fieldLabel(view, field.name)
|
|
@@ -101,21 +89,17 @@ const ImportCheckStep = ({ check, model, resources, views, columns, headers, fil
|
|
|
101
89
|
className: "flex items-center justify-between gap-2",
|
|
102
90
|
children: [/* @__PURE__ */ jsx("h3", {
|
|
103
91
|
className: "font-medium",
|
|
104
|
-
children: "
|
|
92
|
+
children: text("problemRows")
|
|
105
93
|
}), /* @__PURE__ */ jsxs(Button, {
|
|
106
94
|
size: "sm",
|
|
107
95
|
onClick: () => downloadRows(fileName, headers, check.problems),
|
|
108
|
-
children: [/* @__PURE__ */ jsx(Download, { className: "size-3.5" }), "
|
|
96
|
+
children: [/* @__PURE__ */ jsx(Download, { className: "size-3.5" }), text("download")]
|
|
109
97
|
})]
|
|
110
98
|
}), /* @__PURE__ */ jsx(ProblemList, { rows: check.problems })]
|
|
111
99
|
}),
|
|
112
|
-
/* @__PURE__ */
|
|
100
|
+
/* @__PURE__ */ jsx("p", {
|
|
113
101
|
className: "text-xs text-muted-foreground",
|
|
114
|
-
children:
|
|
115
|
-
"Rows are saved in batches of ",
|
|
116
|
-
100,
|
|
117
|
-
". Cancelling, or an error, keeps the batches already saved; a row the server refuses is listed and the others are saved."
|
|
118
|
-
]
|
|
102
|
+
children: text("batches", 100)
|
|
119
103
|
})
|
|
120
104
|
]
|
|
121
105
|
});
|