@protobase/ui 0.65.0 → 0.66.0
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/incoming-card.js +2 -2
- package/dist/app/incoming-relations.js +4 -4
- package/dist/app/record-lines.js +3 -3
- package/dist/app/record-page.js +14 -11
- package/dist/app/use-lines.js +6 -6
- package/dist/app/use-record-lines.js +38 -16
- package/dist/app-shell/top-bar.js +2 -2
- package/dist/locale/en.js +0 -2
- package/dist/locale/nl.js +0 -2
- package/dist/package.js +1 -1
- package/dist/shell/assets/{app-BOuBCV1m.js → app-CdLhzPaH.js} +7 -7
- package/dist/shell/assets/{calls-C22bYKio.js → calls-fbu88Iwx.js} +2 -2
- package/dist/shell/assets/export-worker-Bux-6dp9.js +15 -0
- package/dist/shell/assets/{index-G0fdUd70.js → index-Du6GlNEk.js} +2 -2
- package/dist/shell/assets/{maplibre-CRmpQfDl.js → maplibre-sUHB6Qig.js} +2 -2
- package/dist/shell/assets/parse-worker-ChfW_ehD.js +18 -0
- package/dist/shell/assets/preload-helper-BRlYOzPJ.js +2 -0
- package/dist/shell/assets/{record-map-DsP4sXes.js → record-map-CZ__Yamf.js} +2 -2
- package/dist/shell/assets/{records-map-BtWK38Kn.js → records-map-C1_HI-hA.js} +2 -2
- package/dist/shell/assets/{shared-protobase-ui-xqMMtr7u.js → shared-protobase-ui-o_KsAqf7.js} +2 -2
- package/dist/shell/index.html +4 -4
- package/dist/shell/protobase.shell.json +2 -2
- package/dist/shell/protobase.sw.js +2 -2
- package/dist/shell-source-maps/assets/app-CdLhzPaH.js.map +1 -0
- package/dist/shell-source-maps/assets/{calls-C22bYKio.js.map → calls-fbu88Iwx.js.map} +1 -1
- package/dist/shell-source-maps/assets/export-worker-Bux-6dp9.js.map +1 -0
- package/dist/shell-source-maps/assets/{index-G0fdUd70.js.map → index-Du6GlNEk.js.map} +1 -1
- package/dist/shell-source-maps/assets/{maplibre-CRmpQfDl.js.map → maplibre-sUHB6Qig.js.map} +1 -1
- package/dist/shell-source-maps/assets/parse-worker-ChfW_ehD.js.map +1 -0
- package/dist/shell-source-maps/assets/preload-helper-BRlYOzPJ.js.map +1 -0
- package/dist/shell-source-maps/assets/{record-map-DsP4sXes.js.map → record-map-CZ__Yamf.js.map} +1 -1
- package/dist/shell-source-maps/assets/{records-map-BtWK38Kn.js.map → records-map-C1_HI-hA.js.map} +1 -1
- package/dist/shell-source-maps/assets/{shared-protobase-ui-xqMMtr7u.js.map → shared-protobase-ui-o_KsAqf7.js.map} +1 -1
- package/package.json +4 -4
- package/dist/shell/assets/export-worker-ClXdfeuq.js +0 -15
- package/dist/shell/assets/parse-worker-DxsmAjef.js +0 -18
- package/dist/shell/assets/preload-helper-BgLOXTzV.js +0 -2
- package/dist/shell-source-maps/assets/app-BOuBCV1m.js.map +0 -1
- package/dist/shell-source-maps/assets/export-worker-ClXdfeuq.js.map +0 -1
- package/dist/shell-source-maps/assets/parse-worker-DxsmAjef.js.map +0 -1
- package/dist/shell-source-maps/assets/preload-helper-BgLOXTzV.js.map +0 -1
|
@@ -10,9 +10,9 @@ import { ChevronRight } from "lucide-react";
|
|
|
10
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
//#region src/app/incoming-card.tsx
|
|
12
12
|
/** The rail's card of the records pointing at this one: per resource and field, how many, linking to them in their list. */
|
|
13
|
-
const IncomingCard = ({ model, recordKey, layout
|
|
13
|
+
const IncomingCard = ({ model, recordKey, layout }) => {
|
|
14
14
|
const { resources, views } = useAdminMeta();
|
|
15
|
-
const counts = useIncomingCounts(incomingRelations(model, resources, views, layout
|
|
15
|
+
const counts = useIncomingCounts(incomingRelations(model, resources, views, layout), resources, recordKey);
|
|
16
16
|
if (counts.length === 0) return null;
|
|
17
17
|
return /* @__PURE__ */ jsx(SidebarCard, {
|
|
18
18
|
title: text("relatedRecords"),
|
|
@@ -6,13 +6,13 @@ const where$1 = createWhere();
|
|
|
6
6
|
/**
|
|
7
7
|
* The relations that point at records of `model`, as the rail lists them by default: each filterable relation of
|
|
8
8
|
* another resource the user can see (a hidden resource or field is not in the meta), to a record of one key column.
|
|
9
|
-
* Left out are a resource's tenant, which every record holds,
|
|
10
|
-
*
|
|
9
|
+
* Left out are a resource's tenant, which every record holds, and what an `l.related` section of the page already
|
|
10
|
+
* lists, the record's lines included. Two fields of one resource are told apart by their labels.
|
|
11
11
|
*/
|
|
12
|
-
const incomingRelations = (model, resources, views, layout
|
|
12
|
+
const incomingRelations = (model, resources, views, layout) => {
|
|
13
13
|
if (model.primaryKey.length !== 1) return [];
|
|
14
14
|
const listed = new Set(layoutItems(layout).flatMap((item) => item.kind === "related" && !item.through && !item.from ? [`${item.resource}.${item.field}`] : []));
|
|
15
|
-
const found = Object.values(resources).flatMap((source) => Object.values(source.fields).filter((field) => field.type === "relation" && field.relation?.resource === model.name && field.relation.columns.length === 1 && field.filterable).filter((field) => field.name !== source.tenant &&
|
|
15
|
+
const found = Object.values(resources).flatMap((source) => Object.values(source.fields).filter((field) => field.type === "relation" && field.relation?.resource === model.name && field.relation.columns.length === 1 && field.filterable).filter((field) => field.name !== source.tenant && !listed.has(`${source.name}.${field.name}`)).map((field) => ({
|
|
16
16
|
source,
|
|
17
17
|
field: field.name
|
|
18
18
|
})));
|
package/dist/app/record-lines.js
CHANGED
|
@@ -20,7 +20,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
20
20
|
*/
|
|
21
21
|
const RecordLines = ({ lines, editable, saving }) => {
|
|
22
22
|
const { resources, views } = useAdminMeta();
|
|
23
|
-
const { model, columns, data, draft } = lines;
|
|
23
|
+
const { item, model, columns, data, draft } = lines;
|
|
24
24
|
const permissions = usePermissions(model.name);
|
|
25
25
|
const view = views[model.name];
|
|
26
26
|
const [picked, setPicked] = useState({});
|
|
@@ -89,8 +89,8 @@ const RecordLines = ({ lines, editable, saving }) => {
|
|
|
89
89
|
return rejection.message;
|
|
90
90
|
};
|
|
91
91
|
return /* @__PURE__ */ jsxs(Section, {
|
|
92
|
-
title:
|
|
93
|
-
help:
|
|
92
|
+
title: item.title,
|
|
93
|
+
help: item.help,
|
|
94
94
|
children: [!data.complete && /* @__PURE__ */ jsx("p", {
|
|
95
95
|
className: "mb-2 text-muted-foreground",
|
|
96
96
|
children: text("tooManyLines", { limit: formatInt(1e3) })
|
package/dist/app/record-page.js
CHANGED
|
@@ -412,6 +412,18 @@ const LoadedRecord = ({ model, recordKey, stored, preview }) => {
|
|
|
412
412
|
children
|
|
413
413
|
}, `group:${item.title}`)];
|
|
414
414
|
}
|
|
415
|
+
if (item.kind === "related" && item.lines) {
|
|
416
|
+
if (!lines.model || !lines.item || preview) return [];
|
|
417
|
+
return [/* @__PURE__ */ jsx(RecordLines, {
|
|
418
|
+
lines: {
|
|
419
|
+
...lines,
|
|
420
|
+
model: lines.model,
|
|
421
|
+
item: lines.item
|
|
422
|
+
},
|
|
423
|
+
editable: shown === "form",
|
|
424
|
+
saving: editor.saving
|
|
425
|
+
}, `lines:${item.title}`)];
|
|
426
|
+
}
|
|
415
427
|
if (item.kind === "related") {
|
|
416
428
|
if (item.from !== void 0 && !known(item.from)) return [];
|
|
417
429
|
return [/* @__PURE__ */ jsx(RelatedSection, {
|
|
@@ -548,15 +560,7 @@ const LoadedRecord = ({ model, recordKey, stored, preview }) => {
|
|
|
548
560
|
className: "divide-y divide-border",
|
|
549
561
|
children: tab.items.flatMap(mainItem)
|
|
550
562
|
}, `tab:${tab.title}`),
|
|
551
|
-
after.flatMap(mainItem)
|
|
552
|
-
lines.model && !preview && /* @__PURE__ */ jsx(RecordLines, {
|
|
553
|
-
lines: {
|
|
554
|
-
...lines,
|
|
555
|
-
model: lines.model
|
|
556
|
-
},
|
|
557
|
-
editable: shown === "form",
|
|
558
|
-
saving: editor.saving
|
|
559
|
-
})
|
|
563
|
+
after.flatMap(mainItem)
|
|
560
564
|
]
|
|
561
565
|
}), /* @__PURE__ */ jsxs("aside", {
|
|
562
566
|
className: "space-y-4 md:sticky md:top-[var(--pb-sticky-top,0px)] md:max-h-[calc(100dvh-var(--pb-sticky-top,0px)-var(--pb-sticky-bottom,0px))] md:self-start md:overflow-y-auto md:pb-4 md:pt-8",
|
|
@@ -601,8 +605,7 @@ const LoadedRecord = ({ model, recordKey, stored, preview }) => {
|
|
|
601
605
|
!preview && /* @__PURE__ */ jsx(IncomingCard, {
|
|
602
606
|
model,
|
|
603
607
|
recordKey,
|
|
604
|
-
layout
|
|
605
|
-
lines: lines.model
|
|
608
|
+
layout
|
|
606
609
|
})
|
|
607
610
|
]
|
|
608
611
|
})]
|
package/dist/app/use-lines.js
CHANGED
|
@@ -3,20 +3,20 @@ import { useEffect, useMemo } from "react";
|
|
|
3
3
|
//#region src/app/use-lines.ts
|
|
4
4
|
/** The most lines a record's line editor loads; a record with more shows them read-only, as it cannot save them as a whole. */
|
|
5
5
|
const linesLimit = 1e3;
|
|
6
|
-
const byPosition = (a, b) => Number(a.position) - Number(b.position);
|
|
7
6
|
/**
|
|
8
|
-
* The numbered lines of a record, in position
|
|
9
|
-
* large as the API gives. `labels` names the records their relations point at. Nothing is
|
|
7
|
+
* The numbered lines of a record, in the order of their `position` field, as the server has them: every page, up to
|
|
8
|
+
* `linesLimit`, each as large as the API gives. `labels` names the records their relations point at. Nothing is
|
|
9
|
+
* fetched without a lines resource.
|
|
10
10
|
*/
|
|
11
|
-
const useLines = (lines, link, parentKey, labels) => {
|
|
11
|
+
const useLines = (lines, link, position, parentKey, labels) => {
|
|
12
12
|
const list = useList(lines?.name ?? "", {
|
|
13
13
|
enabled: Boolean(lines && link),
|
|
14
14
|
filter: link ? `${link.name} = "${parentKey}"` : void 0,
|
|
15
15
|
pageSize: 500,
|
|
16
16
|
labels,
|
|
17
|
-
...lines?.fields
|
|
17
|
+
...position && lines?.fields[position]?.sortable && { orderBy: `${position} asc` }
|
|
18
18
|
});
|
|
19
|
-
const items = useMemo(() => [...list.items].sort(
|
|
19
|
+
const items = useMemo(() => position ? [...list.items].sort((a, b) => Number(a[position]) - Number(b[position])) : list.items, [list.data, position]);
|
|
20
20
|
const more = list.hasNextPage && list.items.length < 1e3;
|
|
21
21
|
useEffect(() => {
|
|
22
22
|
if (more && !list.isFetchingNextPage) list.fetchNextPage();
|
|
@@ -5,42 +5,64 @@ import { listLabels } from "../live/relation-labels.js";
|
|
|
5
5
|
import { useLines } from "./use-lines.js";
|
|
6
6
|
import { useLinesDraft } from "./use-lines-draft.js";
|
|
7
7
|
import { useMemo } from "react";
|
|
8
|
+
import { layoutItems } from "@protobase/schema/internal";
|
|
8
9
|
//#region src/app/use-record-lines.ts
|
|
9
|
-
/**
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The record's lines, as its view declares them with `l.related(..., { lines: true })`: the section, the lines'
|
|
12
|
+
* resource, the relation that points at the record and the field that orders them.
|
|
13
|
+
*/
|
|
14
|
+
const findLinesResource = (resources, view) => {
|
|
15
|
+
const item = layoutItems(view?.layout ?? []).find((each) => each.kind === "related" && each.lines === true);
|
|
16
|
+
if (item?.kind !== "related") return;
|
|
17
|
+
const model = resources[item.resource];
|
|
18
|
+
const link = model?.fields[item.field];
|
|
19
|
+
const position = model?.position?.field;
|
|
20
|
+
if (!model || !link || !position || model.position?.within !== item.field) return;
|
|
21
|
+
return {
|
|
22
|
+
item,
|
|
23
|
+
model,
|
|
24
|
+
link,
|
|
25
|
+
position
|
|
26
|
+
};
|
|
27
|
+
};
|
|
11
28
|
/**
|
|
12
29
|
* The lines' columns: the list columns of their view, or its first fields, without what the editor fills in itself:
|
|
13
30
|
* the key, the tenant, the relation to the record and the position, which is the order of the rows.
|
|
14
31
|
*/
|
|
15
|
-
const lineColumnNames = (lines, view, link) => listColumnNames(lines, view).filter((name) => {
|
|
32
|
+
const lineColumnNames = (lines, view, link, position) => listColumnNames(lines, view).filter((name) => {
|
|
16
33
|
const field = lines.fields[name];
|
|
17
|
-
return field && !field.writeOnly && name !== link && name !==
|
|
34
|
+
return field && !field.writeOnly && name !== link && name !== position && name !== lines.tenant && !lines.primaryKey.includes(name);
|
|
18
35
|
});
|
|
19
|
-
/** The record's lines when
|
|
36
|
+
/** The record's lines when its view declares them: the section, the resource, its columns, the lines as stored and the changes made to them. */
|
|
20
37
|
const useRecordLines = (parent, parentKey) => {
|
|
21
38
|
const { resources, views } = useAdminMeta();
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
39
|
+
const found = useMemo(() => findLinesResource(resources, views[parent.name]), [
|
|
40
|
+
resources,
|
|
41
|
+
views,
|
|
42
|
+
parent
|
|
43
|
+
]);
|
|
44
|
+
const model = found?.model;
|
|
45
|
+
const columns = found ? lineColumnNames(found.model, views[found.model.name], found.link.name, found.position) : [];
|
|
46
|
+
const data = useLines(model, found?.link, found?.position, parentKey, model ? listLabels(resources, views, model, columns) : void 0);
|
|
47
|
+
const target = useMemo(() => found ? {
|
|
48
|
+
model: found.model,
|
|
49
|
+
position: found.position,
|
|
29
50
|
link: {
|
|
30
|
-
field: link.name,
|
|
51
|
+
field: found.link.name,
|
|
31
52
|
value: keyValue(parent, parentKey)
|
|
32
53
|
}
|
|
33
54
|
} : void 0, [
|
|
34
|
-
|
|
35
|
-
link,
|
|
55
|
+
found,
|
|
36
56
|
parent,
|
|
37
57
|
parentKey
|
|
38
58
|
]);
|
|
59
|
+
const draft = useLinesDraft(target, data.items);
|
|
39
60
|
return {
|
|
61
|
+
item: found?.item,
|
|
40
62
|
model,
|
|
41
63
|
columns,
|
|
42
64
|
data,
|
|
43
|
-
draft
|
|
65
|
+
draft
|
|
44
66
|
};
|
|
45
67
|
};
|
|
46
68
|
//#endregion
|
|
@@ -3,7 +3,7 @@ import { text } from "./messages.js";
|
|
|
3
3
|
import { Breadcrumb, inApp } from "./breadcrumb.js";
|
|
4
4
|
import { backTarget } from "./back-target.js";
|
|
5
5
|
import { GlobalSearch } from "./global-search.js";
|
|
6
|
-
import {
|
|
6
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
7
7
|
import { ChevronLeft, Menu, Search, X } from "lucide-react";
|
|
8
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/app-shell/top-bar.tsx
|
|
@@ -13,7 +13,7 @@ const TopBar = ({ breadcrumb, onNavigate, onBack, actions, onMenu, menuOpen, men
|
|
|
13
13
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
14
14
|
const back = backTarget(breadcrumb);
|
|
15
15
|
const desktopSearch = useRef(null);
|
|
16
|
-
|
|
16
|
+
useLayoutEffect(() => {
|
|
17
17
|
if (!search) return;
|
|
18
18
|
const onKey = (event) => {
|
|
19
19
|
if (event.key.toLowerCase() !== "k" || !(event.metaKey || event.ctrlKey)) return;
|
package/dist/locale/en.js
CHANGED
|
@@ -734,8 +734,6 @@ var en_default = {
|
|
|
734
734
|
"nothingYet": "Nothing here yet.",
|
|
735
735
|
"couldNotLoadRelated": "Could not load",
|
|
736
736
|
"relatedRecords": "Related records",
|
|
737
|
-
"lines": "Lines",
|
|
738
|
-
"linesHelp": "What the document bills for. Edit a line in place, add one, or drag the handle to change the order; Save applies it all.",
|
|
739
737
|
"lineNumber": "Line {place}",
|
|
740
738
|
"lineField": "{label}, line {place}",
|
|
741
739
|
"tooManyLines": "This record has more than {limit} lines, so they show here read-only."
|
package/dist/locale/nl.js
CHANGED
|
@@ -734,8 +734,6 @@ var nl_default = {
|
|
|
734
734
|
"nothingYet": "Hier staat nog niets.",
|
|
735
735
|
"couldNotLoadRelated": "Kon niet laden",
|
|
736
736
|
"relatedRecords": "Gerelateerde records",
|
|
737
|
-
"lines": "Regels",
|
|
738
|
-
"linesHelp": "Waar het document voor factureert. Wijzig een regel ter plekke, voeg er een toe, of sleep de greep om de volgorde te wijzigen; Bewaren past alles toe.",
|
|
739
737
|
"lineNumber": "Regel {place}",
|
|
740
738
|
"lineField": "{label}, regel {place}",
|
|
741
739
|
"tooManyLines": "Dit record heeft meer dan {limit} regels, dus ze staan hier alleen ter inzage."
|
package/dist/package.js
CHANGED