@protobase/ui 0.46.9 → 0.46.10
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/create/create-page.js +2 -2
- package/dist/app/create/create-values.js +17 -2
- package/dist/app/nav-from-meta.js +7 -3
- package/dist/app-shell/sidebar.js +1 -1
- package/dist/auth/user-to-shell.js +4 -1
- package/dist/format/messages.js +2 -2
- package/dist/format/number.js +1 -1
- package/dist/forms/public-form-page.js +2 -2
- package/dist/package.js +1 -1
- package/dist/shell/assets/app-D_HKIf03.js +9 -0
- package/dist/shell/assets/export-worker-IJWS5-Wc.js +3 -0
- package/dist/shell/assets/{index-1Ue_dZiA.js → index-C6JUrzRh.js} +2 -2
- package/dist/shell/assets/{records-map-DPA8Y3C8.js → records-map-kVCCf9yO.js} +2 -2
- package/dist/shell/assets/{shared-protobase-ui-dWIf89ff.js → shared-protobase-ui-t4TJnncm.js} +2 -2
- package/dist/shell/index.html +3 -3
- package/dist/shell/protobase.shell.json +1 -1
- package/dist/shell/protobase.sw.js +2 -2
- package/dist/shell-source-maps/assets/app-D_HKIf03.js.map +1 -0
- package/dist/shell-source-maps/assets/export-worker-IJWS5-Wc.js.map +1 -0
- package/dist/shell-source-maps/assets/{index-1Ue_dZiA.js.map → index-C6JUrzRh.js.map} +1 -1
- package/dist/shell-source-maps/assets/{records-map-DPA8Y3C8.js.map → records-map-kVCCf9yO.js.map} +1 -1
- package/dist/shell-source-maps/assets/{shared-protobase-ui-dWIf89ff.js.map → shared-protobase-ui-t4TJnncm.js.map} +1 -1
- package/package.json +4 -4
- package/dist/shell/assets/app-axeIZ-10.js +0 -9
- package/dist/shell/assets/export-worker-ClACk00b.js +0 -3
- package/dist/shell-source-maps/assets/app-axeIZ-10.js.map +0 -1
- package/dist/shell-source-maps/assets/export-worker-ClACk00b.js.map +0 -1
|
@@ -6,7 +6,7 @@ import { text } from "../messages.js";
|
|
|
6
6
|
import { useNavigationGuard } from "../router.js";
|
|
7
7
|
import { useAppAddress } from "../use-app-address.js";
|
|
8
8
|
import { text as text$1 } from "./messages.js";
|
|
9
|
-
import { createBody, createSections, hasDatabaseDefault, initialDraft, isChosen, isRequired } from "./create-values.js";
|
|
9
|
+
import { createBody, createSections, hasDatabaseDefault, initialDraft, isChosen, isRequired, numberDefault } from "./create-values.js";
|
|
10
10
|
import { FieldEditor } from "../field-editor.js";
|
|
11
11
|
import { can } from "../permissions.js";
|
|
12
12
|
import { fetchLabels } from "../../live/relation-labels.js";
|
|
@@ -133,7 +133,7 @@ const LoadedCreate = ({ resource, values }) => {
|
|
|
133
133
|
value: isChosen(value) ? value.key : value ?? (field.type === "boolean" ? false : ""),
|
|
134
134
|
stored: void 0,
|
|
135
135
|
relationLabel: isChosen(value) ? value.label : void 0,
|
|
136
|
-
placeholder: hasDatabaseDefault(field) ? text$1("setByDatabase") :
|
|
136
|
+
placeholder: hasDatabaseDefault(field) ? text$1("setByDatabase") : numberDefault(field),
|
|
137
137
|
relationPicker: target ? {
|
|
138
138
|
target,
|
|
139
139
|
view: meta.views[target.name]
|
|
@@ -59,17 +59,32 @@ const givenValue = (field, value) => {
|
|
|
59
59
|
if (field.type === "boolean") return value === "true";
|
|
60
60
|
return value;
|
|
61
61
|
};
|
|
62
|
+
const numeric = /* @__PURE__ */ new Set([
|
|
63
|
+
"integer",
|
|
64
|
+
"bigint",
|
|
65
|
+
"decimal"
|
|
66
|
+
]);
|
|
67
|
+
/**
|
|
68
|
+
* A number field's literal default, which its empty input shows as a placeholder rather than as its value: typing into a
|
|
69
|
+
* prefilled `0` would add to it, and the create applies the default to an empty field.
|
|
70
|
+
*/
|
|
71
|
+
const numberDefault = (field) => {
|
|
72
|
+
if (!numeric.has(field.type) || !field.default || !("value" in field.default)) return void 0;
|
|
73
|
+
const value = field.default.value;
|
|
74
|
+
return value === null || value === void 0 ? void 0 : String(value);
|
|
75
|
+
};
|
|
62
76
|
/**
|
|
63
77
|
* The form's starting values: the values the address gives (`/notes/new?listing_id=42`), for the fields the form has,
|
|
64
|
-
* else literal defaults from `/meta
|
|
78
|
+
* else literal defaults from `/meta`, but for numbers. Database defaults stay empty so the database fills them.
|
|
65
79
|
*/
|
|
66
80
|
const initialDraft = (model, sections, given = {}) => Object.fromEntries(sections.flatMap((section) => section.fields.flatMap((name) => {
|
|
67
81
|
const field = model.fields[name];
|
|
68
82
|
if (Object.hasOwn(given, name)) return [[name, givenValue(field, given[name])]];
|
|
69
83
|
const fallback = field.default;
|
|
84
|
+
if (numberDefault(field) !== void 0) return [];
|
|
70
85
|
if (!fallback || !("value" in fallback) || fallback.value === null || fallback.value === void 0) return [];
|
|
71
86
|
return [[name, typeof fallback.value === "boolean" ? fallback.value : String(fallback.value)]];
|
|
72
87
|
})));
|
|
73
88
|
const hasDatabaseDefault = (field) => Boolean(field.default && "db" in field.default);
|
|
74
89
|
//#endregion
|
|
75
|
-
export { createBody, createSections, hasDatabaseDefault, initialDraft, isChosen, isCreatable, isRequired, keyValue };
|
|
90
|
+
export { createBody, createSections, hasDatabaseDefault, initialDraft, isChosen, isCreatable, isRequired, keyValue, numberDefault };
|
|
@@ -16,8 +16,13 @@ const groupLabels = {
|
|
|
16
16
|
core: "admin",
|
|
17
17
|
hr: "hr"
|
|
18
18
|
};
|
|
19
|
+
/** The group of a schema's resources: none for the default `public` schema, whose name would read as "visible to anyone". */
|
|
20
|
+
const schemaGroup = (schema = "public") => {
|
|
21
|
+
if (schema === "public") return "";
|
|
22
|
+
return groupLabels[schema] ? text(groupLabels[schema]) : humanize(schema);
|
|
23
|
+
};
|
|
19
24
|
/**
|
|
20
|
-
* One sidebar group per `nav.group` (default: the database schema, and "Pages" for pages); `nav.hidden` and a place in
|
|
25
|
+
* One sidebar group per `nav.group` (default: the database schema, none for `public`, and "Pages" for pages); `nav.hidden` and a place in
|
|
21
26
|
* the user menu leave an entry out, `nav.order` sorts within a group, and `recent` (from `useNavRecent`) makes an entry
|
|
22
27
|
* collapsible. Groups with pages come first, so a dashboard leads the sidebar. The resources of a source that cannot be
|
|
23
28
|
* read are listed under its label, each with the problem. A visitor also gets the resources whose views ask them to sign
|
|
@@ -50,8 +55,7 @@ const navFromMeta = (meta, basePath = "", recent = {}) => {
|
|
|
50
55
|
for (const model of Object.values(meta.resources)) {
|
|
51
56
|
const view = meta.views[model.name];
|
|
52
57
|
if (!view || inMenu.has(model.name)) continue;
|
|
53
|
-
const
|
|
54
|
-
const defaultGroup = view.nav?.group ?? (groupLabels[schema] ? text(groupLabels[schema]) : humanize(schema));
|
|
58
|
+
const defaultGroup = view.nav?.group ?? schemaGroup(model.table.schema);
|
|
55
59
|
const add = (groupName, item, order) => {
|
|
56
60
|
const group = groups.get(groupName) ?? {
|
|
57
61
|
label: groupName,
|
|
@@ -34,7 +34,7 @@ const Sidebar = ({ mode, activeItem, user, workspace, appName, appIcon, forceExp
|
|
|
34
34
|
className: cn("flex-1 overflow-y-auto overflow-x-hidden pb-2", mode === "icon-label" ? "px-2" : "px-2"),
|
|
35
35
|
children: groups.map((group, index) => /* @__PURE__ */ jsxs("div", {
|
|
36
36
|
className: cn("flex flex-col gap-0.5", index > 0 && "mt-3"),
|
|
37
|
-
children: [inline ? /* @__PURE__ */ jsx("div", {
|
|
37
|
+
children: [inline ? group.label && /* @__PURE__ */ jsx("div", {
|
|
38
38
|
className: cn("px-3 pb-1 pt-1 text-xs font-medium uppercase tracking-wide text-faint-foreground", expanding && "h-4 whitespace-nowrap py-0 opacity-0 transition-opacity group-hover/side:opacity-100 group-focus-within/side:opacity-100", expanded && "opacity-100"),
|
|
39
39
|
children: group.label
|
|
40
40
|
}) : index > 0 && /* @__PURE__ */ jsx("div", { className: "mx-auto mb-1 h-px w-6 bg-border" }), group.items.map((item) => item.recent && isTextMode(mode) ? /* @__PURE__ */ jsx(SidebarGroup, {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { text } from "./messages.js";
|
|
2
|
+
import { capitalise } from "../live/naming.js";
|
|
2
3
|
//#region src/auth/user-to-shell.ts
|
|
3
4
|
/** The hue of someone's avatar, the same for the same id. */
|
|
4
5
|
const hueOf = (text) => [...text].reduce((sum, char) => (sum * 31 + char.charCodeAt(0)) % 360, 7);
|
|
@@ -7,6 +8,8 @@ const initialsOf = (name) => name.split(/[\s@.]+/).filter(Boolean).slice(0, 2).m
|
|
|
7
8
|
const rolesOf = (user) => (user.role ?? "user").split(",").map((role) => role.trim());
|
|
8
9
|
/** The user holds the `admin` role, among others perhaps. */
|
|
9
10
|
const isAdmin = (user) => rolesOf(user).includes("admin");
|
|
11
|
+
/** A role's name as words: `full_access` becomes "Full access". */
|
|
12
|
+
const roleLabel = (role) => capitalise(role.replace(/[_-]+/g, " ").trim());
|
|
10
13
|
/** What the sidebar's profile menu shows for a signed-in user. */
|
|
11
14
|
const userToShell = (user) => {
|
|
12
15
|
const roles = rolesOf(user);
|
|
@@ -16,7 +19,7 @@ const userToShell = (user) => {
|
|
|
16
19
|
email: user.email,
|
|
17
20
|
initials: initialsOf(user.name || user.email) || "?",
|
|
18
21
|
hue: hueOf(user.id || user.email),
|
|
19
|
-
role: admin ? text("admin") : (roles[0] ?? "user")
|
|
22
|
+
role: admin ? text("admin") : roleLabel(roles[0] ?? "user"),
|
|
20
23
|
roleTone: admin ? "violet" : "blue"
|
|
21
24
|
};
|
|
22
25
|
};
|
package/dist/format/messages.js
CHANGED
|
@@ -2,7 +2,7 @@ import { defineMessages } from "../locale/messages.js";
|
|
|
2
2
|
//#region src/format/messages.ts
|
|
3
3
|
const text = defineMessages({
|
|
4
4
|
en: {
|
|
5
|
-
rows: (count) => `${count} rows`,
|
|
5
|
+
rows: (count, one) => `${count} ${one ? "row" : "rows"}`,
|
|
6
6
|
aboutRows: (count) => `about ${count} rows`,
|
|
7
7
|
secondsAgo: (count) => `${count} s ago`,
|
|
8
8
|
minutesAgo: (count) => `${count} min ago`,
|
|
@@ -11,7 +11,7 @@ const text = defineMessages({
|
|
|
11
11
|
justNow: "just now"
|
|
12
12
|
},
|
|
13
13
|
nl: {
|
|
14
|
-
rows: (count) => `${count} rijen`,
|
|
14
|
+
rows: (count, one) => `${count} ${one ? "rij" : "rijen"}`,
|
|
15
15
|
aboutRows: (count) => `ongeveer ${count} rijen`,
|
|
16
16
|
secondsAgo: (count) => `${count} s geleden`,
|
|
17
17
|
minutesAgo: (count) => `${count} min geleden`,
|
package/dist/format/number.js
CHANGED
|
@@ -6,7 +6,7 @@ const formatInt = (value) => grouped().format(value);
|
|
|
6
6
|
const formatSigned = (value) => value > 0 ? `+${grouped().format(value)}` : grouped().format(value).replace("-", "−");
|
|
7
7
|
const formatPercent = (value) => `${value}%`;
|
|
8
8
|
const formatApproxRows = (count) => {
|
|
9
|
-
if (count < 1e4) return text("rows", formatInt(count));
|
|
9
|
+
if (count < 1e4) return text("rows", formatInt(count), count === 1);
|
|
10
10
|
const magnitude = 10 ** (Math.floor(Math.log10(count)) - 3);
|
|
11
11
|
return text("aboutRows", formatInt(Math.round(count / magnitude) * magnitude));
|
|
12
12
|
};
|
|
@@ -6,7 +6,7 @@ import { Notice } from "../app/meta-gate.js";
|
|
|
6
6
|
import { Button } from "../primitives/button.js";
|
|
7
7
|
import { Field } from "../record-view/field.js";
|
|
8
8
|
import { humanize } from "../live/naming.js";
|
|
9
|
-
import { createBody, hasDatabaseDefault, initialDraft, isRequired } from "../app/create/create-values.js";
|
|
9
|
+
import { createBody, hasDatabaseDefault, initialDraft, isRequired, numberDefault } from "../app/create/create-values.js";
|
|
10
10
|
import { ErrorBanner } from "../app/error-banner.js";
|
|
11
11
|
import { FieldEditor } from "../app/field-editor.js";
|
|
12
12
|
import { fieldErrors, fieldMessage } from "../app/field-errors.js";
|
|
@@ -123,7 +123,7 @@ const LoadedForm = ({ form }) => {
|
|
|
123
123
|
hints,
|
|
124
124
|
value: draft[name] ?? (field.type === "boolean" ? false : ""),
|
|
125
125
|
stored: void 0,
|
|
126
|
-
placeholder: hasDatabaseDefault(field) ? text$1("setByDatabase") :
|
|
126
|
+
placeholder: hasDatabaseDefault(field) ? text$1("setByDatabase") : numberDefault(field),
|
|
127
127
|
invalid: Boolean(problem),
|
|
128
128
|
onChange: (next) => change(name, next)
|
|
129
129
|
})
|
package/dist/package.js
CHANGED