@protobase/ui 0.23.3 → 0.23.5
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/app/app.d.ts +4 -1
- package/dist/app/app.js +25 -19
- package/dist/app/charts/chart-groups.js +3 -2
- package/dist/app/charts/period-chart.js +3 -2
- package/dist/app/create/create-values.js +1 -1
- package/dist/app/custom-section.js +1 -1
- package/dist/app/displays/board-column.js +2 -1
- package/dist/app/displays/custom-display.js +1 -1
- package/dist/app/displays/display-frame.js +3 -2
- package/dist/app/displays/map-display.js +4 -3
- package/dist/app/embedded-list/cut-off-note.js +2 -1
- package/dist/app/hand-order/hand-sorted-list.js +2 -1
- package/dist/app/hand-order/use-hand-order.js +1 -1
- package/dist/app/import/import-check-step.js +3 -2
- package/dist/app/import/import-counts.js +2 -1
- package/dist/app/import/import-dialog.js +2 -1
- package/dist/app/import/import-result-step.js +2 -1
- package/dist/app/incoming-relations.js +1 -1
- package/dist/app/list-edit/use-list-edits.js +1 -1
- package/dist/app/list-page.js +1 -1
- package/dist/app/main.js +3 -1
- package/dist/app/map/records-map.js +4 -3
- package/dist/app/meta-gate-messages.js +16 -0
- package/dist/app/meta-gate.js +14 -5
- package/dist/app/nav-recent.js +1 -1
- package/dist/app/pages/blocks/link.js +1 -1
- package/dist/app/pages/blocks/progress.js +3 -2
- package/dist/app/pages/blocks/stat.js +2 -1
- package/dist/app/pages/render-node.js +1 -1
- package/dist/app/pages/use-layout-data.js +1 -1
- package/dist/app/record-preview.js +1 -1
- package/dist/app/record-row/record-row-body.js +2 -1
- package/dist/app/saved/saved-records.js +1 -1
- package/dist/app/search/messages.js +18 -0
- package/dist/app/search/search-model.js +6 -5
- package/dist/app/searches/saved-search-rows.js +1 -1
- package/dist/app/searches/saved-searches.js +1 -1
- package/dist/app/searches/update-search-dialog.js +1 -1
- package/dist/app/searches/use-save-search.js +1 -1
- package/dist/app-shell/bottom-bar.js +3 -2
- package/dist/app-shell/breadcrumb.js +2 -1
- package/dist/app-shell/drawer.js +2 -1
- package/dist/app-shell/global-search.js +5 -4
- package/dist/app-shell/messages.js +64 -0
- package/dist/app-shell/profile-menu.js +5 -4
- package/dist/app-shell/sidebar-group.js +6 -5
- package/dist/app-shell/sidebar.js +4 -3
- package/dist/app-shell/theme-switch.js +8 -7
- package/dist/app-shell/top-bar.js +5 -4
- package/dist/data/api-provider.d.ts +2 -0
- package/dist/data/focus-refresh.js +2 -0
- package/dist/data/live-refresh.js +29 -0
- package/dist/data/meta-data.d.ts +3 -0
- package/dist/data/use-live-updates.js +36 -0
- package/dist/data/use-meta.js +1 -0
- package/dist/data/use-record.js +1 -1
- package/dist/data/use-update-record.js +1 -1
- package/dist/format/date.js +42 -50
- package/dist/format/intl-cache.js +12 -0
- package/dist/format/messages.js +24 -0
- package/dist/format/money.js +9 -16
- package/dist/format/number-text.js +3 -2
- package/dist/format/number.js +7 -5
- package/dist/format/zone.js +3 -5
- package/dist/invitations/pending-invitation-row.js +2 -1
- package/dist/live/display-value.js +2 -1
- package/dist/locale/active-locale.js +24 -0
- package/dist/locale/app-locale.js +18 -0
- package/dist/locale/messages.js +12 -0
- package/dist/organizations/organizations-page.js +2 -1
- package/dist/package.js +1 -1
- package/dist/shell/assets/app-Di4_EOe7.js +69 -0
- package/dist/shell/assets/export-worker-O1HF9R4j.js +2 -0
- package/dist/shell/assets/{index-BShZnsl_.js → index-DIcL_2pR.js} +2 -2
- package/dist/shell/assets/{maplibre-Z-0y-JM5.js → maplibre-B8VhXCMb.js} +2 -2
- package/dist/shell/assets/{markdown-content-C2__fEXf.js → markdown-content-CDcQeWQm.js} +1 -1
- package/dist/shell/assets/{record-map-sG110J_j.js → record-map-Bd0yjDXL.js} +1 -1
- package/dist/shell/assets/records-map-QR_MUceu.js +1 -0
- package/dist/shell/assets/{shared-protobase-ui-QAWUDrTS.js → shared-protobase-ui-CWBBcLfz.js} +1 -1
- package/dist/shell/index.html +3 -3
- package/dist/shell/protobase.shell.json +1 -1
- package/package.json +4 -4
- package/dist/shell/assets/app-DDou93IP.js +0 -69
- package/dist/shell/assets/export-worker-C1djGgjD.js +0 -2
- package/dist/shell/assets/records-map-mv11CA2m.js +0 -1
package/dist/app/app.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import "../app-shell/index.js";
|
|
|
3
3
|
import { ProjectUi } from "./pages/project-ui.js";
|
|
4
4
|
import { PluginLoader } from "../plugins/load-plugin.js";
|
|
5
5
|
import { AssistantClient, AuthSession, Client, RuntimeClient } from "@protobase/client";
|
|
6
|
+
import { Locale } from "@protobase/schema/internal";
|
|
6
7
|
//#region src/app/app.d.ts
|
|
7
8
|
export type AppProps = {
|
|
8
9
|
/** Where `/api/v1` lives. Defaults to the current origin. */
|
|
@@ -27,11 +28,13 @@ export type AppProps = {
|
|
|
27
28
|
runtime?: RuntimeClient;
|
|
28
29
|
/** How the plugins are loaded, for stories and tests; the page's `fetch` and `import()` by default. */
|
|
29
30
|
pluginLoader?: PluginLoader;
|
|
31
|
+
/** The language the screens are in when the app's `/meta` sets none, such as the browser's (`browserLocale()`); English by default. */
|
|
32
|
+
locale?: Locale;
|
|
30
33
|
};
|
|
31
34
|
/**
|
|
32
35
|
* The admin: a public form at `/-/forms/<name>` for anyone, the sign-in route first, `/-/sign-in`, or browsing as a
|
|
33
36
|
* visitor when the project's anonymous role reads, then a sidebar from `/meta`, `/:page` composed pages, `/:resource`
|
|
34
37
|
* lists and `/:resource/:key` records. Fills its parent, in the theme this browser chose, light, dark or the system's.
|
|
35
38
|
*/
|
|
36
|
-
export declare const App: ({ auth, workspace, basePath, initialUrl, pluginLoader, ...rest }: AppProps) => import("react").JSX.Element;
|
|
39
|
+
export declare const App: ({ auth, workspace, basePath, initialUrl, pluginLoader, locale, ...rest }: AppProps) => import("react").JSX.Element;
|
|
37
40
|
//#endregion
|
package/dist/app/app.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { accountMenuItems } from "../account/account-pages.js";
|
|
2
|
+
import { setFallbackLocale } from "../locale/active-locale.js";
|
|
2
3
|
import { AppShell } from "../app-shell/app-shell.js";
|
|
3
4
|
import { AuthProvider, useAuth } from "../auth/auth-provider.js";
|
|
4
5
|
import { AccountSecurityPage } from "../account/account-security-page.js";
|
|
@@ -12,11 +13,12 @@ import { CustomBoundary } from "./pages/custom-boundary.js";
|
|
|
12
13
|
import { PluginSourceProvider } from "../plugins/plugin-source.js";
|
|
13
14
|
import { AuthGate } from "../auth/auth-gate.js";
|
|
14
15
|
import { isAdmin, userToShell } from "../auth/user-to-shell.js";
|
|
16
|
+
import { sourceStatusOf } from "../data/with-sources.js";
|
|
17
|
+
import { useLiveUpdates } from "../data/use-live-updates.js";
|
|
15
18
|
import { useOpenedRecord } from "../data/use-record.js";
|
|
16
19
|
import { humanize } from "../live/naming.js";
|
|
17
20
|
import { ToastProvider } from "../toasts/toast-provider.js";
|
|
18
21
|
import { recordTitle } from "../live/model-helpers.js";
|
|
19
|
-
import { sourceStatusOf } from "../data/with-sources.js";
|
|
20
22
|
import { MetaGate, Notice, useAdminMeta } from "./meta-gate.js";
|
|
21
23
|
import { useAppAddress } from "./use-app-address.js";
|
|
22
24
|
import { documentTitle, titleParts, useDocumentTitle } from "./document-title.js";
|
|
@@ -49,8 +51,8 @@ import { RuntimeUpdateButton } from "./runtime/runtime-update.js";
|
|
|
49
51
|
import { StaffBanner } from "./staff-banner.js";
|
|
50
52
|
import { useNavRecent } from "./use-nav-recent.js";
|
|
51
53
|
import { useCallback, useEffect, useState } from "react";
|
|
52
|
-
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
53
54
|
import { viewOfList } from "@protobase/schema/internal";
|
|
55
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
54
56
|
//#region src/app/app.tsx
|
|
55
57
|
const placeOf = (address) => {
|
|
56
58
|
if (address?.kind === "page") return address.page;
|
|
@@ -75,6 +77,7 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
|
|
|
75
77
|
resource: shown?.resource,
|
|
76
78
|
key: shown?.key
|
|
77
79
|
});
|
|
80
|
+
useLiveUpdates(meta);
|
|
78
81
|
const groups = navFromMeta(meta, basePath, recent);
|
|
79
82
|
const firstPage = Object.keys(meta.pages)[0];
|
|
80
83
|
const firstResource = Object.keys(meta.resources)[0];
|
|
@@ -303,27 +306,30 @@ const PublicFormGate = ({ baseUrl, client, ui, children }) => {
|
|
|
303
306
|
* visitor when the project's anonymous role reads, then a sidebar from `/meta`, `/:page` composed pages, `/:resource`
|
|
304
307
|
* lists and `/:resource/:key` records. Fills its parent, in the theme this browser chose, light, dark or the system's.
|
|
305
308
|
*/
|
|
306
|
-
const App = ({ auth, workspace, basePath, initialUrl, pluginLoader, ...rest }) =>
|
|
307
|
-
|
|
308
|
-
children: /* @__PURE__ */ jsx(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
children: /* @__PURE__ */ jsx(
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
children: /* @__PURE__ */ jsx(
|
|
309
|
+
const App = ({ auth, workspace, basePath, initialUrl, pluginLoader, locale, ...rest }) => {
|
|
310
|
+
setFallbackLocale(locale ?? "en");
|
|
311
|
+
return /* @__PURE__ */ jsx(ThemeProvider, { children: /* @__PURE__ */ jsx(AuthProvider, {
|
|
312
|
+
session: auth,
|
|
313
|
+
children: /* @__PURE__ */ jsx(Router, {
|
|
314
|
+
basePath,
|
|
315
|
+
initialUrl,
|
|
316
|
+
children: /* @__PURE__ */ jsx(PluginSourceProvider, {
|
|
317
|
+
...pluginLoader && { loader: pluginLoader },
|
|
318
|
+
children: /* @__PURE__ */ jsx(PublicFormGate, {
|
|
319
|
+
baseUrl: rest.baseUrl,
|
|
320
|
+
client: rest.client,
|
|
321
|
+
ui: rest.ui,
|
|
322
|
+
children: /* @__PURE__ */ jsx(AuthGate, {
|
|
320
323
|
workspace,
|
|
321
|
-
|
|
324
|
+
children: /* @__PURE__ */ jsx(Authenticated, {
|
|
325
|
+
workspace,
|
|
326
|
+
...rest
|
|
327
|
+
})
|
|
322
328
|
})
|
|
323
329
|
})
|
|
324
330
|
})
|
|
325
331
|
})
|
|
326
|
-
})
|
|
327
|
-
}
|
|
332
|
+
}) });
|
|
333
|
+
};
|
|
328
334
|
//#endregion
|
|
329
335
|
export { App };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
1
2
|
import { createWhere, enumLabel, printFilter } from "@protobase/schema";
|
|
2
3
|
//#region src/app/charts/chart-groups.ts
|
|
3
4
|
const where$1 = createWhere();
|
|
@@ -40,9 +41,9 @@ const periodPoints = (groups, measure) => groups.map((group) => ({
|
|
|
40
41
|
/** A measured number as text: a count whole, a sum or average with the field's decimals, prefix and suffix. */
|
|
41
42
|
const measureText = (value, measure) => {
|
|
42
43
|
if (value === null) return "—";
|
|
43
|
-
if (measure.kind === "count") return value.toLocaleString(
|
|
44
|
+
if (measure.kind === "count") return value.toLocaleString(formatTag());
|
|
44
45
|
const decimals = measure.hints?.decimals ?? (Number.isInteger(value) ? 0 : 2);
|
|
45
|
-
const text = value.toLocaleString(
|
|
46
|
+
const text = value.toLocaleString(formatTag(), {
|
|
46
47
|
minimumFractionDigits: decimals,
|
|
47
48
|
maximumFractionDigits: decimals
|
|
48
49
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useMediaQuery } from "../../lib/use-media-query.js";
|
|
2
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
2
3
|
import { measureText } from "./chart-groups.js";
|
|
3
4
|
import { LegendItem } from "./legend-item.js";
|
|
4
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -49,7 +50,7 @@ const tooltipFormats = {
|
|
|
49
50
|
year: { year: "numeric" }
|
|
50
51
|
};
|
|
51
52
|
const formatterOf = (options) => {
|
|
52
|
-
const format = new Intl.DateTimeFormat(
|
|
53
|
+
const format = new Intl.DateTimeFormat(formatTag(), {
|
|
53
54
|
...options,
|
|
54
55
|
timeZone: "UTC"
|
|
55
56
|
});
|
|
@@ -121,7 +122,7 @@ const PeriodChart = ({ points, measure, bucket, type, series, resource, view })
|
|
|
121
122
|
axisLine: false,
|
|
122
123
|
tickLine: false,
|
|
123
124
|
tickCount: 3,
|
|
124
|
-
tickFormatter: (value) => value.toLocaleString(
|
|
125
|
+
tickFormatter: (value) => value.toLocaleString(formatTag(), { notation: "compact" })
|
|
125
126
|
});
|
|
126
127
|
const tooltip = /* @__PURE__ */ jsx(Tooltip, {
|
|
127
128
|
cursor: type === "bar" ? { fill: "var(--muted)" } : { stroke: "var(--border-strong)" },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isEditable, toPatchValue } from "../../live/field-values.js";
|
|
2
2
|
import { whenShown } from "../record-mode/record-mode.js";
|
|
3
|
-
import { isRecordCondition } from "@protobase/schema";
|
|
4
3
|
import { layoutItems } from "@protobase/schema/internal";
|
|
4
|
+
import { isRecordCondition } from "@protobase/schema";
|
|
5
5
|
//#region src/app/create/create-values.ts
|
|
6
6
|
const isChosen = (value) => typeof value === "object" && value !== null && "key" in value;
|
|
7
7
|
/** Fields the user can set on a new record: not read-only, not the tenant, and not structured data. */
|
|
@@ -4,8 +4,8 @@ import { Section } from "../record-view/section.js";
|
|
|
4
4
|
import { SidebarCard } from "../record-view/record-sidebar.js";
|
|
5
5
|
import { useProjectUi } from "./pages/project-ui.js";
|
|
6
6
|
import { RecordScope } from "./pages/record-scope.js";
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
7
|
import { unmarkFieldRefs } from "@protobase/schema/internal";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/app/custom-section.tsx
|
|
10
10
|
/**
|
|
11
11
|
* A component of the record layout (`l.custom`), drawn with the record around it, so `useLayoutRecord()` gives it, in a
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
2
3
|
import { Skeleton } from "../../primitives/skeleton.js";
|
|
3
4
|
import { Button } from "../../primitives/button.js";
|
|
4
5
|
import { humanize } from "../../live/naming.js";
|
|
@@ -70,7 +71,7 @@ const BoardColumnView = ({ model, view, display, column, fields, filter, orderBy
|
|
|
70
71
|
})
|
|
71
72
|
}), !list.loading && /* @__PURE__ */ jsx("span", {
|
|
72
73
|
className: "text-xs tabular-nums text-muted-foreground",
|
|
73
|
-
children: count.toLocaleString(
|
|
74
|
+
children: count.toLocaleString(formatTag())
|
|
74
75
|
})]
|
|
75
76
|
}),
|
|
76
77
|
list.loading ? Array.from({ length: 3 }, (_, index) => /* @__PURE__ */ jsx(Skeleton, { className: "h-20" }, index)) : list.error ? /* @__PURE__ */ jsx(ErrorBanner, {
|
|
@@ -2,8 +2,8 @@ import { Problem } from "../pages/problem.js";
|
|
|
2
2
|
import { CustomBoundary } from "../pages/custom-boundary.js";
|
|
3
3
|
import { useProjectUi } from "../pages/project-ui.js";
|
|
4
4
|
import { ListDisplayProvider } from "./display-context.js";
|
|
5
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
5
|
import { unmarkFieldRefs } from "@protobase/schema/internal";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/app/displays/custom-display.tsx
|
|
8
8
|
/**
|
|
9
9
|
* A display the project draws: the component registered under its name gets the display's props, field references
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
1
2
|
import { Button } from "../../primitives/button.js";
|
|
2
3
|
import { ErrorBanner } from "../error-banner.js";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -17,9 +18,9 @@ const DisplayState = ({ list, empty, loading, children }) => /* @__PURE__ */ jsx
|
|
|
17
18
|
const DisplayFooter = ({ list }) => /* @__PURE__ */ jsxs("div", {
|
|
18
19
|
className: "flex items-center justify-between gap-3 py-3 text-xs text-muted-foreground",
|
|
19
20
|
children: [/* @__PURE__ */ jsxs("span", { children: [
|
|
20
|
-
list.rows.length.toLocaleString(
|
|
21
|
+
list.rows.length.toLocaleString(formatTag()),
|
|
21
22
|
" of ",
|
|
22
|
-
list.total.toLocaleString(
|
|
23
|
+
list.total.toLocaleString(formatTag())
|
|
23
24
|
] }), list.more && /* @__PURE__ */ jsx(Button, {
|
|
24
25
|
size: "sm",
|
|
25
26
|
onClick: list.loadMore,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
2
3
|
import { Button } from "../../primitives/button.js";
|
|
3
4
|
import { Problem } from "../pages/problem.js";
|
|
4
5
|
import { humanize } from "../../live/naming.js";
|
|
@@ -57,7 +58,7 @@ const MapDisplay = ({ model, view, display, filter, orderBy, fields, at, onMove,
|
|
|
57
58
|
if (near === 0) return `Show ${keys.length} ${plural}`;
|
|
58
59
|
return near === keys.length ? `Show ${keys.length} ${plural}, at approximate positions` : `Show ${keys.length} ${plural}, ${near} at approximate positions`;
|
|
59
60
|
};
|
|
60
|
-
const bucketLabel = (count) => `Zoom in on ${count.toLocaleString(
|
|
61
|
+
const bucketLabel = (count) => `Zoom in on ${count.toLocaleString(formatTag())} ${count === 1 ? singular : plural}`;
|
|
61
62
|
const overlay = useRef(null);
|
|
62
63
|
const [covered, setCovered] = useState(0);
|
|
63
64
|
useLayoutEffect(() => setCovered(overlay.current?.offsetHeight ?? 0), [row?.key]);
|
|
@@ -192,8 +193,8 @@ const MapDisplay = ({ model, view, display, filter, orderBy, fields, at, onMove,
|
|
|
192
193
|
/** How many of the matching records are in view, and how many the map shows when it cannot show them all. */
|
|
193
194
|
const inView = (data, plural) => {
|
|
194
195
|
if (!data) return "\xA0";
|
|
195
|
-
const total = data.total.toLocaleString(
|
|
196
|
-
if (data.buckets.length === 0 && data.rows.length < data.total) return `${data.rows.length.toLocaleString(
|
|
196
|
+
const total = data.total.toLocaleString(formatTag());
|
|
197
|
+
if (data.buckets.length === 0 && data.rows.length < data.total) return `${data.rows.length.toLocaleString(formatTag())} of ${total} ${plural} in view`;
|
|
197
198
|
return `${total} ${plural} in view`;
|
|
198
199
|
};
|
|
199
200
|
//#endregion
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
1
2
|
//#region src/app/embedded-list/cut-off-note.ts
|
|
2
3
|
/**
|
|
3
4
|
* What a list that shows only its first `shown` of `total` records says about the rest, as "The first 10 of 37.";
|
|
@@ -5,7 +6,7 @@
|
|
|
5
6
|
*/
|
|
6
7
|
const cutOffNote = (shown, total, estimated) => {
|
|
7
8
|
if (shown >= total) return void 0;
|
|
8
|
-
return `The first ${shown} of ${estimated ? "about " : ""}${total.toLocaleString(
|
|
9
|
+
return `The first ${shown} of ${estimated ? "about " : ""}${total.toLocaleString(formatTag())}.`;
|
|
9
10
|
};
|
|
10
11
|
//#endregion
|
|
11
12
|
export { cutOffNote };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
1
2
|
import { Skeleton } from "../../primitives/skeleton.js";
|
|
2
3
|
import { humanize } from "../../live/naming.js";
|
|
3
4
|
import { recordKey, recordTitle } from "../../live/model-helpers.js";
|
|
@@ -65,7 +66,7 @@ const HandSortedList = ({ model, view, field, filter, columns }) => {
|
|
|
65
66
|
className: "text-muted-foreground",
|
|
66
67
|
children: [
|
|
67
68
|
"There are more than ",
|
|
68
|
-
500 .toLocaleString(
|
|
69
|
+
500 .toLocaleString(formatTag()),
|
|
69
70
|
" ",
|
|
70
71
|
plural,
|
|
71
72
|
", too many to sort by hand."
|
|
@@ -7,8 +7,8 @@ import { useAdminMeta } from "../meta-gate.js";
|
|
|
7
7
|
import { useRefreshResource } from "../pages/use-layout-data.js";
|
|
8
8
|
import { listLabels, withLabels } from "../../live/relation-labels.js";
|
|
9
9
|
import { useRef, useState } from "react";
|
|
10
|
-
import { useQuery } from "@tanstack/react-query";
|
|
11
10
|
import { encodeKey } from "@protobase/schema/internal";
|
|
11
|
+
import { useQuery } from "@tanstack/react-query";
|
|
12
12
|
import { arrayMove } from "@dnd-kit/sortable";
|
|
13
13
|
//#region src/app/hand-order/use-hand-order.ts
|
|
14
14
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
1
2
|
import { Spinner } from "../../primitives/spinner.js";
|
|
2
3
|
import { Button } from "../../primitives/button.js";
|
|
3
4
|
import { saveFile } from "../../lib/save-file.js";
|
|
@@ -31,7 +32,7 @@ const ProblemList = ({ rows }) => /* @__PURE__ */ jsxs("ul", {
|
|
|
31
32
|
className: "text-muted-foreground",
|
|
32
33
|
children: [
|
|
33
34
|
"And ",
|
|
34
|
-
(rows.length - listedProblems).toLocaleString(
|
|
35
|
+
(rows.length - listedProblems).toLocaleString(formatTag()),
|
|
35
36
|
" more rows, all in the file."
|
|
36
37
|
]
|
|
37
38
|
})]
|
|
@@ -42,7 +43,7 @@ const ImportChecking = ({ rows }) => /* @__PURE__ */ jsxs("p", {
|
|
|
42
43
|
children: [
|
|
43
44
|
/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }),
|
|
44
45
|
"Checking rows… ",
|
|
45
|
-
rows.toLocaleString(
|
|
46
|
+
rows.toLocaleString(formatTag()),
|
|
46
47
|
" read"
|
|
47
48
|
]
|
|
48
49
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
1
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
3
|
//#region src/app/import/import-counts.tsx
|
|
3
4
|
/** Counts side by side, each under its label, such as the rows an import created and updated. */
|
|
@@ -11,7 +12,7 @@ const ImportCounts = ({ label, counts }) => /* @__PURE__ */ jsx("dl", {
|
|
|
11
12
|
children: name
|
|
12
13
|
}), /* @__PURE__ */ jsx("dd", {
|
|
13
14
|
className: "text-lg font-semibold tabular-nums",
|
|
14
|
-
children: value.toLocaleString(
|
|
15
|
+
children: value.toLocaleString(formatTag())
|
|
15
16
|
})]
|
|
16
17
|
}, name))
|
|
17
18
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
1
2
|
import { Button } from "../../primitives/button.js";
|
|
2
3
|
import { humanize } from "../../live/naming.js";
|
|
3
4
|
import { ErrorBanner } from "../error-banner.js";
|
|
@@ -73,7 +74,7 @@ const ImportDialog = ({ model, resources, views, canUpdate, onClose, sourceFor }
|
|
|
73
74
|
onClick: () => flow.start(rows),
|
|
74
75
|
children: [
|
|
75
76
|
"Import ",
|
|
76
|
-
rows.toLocaleString(
|
|
77
|
+
rows.toLocaleString(formatTag()),
|
|
77
78
|
" ",
|
|
78
79
|
rows === 1 ? "row" : "rows"
|
|
79
80
|
]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
1
2
|
import { Button } from "../../primitives/button.js";
|
|
2
3
|
import { ErrorBanner } from "../error-banner.js";
|
|
3
4
|
import { ImportCounts } from "./import-counts.js";
|
|
@@ -5,7 +6,7 @@ import { ProblemList, downloadRows } from "./import-check-step.js";
|
|
|
5
6
|
import { Download } from "lucide-react";
|
|
6
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
//#region src/app/import/import-result-step.tsx
|
|
8
|
-
const count = (value) => value.toLocaleString(
|
|
9
|
+
const count = (value) => value.toLocaleString(formatTag());
|
|
9
10
|
/** The rows written so far out of those to write, as a bar. */
|
|
10
11
|
const ImportProgressStep = ({ progress, total, cancelling }) => {
|
|
11
12
|
const done = progress.created + progress.updated + progress.failed;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { humanize } from "../live/naming.js";
|
|
2
|
-
import { createWhere, printFilter } from "@protobase/schema";
|
|
3
2
|
import { layoutItems } from "@protobase/schema/internal";
|
|
3
|
+
import { createWhere, printFilter } from "@protobase/schema";
|
|
4
4
|
//#region src/app/incoming-relations.ts
|
|
5
5
|
const where$1 = createWhere();
|
|
6
6
|
/**
|
|
@@ -4,8 +4,8 @@ import { useToast } from "../../toasts/toast-provider.js";
|
|
|
4
4
|
import { recordKey } from "../../live/model-helpers.js";
|
|
5
5
|
import { useRef, useState } from "react";
|
|
6
6
|
import { isApiError } from "@protobase/client";
|
|
7
|
-
import { useQueryClient } from "@tanstack/react-query";
|
|
8
7
|
import { encodeKey } from "@protobase/schema/internal";
|
|
8
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
9
9
|
//#region src/app/list-edit/use-list-edits.ts
|
|
10
10
|
/**
|
|
11
11
|
* The list's edits in place: `patches` holds, by row id, the values saving or saved since the rows loaded, with the
|
package/dist/app/list-page.js
CHANGED
|
@@ -62,9 +62,9 @@ import { HandSortedList } from "./hand-order/hand-sorted-list.js";
|
|
|
62
62
|
import { SortButton } from "./hand-order/sort-button.js";
|
|
63
63
|
import { useMemo, useState } from "react";
|
|
64
64
|
import { Download, Plus, SlidersHorizontal } from "lucide-react";
|
|
65
|
+
import { isGroupChart, tableDisplay, viewOfList } from "@protobase/schema/internal";
|
|
65
66
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
66
67
|
import { createWhere } from "@protobase/schema";
|
|
67
|
-
import { isGroupChart, tableDisplay, viewOfList } from "@protobase/schema/internal";
|
|
68
68
|
//#region src/app/list-page.tsx
|
|
69
69
|
const where$1 = createWhere();
|
|
70
70
|
const searchText = (extras) => extras.find((clause) => clause.kind === "search");
|
package/dist/app/main.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { browserLocale } from "../locale/active-locale.js";
|
|
1
2
|
import { uiFromModule } from "./pages/ui-from-module.js";
|
|
2
3
|
import { App } from "./app.js";
|
|
3
4
|
import { StrictMode } from "react";
|
|
@@ -10,6 +11,7 @@ const root = document.getElementById("root");
|
|
|
10
11
|
if (!root) throw new Error("index.html needs an element with id \"root\"");
|
|
11
12
|
createRoot(root).render(/* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(App, {
|
|
12
13
|
baseUrl: "/api/v1",
|
|
13
|
-
ui: uiFromModule(projectUi)
|
|
14
|
+
ui: uiFromModule(projectUi),
|
|
15
|
+
locale: browserLocale()
|
|
14
16
|
}) }));
|
|
15
17
|
//#endregion
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { cachedFormat } from "../../format/intl-cache.js";
|
|
2
3
|
import { groupPoints } from "../displays/map-groups.js";
|
|
3
4
|
import { MapLayerSwitch } from "./map-layer-switch.js";
|
|
4
5
|
import { mapLib } from "./maplibre.js";
|
|
@@ -21,10 +22,10 @@ const bucketOptions = {
|
|
|
21
22
|
duration: 300
|
|
22
23
|
};
|
|
23
24
|
const markerHeight = 32;
|
|
24
|
-
const compact = new Intl.NumberFormat(
|
|
25
|
+
const compact = () => cachedFormat("compact", (tag) => new Intl.NumberFormat(tag, {
|
|
25
26
|
notation: "compact",
|
|
26
27
|
maximumFractionDigits: 1
|
|
27
|
-
});
|
|
28
|
+
}));
|
|
28
29
|
const corners = (bounds) => [[bounds.west, bounds.south], [bounds.east, bounds.north]];
|
|
29
30
|
/**
|
|
30
31
|
* A map of `style` with a marker for each group of records that lie close together at the zoom, showing how many it
|
|
@@ -139,7 +140,7 @@ const RecordsMap = ({ style, layers, initial, points, buckets, fit, onFitted, on
|
|
|
139
140
|
event.stopPropagation();
|
|
140
141
|
ref.current?.getMap().fitBounds(corners(bucket.bounds), bucketOptions);
|
|
141
142
|
},
|
|
142
|
-
children: compact.format(bucket.count)
|
|
143
|
+
children: compact().format(bucket.count)
|
|
143
144
|
})
|
|
144
145
|
}, `${bucket.latitude},${bucket.longitude}`)),
|
|
145
146
|
groups.map((group) => {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineMessages } from "../locale/messages.js";
|
|
2
|
+
//#region src/app/meta-gate-messages.ts
|
|
3
|
+
const text = defineMessages({
|
|
4
|
+
en: {
|
|
5
|
+
loading: "Loading",
|
|
6
|
+
cannotReach: "Cannot reach the API",
|
|
7
|
+
noAnswer: "The server did not answer. Is it running?"
|
|
8
|
+
},
|
|
9
|
+
nl: {
|
|
10
|
+
loading: "Laden",
|
|
11
|
+
cannotReach: "De API is niet bereikbaar",
|
|
12
|
+
noAnswer: "De server gaf geen antwoord. Draait hij?"
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { text };
|
package/dist/app/meta-gate.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Spinner } from "../primitives/spinner.js";
|
|
2
2
|
import { ClientProvider, useClient, useSourceClients } from "../data/api-provider.js";
|
|
3
|
+
import { withSources } from "../data/with-sources.js";
|
|
3
4
|
import { MetaContext } from "../data/meta-context.js";
|
|
4
5
|
import { allowEverything } from "../data/meta-data.js";
|
|
5
6
|
import { useMeta } from "../data/use-meta.js";
|
|
6
7
|
import { useSourceMetas } from "../data/use-source-metas.js";
|
|
7
|
-
import {
|
|
8
|
+
import { AppLocale } from "../locale/app-locale.js";
|
|
9
|
+
import { text } from "./meta-gate-messages.js";
|
|
8
10
|
import { useContext, useMemo } from "react";
|
|
9
11
|
import { isApiError, routedClient } from "@protobase/client";
|
|
10
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -58,7 +60,10 @@ const WithSources = ({ meta, children }) => {
|
|
|
58
60
|
resourceClient: routing.resourceClient,
|
|
59
61
|
children: /* @__PURE__ */ jsx(MetaContext.Provider, {
|
|
60
62
|
value: merged,
|
|
61
|
-
children
|
|
63
|
+
children: /* @__PURE__ */ jsx(AppLocale, {
|
|
64
|
+
locale: meta.locale,
|
|
65
|
+
children
|
|
66
|
+
})
|
|
62
67
|
})
|
|
63
68
|
});
|
|
64
69
|
};
|
|
@@ -70,11 +75,15 @@ const MetaGate = ({ children }) => {
|
|
|
70
75
|
const meta = useMeta();
|
|
71
76
|
if (meta.isPending) return /* @__PURE__ */ jsxs("div", {
|
|
72
77
|
className: "flex h-full min-h-48 items-center justify-center gap-2 text-muted-foreground",
|
|
73
|
-
children: [
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ jsx(Spinner, {}),
|
|
80
|
+
" ",
|
|
81
|
+
text("loading")
|
|
82
|
+
]
|
|
74
83
|
});
|
|
75
84
|
if (meta.error) return /* @__PURE__ */ jsx(Notice, {
|
|
76
|
-
title: "
|
|
77
|
-
children: isApiError(meta.error) ? meta.error.message : "
|
|
85
|
+
title: text("cannotReach"),
|
|
86
|
+
children: isApiError(meta.error) ? meta.error.message : text("noAnswer")
|
|
78
87
|
});
|
|
79
88
|
return /* @__PURE__ */ jsx(WithSources, {
|
|
80
89
|
meta: meta.data,
|
package/dist/app/nav-recent.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { recordKey, recordTitle, recordTitleField } from "../live/model-helpers.js";
|
|
2
2
|
import { defaultOrderBy } from "./list-order.js";
|
|
3
|
-
import { appPath, enumLabel } from "@protobase/schema";
|
|
4
3
|
import { defaultRecentLimit, encodeKey } from "@protobase/schema/internal";
|
|
4
|
+
import { appPath, enumLabel } from "@protobase/schema";
|
|
5
5
|
//#region src/app/nav-recent.ts
|
|
6
6
|
/** The list request behind a sidebar group: its filter, order (the list's sort when unset), size, and only the fields it shows. */
|
|
7
7
|
const recentRequest = (model, view, recent) => ({
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AppLink } from "../../use-app-address.js";
|
|
2
2
|
import { useLayoutRecord } from "../record-scope.js";
|
|
3
3
|
import { propsOf } from "./block-props.js";
|
|
4
|
+
import { fillAddress } from "@protobase/schema/internal";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
5
6
|
import { appPath } from "@protobase/schema";
|
|
6
|
-
import { fillAddress } from "@protobase/schema/internal";
|
|
7
7
|
//#region src/app/pages/blocks/link.tsx
|
|
8
8
|
const style = "font-medium text-primary-text hover:underline";
|
|
9
9
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../../locale/active-locale.js";
|
|
1
2
|
import { Skeleton } from "../../../primitives/skeleton.js";
|
|
2
3
|
import { useLayoutRecord } from "../record-scope.js";
|
|
3
4
|
import { propsOf } from "./block-props.js";
|
|
@@ -31,9 +32,9 @@ const ProgressBlock = ({ node }) => {
|
|
|
31
32
|
}), /* @__PURE__ */ jsxs("span", {
|
|
32
33
|
className: "tabular-nums",
|
|
33
34
|
children: [
|
|
34
|
-
current.toLocaleString(
|
|
35
|
+
current.toLocaleString(formatTag()),
|
|
35
36
|
" / ",
|
|
36
|
-
total.toLocaleString(
|
|
37
|
+
total.toLocaleString(formatTag())
|
|
37
38
|
]
|
|
38
39
|
})]
|
|
39
40
|
}), /* @__PURE__ */ jsx("div", {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatTag } from "../../../locale/active-locale.js";
|
|
1
2
|
import { Skeleton } from "../../../primitives/skeleton.js";
|
|
2
3
|
import { useAdminMeta } from "../../meta-gate.js";
|
|
3
4
|
import { AppLink } from "../../use-app-address.js";
|
|
@@ -22,7 +23,7 @@ const Count = ({ model, filter }) => {
|
|
|
22
23
|
return /* @__PURE__ */ jsx(AppLink, {
|
|
23
24
|
to: filteredListAddress(views[model.name], model.name, filter),
|
|
24
25
|
className: `${big} hover:text-primary-text after:absolute after:inset-0 after:content-['']`,
|
|
25
|
-
children: count.data.toLocaleString(
|
|
26
|
+
children: count.data.toLocaleString(formatTag())
|
|
26
27
|
});
|
|
27
28
|
};
|
|
28
29
|
const RecordValue = ({ field, format }) => {
|
|
@@ -18,8 +18,8 @@ import { StatBlock } from "./blocks/stat.js";
|
|
|
18
18
|
import { TableBlock } from "./blocks/table.js";
|
|
19
19
|
import { UsersBlock } from "../../users/users-block.js";
|
|
20
20
|
import { Fragment } from "react";
|
|
21
|
-
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
22
21
|
import { unmarkFieldRefs } from "@protobase/schema/internal";
|
|
22
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
23
23
|
import { isLayoutNode } from "@protobase/layout";
|
|
24
24
|
//#region src/app/pages/render-node.tsx
|
|
25
25
|
const blocks = {
|
|
@@ -2,8 +2,8 @@ import { keys } from "../../data/query-keys.js";
|
|
|
2
2
|
import { useClient } from "../../data/api-provider.js";
|
|
3
3
|
import { recordKey } from "../../live/model-helpers.js";
|
|
4
4
|
import { useCallback } from "react";
|
|
5
|
-
import { keepPreviousData, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
5
|
import { encodeKey } from "@protobase/schema/internal";
|
|
6
|
+
import { keepPreviousData, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
7
7
|
//#region src/app/pages/use-layout-data.ts
|
|
8
8
|
/** A list item as a record scope: the key as the URL carries it, and the etag and permissions the item carries. */
|
|
9
9
|
const scopeOf = (model, row) => ({
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { keys } from "../data/query-keys.js";
|
|
2
2
|
import { recordKey } from "../live/model-helpers.js";
|
|
3
3
|
import { useCallback } from "react";
|
|
4
|
-
import { useQueryClient } from "@tanstack/react-query";
|
|
5
4
|
import { encodeKey } from "@protobase/schema/internal";
|
|
5
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
6
6
|
//#region src/app/record-preview.ts
|
|
7
7
|
/**
|
|
8
8
|
* A record as far as a list row knows it: the fields the row loaded, its ETag and permissions as the list gives them.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useIsXs } from "../../lib/use-media-query.js";
|
|
2
|
+
import { formatTag } from "../../locale/active-locale.js";
|
|
2
3
|
import { Skeleton } from "../../primitives/skeleton.js";
|
|
3
4
|
import { humanize } from "../../live/naming.js";
|
|
4
5
|
import { displaysOf, loadedFields } from "../displays/list-displays.js";
|
|
@@ -71,7 +72,7 @@ const RecordRowBody = ({ model, view, filter, sort = "", display: named, limit,
|
|
|
71
72
|
className: "flex flex-wrap gap-x-3 text-muted-foreground",
|
|
72
73
|
children: [note && /* @__PURE__ */ jsx("span", { children: note }), total !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
73
74
|
className: "tabular-nums",
|
|
74
|
-
children: `${total.toLocaleString(
|
|
75
|
+
children: `${total.toLocaleString(formatTag())} ${total === 1 ? singular : plural.toLowerCase()}`
|
|
75
76
|
})]
|
|
76
77
|
})]
|
|
77
78
|
}) : null,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { recordKey } from "../../live/model-helpers.js";
|
|
2
|
-
import { createWhere } from "@protobase/schema";
|
|
3
2
|
import { encodeKey } from "@protobase/schema/internal";
|
|
3
|
+
import { createWhere } from "@protobase/schema";
|
|
4
4
|
//#region src/app/saved/saved-records.ts
|
|
5
5
|
const where$1 = createWhere();
|
|
6
6
|
const relationValue = (value) => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineMessages } from "../../locale/messages.js";
|
|
2
|
+
//#region src/app/search/messages.ts
|
|
3
|
+
const text = defineMessages({
|
|
4
|
+
en: {
|
|
5
|
+
search: "Search",
|
|
6
|
+
searchOne: (name) => `Search ${name}`,
|
|
7
|
+
searchTwo: (first, second) => `Search ${first} and ${second}`,
|
|
8
|
+
searchMore: (first, second) => `Search ${first}, ${second} and more`
|
|
9
|
+
},
|
|
10
|
+
nl: {
|
|
11
|
+
search: "Zoeken",
|
|
12
|
+
searchOne: (name) => `Zoek in ${name}`,
|
|
13
|
+
searchTwo: (first, second) => `Zoek in ${first} en ${second}`,
|
|
14
|
+
searchMore: (first, second) => `Zoek in ${first}, ${second} en meer`
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { text };
|