@protobase/ui 0.25.1 → 0.25.3

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.
Files changed (255) hide show
  1. package/dist/account/account-pages.js +3 -2
  2. package/dist/account/account-security-page.js +9 -4
  3. package/dist/account/backup-codes.js +7 -6
  4. package/dist/account/messages.js +214 -0
  5. package/dist/account/passkeys-section.js +23 -22
  6. package/dist/account/password-dialog.js +3 -2
  7. package/dist/account/sign-in-policy-form.js +11 -10
  8. package/dist/account/sign-in-policy-labels.js +30 -29
  9. package/dist/account/sign-in-policy-page.js +11 -6
  10. package/dist/account/sign-in-providers-section.js +6 -5
  11. package/dist/account/staff-sign-in-log.js +11 -10
  12. package/dist/account/totp-qr.js +2 -1
  13. package/dist/account/two-factor-section.js +24 -23
  14. package/dist/account/two-factor-setup.js +18 -17
  15. package/dist/action-card/action-card.js +2 -1
  16. package/dist/action-card/messages.js +8 -0
  17. package/dist/activity-chart/activity-chart.js +3 -2
  18. package/dist/activity-chart/messages.js +14 -0
  19. package/dist/app/app.d.ts +1 -1
  20. package/dist/app/app.js +20 -21
  21. package/dist/app/assistant-shell.js +2 -1
  22. package/dist/app/batch-failure.js +2 -1
  23. package/dist/app/breadcrumb-for.js +4 -3
  24. package/dist/app/charts/chart-groups.js +3 -2
  25. package/dist/app/charts/chart-view.js +3 -2
  26. package/dist/app/charts/group-bars.js +2 -1
  27. package/dist/app/charts/messages.js +26 -0
  28. package/dist/app/charts/period-chart.js +3 -2
  29. package/dist/app/charts/split-points.js +2 -1
  30. package/dist/app/comments/comment-composer.js +19 -18
  31. package/dist/app/comments/comments-section.js +4 -3
  32. package/dist/app/comments/messages.js +26 -0
  33. package/dist/app/create/create-page.js +11 -18
  34. package/dist/app/custom-section.js +4 -6
  35. package/dist/app/displays/board-column.js +6 -5
  36. package/dist/app/displays/board-columns.js +3 -2
  37. package/dist/app/displays/board-display.js +13 -15
  38. package/dist/app/displays/calendar-controls.js +3 -2
  39. package/dist/app/displays/calendar-display.js +12 -17
  40. package/dist/app/displays/card-carousel.js +4 -3
  41. package/dist/app/displays/cards-display.js +2 -1
  42. package/dist/app/displays/custom-display.js +4 -6
  43. package/dist/app/displays/display-frame.js +3 -2
  44. package/dist/app/displays/list-cards.js +5 -8
  45. package/dist/app/displays/list-displays.js +3 -3
  46. package/dist/app/displays/map-display.js +15 -14
  47. package/dist/app/displays/messages.js +128 -2
  48. package/dist/app/displays/period-controls.js +4 -3
  49. package/dist/app/displays/record-card.js +7 -6
  50. package/dist/app/displays/timeline-display.js +17 -26
  51. package/dist/app/displays/timeline-range.js +2 -1
  52. package/dist/app/displays/use-board-move.js +2 -2
  53. package/dist/app/displays/use-calendar-move.js +2 -1
  54. package/dist/app/document-title.js +2 -1
  55. package/dist/app/export/builder-port.js +2 -1
  56. package/dist/app/export/export-dialog.js +36 -40
  57. package/dist/app/export/export-worker.js +2 -0
  58. package/dist/app/export/messages.js +78 -0
  59. package/dist/app/export/run-export.js +5 -2
  60. package/dist/app/export/sink.js +4 -3
  61. package/dist/app/export/use-export-flow.js +4 -3
  62. package/dist/app/field-editor.js +4 -3
  63. package/dist/app/field-types/messages.js +8 -0
  64. package/dist/app/field-types/widget-part.js +2 -1
  65. package/dist/app/file-field.js +11 -14
  66. package/dist/app/gallery/gallery-section.js +4 -3
  67. package/dist/app/gallery/lightbox.js +5 -4
  68. package/dist/app/gallery/messages.js +30 -0
  69. package/dist/app/gallery/photo-details.js +3 -2
  70. package/dist/app/hand-order/hand-sorted-list.js +3 -6
  71. package/dist/app/hand-order/messages.js +4 -2
  72. package/dist/app/history/describe-change.js +3 -8
  73. package/dist/app/history/messages.js +32 -0
  74. package/dist/app/import/convert.js +20 -19
  75. package/dist/app/import/failed-rows.js +3 -2
  76. package/dist/app/import/import-button.js +2 -1
  77. package/dist/app/import/import-check-step.js +19 -35
  78. package/dist/app/import/import-dialog.js +13 -17
  79. package/dist/app/import/import-file-step.js +5 -9
  80. package/dist/app/import/import-mapping-step.js +32 -35
  81. package/dist/app/import/import-result-step.js +13 -12
  82. package/dist/app/import/messages.js +200 -0
  83. package/dist/app/import/parse-worker.js +2 -0
  84. package/dist/app/import/prepare-rows.js +5 -4
  85. package/dist/app/import/sheet-cell.js +2 -1
  86. package/dist/app/import/sheet-file.js +3 -2
  87. package/dist/app/import/sheet-source.js +7 -3
  88. package/dist/app/import/xlsx-reader.js +4 -3
  89. package/dist/app/import/xlsx-xml.js +2 -1
  90. package/dist/app/import/zip-reader.js +4 -3
  91. package/dist/app/list-edit/use-list-edits.js +1 -1
  92. package/dist/app/list-group-chart.js +2 -1
  93. package/dist/app/list-page.js +1 -1
  94. package/dist/app/map/map-layer-switch.js +3 -2
  95. package/dist/app/map/messages.js +14 -0
  96. package/dist/app/messages.js +116 -2
  97. package/dist/app/meta-gate.js +1 -1
  98. package/dist/app/nav-from-meta.js +11 -10
  99. package/dist/app/pages/action-inputs/action-inputs-dialog.js +3 -2
  100. package/dist/app/pages/action-inputs/input-answers.js +6 -5
  101. package/dist/app/pages/blocks/card-row.js +3 -2
  102. package/dist/app/pages/blocks/modal-form.js +5 -4
  103. package/dist/app/pages/blocks/record-card.js +3 -2
  104. package/dist/app/pages/blocks/stat.js +2 -1
  105. package/dist/app/pages/composed-page.js +6 -8
  106. package/dist/app/pages/confirm-action.js +2 -1
  107. package/dist/app/pages/custom-boundary.js +4 -2
  108. package/dist/app/pages/messages.js +64 -0
  109. package/dist/app/pages/render-node.js +5 -7
  110. package/dist/app/pages/use-run-action.js +11 -10
  111. package/dist/app/record-page.js +1 -1
  112. package/dist/app/record-row/messages.js +26 -0
  113. package/dist/app/record-row/record-row-body.js +12 -7
  114. package/dist/app/record-row/record-row.js +4 -3
  115. package/dist/app/record-row/saved-record-row.js +3 -2
  116. package/dist/app/related-dots/dots-summary.js +2 -1
  117. package/dist/app/related-dots/messages.js +8 -0
  118. package/dist/app/relation-picker.js +9 -8
  119. package/dist/app/router.js +5 -4
  120. package/dist/app/runtime/messages.js +58 -0
  121. package/dist/app/runtime/runtime-status.js +10 -23
  122. package/dist/app/runtime/runtime-update-dialog.js +7 -6
  123. package/dist/app/runtime/runtime-update.js +4 -3
  124. package/dist/app/saved/favorite-button.js +2 -1
  125. package/dist/app/saved/messages.js +22 -0
  126. package/dist/app/saved/saved-list.js +4 -7
  127. package/dist/app/saved/use-favorite.js +3 -2
  128. package/dist/app/search/messages.js +6 -2
  129. package/dist/app/search/navigation-hits.js +9 -7
  130. package/dist/app/searches/filter-chip-list.js +2 -1
  131. package/dist/app/searches/messages.js +96 -0
  132. package/dist/app/searches/save-search-button.js +5 -4
  133. package/dist/app/searches/saved-search-rows.js +3 -2
  134. package/dist/app/searches/saved-search-section.js +6 -5
  135. package/dist/app/searches/saved-search.js +4 -3
  136. package/dist/app/searches/saved-searches.js +15 -25
  137. package/dist/app/searches/search-controls.js +5 -4
  138. package/dist/app/searches/search-diff.js +4 -2
  139. package/dist/app/searches/search-name-dialog.js +4 -3
  140. package/dist/app/searches/update-search-dialog.js +15 -30
  141. package/dist/app/searches/use-save-search.js +8 -7
  142. package/dist/app/searches/use-search-row.js +4 -3
  143. package/dist/app/sensitive-field.js +5 -4
  144. package/dist/app/source-notice.js +13 -8
  145. package/dist/app/staff-banner.js +12 -19
  146. package/dist/app-shell/global-search.js +2 -2
  147. package/dist/app-shell/messages.js +4 -2
  148. package/dist/assistant-dock/assistant-dock.js +5 -5
  149. package/dist/assistant-dock/messages.js +26 -0
  150. package/dist/assistant-dock/use-assistant.js +2 -1
  151. package/dist/assistant-dock/use-backend-data.js +2 -1
  152. package/dist/assistant-dock/widget-view.js +3 -2
  153. package/dist/auth/auth-gate.js +10 -5
  154. package/dist/auth/auth-locale.js +14 -0
  155. package/dist/auth/auth-messages.js +122 -43
  156. package/dist/auth/auth-provider.js +6 -1
  157. package/dist/auth/code-form.js +2 -1
  158. package/dist/auth/email-code-form.js +11 -13
  159. package/dist/auth/email-code-page.js +2 -1
  160. package/dist/auth/first-run-page.js +6 -5
  161. package/dist/auth/forgot-password-form.js +14 -16
  162. package/dist/auth/forgot-password-page.js +2 -1
  163. package/dist/auth/messages.js +200 -0
  164. package/dist/auth/provider-sign-in-page.js +5 -5
  165. package/dist/auth/resend-code-button.js +2 -1
  166. package/dist/auth/reset-password-form.js +11 -10
  167. package/dist/auth/reset-password-page.js +4 -3
  168. package/dist/auth/setup-required-form.js +7 -9
  169. package/dist/auth/setup-required-page.js +7 -2
  170. package/dist/auth/sign-in-form.js +15 -18
  171. package/dist/auth/sign-in-prompt.js +4 -3
  172. package/dist/auth/sign-up-code-form.js +11 -13
  173. package/dist/auth/sign-up-details-form.js +14 -21
  174. package/dist/auth/sign-up-email-form.js +8 -7
  175. package/dist/auth/sign-up-page.js +2 -1
  176. package/dist/auth/staff-sign-in-form.js +14 -17
  177. package/dist/auth/two-factor-form.js +17 -16
  178. package/dist/auth/user-to-shell.js +2 -1
  179. package/dist/chat/composer.js +8 -7
  180. package/dist/chat/messages.js +14 -0
  181. package/dist/compact-table/compact-table.js +4 -8
  182. package/dist/compact-table/messages.js +18 -0
  183. package/dist/data/meta-data.d.ts +1 -1
  184. package/dist/data/use-update-record.js +1 -1
  185. package/dist/inline-child-table/inline-child-table.js +12 -12
  186. package/dist/inline-child-table/line-row.js +10 -9
  187. package/dist/inline-child-table/messages.js +52 -0
  188. package/dist/inline-child-table/totals-footer.js +5 -8
  189. package/dist/invitations/invite-form.js +3 -2
  190. package/dist/invitations/link-notice.js +6 -4
  191. package/dist/invitations/messages.js +24 -0
  192. package/dist/invitations/pending-invitation-row.js +4 -3
  193. package/dist/lists/messages.js +8 -0
  194. package/dist/lists/paged-search-list.js +2 -1
  195. package/dist/locale/slotted.js +14 -0
  196. package/dist/markdown/markdown-editor.js +6 -5
  197. package/dist/markdown/messages.js +16 -0
  198. package/dist/organizations/all-organizations.js +6 -5
  199. package/dist/organizations/app-roles-picker.js +2 -1
  200. package/dist/organizations/invitation-page.js +39 -49
  201. package/dist/organizations/invitations-page.js +11 -10
  202. package/dist/organizations/members-page.js +15 -10
  203. package/dist/organizations/messages.js +180 -0
  204. package/dist/organizations/organization-page.js +27 -26
  205. package/dist/organizations/organization-paths.js +16 -13
  206. package/dist/organizations/organization-row.js +3 -2
  207. package/dist/organizations/organizations-page.js +17 -16
  208. package/dist/organizations/use-organizations.js +2 -1
  209. package/dist/package.js +1 -1
  210. package/dist/plugins/before-sign-in.js +6 -1
  211. package/dist/plugins/load-plugin.d.ts +1 -1
  212. package/dist/plugins/load-plugin.js +3 -2
  213. package/dist/plugins/messages.js +36 -0
  214. package/dist/plugins/plugin-gate.js +6 -1
  215. package/dist/plugins/plugin-manifest.js +8 -7
  216. package/dist/plugins/plugin-notice.js +8 -12
  217. package/dist/primitives/messages.js +16 -0
  218. package/dist/primitives/sheet.js +2 -1
  219. package/dist/primitives/spinner.js +2 -1
  220. package/dist/primitives/token.js +2 -1
  221. package/dist/record-view/messages.js +4 -2
  222. package/dist/record-view/record-tabs.js +2 -1
  223. package/dist/roles/messages.js +14 -0
  224. package/dist/roles/use-active-role.js +3 -2
  225. package/dist/shell/assets/app-CW3U56yM.js +69 -0
  226. package/dist/shell/assets/cn-Bi0ZEjD9.js +1 -0
  227. package/dist/shell/assets/export-worker-ClACk00b.js +2 -0
  228. package/dist/shell/assets/{index-BuKnJ48y.js → index-B7cIjCuz.js} +2 -2
  229. package/dist/shell/assets/maplibre-CVG5L9FD.js +814 -0
  230. package/dist/shell/assets/{markdown-content-CvNiaqsy.js → markdown-content-CtGUP4W6.js} +1 -1
  231. package/dist/shell/assets/parse-worker-UhbwEjS0.js +5 -0
  232. package/dist/shell/assets/preload-helper-BX9CcZkY.js +1 -0
  233. package/dist/shell/assets/{record-map-BmPHHEMK.js → record-map-Cw3_NcUl.js} +1 -1
  234. package/dist/shell/assets/records-map-D4f3ZeDL.js +1 -0
  235. package/dist/shell/assets/shared-protobase-ui-CB_i50NP.js +1 -0
  236. package/dist/shell/index.html +5 -3
  237. package/dist/shell/protobase.shell.json +1 -1
  238. package/dist/shell/protobase.sw.js +2 -2
  239. package/dist/side-panel/messages.js +8 -0
  240. package/dist/side-panel/side-panel.js +2 -1
  241. package/dist/toasts/messages.js +8 -0
  242. package/dist/toasts/toast.js +2 -1
  243. package/dist/users/app-invitations.js +5 -4
  244. package/dist/users/create-user-form.js +9 -8
  245. package/dist/users/messages.js +52 -0
  246. package/dist/users/use-user-roles.js +2 -1
  247. package/dist/users/user-list.js +6 -5
  248. package/dist/users/user-row.js +5 -4
  249. package/package.json +4 -4
  250. package/dist/shell/assets/app-BPHSSo4E.js +0 -69
  251. package/dist/shell/assets/export-worker-Bz57Pf5g.js +0 -2
  252. package/dist/shell/assets/maplibre-C2VkKdp3.js +0 -814
  253. package/dist/shell/assets/parse-worker-BtcY0dQw.js +0 -5
  254. package/dist/shell/assets/records-map-BvUD1Fqc.js +0 -1
  255. package/dist/shell/assets/shared-protobase-ui-B-pEBDQf.js +0 -1
