@protobase/ui 0.12.22 → 0.13.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/displays/card-layout.js +19 -0
- package/dist/app/displays/cards-display.js +16 -11
- package/dist/app/displays/list-cards.js +50 -0
- package/dist/app/displays/list-displays.js +4 -3
- package/dist/app/displays/map-display.js +3 -3
- package/dist/app/displays/virtual-cards.js +138 -0
- package/dist/app/embedded-list/embedded-columns.js +52 -0
- package/dist/app/embedded-list/embedded-display.js +26 -0
- package/dist/app/embedded-list/embedded-list.js +155 -0
- package/dist/app/embedded-list/use-embedded-display.js +23 -0
- package/dist/app/embedded-list/use-embedded-rows.js +33 -0
- package/dist/app/list-page.js +14 -5
- package/dist/app/list-scroll.js +25 -0
- package/dist/app/pages/blocks/table.js +21 -41
- package/dist/app/record-page.js +2 -1
- package/dist/app/related-section.js +30 -52
- package/dist/app/router.js +1 -0
- package/dist/data-grid/data-grid.js +19 -39
- package/dist/data-grid/geometry.js +7 -9
- package/dist/data-grid/use-grid-scroll.js +8 -1
- package/dist/data-grid/use-virtual-rows.js +31 -0
- package/dist/live/columns-from-model.js +6 -4
- package/dist/live/grid-loader.js +26 -10
- package/dist/package.js +1 -1
- package/dist/record-view/section.js +24 -17
- package/dist/shell/assets/app-DLjaMVJD.js +66 -0
- package/dist/shell/assets/index-BYPphaEm.css +2 -0
- package/dist/shell/assets/{index-B8MhIaLr.js → index-D7IcSr6n.js} +3 -3
- package/dist/shell/assets/maplibre-gl-Bt-3iOM-.js +1 -0
- package/dist/shell/assets/record-map-DL4b9dZO.js +814 -0
- package/dist/shell/assets/records-map-D0EOO5kZ.js +1 -0
- package/dist/shell/assets/shared-protobase-ui-B8UXOIeW.js +1 -0
- package/dist/shell/index.html +5 -5
- package/dist/shell/protobase.shell.json +1 -1
- package/package.json +4 -5
- package/dist/app/pages/record-table.js +0 -114
- package/dist/app/pages/use-relation-labels.js +0 -30
- package/dist/shell/assets/app-BYw-8qpE.js +0 -66
- package/dist/shell/assets/index-CdSIk0BQ.css +0 -2
- package/dist/shell/assets/navigation-control-CGS0pamh.js +0 -814
- package/dist/shell/assets/record-map-9Y3IL_dg.js +0 -1
- package/dist/shell/assets/records-map-DXIWowJ3.js +0 -1
- package/dist/shell/assets/shared-protobase-ui-Bol6wL_S.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{t}from"./react-Cvdyeg_0.js";import{G as n,_ as r,g as i}from"./app-DLjaMVJD.js";import{t as a}from"./jsx-runtime-NZYk81nU.js";import{Ft as o,it as s,n as c,r as l,t as u}from"./record-map-DL4b9dZO.js";var d=e(t(),1),f=e(a(),1),p=28,m={padding:48,maxZoom:15,duration:0},h=32,g=({style:e,points:t,selected:a,covered:g,onSelect:_,onClear:v,markerLabel:y})=>{let b=(0,d.useRef)(null),[x,S]=(0,d.useState)([]),C=new globalThis.Map(t.map(e=>[e.key,e])),w=t.map(e=>e.key).join(`,`),T=r(t),E=()=>{let e=b.current?.getMap();e&&S(i(t.map(t=>({key:t.key,...e.project([t.longitude,t.latitude])})),p))};(0,d.useEffect)(()=>{let e=b.current?.getMap();e&&(T&&e.fitBounds(T,m),E())},[w]);let D=x.find(e=>a!==void 0&&e.keys.some(e=>a.includes(e)))?.at;return(0,d.useEffect)(()=>{let e=b.current?.getMap(),t=D===void 0?void 0:C.get(D);if(!e||!t||g===0)return;let{y:n}=e.project([t.longitude,t.latitude]),r=e.getContainer().clientHeight-g;n>h&&n<r||e.easeTo({center:[t.longitude,t.latitude],offset:[0,(h-g)/2],duration:300})},[D,g]),(0,f.jsxs)(l,{ref:b,mapLib:s,mapStyle:e,initialViewState:T?{bounds:T,fitBoundsOptions:m}:{latitude:0,longitude:0,zoom:1},style:{width:`100%`,height:`100%`},onLoad:E,onZoomEnd:E,onClick:v,children:[(0,f.jsx)(u,{showCompass:!1}),x.map(e=>{let t=C.get(e.at);if(!t)return null;let r=a!==void 0&&e.keys.some(e=>a.includes(e));return(0,f.jsx)(c,{latitude:t.latitude,longitude:t.longitude,anchor:`bottom`,style:{zIndex:+!!r},children:(0,f.jsxs)(`button`,{type:`button`,"aria-label":y(e.keys),"aria-pressed":r,className:`relative block cursor-pointer`,onClick:t=>{t.stopPropagation(),_(e.keys)},children:[(0,f.jsx)(o,{"aria-hidden":!0,className:n(`size-8 drop-shadow`,r?`fill-foreground text-background`:`fill-primary text-primary-foreground`),strokeWidth:1.5}),e.keys.length>1&&(0,f.jsx)(`span`,{className:`absolute -right-2 -top-1 min-w-5 rounded-full border border-background bg-foreground px-1 text-center text-[11px] font-medium leading-4 text-background tabular-nums`,children:e.keys.length})]})},e.at)})]})};export{g as RecordsMap};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{A as t,B as n,C as r,D as i,E as a,F as o,H as s,I as c,L as l,M as u,N as d,P as f,R as p,S as m,T as h,U as g,V as _,W as v,a as y,b,c as x,d as S,f as C,h as w,i as T,j as E,k as D,l as O,m as k,n as A,o as j,p as M,r as N,s as P,t as F,u as I,v as L,w as R,x as z,y as B,z as V}from"./app-DLjaMVJD.js";import{t as H}from"./jsx-runtime-NZYk81nU.js";var U=e(H(),1),W=({row:e,resource:t,recordKey:n,...r})=>{let i=w(),a=I(),o=t??i?.resource??a?.model.name;if(o===void 0)throw Error(`RecordLink needs a resource outside a list display or a record`);return(0,U.jsx)(L,{to:{kind:`record`,resource:o,key:e?e.key:n},...r})};export{o as ActionCard,s as ApiProvider,F as App,L as AppLink,r as AssistantDock,V as ChatMessage,p as ChatThread,d as CompactTable,l as Composer,t as DiffView,f as FieldList,h as PartView,W as RecordLink,c as SidePanel,D as StepList,a as definePlugin,i as defineUi,E as diffStats,A as isConflict,x as mergeUi,u as parseDiff,y as pluginApi,j as protobaseVersion,O as uiFromModule,_ as useApiToken,B as useAppAddress,m as useAssistant,z as useAssistantClient,R as useBackendData,g as useClient,S as useFacets,C as useHistogram,I as useLayoutRecord,T as useList,k as useListDisplay,b as useMeta,P as usePlugin,n as useRecord,v as useResourceClient,M as useSeries,N as useUpdateRecord};
|
package/dist/shell/index.html
CHANGED
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
<meta charset="utf-8" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
8
8
|
<title>Protobase</title>
|
|
9
|
-
<script type="importmap">{"imports":{"react":"/assets/shared-react-DhkZ2M4l.js","react/jsx-runtime":"/assets/shared-react-jsx-runtime-xPQrWk0g.js","react-dom":"/assets/shared-react-dom-D508a1cq.js","@protobase/ui":"/assets/shared-protobase-ui-
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="importmap">{"imports":{"react":"/assets/shared-react-DhkZ2M4l.js","react/jsx-runtime":"/assets/shared-react-jsx-runtime-xPQrWk0g.js","react-dom":"/assets/shared-react-dom-D508a1cq.js","@protobase/ui":"/assets/shared-protobase-ui-B8UXOIeW.js"}}</script>
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-D7IcSr6n.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-hePW80VL.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/react-Cvdyeg_0.js">
|
|
13
|
-
<link rel="modulepreload" crossorigin href="/assets/jsx-runtime-NZYk81nU.js">
|
|
14
13
|
<link rel="modulepreload" crossorigin href="/assets/react-dom-B-VxWsjA.js">
|
|
15
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
14
|
+
<link rel="modulepreload" crossorigin href="/assets/jsx-runtime-NZYk81nU.js">
|
|
15
|
+
<link rel="modulepreload" crossorigin href="/assets/app-DLjaMVJD.js">
|
|
16
16
|
<link rel="stylesheet" crossorigin href="/assets/app-GUjJKojE.css">
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BYPphaEm.css">
|
|
18
18
|
<link rel="stylesheet" href="/protobase.theme.css">
|
|
19
19
|
</head>
|
|
20
20
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "The Protobase admin app and the React hooks and components for custom UI.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -38,13 +38,12 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@dnd-kit/core": "^6.3.1",
|
|
40
40
|
"@dnd-kit/sortable": "^10.0.0",
|
|
41
|
-
"@protobase/client": "0.
|
|
42
|
-
"@protobase/layout": "0.
|
|
43
|
-
"@protobase/schema": "0.
|
|
41
|
+
"@protobase/client": "0.13.0",
|
|
42
|
+
"@protobase/layout": "0.13.0",
|
|
43
|
+
"@protobase/schema": "0.13.0",
|
|
44
44
|
"@sentry/browser": "^11.7.0",
|
|
45
45
|
"@tanstack/react-query": "^5.104.1",
|
|
46
46
|
"@tanstack/react-table": "^9.2.6",
|
|
47
|
-
"@tanstack/react-virtual": "^3.14.13",
|
|
48
47
|
"lucide-react": "^1.52.0",
|
|
49
48
|
"maplibre-gl": "^6.14.0",
|
|
50
49
|
"pmtiles": "^4.5.0",
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { Button } from "../../primitives/button.js";
|
|
2
|
-
import { humanize } from "../../live/naming.js";
|
|
3
|
-
import { useAdminMeta } from "../meta-gate.js";
|
|
4
|
-
import { AppLink } from "../use-app-address.js";
|
|
5
|
-
import { scopeOf } from "./use-layout-data.js";
|
|
6
|
-
import { FieldValue } from "./field-value.js";
|
|
7
|
-
import { usePathValue } from "./use-path-value.js";
|
|
8
|
-
import { useRelationLabels } from "./use-relation-labels.js";
|
|
9
|
-
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
10
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
-
import { resolveFieldPath } from "@protobase/layout";
|
|
12
|
-
//#region src/app/pages/record-table.tsx
|
|
13
|
-
const isPath = (column) => column.includes(".");
|
|
14
|
-
/** The header of a column: the label of the field it ends at, from that field's view. */
|
|
15
|
-
const useHeader = (model) => {
|
|
16
|
-
const { resources, views } = useAdminMeta();
|
|
17
|
-
return (column) => {
|
|
18
|
-
const resolved = resolveFieldPath(resources, model.name, column);
|
|
19
|
-
const last = resolved.ok ? resolved.steps.at(-1) : void 0;
|
|
20
|
-
const name = last?.field.name ?? column;
|
|
21
|
-
return views[last?.model.name ?? model.name]?.fields[name]?.label ?? humanize(name);
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
/** A value through relations (`unitId.propertyId`), fetched like the record page fetches it and cached. */
|
|
25
|
-
const PathCell = ({ model, row, column }) => {
|
|
26
|
-
const value = usePathValue(scopeOf(model, row), column);
|
|
27
|
-
if (value.state === "loading") return /* @__PURE__ */ jsx("span", {
|
|
28
|
-
className: "text-muted-foreground",
|
|
29
|
-
children: "…"
|
|
30
|
-
});
|
|
31
|
-
if (value.state === "missing") return /* @__PURE__ */ jsx("span", {
|
|
32
|
-
className: "text-muted-foreground",
|
|
33
|
-
children: "—"
|
|
34
|
-
});
|
|
35
|
-
return /* @__PURE__ */ jsx(FieldValue, {
|
|
36
|
-
model: value.model,
|
|
37
|
-
field: value.field,
|
|
38
|
-
value: value.value
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Records as table rows; the first column opens the record, unless it is a relation, which links to the record it
|
|
43
|
-
* names instead (a join record's first column is usually what it joins). Columns may follow relations (`unitId.propertyId`).
|
|
44
|
-
*/
|
|
45
|
-
const RecordTable = ({ model, columns, rows, label, pager }) => {
|
|
46
|
-
const { resources } = useAdminMeta();
|
|
47
|
-
const header = useHeader(model);
|
|
48
|
-
const first = columns[0] === void 0 ? void 0 : resolveFieldPath(resources, model.name, columns[0]);
|
|
49
|
-
const opensRecord = !first?.ok || first.steps.at(-1).field.type !== "relation";
|
|
50
|
-
const labels = useRelationLabels(model, columns.filter((column) => !isPath(column)), rows);
|
|
51
|
-
const cell = (row, column) => isPath(column) ? /* @__PURE__ */ jsx(PathCell, {
|
|
52
|
-
model,
|
|
53
|
-
row,
|
|
54
|
-
column
|
|
55
|
-
}) : /* @__PURE__ */ jsx(FieldValue, {
|
|
56
|
-
model,
|
|
57
|
-
field: model.fields[column],
|
|
58
|
-
value: row[column],
|
|
59
|
-
relationLabel: labels.get(column)?.get(String(row[column]))
|
|
60
|
-
});
|
|
61
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
62
|
-
className: "-mx-4 overflow-x-auto",
|
|
63
|
-
children: /* @__PURE__ */ jsxs("table", {
|
|
64
|
-
className: "w-full min-w-max text-left text-[13px]",
|
|
65
|
-
children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", {
|
|
66
|
-
className: "border-b text-xs text-muted-foreground",
|
|
67
|
-
children: columns.map((column) => /* @__PURE__ */ jsx("th", {
|
|
68
|
-
scope: "col",
|
|
69
|
-
className: "px-4 py-2 font-medium",
|
|
70
|
-
children: header(column)
|
|
71
|
-
}, column))
|
|
72
|
-
}) }), /* @__PURE__ */ jsx("tbody", { children: rows.map((row) => {
|
|
73
|
-
const scope = scopeOf(model, row);
|
|
74
|
-
return /* @__PURE__ */ jsx("tr", {
|
|
75
|
-
className: "border-b last:border-0 hover:bg-surface",
|
|
76
|
-
children: columns.map((column, index) => /* @__PURE__ */ jsx("td", {
|
|
77
|
-
className: "px-4 py-2",
|
|
78
|
-
children: index === 0 && opensRecord ? /* @__PURE__ */ jsx(AppLink, {
|
|
79
|
-
to: {
|
|
80
|
-
kind: "record",
|
|
81
|
-
resource: model.name,
|
|
82
|
-
key: scope.key
|
|
83
|
-
},
|
|
84
|
-
className: "font-medium text-primary-text hover:underline",
|
|
85
|
-
children: cell(row, column)
|
|
86
|
-
}) : cell(row, column)
|
|
87
|
-
}, column))
|
|
88
|
-
}, scope.key);
|
|
89
|
-
}) })]
|
|
90
|
-
})
|
|
91
|
-
}), pager && (pager.hasPrevious || pager.hasNext) && /* @__PURE__ */ jsxs("nav", {
|
|
92
|
-
"aria-label": `${label} pages`,
|
|
93
|
-
className: "mt-3 flex items-center justify-end gap-2 text-xs text-muted-foreground",
|
|
94
|
-
children: [
|
|
95
|
-
/* @__PURE__ */ jsxs("span", { children: ["Page ", pager.page] }),
|
|
96
|
-
/* @__PURE__ */ jsx(Button, {
|
|
97
|
-
size: "sm",
|
|
98
|
-
"aria-label": "Previous page",
|
|
99
|
-
disabled: !pager.hasPrevious || pager.busy,
|
|
100
|
-
onClick: pager.previous,
|
|
101
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5" })
|
|
102
|
-
}),
|
|
103
|
-
/* @__PURE__ */ jsx(Button, {
|
|
104
|
-
size: "sm",
|
|
105
|
-
"aria-label": "Next page",
|
|
106
|
-
disabled: !pager.hasNext || pager.busy,
|
|
107
|
-
onClick: pager.next,
|
|
108
|
-
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5" })
|
|
109
|
-
})
|
|
110
|
-
]
|
|
111
|
-
})] });
|
|
112
|
-
};
|
|
113
|
-
//#endregion
|
|
114
|
-
export { RecordTable };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { keys } from "../../data/query-keys.js";
|
|
2
|
-
import { useClient } from "../../data/api-provider.js";
|
|
3
|
-
import { fetchLabels } from "../../live/relation-labels.js";
|
|
4
|
-
import { useAdminMeta } from "../meta-gate.js";
|
|
5
|
-
import { useQueries, useQueryClient } from "@tanstack/react-query";
|
|
6
|
-
//#region src/app/pages/use-relation-labels.ts
|
|
7
|
-
/** Names for the relation columns of the rows on screen, one list call per column, by column then key. */
|
|
8
|
-
const useRelationLabels = (model, columns, rows) => {
|
|
9
|
-
const { resources, views } = useAdminMeta();
|
|
10
|
-
const client = useClient();
|
|
11
|
-
const queryClient = useQueryClient();
|
|
12
|
-
const relations = columns.flatMap((name) => {
|
|
13
|
-
const field = model.fields[name];
|
|
14
|
-
const target = field?.type === "relation" && field.relation ? resources[field.relation.resource] : void 0;
|
|
15
|
-
if (!target || target.primaryKey.length !== 1) return [];
|
|
16
|
-
const ids = [...new Set(rows.flatMap((row) => row[name] === null || row[name] === void 0 ? [] : [String(row[name])]))].sort();
|
|
17
|
-
return ids.length > 0 ? [{
|
|
18
|
-
name,
|
|
19
|
-
target,
|
|
20
|
-
ids
|
|
21
|
-
}] : [];
|
|
22
|
-
});
|
|
23
|
-
const results = useQueries({ queries: relations.map(({ target, ids }) => ({
|
|
24
|
-
queryKey: keys.labelMap(target.name, ids.join(",")),
|
|
25
|
-
queryFn: () => fetchLabels(queryClient, client, target, ids, views[target.name])
|
|
26
|
-
})) });
|
|
27
|
-
return new Map(relations.flatMap(({ name }, index) => results[index]?.data ? [[name, results[index].data]] : []));
|
|
28
|
-
};
|
|
29
|
-
//#endregion
|
|
30
|
-
export { useRelationLabels };
|