@questpie/admin 3.5.0 → 3.5.2
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/client/blocks/block-renderer.d.mts +2 -2
- package/dist/client/components/blocks/block-canvas.mjs +1 -1
- package/dist/client/components/blocks/block-editor-layout.mjs +2 -2
- package/dist/client/components/blocks/block-insert-button.mjs +3 -3
- package/dist/client/components/blocks/block-item-menu.mjs +9 -9
- package/dist/client/components/blocks/block-item.mjs +5 -5
- package/dist/client/components/blocks/block-library-sidebar.mjs +3 -3
- package/dist/client/components/fields/array-field.mjs +2 -2
- package/dist/client/components/fields/date-field.mjs +6 -5
- package/dist/client/components/fields/datetime-field.mjs +6 -1
- package/dist/client/components/fields/object-array-field.mjs +2 -2
- package/dist/client/components/fields/relation/displays/cards-display.mjs +1 -1
- package/dist/client/components/fields/relation/displays/grid-display.mjs +1 -1
- package/dist/client/components/fields/relation/displays/list-display.mjs +3 -3
- package/dist/client/components/fields/relation/displays/table-display.mjs +1 -1
- package/dist/client/components/fields/relation-picker.mjs +3 -3
- package/dist/client/components/fields/relation-select.mjs +2 -2
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs +16 -16
- package/dist/client/components/history-sidebar.mjs +12 -4
- package/dist/client/components/layout/field-layout-renderer.mjs +8 -3
- package/dist/client/components/media/media-grid.mjs +2 -2
- package/dist/client/components/preview/live-preview-mode.mjs +4 -4
- package/dist/client/components/preview/preview-pane.mjs +4 -4
- package/dist/client/components/primitives/asset-preview.mjs +5 -5
- package/dist/client/components/primitives/dropzone.mjs +1 -1
- package/dist/client/components/ui/kbd.mjs +1 -1
- package/dist/client/components/ui/scroll-fade.mjs +4 -4
- package/dist/client/components/ui/sidebar.mjs +1 -1
- package/dist/client/components/ui/skeleton.mjs +1 -1
- package/dist/client/components/ui/table.mjs +1 -1
- package/dist/client/components/widgets/quick-actions-widget.mjs +6 -6
- package/dist/client/components/widgets/timeline-widget.mjs +3 -3
- package/dist/client/components/widgets/value-widget.mjs +1 -1
- package/dist/client/components/widgets/widget-skeletons.mjs +2 -2
- package/dist/client/hooks/typed-hooks.mjs +66 -21
- package/dist/client/hooks/use-collection.mjs +48 -7
- package/dist/client/i18n/date-locale.mjs +0 -14
- package/dist/client/preview/block-scope-context.d.mts +2 -2
- package/dist/client/preview/diff.mjs +4 -1
- package/dist/client/preview/patch.mjs +1 -1
- package/dist/client/preview/paths.mjs +85 -0
- package/dist/client/preview/preview-banner.d.mts +2 -2
- package/dist/client/preview/preview-field.d.mts +4 -4
- package/dist/client/runtime/translations-provider.mjs +1 -1
- package/dist/client/styles/base.css +51 -1
- package/dist/client/views/auth/accept-invite-form.d.mts +2 -2
- package/dist/client/views/auth/auth-layout.d.mts +3 -3
- package/dist/client/views/auth/login-form.d.mts +2 -2
- package/dist/client/views/auth/reset-password-form.d.mts +2 -2
- package/dist/client/views/collection/auto-form-fields.mjs +1 -1
- package/dist/client/views/collection/cells/primitive-cells.mjs +2 -2
- package/dist/client/views/collection/cells/upload-cells.mjs +2 -2
- package/dist/client/views/collection/form-view.mjs +45 -26
- package/dist/client/views/collection/table-view.mjs +33 -20
- package/dist/client/views/collection/view-skeletons.mjs +37 -38
- package/dist/client/views/common/global-search.mjs +3 -3
- package/dist/client/views/dashboard/widget-card.mjs +7 -7
- package/dist/client/views/layout/admin-router.mjs +84 -37
- package/dist/client/views/layout/admin-sidebar.mjs +22 -21
- package/dist/components/rich-text/rich-text-renderer.d.mts +2 -2
- package/dist/server/codegen/admin-client-template.mjs +48 -32
- package/dist/server/modules/admin/collections/account.d.mts +50 -50
- package/dist/server/modules/admin/collections/admin-locks.d.mts +54 -54
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +35 -35
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +47 -47
- package/dist/server/modules/admin/collections/apikey.d.mts +64 -64
- package/dist/server/modules/admin/collections/assets.d.mts +34 -34
- package/dist/server/modules/admin/collections/session.d.mts +38 -38
- package/dist/server/modules/admin/collections/user.d.mts +53 -53
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/locales.d.mts +2 -2
- package/dist/server/modules/admin/routes/preview.d.mts +11 -11
- package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
- package/dist/server/modules/admin/routes/setup.d.mts +7 -7
- package/dist/server/modules/admin/routes/translations.d.mts +4 -4
- package/dist/server/modules/admin/routes/widget-data.d.mts +5 -5
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +23 -23
- package/package.json +3 -3
|
@@ -110,10 +110,10 @@ function AssetPreview({ asset, pendingFile, onRemove, onEdit, loading = false, p
|
|
|
110
110
|
thumbnailUrl && !imageError ? /* @__PURE__ */ jsx("img", {
|
|
111
111
|
src: thumbnailUrl,
|
|
112
112
|
alt: asset.alt || filename,
|
|
113
|
-
className: "image-outline
|
|
113
|
+
className: "image-outline size-full object-cover",
|
|
114
114
|
onError: () => setImageError(true)
|
|
115
115
|
}) : /* @__PURE__ */ jsx("div", {
|
|
116
|
-
className: "flex
|
|
116
|
+
className: "flex size-full items-center justify-center",
|
|
117
117
|
children: /* @__PURE__ */ jsx(Icon, {
|
|
118
118
|
icon: fileIconName,
|
|
119
119
|
className: "text-muted-foreground size-8"
|
|
@@ -221,7 +221,7 @@ function AssetPreview({ asset, pendingFile, onRemove, onEdit, loading = false, p
|
|
|
221
221
|
children: thumbnailUrl && !imageError ? /* @__PURE__ */ jsx("img", {
|
|
222
222
|
src: thumbnailUrl,
|
|
223
223
|
alt: asset.alt || filename,
|
|
224
|
-
className: "image-outline
|
|
224
|
+
className: "image-outline size-full object-cover",
|
|
225
225
|
onError: () => setImageError(true)
|
|
226
226
|
}) : /* @__PURE__ */ jsx(Icon, {
|
|
227
227
|
icon: fileIconName,
|
|
@@ -325,10 +325,10 @@ function AssetPreview({ asset, pendingFile, onRemove, onEdit, loading = false, p
|
|
|
325
325
|
thumbnailUrl && !imageError ? /* @__PURE__ */ jsx("img", {
|
|
326
326
|
src: thumbnailUrl,
|
|
327
327
|
alt: asset.alt || filename,
|
|
328
|
-
className: "image-outline
|
|
328
|
+
className: "image-outline size-full object-contain",
|
|
329
329
|
onError: () => setImageError(true)
|
|
330
330
|
}) : /* @__PURE__ */ jsxs("div", {
|
|
331
|
-
className: "flex
|
|
331
|
+
className: "flex size-full flex-col items-center justify-center gap-2",
|
|
332
332
|
children: [/* @__PURE__ */ jsx(Icon, {
|
|
333
333
|
icon: fileIconName,
|
|
334
334
|
className: "text-muted-foreground size-12"
|
|
@@ -189,7 +189,7 @@ function Dropzone({ onDrop, accept, maxSize, multiple = false, disabled = false,
|
|
|
189
189
|
onDragLeave: handleDragLeave,
|
|
190
190
|
onDragOver: handleDragOver,
|
|
191
191
|
onDrop: handleDrop,
|
|
192
|
-
className: cn("qa-dropzone control-surface relative flex cursor-pointer
|
|
192
|
+
className: cn("qa-dropzone control-surface hover:bg-muted/40 relative flex cursor-pointer rounded-lg border transition-colors", isCompact ? "min-h-16 flex-row items-center justify-start gap-3 border border-dashed p-3 text-left" : "min-h-[120px] flex-col items-center justify-center gap-2 border-2 p-6 text-center", isDragging && "border-border-strong bg-surface-high", error && "border-destructive/50 bg-destructive/5", (disabled || loading) && "pointer-events-none opacity-60", className),
|
|
193
193
|
"aria-disabled": disabled || loading,
|
|
194
194
|
"data-dragging": isDragging || void 0,
|
|
195
195
|
children: [
|
|
@@ -13,7 +13,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
13
13
|
*/
|
|
14
14
|
function Kbd({ className, children, ...props }) {
|
|
15
15
|
return /* @__PURE__ */ jsx("kbd", {
|
|
16
|
-
className: cn("qa-kbd
|
|
16
|
+
className: cn("qa-kbd bg-muted text-muted-foreground pointer-events-none inline-flex h-5 items-center gap-1 rounded-xs border px-1.5 font-mono text-[10px] font-medium select-none", className),
|
|
17
17
|
...props,
|
|
18
18
|
children
|
|
19
19
|
});
|
|
@@ -45,7 +45,7 @@ function ScrollFade({ orientation = "horizontal", fadeSize = 20, leftInset = 0,
|
|
|
45
45
|
children: [
|
|
46
46
|
children,
|
|
47
47
|
h && /* @__PURE__ */ jsx("div", {
|
|
48
|
-
className: cn(fade, "inset-y-0 bg-gradient-to-r
|
|
48
|
+
className: cn(fade, "from-background inset-y-0 bg-gradient-to-r to-transparent", overflow.left ? "opacity-100" : "opacity-0"),
|
|
49
49
|
style: {
|
|
50
50
|
left: leftInset,
|
|
51
51
|
width: fadeSize
|
|
@@ -53,17 +53,17 @@ function ScrollFade({ orientation = "horizontal", fadeSize = 20, leftInset = 0,
|
|
|
53
53
|
"aria-hidden": true
|
|
54
54
|
}),
|
|
55
55
|
h && /* @__PURE__ */ jsx("div", {
|
|
56
|
-
className: cn(fade, "inset-y-0 right-0 bg-gradient-to-l
|
|
56
|
+
className: cn(fade, "from-background inset-y-0 right-0 bg-gradient-to-l to-transparent", overflow.right ? "opacity-100" : "opacity-0"),
|
|
57
57
|
style: { width: fadeSize },
|
|
58
58
|
"aria-hidden": true
|
|
59
59
|
}),
|
|
60
60
|
v && /* @__PURE__ */ jsx("div", {
|
|
61
|
-
className: cn(fade, "inset-x-0 top-0 bg-gradient-to-b
|
|
61
|
+
className: cn(fade, "from-background inset-x-0 top-0 bg-gradient-to-b to-transparent", overflow.top ? "opacity-100" : "opacity-0"),
|
|
62
62
|
style: { height: fadeSize },
|
|
63
63
|
"aria-hidden": true
|
|
64
64
|
}),
|
|
65
65
|
v && /* @__PURE__ */ jsx("div", {
|
|
66
|
-
className: cn(fade, "inset-x-0 bottom-0 bg-gradient-to-t
|
|
66
|
+
className: cn(fade, "from-background inset-x-0 bottom-0 bg-gradient-to-t to-transparent", overflow.bottom ? "opacity-100" : "opacity-0"),
|
|
67
67
|
style: { height: fadeSize },
|
|
68
68
|
"aria-hidden": true
|
|
69
69
|
})
|
|
@@ -105,7 +105,7 @@ function Sidebar({ side = "left", variant = "sidebar", collapsible = "offExample
|
|
|
105
105
|
className: "sr-only",
|
|
106
106
|
children: [/* @__PURE__ */ jsx(SheetTitle, { children: "Sidebar" }), /* @__PURE__ */ jsx(SheetDescription, { children: "Displays the mobile sidebar." })]
|
|
107
107
|
}), /* @__PURE__ */ jsx("div", {
|
|
108
|
-
className: "bg-sidebar border-sidebar-border flex
|
|
108
|
+
className: "bg-sidebar border-sidebar-border flex size-full flex-col overflow-hidden rounded-xl border shadow-lg",
|
|
109
109
|
children
|
|
110
110
|
})]
|
|
111
111
|
})
|
|
@@ -3,7 +3,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
|
|
5
5
|
//#region src/client/components/ui/skeleton.tsx
|
|
6
|
-
const skeletonVariants = cva("qa-skeleton bg-muted
|
|
6
|
+
const skeletonVariants = cva("qa-skeleton bg-muted", {
|
|
7
7
|
variants: { variant: {
|
|
8
8
|
default: "rounded-sm",
|
|
9
9
|
text: "rounded-xs",
|
|
@@ -6,7 +6,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
6
6
|
function Table({ className, ...props }) {
|
|
7
7
|
return /* @__PURE__ */ jsx("div", {
|
|
8
8
|
"data-slot": "table-container",
|
|
9
|
-
className: "qa-table-container
|
|
9
|
+
className: "qa-table-container relative w-full min-w-0 scrollbar-thin overflow-x-auto",
|
|
10
10
|
children: /* @__PURE__ */ jsx("table", {
|
|
11
11
|
"data-slot": "table",
|
|
12
12
|
className: cn("qa-table w-full caption-bottom border-separate border-spacing-0 text-sm", className),
|
|
@@ -89,13 +89,13 @@ function QuickActionsWidget({ config, basePath = "/admin", navigate }) {
|
|
|
89
89
|
children: /* @__PURE__ */ jsx("div", {
|
|
90
90
|
className: "grid h-full grid-cols-2 gap-3",
|
|
91
91
|
children: parsedActions.map((action) => {
|
|
92
|
-
const iconElement = resolveIconElement(action.icon, { className: "
|
|
92
|
+
const iconElement = resolveIconElement(action.icon, { className: "size-4" });
|
|
93
93
|
return /* @__PURE__ */ jsxs("button", {
|
|
94
94
|
type: "button",
|
|
95
95
|
onClick: () => handleClick(action),
|
|
96
96
|
className: cn("flex min-h-24 flex-col items-center justify-center gap-2 rounded-md border p-3 text-center", "transition-[background-color,border-color,transform] active:scale-[0.96]", variantStyles[action.variant]),
|
|
97
97
|
children: [iconElement && /* @__PURE__ */ jsx("div", {
|
|
98
|
-
className: cn("flex
|
|
98
|
+
className: cn("flex size-9 items-center justify-center rounded-md", iconVariantStyles[action.variant]),
|
|
99
99
|
children: iconElement
|
|
100
100
|
}), /* @__PURE__ */ jsx("span", {
|
|
101
101
|
className: "text-xs leading-tight font-medium text-balance",
|
|
@@ -113,14 +113,14 @@ function QuickActionsWidget({ config, basePath = "/admin", navigate }) {
|
|
|
113
113
|
children: /* @__PURE__ */ jsx("div", {
|
|
114
114
|
className: "-mx-1 space-y-1",
|
|
115
115
|
children: parsedActions.map((action) => {
|
|
116
|
-
const iconElement = resolveIconElement(action.icon, { className: "
|
|
116
|
+
const iconElement = resolveIconElement(action.icon, { className: "size-4" });
|
|
117
117
|
return /* @__PURE__ */ jsxs("button", {
|
|
118
118
|
type: "button",
|
|
119
119
|
onClick: () => handleClick(action),
|
|
120
|
-
className: cn("group flex min-h-10 w-full items-center gap-3 rounded-md
|
|
120
|
+
className: cn("group flex min-h-10 w-full items-center gap-3 rounded-md p-2 text-left transition-[background-color,transform] active:scale-[0.96]", variantStyles[action.variant]),
|
|
121
121
|
children: [
|
|
122
122
|
iconElement && /* @__PURE__ */ jsx("div", {
|
|
123
|
-
className: cn("flex
|
|
123
|
+
className: cn("flex size-8 shrink-0 items-center justify-center rounded-md", iconVariantStyles[action.variant]),
|
|
124
124
|
children: iconElement
|
|
125
125
|
}),
|
|
126
126
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -129,7 +129,7 @@ function QuickActionsWidget({ config, basePath = "/admin", navigate }) {
|
|
|
129
129
|
}),
|
|
130
130
|
/* @__PURE__ */ jsx(Icon, {
|
|
131
131
|
icon: "ph:arrow-right",
|
|
132
|
-
className: "text-muted-foreground
|
|
132
|
+
className: "text-muted-foreground size-4 opacity-0 transition-opacity group-hover:opacity-100"
|
|
133
133
|
})
|
|
134
134
|
]
|
|
135
135
|
}, action.id);
|
|
@@ -114,17 +114,17 @@ function TimelineWidget({ config, navigate }) {
|
|
|
114
114
|
const timelineContent = items.length === 0 ? emptyContent : /* @__PURE__ */ jsx("div", {
|
|
115
115
|
className: "space-y-0",
|
|
116
116
|
children: items.map((item, index) => {
|
|
117
|
-
const iconElement = resolveIconElement(item.icon, { className: "
|
|
117
|
+
const iconElement = resolveIconElement(item.icon, { className: "size-3 text-white" });
|
|
118
118
|
const variant = item.variant || "default";
|
|
119
119
|
const isLast = index === items.length - 1;
|
|
120
120
|
const isClickable = !!(item.href && navigate);
|
|
121
121
|
const itemContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
122
122
|
!isLast && /* @__PURE__ */ jsx("div", { className: "bg-border absolute top-6 bottom-0 left-[11px] w-px" }),
|
|
123
123
|
/* @__PURE__ */ jsx("div", {
|
|
124
|
-
className: cn("relative z-10 flex
|
|
124
|
+
className: cn("relative z-10 flex size-6 shrink-0 items-center justify-center rounded-full", variantStyles[variant]),
|
|
125
125
|
children: iconElement ?? /* @__PURE__ */ jsx(Icon, {
|
|
126
126
|
icon: "ph:circle-bold",
|
|
127
|
-
className: "
|
|
127
|
+
className: "size-3 text-white"
|
|
128
128
|
})
|
|
129
129
|
}),
|
|
130
130
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -115,7 +115,7 @@ function ValueWidget({ config }) {
|
|
|
115
115
|
}),
|
|
116
116
|
data.trend && /* @__PURE__ */ jsxs("div", {
|
|
117
117
|
className: cn("flex items-center gap-1 text-sm", cls.trend),
|
|
118
|
-
children: [resolveIconElement(TrendIcon, { className: cn("
|
|
118
|
+
children: [resolveIconElement(TrendIcon, { className: cn("size-3", cls.trendIcon) }), /* @__PURE__ */ jsx("span", { children: data.trend.value })]
|
|
119
119
|
}),
|
|
120
120
|
subtitle && /* @__PURE__ */ jsx("p", {
|
|
121
121
|
className: cn("text-muted-foreground text-xs", cls.subtitle),
|
|
@@ -123,7 +123,7 @@ function TimelineSkeletonItem({ last = false }) {
|
|
|
123
123
|
className: "flex flex-col items-center",
|
|
124
124
|
children: [/* @__PURE__ */ jsx(Skeleton, {
|
|
125
125
|
variant: "avatar",
|
|
126
|
-
className: "
|
|
126
|
+
className: "size-3"
|
|
127
127
|
}), !last && /* @__PURE__ */ jsx(Skeleton, { className: "mt-1 w-0.5 flex-1" })]
|
|
128
128
|
}), /* @__PURE__ */ jsxs("div", {
|
|
129
129
|
className: "flex-1 space-y-1 pb-4",
|
|
@@ -165,7 +165,7 @@ function ValueWidgetSkeleton({ featured = false }) {
|
|
|
165
165
|
className: "space-y-3",
|
|
166
166
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
167
167
|
className: "flex items-start gap-3",
|
|
168
|
-
children: [/* @__PURE__ */ jsx(Skeleton, { className: "
|
|
168
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "size-10 shrink-0" }), /* @__PURE__ */ jsxs("div", {
|
|
169
169
|
className: "flex-1 space-y-2",
|
|
170
170
|
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }), /* @__PURE__ */ jsx(Skeleton, { className: cn("h-8", featured ? "w-40" : "w-24") })]
|
|
171
171
|
})]
|
|
@@ -59,43 +59,76 @@ function createTypedHooks() {
|
|
|
59
59
|
function useCollectionList(collection, options, queryOptions) {
|
|
60
60
|
const client = useAdminStore(selectClient);
|
|
61
61
|
const { locale: contentLocale } = useScopedLocale();
|
|
62
|
+
const queryOpts = createQuestpieQueryOptions(client, {
|
|
63
|
+
keyPrefix: ["questpie", "collections"],
|
|
64
|
+
locale: contentLocale
|
|
65
|
+
});
|
|
62
66
|
return useQuery({
|
|
63
|
-
...
|
|
64
|
-
keyPrefix: ["questpie", "collections"],
|
|
65
|
-
locale: contentLocale
|
|
66
|
-
}).collections[collection].find({
|
|
67
|
+
...collection ? queryOpts.collections[collection].find({
|
|
67
68
|
...options,
|
|
68
69
|
locale: contentLocale
|
|
69
|
-
})
|
|
70
|
+
}) : {
|
|
71
|
+
queryKey: [
|
|
72
|
+
"questpie",
|
|
73
|
+
"collections",
|
|
74
|
+
"__none__",
|
|
75
|
+
"find"
|
|
76
|
+
],
|
|
77
|
+
queryFn: () => ({
|
|
78
|
+
docs: [],
|
|
79
|
+
totalDocs: 0
|
|
80
|
+
})
|
|
81
|
+
},
|
|
82
|
+
enabled: !!collection && (queryOptions?.enabled ?? true),
|
|
70
83
|
...queryOptions
|
|
71
84
|
});
|
|
72
85
|
}
|
|
73
86
|
function useCollectionCount(collection, options, queryOptions) {
|
|
74
87
|
const client = useAdminStore(selectClient);
|
|
75
88
|
const { locale: contentLocale } = useScopedLocale();
|
|
89
|
+
const queryOpts = createQuestpieQueryOptions(client, {
|
|
90
|
+
keyPrefix: ["questpie", "collections"],
|
|
91
|
+
locale: contentLocale
|
|
92
|
+
});
|
|
76
93
|
return useQuery({
|
|
77
|
-
...
|
|
78
|
-
keyPrefix: ["questpie", "collections"],
|
|
79
|
-
locale: contentLocale
|
|
80
|
-
}).collections[collection].count({
|
|
94
|
+
...collection ? queryOpts.collections[collection].count({
|
|
81
95
|
...options,
|
|
82
96
|
locale: contentLocale
|
|
83
|
-
})
|
|
97
|
+
}) : {
|
|
98
|
+
queryKey: [
|
|
99
|
+
"questpie",
|
|
100
|
+
"collections",
|
|
101
|
+
"__none__",
|
|
102
|
+
"count"
|
|
103
|
+
],
|
|
104
|
+
queryFn: () => 0
|
|
105
|
+
},
|
|
106
|
+
enabled: !!collection && (queryOptions?.enabled ?? true),
|
|
84
107
|
...queryOptions
|
|
85
108
|
});
|
|
86
109
|
}
|
|
87
110
|
function useCollectionItem(collection, id, options, queryOptions) {
|
|
88
111
|
const client = useAdminStore(selectClient);
|
|
89
112
|
const { locale: contentLocale } = useScopedLocale();
|
|
113
|
+
const queryOpts = createQuestpieQueryOptions(client, {
|
|
114
|
+
keyPrefix: ["questpie", "collections"],
|
|
115
|
+
locale: contentLocale
|
|
116
|
+
});
|
|
90
117
|
return useQuery({
|
|
91
|
-
...
|
|
92
|
-
keyPrefix: ["questpie", "collections"],
|
|
93
|
-
locale: contentLocale
|
|
94
|
-
}).collections[collection].findOne({
|
|
118
|
+
...collection ? queryOpts.collections[collection].findOne({
|
|
95
119
|
where: { id },
|
|
96
120
|
locale: contentLocale,
|
|
97
121
|
...options
|
|
98
|
-
})
|
|
122
|
+
}) : {
|
|
123
|
+
queryKey: [
|
|
124
|
+
"questpie",
|
|
125
|
+
"collections",
|
|
126
|
+
"__none__",
|
|
127
|
+
"findOne"
|
|
128
|
+
],
|
|
129
|
+
queryFn: () => null
|
|
130
|
+
},
|
|
131
|
+
enabled: !!collection && (queryOptions?.enabled ?? true),
|
|
99
132
|
...queryOptions
|
|
100
133
|
});
|
|
101
134
|
}
|
|
@@ -259,16 +292,28 @@ function createTypedHooks() {
|
|
|
259
292
|
function useCollectionVersions(collection, id, options, queryOptions) {
|
|
260
293
|
const client = useAdminStore(selectClient);
|
|
261
294
|
const { locale: contentLocale } = useScopedLocale();
|
|
295
|
+
const queryOpts = createQuestpieQueryOptions(client, {
|
|
296
|
+
keyPrefix: ["questpie", "collections"],
|
|
297
|
+
locale: contentLocale
|
|
298
|
+
});
|
|
262
299
|
return useQuery({
|
|
263
|
-
...
|
|
264
|
-
keyPrefix: ["questpie", "collections"],
|
|
265
|
-
locale: contentLocale
|
|
266
|
-
}).collections[collection].findVersions({
|
|
300
|
+
...collection ? queryOpts.collections[collection].findVersions({
|
|
267
301
|
id,
|
|
268
302
|
...options?.limit !== void 0 ? { limit: options.limit } : {},
|
|
269
303
|
...options?.offset !== void 0 ? { offset: options.offset } : {}
|
|
270
|
-
})
|
|
271
|
-
|
|
304
|
+
}) : {
|
|
305
|
+
queryKey: [
|
|
306
|
+
"questpie",
|
|
307
|
+
"collections",
|
|
308
|
+
"__none__",
|
|
309
|
+
"findVersions"
|
|
310
|
+
],
|
|
311
|
+
queryFn: () => ({
|
|
312
|
+
docs: [],
|
|
313
|
+
totalDocs: 0
|
|
314
|
+
})
|
|
315
|
+
},
|
|
316
|
+
enabled: !!collection && !!id && (queryOptions?.enabled ?? true),
|
|
272
317
|
...queryOptions
|
|
273
318
|
});
|
|
274
319
|
}
|
|
@@ -20,7 +20,19 @@ function useCollectionList(collection, options, queryOptions, realtimeOptions) {
|
|
|
20
20
|
locale
|
|
21
21
|
};
|
|
22
22
|
return useQuery({
|
|
23
|
-
...queryOpts.collections[collection].find(findOptions, { realtime: realtimeOptions?.realtime })
|
|
23
|
+
...collection ? queryOpts.collections[collection].find(findOptions, { realtime: realtimeOptions?.realtime }) : {
|
|
24
|
+
queryKey: [
|
|
25
|
+
"questpie",
|
|
26
|
+
"collections",
|
|
27
|
+
"__none__",
|
|
28
|
+
"find"
|
|
29
|
+
],
|
|
30
|
+
queryFn: () => ({
|
|
31
|
+
docs: [],
|
|
32
|
+
totalDocs: 0
|
|
33
|
+
})
|
|
34
|
+
},
|
|
35
|
+
enabled: !!collection && (queryOptions?.enabled ?? true),
|
|
24
36
|
...queryOptions
|
|
25
37
|
});
|
|
26
38
|
}
|
|
@@ -48,7 +60,16 @@ function useCollectionCount(collection, options, queryOptions, realtimeOptions)
|
|
|
48
60
|
locale
|
|
49
61
|
};
|
|
50
62
|
return useQuery({
|
|
51
|
-
...queryOpts.collections[collection].count(countOptions, { realtime: realtimeOptions?.realtime })
|
|
63
|
+
...collection ? queryOpts.collections[collection].count(countOptions, { realtime: realtimeOptions?.realtime }) : {
|
|
64
|
+
queryKey: [
|
|
65
|
+
"questpie",
|
|
66
|
+
"collections",
|
|
67
|
+
"__none__",
|
|
68
|
+
"count"
|
|
69
|
+
],
|
|
70
|
+
queryFn: () => 0
|
|
71
|
+
},
|
|
72
|
+
enabled: !!collection && (queryOptions?.enabled ?? true),
|
|
52
73
|
...queryOptions
|
|
53
74
|
});
|
|
54
75
|
}
|
|
@@ -66,11 +87,20 @@ function useCollectionCount(collection, options, queryOptions, realtimeOptions)
|
|
|
66
87
|
function useCollectionItem(collection, id, options, queryOptions) {
|
|
67
88
|
const { queryOpts, locale } = useQuestpieQueryOptions();
|
|
68
89
|
return useQuery({
|
|
69
|
-
...queryOpts.collections[collection].findOne({
|
|
90
|
+
...collection ? queryOpts.collections[collection].findOne({
|
|
70
91
|
where: { id },
|
|
71
92
|
locale,
|
|
72
93
|
...options
|
|
73
|
-
})
|
|
94
|
+
}) : {
|
|
95
|
+
queryKey: [
|
|
96
|
+
"questpie",
|
|
97
|
+
"collections",
|
|
98
|
+
"__none__",
|
|
99
|
+
"findOne"
|
|
100
|
+
],
|
|
101
|
+
queryFn: () => null
|
|
102
|
+
},
|
|
103
|
+
enabled: !!collection && (queryOptions?.enabled ?? true),
|
|
74
104
|
...queryOptions
|
|
75
105
|
});
|
|
76
106
|
}
|
|
@@ -289,12 +319,23 @@ function useCollectionRestore(collection, mutationOptions) {
|
|
|
289
319
|
function useCollectionVersions(collection, id, options, queryOptions) {
|
|
290
320
|
const { queryOpts } = useQuestpieQueryOptions();
|
|
291
321
|
return useQuery({
|
|
292
|
-
...queryOpts.collections[collection].findVersions({
|
|
322
|
+
...collection ? queryOpts.collections[collection].findVersions({
|
|
293
323
|
id,
|
|
294
324
|
...options?.limit !== void 0 ? { limit: options.limit } : {},
|
|
295
325
|
...options?.offset !== void 0 ? { offset: options.offset } : {}
|
|
296
|
-
})
|
|
297
|
-
|
|
326
|
+
}) : {
|
|
327
|
+
queryKey: [
|
|
328
|
+
"questpie",
|
|
329
|
+
"collections",
|
|
330
|
+
"__none__",
|
|
331
|
+
"findVersions"
|
|
332
|
+
],
|
|
333
|
+
queryFn: () => ({
|
|
334
|
+
docs: [],
|
|
335
|
+
totalDocs: 0
|
|
336
|
+
})
|
|
337
|
+
},
|
|
338
|
+
enabled: !!collection && !!id && (queryOptions?.enabled ?? true),
|
|
298
339
|
...queryOptions
|
|
299
340
|
});
|
|
300
341
|
}
|
|
@@ -1,20 +1,6 @@
|
|
|
1
1
|
import { enUS } from "date-fns/locale/en-US";
|
|
2
2
|
|
|
3
3
|
//#region src/client/i18n/date-locale.ts
|
|
4
|
-
/**
|
|
5
|
-
* date-fns locale resolver for DayPicker and date formatting.
|
|
6
|
-
*
|
|
7
|
-
* Only `enUS` is included by default to keep bundle size small.
|
|
8
|
-
* Register additional locales at admin setup time:
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* import { sk } from "date-fns/locale/sk";
|
|
13
|
-
* import { registerDateFnsLocale } from "@questpie/admin/client-module";
|
|
14
|
-
*
|
|
15
|
-
* registerDateFnsLocale("sk", sk);
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
4
|
const localeRegistry = new Map([["en", enUS], ["en-US", enUS]]);
|
|
19
5
|
/**
|
|
20
6
|
* Resolve a date-fns Locale from a BCP-47 locale code (e.g. "sk", "en-US").
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime20 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/client/preview/block-scope-context.d.ts
|
|
5
5
|
|
|
@@ -35,7 +35,7 @@ declare function BlockScopeProvider({
|
|
|
35
35
|
blockId,
|
|
36
36
|
basePath,
|
|
37
37
|
children
|
|
38
|
-
}: BlockScopeProviderProps):
|
|
38
|
+
}: BlockScopeProviderProps): react_jsx_runtime20.JSX.Element;
|
|
39
39
|
/**
|
|
40
40
|
* Get current block scope context.
|
|
41
41
|
*
|
|
@@ -44,7 +44,7 @@ function diffSnapshotAtPath(previous, next, path) {
|
|
|
44
44
|
op: "remove",
|
|
45
45
|
path
|
|
46
46
|
}] : [];
|
|
47
|
-
if (previousValue.exists &&
|
|
47
|
+
if (previousValue.exists && isPatchValueEqual(previousValue.value, nextValue.value)) return [];
|
|
48
48
|
return [{
|
|
49
49
|
op: "set",
|
|
50
50
|
path,
|
|
@@ -75,6 +75,9 @@ function isDeepEqual(left, right) {
|
|
|
75
75
|
}
|
|
76
76
|
return false;
|
|
77
77
|
}
|
|
78
|
+
function isPatchValueEqual(left, right) {
|
|
79
|
+
return Object.is(left, right);
|
|
80
|
+
}
|
|
78
81
|
function isArrayIndex(segment) {
|
|
79
82
|
return /^(0|[1-9]\d*)$/.test(segment);
|
|
80
83
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/client/preview/patch.ts
|
|
2
2
|
function cloneSnapshot(value) {
|
|
3
|
+
if (value === null || typeof value !== "object") return value;
|
|
3
4
|
if (typeof globalThis.structuredClone === "function") return globalThis.structuredClone(value);
|
|
4
|
-
if (value === void 0) return value;
|
|
5
5
|
return JSON.parse(JSON.stringify(value));
|
|
6
6
|
}
|
|
7
7
|
function shouldApplyPatchBatch(lastAppliedSeq, nextSeq) {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//#region src/client/preview/paths.ts
|
|
2
|
+
function resolveKnownPreviewPath(path, { schema, blocks, values, previousValues }) {
|
|
3
|
+
if (!schema?.fields || !isSafePreviewPath(path)) return;
|
|
4
|
+
const [fieldName, ...rest] = path.split(".");
|
|
5
|
+
if (!fieldName) return void 0;
|
|
6
|
+
const field = schema.fields[fieldName];
|
|
7
|
+
if (!field) return void 0;
|
|
8
|
+
if (rest.length === 0) return fieldName;
|
|
9
|
+
if (resolveFieldPath({
|
|
10
|
+
field,
|
|
11
|
+
fieldName,
|
|
12
|
+
segments: rest,
|
|
13
|
+
blocks,
|
|
14
|
+
values,
|
|
15
|
+
previousValues
|
|
16
|
+
})) return path;
|
|
17
|
+
}
|
|
18
|
+
function isSafePreviewPath(path) {
|
|
19
|
+
if (!path || path.length > 512) return false;
|
|
20
|
+
return path.split(".").every((segment) => segment.length > 0 && segment !== "__proto__" && segment !== "prototype" && segment !== "constructor");
|
|
21
|
+
}
|
|
22
|
+
function resolveFieldPath({ field, fieldName, segments, blocks, values, previousValues }) {
|
|
23
|
+
const metadata = field.metadata;
|
|
24
|
+
if (!metadata) return false;
|
|
25
|
+
if (metadata.type === "blocks") return resolveBlocksPath({
|
|
26
|
+
fieldName,
|
|
27
|
+
segments,
|
|
28
|
+
blocks,
|
|
29
|
+
values,
|
|
30
|
+
previousValues
|
|
31
|
+
});
|
|
32
|
+
return resolveMetadataPath(metadata, segments);
|
|
33
|
+
}
|
|
34
|
+
function resolveMetadataPath(metadata, segments) {
|
|
35
|
+
if (segments.length === 0) return true;
|
|
36
|
+
if (metadata.type === "richText" || metadata.type === "json") return true;
|
|
37
|
+
if (metadata.type === "object") {
|
|
38
|
+
const [fieldName, ...rest] = segments;
|
|
39
|
+
const nested = fieldName ? metadata.nestedFields?.[fieldName] : void 0;
|
|
40
|
+
return nested ? resolveMetadataPath(nested, rest) : false;
|
|
41
|
+
}
|
|
42
|
+
if (metadata.type === "array") {
|
|
43
|
+
const [first, ...rest] = segments;
|
|
44
|
+
const itemSegments = first && isArrayIndex(first) ? rest : segments;
|
|
45
|
+
if (itemSegments.length === 0) return true;
|
|
46
|
+
const [fieldName, ...fieldRest] = itemSegments;
|
|
47
|
+
const nested = fieldName ? metadata.nestedFields?.[fieldName] : void 0;
|
|
48
|
+
return nested ? resolveMetadataPath(nested, fieldRest) : false;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
function resolveBlocksPath({ fieldName, segments, blocks, values, previousValues }) {
|
|
53
|
+
const [section, blockId, blockFieldName, ...rest] = segments;
|
|
54
|
+
if (section === "_tree") return true;
|
|
55
|
+
if (section !== "_values" || !blockId || !blockFieldName) return false;
|
|
56
|
+
const blockType = findBlockTypeById(readPath(values, `${fieldName}._tree`), blockId) ?? findBlockTypeById(readPath(previousValues, `${fieldName}._tree`), blockId);
|
|
57
|
+
if (!blockType) return false;
|
|
58
|
+
const blockField = blocks?.[blockType]?.fields?.[blockFieldName];
|
|
59
|
+
if (!blockField) return false;
|
|
60
|
+
return resolveMetadataPath(blockField.metadata, rest);
|
|
61
|
+
}
|
|
62
|
+
function findBlockTypeById(tree, blockId) {
|
|
63
|
+
if (!Array.isArray(tree)) return;
|
|
64
|
+
for (const node of tree) {
|
|
65
|
+
if (!node || typeof node !== "object") continue;
|
|
66
|
+
const record = node;
|
|
67
|
+
if (record.id === blockId && typeof record.type === "string") return record.type;
|
|
68
|
+
const childType = findBlockTypeById(record.children, blockId);
|
|
69
|
+
if (childType) return childType;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function readPath(value, path) {
|
|
73
|
+
let current = value;
|
|
74
|
+
for (const segment of path.split(".")) {
|
|
75
|
+
if (!current || typeof current !== "object") return;
|
|
76
|
+
current = current[segment];
|
|
77
|
+
}
|
|
78
|
+
return current;
|
|
79
|
+
}
|
|
80
|
+
function isArrayIndex(segment) {
|
|
81
|
+
return /^(0|[1-9]\d*)$/.test(segment);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
export { resolveKnownPreviewPath };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime21 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/client/preview/preview-banner.d.ts
|
|
4
4
|
|
|
@@ -40,6 +40,6 @@ declare function PreviewBanner({
|
|
|
40
40
|
isPreviewMode,
|
|
41
41
|
className,
|
|
42
42
|
exitPreviewUrl
|
|
43
|
-
}: PreviewBannerProps):
|
|
43
|
+
}: PreviewBannerProps): react_jsx_runtime21.JSX.Element | null;
|
|
44
44
|
//#endregion
|
|
45
45
|
export { PreviewBanner, PreviewBannerProps };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime22 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/client/preview/preview-field.d.ts
|
|
5
5
|
|
|
@@ -68,7 +68,7 @@ declare function PreviewProvider({
|
|
|
68
68
|
}) => void;
|
|
69
69
|
onFieldValueEdited?: (payload: PreviewFieldValueEditedPayload) => void;
|
|
70
70
|
children: React.ReactNode;
|
|
71
|
-
}):
|
|
71
|
+
}): react_jsx_runtime22.JSX.Element;
|
|
72
72
|
/**
|
|
73
73
|
* Hook to access preview context.
|
|
74
74
|
*/
|
|
@@ -107,7 +107,7 @@ declare function PreviewField({
|
|
|
107
107
|
style,
|
|
108
108
|
onClick,
|
|
109
109
|
onValueCommit
|
|
110
|
-
}: PreviewFieldProps):
|
|
110
|
+
}: PreviewFieldProps): react_jsx_runtime22.JSX.Element;
|
|
111
111
|
/**
|
|
112
112
|
* Standalone PreviewField that works without context.
|
|
113
113
|
* Useful when you can't use PreviewProvider.
|
|
@@ -131,6 +131,6 @@ declare function StandalonePreviewField({
|
|
|
131
131
|
blockId?: string;
|
|
132
132
|
fieldType?: "regular" | "block" | "relation";
|
|
133
133
|
}) => void;
|
|
134
|
-
}):
|
|
134
|
+
}): react_jsx_runtime22.JSX.Element;
|
|
135
135
|
//#endregion
|
|
136
136
|
export { PreviewField, PreviewFieldProps, PreviewProvider, StandalonePreviewField, usePreviewContext };
|
|
@@ -139,7 +139,7 @@ function LoadingFallback() {
|
|
|
139
139
|
className: "qp-flex qp-flex-col qp-items-center qp-gap-4",
|
|
140
140
|
children: [/* @__PURE__ */ jsx("div", { className: "qp-h-8 qp-w-8 qp-animate-spin qp-rounded-full qp-border-4 qp-border-foreground qp-border-t-transparent" }), /* @__PURE__ */ jsx("span", {
|
|
141
141
|
className: "qp-text-sm qp-text-muted-foreground",
|
|
142
|
-
children: "Loading
|
|
142
|
+
children: "Loading…"
|
|
143
143
|
})]
|
|
144
144
|
})
|
|
145
145
|
});
|