@protobase/ui 0.25.4 → 0.25.6
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/displays/board-display.js +6 -7
- package/dist/app/displays/board-place.js +24 -11
- package/dist/app/displays/use-board-move.js +55 -19
- package/dist/app/hand-order/hand-sorted-list.js +2 -1
- package/dist/app/hand-order/use-hand-order.js +19 -5
- package/dist/app/named-icon.js +3 -2
- package/dist/app/pages/blocks/action.js +8 -4
- package/dist/app/rank-after/dependency-rule.js +17 -0
- package/dist/app/rank-after/messages.js +8 -0
- package/dist/app/rank-after/rank-bounds.js +54 -0
- package/dist/app/rank-after/ranked-place.js +45 -0
- package/dist/app/related-cards/clamped.js +43 -0
- package/dist/app/related-cards/messages.js +18 -0
- package/dist/app/related-cards/related-card.js +66 -0
- package/dist/app/related-cards/related-cards.js +85 -0
- package/dist/app/related-section.js +24 -7
- package/dist/package.js +1 -1
- package/dist/shell/assets/app-G4GViEwd.js +69 -0
- package/dist/shell/assets/index-BrgzNBVN.css +2 -0
- package/dist/shell/assets/{index-HkjqX_O-.js → index-uYJB6y6I.js} +1 -1
- package/dist/shell/assets/{records-map-MfQEuiFB.js → records-map-BzzaFH1s.js} +1 -1
- package/dist/shell/assets/{shared-protobase-ui-Bfa59vx6.js → shared-protobase-ui-CJc7TMx0.js} +1 -1
- package/dist/shell/index.html +4 -4
- package/dist/shell/protobase.shell.json +1 -1
- package/dist/shell/protobase.sw.js +2 -2
- package/package.json +4 -4
- package/dist/shell/assets/app-yCMYvqMX.js +0 -69
- package/dist/shell/assets/index-Bkc7w8I4.css +0 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useIsXs } from "../../lib/use-media-query.js";
|
|
2
|
+
import { Skeleton } from "../../primitives/skeleton.js";
|
|
3
|
+
import { humanize } from "../../live/naming.js";
|
|
4
|
+
import { defaultOrderBy } from "../list-order.js";
|
|
5
|
+
import { AppLink } from "../use-app-address.js";
|
|
6
|
+
import { ErrorBanner } from "../error-banner.js";
|
|
7
|
+
import { scopeOf, useCount, useListPage } from "../pages/use-layout-data.js";
|
|
8
|
+
import { embeddedDisplay, viewAllAddress } from "../embedded-list/embedded-display.js";
|
|
9
|
+
import { text } from "../embedded-list/messages.js";
|
|
10
|
+
import { cutOffNote } from "../embedded-list/cut-off-note.js";
|
|
11
|
+
import { text as text$1 } from "./messages.js";
|
|
12
|
+
import { RelatedCard } from "./related-card.js";
|
|
13
|
+
import { ArrowRight } from "lucide-react";
|
|
14
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
//#region src/app/related-cards/related-cards.tsx
|
|
16
|
+
/**
|
|
17
|
+
* The first `limit` records of a list as cards stacked full width, each with its fields and its actions' buttons, and a
|
|
18
|
+
* link to the whole list beside a note such as "The first 10 of 37." when there are more.
|
|
19
|
+
*/
|
|
20
|
+
const RelatedCards = ({ model, view, filter, sort, fields, actions, limit, display, empty }) => {
|
|
21
|
+
const xs = useIsXs();
|
|
22
|
+
const orderBy = sort || defaultOrderBy(model, view);
|
|
23
|
+
const page = useListPage(model, {
|
|
24
|
+
filter,
|
|
25
|
+
sort: orderBy,
|
|
26
|
+
pageSize: limit
|
|
27
|
+
});
|
|
28
|
+
const count = useCount(model, filter);
|
|
29
|
+
if (page.isPending) return /* @__PURE__ */ jsx("div", {
|
|
30
|
+
className: "flex flex-col gap-3",
|
|
31
|
+
children: Array.from({ length: 2 }, (_, index) => /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" }, index))
|
|
32
|
+
});
|
|
33
|
+
if (page.error) return /* @__PURE__ */ jsx(ErrorBanner, {
|
|
34
|
+
title: text$1("couldNotLoad"),
|
|
35
|
+
error: page.error
|
|
36
|
+
});
|
|
37
|
+
const rows = page.data.items;
|
|
38
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx("p", {
|
|
39
|
+
className: "text-muted-foreground",
|
|
40
|
+
children: empty ?? text$1("nothingYet")
|
|
41
|
+
});
|
|
42
|
+
const note = count.data === void 0 ? void 0 : cutOffNote(rows.length, count.data, false);
|
|
43
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
44
|
+
className: "flex flex-col gap-3",
|
|
45
|
+
children: [/* @__PURE__ */ jsx("ul", {
|
|
46
|
+
className: "flex flex-col gap-3",
|
|
47
|
+
children: rows.map((row) => {
|
|
48
|
+
const scope = scopeOf(model, row);
|
|
49
|
+
return /* @__PURE__ */ jsx(RelatedCard, {
|
|
50
|
+
scope,
|
|
51
|
+
view,
|
|
52
|
+
fields,
|
|
53
|
+
actions
|
|
54
|
+
}, scope.key);
|
|
55
|
+
})
|
|
56
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
57
|
+
className: "flex flex-wrap items-center justify-between gap-2",
|
|
58
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
59
|
+
className: "text-xs text-muted-foreground",
|
|
60
|
+
children: note
|
|
61
|
+
}), /* @__PURE__ */ jsxs(AppLink, {
|
|
62
|
+
to: viewAllAddress(model, view, xs, {
|
|
63
|
+
filter,
|
|
64
|
+
orderBy,
|
|
65
|
+
display: embeddedDisplay(view, xs, { preferred: display })
|
|
66
|
+
}),
|
|
67
|
+
className: "flex items-center gap-1 font-medium text-primary-text hover:underline",
|
|
68
|
+
children: [
|
|
69
|
+
text("viewAll"),
|
|
70
|
+
" ",
|
|
71
|
+
/* @__PURE__ */ jsx("span", {
|
|
72
|
+
className: "sr-only",
|
|
73
|
+
children: (view?.names?.plural ?? humanize(model.name)).toLowerCase()
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ jsx(ArrowRight, {
|
|
76
|
+
className: "size-3.5",
|
|
77
|
+
"aria-hidden": true
|
|
78
|
+
})
|
|
79
|
+
]
|
|
80
|
+
})]
|
|
81
|
+
})]
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
85
|
+
export { RelatedCards };
|
|
@@ -14,6 +14,7 @@ import { useEmbeddedDisplay } from "./embedded-list/use-embedded-display.js";
|
|
|
14
14
|
import { text } from "./record-messages.js";
|
|
15
15
|
import { HandSortedList } from "./hand-order/hand-sorted-list.js";
|
|
16
16
|
import { ReorderButton } from "./hand-order/reorder-button.js";
|
|
17
|
+
import { RelatedCards } from "./related-cards/related-cards.js";
|
|
17
18
|
import { useState } from "react";
|
|
18
19
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
20
|
import { useQuery } from "@tanstack/react-query";
|
|
@@ -78,7 +79,7 @@ const Empty = ({ empty }) => /* @__PURE__ */ jsx("p", {
|
|
|
78
79
|
});
|
|
79
80
|
/**
|
|
80
81
|
* A record page section listing the first records of another resource that point at this record, directly or through
|
|
81
|
-
* a join resource, in the list page's table or display, with a link to them all in the list. When they are ordered by
|
|
82
|
+
* a join resource, in the list page's table or display, or as cards with their actions, with a link to them all in the list. When they are ordered by
|
|
82
83
|
* hand within this record, **Reorder** shows them all in their order, to be moved by their drag handles.
|
|
83
84
|
*/
|
|
84
85
|
const RelatedSection = ({ item, value, owner }) => {
|
|
@@ -100,6 +101,25 @@ const RelatedSection = ({ item, value, owner }) => {
|
|
|
100
101
|
if (item.hideEmpty && (match.isPending || match.filter === null || counting && (count.isPending || count.data === 0))) return null;
|
|
101
102
|
const opens = relatedOpens(item, model, resources);
|
|
102
103
|
const columns = item.columns ?? listColumnNames(model, view).filter((name) => name !== item.field);
|
|
104
|
+
const listed = (list) => match.isPending ? /* @__PURE__ */ jsx(Loading, {}) : match.error ? /* @__PURE__ */ jsx(ErrorBanner, {
|
|
105
|
+
title: text("couldNotLoadRelated"),
|
|
106
|
+
error: match.error
|
|
107
|
+
}) : match.filter === null || match.filter === void 0 ? /* @__PURE__ */ jsx(Empty, { empty: item.empty }) : list(match.filter);
|
|
108
|
+
if (item.presentation === "cards") return /* @__PURE__ */ jsx(Section, {
|
|
109
|
+
title: item.title,
|
|
110
|
+
help: item.help,
|
|
111
|
+
children: listed((filter) => /* @__PURE__ */ jsx(RelatedCards, {
|
|
112
|
+
model,
|
|
113
|
+
view,
|
|
114
|
+
filter,
|
|
115
|
+
sort: item.sort ?? "",
|
|
116
|
+
fields: columns,
|
|
117
|
+
actions: item.actions ?? [],
|
|
118
|
+
limit: item.limit ?? 10,
|
|
119
|
+
display: item.display,
|
|
120
|
+
empty: item.empty
|
|
121
|
+
}))
|
|
122
|
+
});
|
|
103
123
|
const handOrder = relatedHandOrder(item, model, permissions);
|
|
104
124
|
const displaySwitch = /* @__PURE__ */ jsx(EmbeddedDisplaySwitch, {
|
|
105
125
|
view,
|
|
@@ -130,20 +150,17 @@ const RelatedSection = ({ item, value, owner }) => {
|
|
|
130
150
|
title: item.title,
|
|
131
151
|
help: item.help,
|
|
132
152
|
actions,
|
|
133
|
-
children:
|
|
134
|
-
title: text("couldNotLoadRelated"),
|
|
135
|
-
error: match.error
|
|
136
|
-
}) : match.filter === null || match.filter === void 0 ? /* @__PURE__ */ jsx(Empty, { empty: item.empty }) : /* @__PURE__ */ jsx(EmbeddedList, {
|
|
153
|
+
children: listed((filter) => /* @__PURE__ */ jsx(EmbeddedList, {
|
|
137
154
|
model,
|
|
138
155
|
view,
|
|
139
|
-
filter
|
|
156
|
+
filter,
|
|
140
157
|
sort: item.sort ?? "",
|
|
141
158
|
columns,
|
|
142
159
|
limit: item.limit ?? 10,
|
|
143
160
|
display,
|
|
144
161
|
empty: item.empty,
|
|
145
162
|
opens
|
|
146
|
-
},
|
|
163
|
+
}, filter))
|
|
147
164
|
});
|
|
148
165
|
};
|
|
149
166
|
//#endregion
|
package/dist/package.js
CHANGED