@@ -4,8 +4,8 @@ import { useToast } from "../../toasts/toast-provider.js";
4
4
  import { recordKey } from "../../live/model-helpers.js";
5
5
  import { text } from "./messages.js";
6
6
  import { useRef, useState } from "react";
7
- import { isApiError } from "@protobase/client";
8
7
  import { encodeKey } from "@protobase/schema/internal";
8
+ import { isApiError } from "@protobase/client";
9
9
  import { useQueryClient } from "@tanstack/react-query";
10
10
  //#region src/app/list-edit/use-list-edits.ts
11
11
  /**
@@ -1,3 +1,4 @@
1
+ import { text } from "./messages.js";
1
2
  import { humanize } from "../live/naming.js";
2
3
  import { ChartView } from "./charts/chart-view.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -6,7 +7,7 @@ const measureTitle = (chart, view, plural) => {
6
7
  const name = chart.sum ?? chart.average;
7
8
  if (name === void 0) return plural;
8
9
  const label = view?.fields[name]?.label ?? humanize(name);
9
- return chart.sum !== void 0 ? `${label}` : `Average ${label.toLowerCase()}`;
10
+ return chart.sum !== void 0 ? `${label}` : text("average", label);
10
11
  };
11
12
  /** The view's chart per value of a field, above the list and following its filter. */
12
13
  const ListGroupChart = ({ model, view, chart, plural, filter }) => {
@@ -3,6 +3,7 @@ import { usePageScroll } from "../app-shell/page-scroll.js";
3
3
  import { PageHeader } from "../app-shell/page-header.js";
4
4
  import { useAuth } from "../auth/auth-provider.js";
5
5
  import { Button, buttonClass } from "../primitives/button.js";
6
+ import { text } from "./messages.js";
6
7
  import { humanize } from "../live/naming.js";
7
8
  import { recordKey, recordTitleField } from "../live/model-helpers.js";
8
9
  import { columnsFromModel, listColumnNames } from "../live/columns-from-model.js";
@@ -12,7 +13,6 @@ import { parseSort, sortToOrderBy } from "./list-order.js";
12
13
  import { listedResource } from "./current-address.js";
13
14
  import { Notice, useAdminMeta, usePermissions } from "./meta-gate.js";
14
15
  import { AppLink, useAppAddress } from "./use-app-address.js";
15
- import { text } from "./messages.js";
16
16
  import { ErrorBanner } from "./error-banner.js";
17
17
  import { useProjectUi } from "./pages/project-ui.js";
18
18
  import { Sheet } from "../primitives/sheet.js";
@@ -1,5 +1,6 @@
1
1
  import { Segmented } from "../../primitives/segmented.js";
2
2
  import { chosenMapLayer, readMapLayer, writeMapLayer } from "./map-layer-choice.js";
3
+ import { text } from "./messages.js";
3
4
  import { useState } from "react";
4
5
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
6
  import { Layer, Source, useMap } from "react-map-gl/maplibre";
@@ -38,12 +39,12 @@ const MapLayerSwitch = ({ layers, below }) => {
38
39
  }, chosen.id), /* @__PURE__ */ jsx("div", {
39
40
  className: "absolute left-2.5 top-2.5 z-10 rounded-md shadow",
40
41
  children: /* @__PURE__ */ jsx(Segmented, {
41
- label: "Map layer",
42
+ label: text("mapLayer"),
42
43
  value: chosen?.id ?? styleValue,
43
44
  onChange: choose,
44
45
  options: [{
45
46
  value: styleValue,
46
- label: "Map"
47
+ label: text("map")
47
48
  }, ...layers.map((layer) => ({
48
49
  value: layer.id,
49
50
  label: layer.label
@@ -0,0 +1,14 @@
1
+ import { defineMessages } from "../../locale/messages.js";
2
+ //#region src/app/map/messages.ts
3
+ const text = defineMessages({
4
+ en: {
5
+ mapLayer: "Map layer",
6
+ map: "Map"
7
+ },
8
+ nl: {
9
+ mapLayer: "Kaartlaag",
10
+ map: "Kaart"
11
+ }
12
+ });
13
+ //#endregion
14
+ export { text };
@@ -4,12 +4,126 @@ const text = defineMessages({
4
4
  en: {
5
5
  notFound: "Not found",
6
6
  noResource: (name) => `There is no resource called ${name}.`,
7
- somethingWentWrong: "Something went wrong"
7
+ somethingWentWrong: "Something went wrong",
8
+ signInSecurity: "Sign-in & security",
9
+ signInPolicy: "Sign-in policy",
10
+ adminsOnly: "Admins only",
11
+ onlyAdminPolicy: "Only an admin can change how people sign in.",
12
+ ownersOnly: "Owners and admins only",
13
+ onlyOwners: "Only the organization's owners and admins manage its members.",
14
+ chooseResource: "Choose a resource",
15
+ pickFromSidebar: "Pick one from the sidebar.",
16
+ nothingHere: "There is nothing at this address.",
17
+ noPage: "There is no page called {}.",
18
+ assistant: "Assistant",
19
+ operationFailed: (index, label, message) => `Operation ${index} (${label}) failed: ${message} Nothing was saved.`,
20
+ nothingSaved: (message) => `${message} Nothing was saved.`,
21
+ admin: "Admin",
22
+ new: "New",
23
+ loadingRecord: "Loading record",
24
+ noComponent: "No component is registered as {}. Export it from protobase.ui.tsx, or load the plugin that provides it.",
25
+ choose: "Choose...",
26
+ fileMissing: "The file is missing from storage",
27
+ chooseFileFor: (label) => `Choose a file for ${label}`,
28
+ notUploaded: "Not uploaded",
29
+ uploadingLabel: (label) => `Uploading ${label}`,
30
+ uploading: (percent) => `Uploading… ${percent}%`,
31
+ replace: "Replace",
32
+ remove: "Remove",
33
+ dropFile: "Drop a file here or",
34
+ chooseFile: "Choose a file",
35
+ average: (label) => `Average ${label.toLowerCase()}`,
36
+ pages: "Pages",
37
+ account: "Account",
38
+ sales: "Sales",
39
+ crm: "CRM",
40
+ catalog: "Catalog",
41
+ inventory: "Inventory",
42
+ hr: "HR",
43
+ cannotReach: (label) => `Cannot reach ${label}`,
44
+ searchPlural: (plural) => `Search ${plural}`,
45
+ couldNotLoadOptions: "Could not load the options",
46
+ noMatches: "No matches",
47
+ loading: "Loading",
48
+ leaveTitle: "Leave without saving?",
49
+ leaveDescription: "You have unsaved changes on this page. They stay in this browser, and come back when you open the record again.",
50
+ stay: "Stay",
51
+ leave: "Leave",
52
+ show: (label) => `Show ${label}`,
53
+ hide: (label) => `Hide ${label}`,
54
+ couldNotShow: (label) => `Could not show the ${label}`,
55
+ noAnswer: "It did not answer.",
56
+ signInRefused: (message) => `It did not accept your sign-in: ${message}`,
57
+ loadingFrom: (label) => `Loading from ${label}`,
58
+ restWorks: "The rest of the app works as before.",
59
+ tryAgain: "Try again",
60
+ staffSession: "Staff session",
61
+ staffSignedIn: "{} is signed in as {} until {}. Reason: {}",
62
+ stopStaffSession: "Stop staff session",
63
+ open: "Open",
64
+ openLabel: (label) => `Open ${label}`
8
65
  },
9
66
  nl: {
10
67
  notFound: "Niet gevonden",
11
68
  noResource: (name) => `Er is geen onderdeel met de naam ${name}.`,
12
- somethingWentWrong: "Er ging iets mis"
69
+ somethingWentWrong: "Er ging iets mis",
70
+ signInSecurity: "Inloggen en beveiliging",
71
+ signInPolicy: "Inlogbeleid",
72
+ adminsOnly: "Alleen beheerders",
73
+ onlyAdminPolicy: "Alleen een beheerder kan wijzigen hoe mensen inloggen.",
74
+ ownersOnly: "Alleen eigenaren en beheerders",
75
+ onlyOwners: "Alleen de eigenaren en beheerders van de organisatie beheren de leden.",
76
+ chooseResource: "Kies een onderdeel",
77
+ pickFromSidebar: "Kies er een in de zijbalk.",
78
+ nothingHere: "Er is niets op dit adres.",
79
+ noPage: "Er is geen pagina met de naam {}.",
80
+ assistant: "Assistent",
81
+ operationFailed: (index, label, message) => `Bewerking ${index} (${label}) mislukte: ${message} Er is niets bewaard.`,
82
+ nothingSaved: (message) => `${message} Er is niets bewaard.`,
83
+ admin: "Beheer",
84
+ new: "Nieuw",
85
+ loadingRecord: "Record laden",
86
+ noComponent: "Er is geen component geregistreerd als {}. Exporteer die uit protobase.ui.tsx, of laad de plug-in die haar levert.",
87
+ choose: "Kiezen...",
88
+ fileMissing: "Het bestand ontbreekt in de opslag",
89
+ chooseFileFor: (label) => `Kies een bestand voor ${label}`,
90
+ notUploaded: "Niet geüpload",
91
+ uploadingLabel: (label) => `${label} uploaden`,
92
+ uploading: (percent) => `Uploaden… ${percent}%`,
93
+ replace: "Vervangen",
94
+ remove: "Verwijderen",
95
+ dropFile: "Zet hier een bestand neer of",
96
+ chooseFile: "Kies een bestand",
97
+ average: (label) => `${label}, gemiddeld`,
98
+ pages: "Pagina's",
99
+ account: "Account",
100
+ sales: "Verkoop",
101
+ crm: "CRM",
102
+ catalog: "Catalogus",
103
+ inventory: "Voorraad",
104
+ hr: "HR",
105
+ cannotReach: (label) => `Kan ${label} niet bereiken`,
106
+ searchPlural: (plural) => `${plural} zoeken`,
107
+ couldNotLoadOptions: "Kon de keuzes niet laden",
108
+ noMatches: "Niets gevonden",
109
+ loading: "Laden",
110
+ leaveTitle: "Weggaan zonder te bewaren?",
111
+ leaveDescription: "Je hebt niet-bewaarde wijzigingen op deze pagina. Ze blijven in deze browser, en komen terug als je het record weer opent.",
112
+ stay: "Blijven",
113
+ leave: "Weggaan",
114
+ show: (label) => `${label} tonen`,
115
+ hide: (label) => `${label} verbergen`,
116
+ couldNotShow: (label) => `Kon ${label} niet tonen`,
117
+ noAnswer: "Het antwoordde niet.",
118
+ signInRefused: (message) => `Het accepteerde je inlog niet: ${message}`,
119
+ loadingFrom: (label) => `Laden van ${label}`,
120
+ restWorks: "De rest van de app werkt zoals eerst.",
121
+ tryAgain: "Opnieuw proberen",
122
+ staffSession: "Sessie van een medewerker",
123
+ staffSignedIn: "{} is ingelogd als {} tot {}. Reden: {}",
124
+ stopStaffSession: "Sessie van medewerker stoppen",
125
+ open: "Openen",
126
+ openLabel: (label) => `${label} openen`
13
127
  }
14
128
  });
15
129
  //#endregion
@@ -1,11 +1,11 @@
1
1
  import { Spinner } from "../primitives/spinner.js";
2
2
  import { ClientProvider, useClient, useSourceClients } from "../data/api-provider.js";
3
+ import { AppLocale } from "../locale/app-locale.js";
3
4
  import { withSources } from "../data/with-sources.js";
4
5
  import { MetaContext } from "../data/meta-context.js";
5
6
  import { allowEverything } from "../data/meta-data.js";
6
7
  import { useMeta } from "../data/use-meta.js";
7
8
  import { useSourceMetas } from "../data/use-source-metas.js";
8
- import { AppLocale } from "../locale/app-locale.js";
9
9
  import { text } from "./meta-gate-messages.js";
10
10
  import { useContext, useMemo } from "react";
11
11
  import { isApiError, routedClient } from "@protobase/client";
@@ -1,3 +1,4 @@
1
+ import { text } from "./messages.js";
1
2
  import { humanize } from "../live/naming.js";
2
3
  import { iconFor } from "./icons.js";
3
4
  import { menuIcon } from "./menu-icons.js";
@@ -8,12 +9,12 @@ import { appPath } from "@protobase/schema";
8
9
  /** The sidebar item of a resource's list, or of one of its named lists. */
9
10
  const navItemId = (resource, list) => list === void 0 ? resource : `${resource}/${list}`;
10
11
  const groupLabels = {
11
- sales: "Sales",
12
- crm: "CRM",
13
- catalog: "Catalog",
14
- inventory: "Inventory",
15
- core: "Admin",
16
- hr: "HR"
12
+ sales: "sales",
13
+ crm: "crm",
14
+ catalog: "catalog",
15
+ inventory: "inventory",
16
+ core: "admin",
17
+ hr: "hr"
17
18
  };
18
19
  /**
19
20
  * One sidebar group per `nav.group` (default: the database schema, and "Pages" for pages); `nav.hidden` and a place in
@@ -29,7 +30,7 @@ const navFromMeta = (meta, basePath = "", recent = {}) => {
29
30
  const inMenu = userMenuResources(meta);
30
31
  for (const page of Object.values(meta.pages)) {
31
32
  if (page.nav?.hidden || inMenu.has(page.name)) continue;
32
- const groupName = page.nav?.group ?? "Pages";
33
+ const groupName = page.nav?.group ?? text("pages");
33
34
  const group = groups.get(groupName) ?? {
34
35
  label: groupName,
35
36
  items: []
@@ -50,7 +51,7 @@ const navFromMeta = (meta, basePath = "", recent = {}) => {
50
51
  const view = meta.views[model.name];
51
52
  if (!view || inMenu.has(model.name)) continue;
52
53
  const schema = model.table.schema ?? "public";
53
- const defaultGroup = view.nav?.group ?? groupLabels[schema] ?? humanize(schema);
54
+ const defaultGroup = view.nav?.group ?? (groupLabels[schema] ? text(groupLabels[schema]) : humanize(schema));
54
55
  const add = (groupName, item, order) => {
55
56
  const group = groups.get(groupName) ?? {
56
57
  label: groupName,
@@ -86,7 +87,7 @@ const navFromMeta = (meta, basePath = "", recent = {}) => {
86
87
  }
87
88
  for (const entry of Object.values(meta.signIn ?? {})) {
88
89
  if (entry.nav?.hidden || inMenu.has(entry.resource)) continue;
89
- const groupName = entry.nav?.group ?? "Account";
90
+ const groupName = entry.nav?.group ?? text("account");
90
91
  const group = groups.get(groupName) ?? {
91
92
  label: groupName,
92
93
  items: []
@@ -117,7 +118,7 @@ const navFromMeta = (meta, basePath = "", recent = {}) => {
117
118
  kind: "list",
118
119
  resource
119
120
  }, basePath),
120
- problem: `Cannot reach ${status.source.label}`
121
+ problem: text("cannotReach", status.source.label)
121
122
  });
122
123
  groups.set(status.source.label, group);
123
124
  }
@@ -1,4 +1,5 @@
1
1
  import { Button } from "../../../primitives/button.js";
2
+ import { text } from "../messages.js";
2
3
  import { Field } from "../../../record-view/field.js";
3
4
  import { useAdminMeta } from "../../meta-gate.js";
4
5
  import { isChosen } from "../../create/create-values.js";
@@ -74,7 +75,7 @@ const ActionInputsDialog = ({ action, label, danger, onCancel, onSubmit }) => {
74
75
  onClose: onCancel,
75
76
  actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
76
77
  onClick: onCancel,
77
- children: "Cancel"
78
+ children: text("cancel")
78
79
  }), /* @__PURE__ */ jsx(Button, {
79
80
  variant: danger ? "danger" : "primary",
80
81
  type: "submit",
@@ -90,7 +91,7 @@ const ActionInputsDialog = ({ action, label, danger, onCancel, onSubmit }) => {
90
91
  submit();
91
92
  },
92
93
  children: [failure !== void 0 && Object.keys(errors).length === 0 && /* @__PURE__ */ jsx(ErrorBanner, {
93
- title: `${label} failed`,
94
+ title: text("failed", label),
94
95
  error: failure
95
96
  }), action.inputs.filter((input) => shown.has(input.name)).map((input) => /* @__PURE__ */ jsx(Field, {
96
97
  label: input.label,
@@ -1,3 +1,4 @@
1
+ import { text } from "../messages.js";
1
2
  import { toDraft, toPatchValue } from "../../../live/field-values.js";
2
3
  import { isChosen } from "../../create/create-values.js";
3
4
  import { shownInputs } from "@protobase/schema/internal";
@@ -72,11 +73,11 @@ const answeredValues = (inputs, draft) => {
72
73
  const decimal = /^-?\d+(\.\d+)?$/;
73
74
  const date = /^\d{4}-\d{2}-\d{2}$/;
74
75
  const refusal = (input, value) => {
75
- if (value === null || value === "") return input.required ? "Required" : void 0;
76
- if (input.kind === "integer" && !Number.isInteger(value)) return "A whole number";
77
- if (input.kind === "decimal" && !decimal.test(String(value))) return "A number";
78
- if (input.kind === "date" && !date.test(String(value))) return "A date as YYYY-MM-DD";
79
- if (input.max !== void 0 && String(value).length > input.max) return `At most ${input.max} characters`;
76
+ if (value === null || value === "") return input.required ? text("required") : void 0;
77
+ if (input.kind === "integer" && !Number.isInteger(value)) return text("wholeNumber");
78
+ if (input.kind === "decimal" && !decimal.test(String(value))) return text("number");
79
+ if (input.kind === "date" && !date.test(String(value))) return text("dateFormat");
80
+ if (input.max !== void 0 && String(value).length > input.max) return text("atMost", input.max);
80
81
  };
81
82
  /** What is wrong with the answers that show, by input name: one left empty that is required, a number that is none, a text too long. */
82
83
  const refusedAnswers = (inputs, values) => Object.fromEntries(inputs.flatMap((input) => {
@@ -1,4 +1,5 @@
1
1
  import { Skeleton } from "../../../primitives/skeleton.js";
2
+ import { text } from "../messages.js";
2
3
  import { useAdminMeta } from "../../meta-gate.js";
3
4
  import { ErrorBanner } from "../../error-banner.js";
4
5
  import { RecordScope } from "../record-scope.js";
@@ -22,9 +23,9 @@ const LoadedCardRow = ({ model, filter, sort, limit = 12, title, description, em
22
23
  className: "flex gap-3",
23
24
  children: Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-56" }, index))
24
25
  }) : page.error ? /* @__PURE__ */ jsx(ErrorBanner, {
25
- title: "Could not load",
26
+ title: text("couldNotLoad"),
26
27
  error: page.error
27
- }) : rows.length === 0 ? /* @__PURE__ */ jsx(Quiet, { children: empty ?? "Nothing here yet." }) : /* @__PURE__ */ jsx("ul", {
28
+ }) : rows.length === 0 ? /* @__PURE__ */ jsx(Quiet, { children: empty ?? text("nothingYet") }) : /* @__PURE__ */ jsx("ul", {
28
29
  className: "relative -mx-4 flex snap-x gap-3 overflow-x-auto px-4 pb-1",
29
30
  children: rows.map((row) => {
30
31
  const scope = scopeOf(model, row);
@@ -1,6 +1,7 @@
1
1
  import { Button } from "../../../primitives/button.js";
2
2
  import { Dialog } from "../../../primitives/dialog.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 { useToast } from "../../../toasts/toast-provider.js";
6
7
  import { Field } from "../../../record-view/field.js";
@@ -54,7 +55,7 @@ const ModalFormDialog = ({ model, record, mode, label, title, fields, values, on
54
55
  await refresh(model.name);
55
56
  toast.show({
56
57
  state: "success",
57
- title: `${title ?? label}: saved`
58
+ title: text("saved", title ?? label)
58
59
  });
59
60
  onClose();
60
61
  }, (error) => {
@@ -70,12 +71,12 @@ const ModalFormDialog = ({ model, record, mode, label, title, fields, values, on
70
71
  onClose,
71
72
  actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
72
73
  onClick: onClose,
73
- children: "Cancel"
74
+ children: text("cancel")
74
75
  }), /* @__PURE__ */ jsx(Button, {
75
76
  variant: "primary",
76
77
  loading: saving,
77
78
  onClick: () => void submit(),
78
- children: mode === "create" ? "Create" : "Save"
79
+ children: mode === "create" ? text("create") : text("save")
79
80
  })] }),
80
81
  children: /* @__PURE__ */ jsxs("form", {
81
82
  ref: formRef,
@@ -85,7 +86,7 @@ const ModalFormDialog = ({ model, record, mode, label, title, fields, values, on
85
86
  submit();
86
87
  },
87
88
  children: [failure !== void 0 && Object.keys(errors).length === 0 && /* @__PURE__ */ jsx(ErrorBanner, {
88
- title: "Not saved",
89
+ title: text("notSaved"),
89
90
  error: failure
90
91
  }), fields.map((name) => {
91
92
  const field = model.fields[name];
@@ -1,4 +1,5 @@
1
1
  import { Skeleton } from "../../../primitives/skeleton.js";
2
+ import { text } from "../messages.js";
2
3
  import { useAdminMeta } from "../../meta-gate.js";
3
4
  import { ErrorBanner } from "../../error-banner.js";
4
5
  import { RecordScope } from "../record-scope.js";
@@ -21,12 +22,12 @@ const LoadedRecordCard = ({ model, filter, sort, recordKey, title, description,
21
22
  className: "flex flex-col gap-2",
22
23
  children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/2" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/3" })]
23
24
  }) : record.error ? /* @__PURE__ */ jsx(ErrorBanner, {
24
- title: "Could not load",
25
+ title: text("couldNotLoad"),
25
26
  error: record.error
26
27
  }) : record.data ? scoped(/* @__PURE__ */ jsx("div", {
27
28
  className: "flex flex-col gap-3",
28
29
  children
29
- })) : /* @__PURE__ */ jsx(Quiet, { children: empty ?? "Nothing here yet." });
30
+ })) : /* @__PURE__ */ jsx(Quiet, { children: empty ?? text("nothingYet") });
30
31
  return /* @__PURE__ */ jsx(CardFrame, {
31
32
  title,
32
33
  description,
@@ -1,5 +1,6 @@
1
1
  import { formatTag } from "../../../locale/active-locale.js";
2
2
  import { Skeleton } from "../../../primitives/skeleton.js";
3
+ import { text } from "../messages.js";
3
4
  import { useAdminMeta } from "../../meta-gate.js";
4
5
  import { AppLink } from "../../use-app-address.js";
5
6
  import { useLayoutRecord } from "../record-scope.js";
@@ -18,7 +19,7 @@ const Count = ({ model, filter }) => {
18
19
  if (count.isPending) return /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-16" });
19
20
  if (count.error) return /* @__PURE__ */ jsx("span", {
20
21
  className: "text-danger-text",
21
- children: "Could not count"
22
+ children: text("couldNotCount")
22
23
  });
23
24
  return /* @__PURE__ */ jsx(AppLink, {
24
25
  to: filteredListAddress(views[model.name], model.name, filter),
@@ -1,17 +1,15 @@
1
+ import { slotted } from "../../locale/slotted.js";
2
+ import { text } from "./messages.js";
1
3
  import { Notice, useAdminMeta } from "../meta-gate.js";
2
4
  import { RenderNode } from "./render-node.js";
3
- import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { jsx } from "react/jsx-runtime";
4
6
  //#region src/app/pages/composed-page.tsx
5
7
  /** `/<page>`: the page's tree as `/meta` gave it to this user. */
6
8
  const ComposedPage = ({ name }) => {
7
9
  const page = useAdminMeta().pages[name];
8
- if (!page) return /* @__PURE__ */ jsxs(Notice, {
9
- title: "Not found",
10
- children: [
11
- "There is no page called ",
12
- name,
13
- "."
14
- ]
10
+ if (!page) return /* @__PURE__ */ jsx(Notice, {
11
+ title: text("notFound"),
12
+ children: slotted(text("noPage"), name)
15
13
  });
16
14
  return /* @__PURE__ */ jsx(RenderNode, { node: page.tree });
17
15
  };
@@ -1,5 +1,6 @@
1
1
  import { Button } from "../../primitives/button.js";
2
2
  import { Dialog } from "../../primitives/dialog.js";
3
+ import { text } from "./messages.js";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  //#region src/app/pages/confirm-action.tsx
5
6
  /** The question an action with `confirm` asks before it runs. */
@@ -9,7 +10,7 @@ const ConfirmAction = ({ action, label, danger, onCancel, onConfirm }) => /* @__
9
10
  onClose: onCancel,
10
11
  actions: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
11
12
  onClick: onCancel,
12
- children: "Cancel"
13
+ children: text("cancel")
13
14
  }), /* @__PURE__ */ jsx(Button, {
14
15
  variant: danger ? "danger" : "primary",
15
16
  onClick: onConfirm,
@@ -1,7 +1,9 @@
1
+ import { slotted } from "../../locale/slotted.js";
1
2
  import { reportRenderError } from "../error-reporting.js";
2
3
  import { Problem } from "./problem.js";
4
+ import { text } from "./messages.js";
3
5
  import { Component } from "react";
4
- import { jsxs } from "react/jsx-runtime";
6
+ import { jsx } from "react/jsx-runtime";
5
7
  //#region src/app/pages/custom-boundary.tsx
6
8
  /** Draws a warning in place of a project's or plugin's component that throws, so one component cannot blank the app. */
7
9
  var CustomBoundary = class extends Component {
@@ -14,7 +16,7 @@ var CustomBoundary = class extends Component {
14
16
  }
15
17
  render() {
16
18
  if (!this.state.failed) return this.props.children;
17
- return this.props.fallback === void 0 ? /* @__PURE__ */ jsxs(Problem, { children: [this.props.name, " could not be drawn."] }) : this.props.fallback;
19
+ return this.props.fallback === void 0 ? /* @__PURE__ */ jsx(Problem, { children: slotted(text("couldNotDraw"), this.props.name) }) : this.props.fallback;
18
20
  }
19
21
  };
20
22
  //#endregion
@@ -0,0 +1,64 @@
1
+ import { defineMessages } from "../../locale/messages.js";
2
+ //#region src/app/pages/messages.ts
3
+ const text = defineMessages({
4
+ en: {
5
+ notFound: "Not found",
6
+ noPage: "There is no page called {}.",
7
+ cancel: "Cancel",
8
+ couldNotDraw: "{} could not be drawn.",
9
+ noComponent: "No component is registered as {}. Export it from protobase.ui.tsx, or load the plugin that provides it.",
10
+ unknownBlock: "{} is not a block this version of the app knows.",
11
+ somethingWrong: "Something went wrong",
12
+ needsRecord: "Needs a record",
13
+ cannotChange: "You cannot change this record",
14
+ cannotDelete: "You cannot delete this record",
15
+ noHandler: (name) => `The app has no handler for "${name}"`,
16
+ noInputComponent: (component, input) => `The app has no component "${component}" for input "${input}"`,
17
+ done: (label) => `${label}: done`,
18
+ failed: (label) => `${label} failed`,
19
+ noAction: (name) => `No action "${name}"`,
20
+ couldNotLoad: "Could not load",
21
+ nothingYet: "Nothing here yet.",
22
+ saved: (label) => `${label}: saved`,
23
+ create: "Create",
24
+ save: "Save",
25
+ notSaved: "Not saved",
26
+ couldNotCount: "Could not count",
27
+ required: "Required",
28
+ wholeNumber: "A whole number",
29
+ number: "A number",
30
+ dateFormat: "A date as YYYY-MM-DD",
31
+ atMost: (max) => `At most ${max} characters`
32
+ },
33
+ nl: {
34
+ notFound: "Niet gevonden",
35
+ noPage: "Er is geen pagina met de naam {}.",
36
+ cancel: "Annuleren",
37
+ couldNotDraw: "{} kon niet worden getekend.",
38
+ noComponent: "Er is geen component geregistreerd als {}. Exporteer die uit protobase.ui.tsx, of laad de plug-in die haar levert.",
39
+ unknownBlock: "{} is geen blok dat deze versie van de app kent.",
40
+ somethingWrong: "Er ging iets mis",
41
+ needsRecord: "Vraagt een record",
42
+ cannotChange: "Je kunt dit record niet wijzigen",
43
+ cannotDelete: "Je kunt dit record niet verwijderen",
44
+ noHandler: (name) => `De app heeft geen handler voor "${name}"`,
45
+ noInputComponent: (component, input) => `De app heeft geen component "${component}" voor invoer "${input}"`,
46
+ done: (label) => `${label}: klaar`,
47
+ failed: (label) => `${label} mislukt`,
48
+ noAction: (name) => `Geen actie "${name}"`,
49
+ couldNotLoad: "Kon niet laden",
50
+ nothingYet: "Hier staat nog niets.",
51
+ saved: (label) => `${label}: bewaard`,
52
+ create: "Maken",
53
+ save: "Bewaren",
54
+ notSaved: "Niet bewaard",
55
+ couldNotCount: "Kon niet tellen",
56
+ required: "Verplicht",
57
+ wholeNumber: "Een geheel getal",
58
+ number: "Een getal",
59
+ dateFormat: "Een datum als JJJJ-MM-DD",
60
+ atMost: (max) => `Hoogstens ${max} tekens`
61
+ }
62
+ });
63
+ //#endregion
64
+ export { text };
@@ -1,4 +1,6 @@
1
+ import { slotted } from "../../locale/slotted.js";
1
2
  import { Problem } from "./problem.js";
3
+ import { text } from "./messages.js";
2
4
  import { CustomBoundary } from "./custom-boundary.js";
3
5
  import { useProjectUi } from "./project-ui.js";
4
6
  import { ActionBlock } from "./blocks/action.js";
@@ -19,7 +21,7 @@ import { TableBlock } from "./blocks/table.js";
19
21
  import { UsersBlock } from "../../users/users-block.js";
20
22
  import { Fragment } from "react";
21
23
  import { unmarkFieldRefs } from "@protobase/schema/internal";
22
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
24
+ import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
23
25
  import { isLayoutNode } from "@protobase/layout";
24
26
  //#region src/app/pages/render-node.tsx
25
27
  const blocks = {
@@ -66,11 +68,7 @@ const RenderNode = ({ node }) => {
66
68
  const { components } = useProjectUi();
67
69
  if (node.custom) {
68
70
  const Custom = components?.[node.type];
69
- if (!Custom) return /* @__PURE__ */ jsxs(Problem, { children: [
70
- "No component is registered as ",
71
- node.type,
72
- ". Export it from protobase.ui.tsx, or load the plugin that provides it."
73
- ] });
71
+ if (!Custom) return /* @__PURE__ */ jsx(Problem, { children: slotted(text("noComponent"), node.type) });
74
72
  return /* @__PURE__ */ jsx(CustomBoundary, {
75
73
  name: node.type,
76
74
  children: /* @__PURE__ */ jsx(Custom, {
@@ -80,7 +78,7 @@ const RenderNode = ({ node }) => {
80
78
  });
81
79
  }
82
80
  const Block = blocks[node.type];
83
- if (!Block) return /* @__PURE__ */ jsxs(Problem, { children: [node.type, " is not a block this version of the app knows."] });
81
+ if (!Block) return /* @__PURE__ */ jsx(Problem, { children: slotted(text("unknownBlock"), node.type) });
84
82
  return /* @__PURE__ */ jsx(Block, {
85
83
  node,
86
84
  slots: renderSlots(node),