@questpie/admin 3.5.2 → 3.5.4
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/README.md +8 -0
- package/dist/client/blocks/block-renderer.d.mts +2 -2
- package/dist/client/builder/index.d.mts +1 -1
- package/dist/client/builder/types/collection-types.d.mts +89 -5
- package/dist/client/builder/types/common.d.mts +5 -0
- package/dist/client/builder/types/field-types.d.mts +41 -1
- package/dist/client/builder/view/view.d.mts +3 -2
- package/dist/client/components/actions/action-dialog.mjs +5 -0
- package/dist/client/components/admin-link.d.mts +2 -2
- package/dist/client/components/fields/boolean-field.mjs +2 -1
- package/dist/client/components/fields/date-field.mjs +2 -1
- package/dist/client/components/fields/datetime-field.mjs +2 -1
- package/dist/client/components/fields/email-field.mjs +2 -1
- package/dist/client/components/fields/field-utils.d.mts +11 -0
- package/dist/client/components/fields/field-utils.mjs +3 -1
- package/dist/client/components/fields/field-wrapper.mjs +3 -3
- package/dist/client/components/fields/number-field.mjs +2 -1
- package/dist/client/components/fields/object-field.mjs +2 -1
- package/dist/client/components/fields/relation/displays/types.mjs +3 -3
- package/dist/client/components/fields/rich-text-editor/bubble-menu.mjs +7 -0
- package/dist/client/components/fields/rich-text-editor/extensions.mjs +19 -2
- package/dist/client/components/fields/rich-text-editor/image-popover.mjs +6 -2
- package/dist/client/components/fields/rich-text-editor/image-upload.mjs +2 -1
- package/dist/client/components/fields/rich-text-editor/index.d.mts +5 -3
- package/dist/client/components/fields/rich-text-editor/index.mjs +38 -76
- package/dist/client/components/fields/rich-text-editor/slash-commands.mjs +30 -7
- package/dist/client/components/fields/rich-text-editor/toolbar.mjs +1 -312
- package/dist/client/components/fields/rich-text-editor/types.d.mts +4 -0
- package/dist/client/components/fields/rich-text-editor/types.mjs +1 -1
- package/dist/client/components/fields/rich-text-editor/utils.mjs +6 -12
- package/dist/client/components/fields/select-field.mjs +2 -1
- package/dist/client/components/fields/text-field.mjs +2 -1
- package/dist/client/components/fields/textarea-field.mjs +2 -1
- package/dist/client/components/fields/time-field.mjs +2 -1
- package/dist/client/components/filter-builder/filter-builder-sheet.mjs +75 -22
- package/dist/client/components/layout/field-layout-renderer.mjs +4 -4
- package/dist/client/components/media/media-grid.mjs +2 -1
- package/dist/client/components/primitives/asset-preview.mjs +4 -2
- package/dist/client/components/primitives/dropzone.d.mts +100 -0
- package/dist/client/components/primitives/field-select-control.mjs +2 -1
- package/dist/client/components/ui/button.d.mts +23 -0
- package/dist/client/components/ui/button.mjs +2 -2
- package/dist/client/components/ui/dropdown-menu.d.mts +49 -0
- package/dist/client/components/ui/dropdown-menu.mjs +7 -19
- package/dist/client/components/ui/popover.mjs +1 -1
- package/dist/client/components/ui/search-input.d.mts +56 -0
- package/dist/client/components/ui/select.mjs +2 -2
- package/dist/client/components/ui/sheet.d.mts +40 -0
- package/dist/client/components/ui/table.d.mts +49 -0
- package/dist/client/components/ui/table.mjs +15 -1
- package/dist/client/components/ui/tooltip.d.mts +21 -0
- package/dist/client/contexts/focus-context.d.mts +2 -2
- package/dist/client/hooks/query-access.d.mts +9 -0
- package/dist/client/hooks/query-access.mjs +20 -0
- package/dist/client/hooks/typed-hooks.d.mts +4 -2
- package/dist/client/hooks/typed-hooks.mjs +30 -29
- package/dist/client/hooks/use-admin-config.mjs +20 -1
- package/dist/client/hooks/use-autosave.mjs +91 -0
- package/dist/client/hooks/use-collection.mjs +65 -23
- package/dist/client/hooks/use-reactive-fields.d.mts +1 -0
- package/dist/client/hooks/use-reactive-fields.mjs +16 -1
- package/dist/client/hooks/use-server-actions.mjs +12 -1
- package/dist/client/hooks/use-upload.d.mts +40 -0
- package/dist/client/hooks/use-upload.mjs +4 -2
- package/dist/client/hooks/use-view-state.mjs +15 -7
- package/dist/client/i18n/hooks.d.mts +20 -0
- package/dist/client/lib/utils.d.mts +6 -0
- package/dist/client/lib/view-filter-utils.mjs +30 -0
- package/dist/client/preview/block-scope-context.d.mts +2 -2
- package/dist/client/preview/preview-banner.d.mts +2 -2
- package/dist/client/preview/preview-field.d.mts +4 -4
- package/dist/client/runtime/provider.mjs +22 -3
- package/dist/client/scope/picker.d.mts +2 -2
- package/dist/client/scope/provider.d.mts +2 -2
- package/dist/client/styles/base.css +75 -79
- package/dist/client/utils/asset-url.mjs +27 -0
- package/dist/client/utils/build-field-definitions-from-schema.mjs +1 -0
- 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/forgot-password-form.d.mts +2 -2
- 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/auth/setup-form.d.mts +2 -2
- package/dist/client/views/collection/auto-form-fields.mjs +7 -6
- package/dist/client/views/collection/cells/primitive-cells.mjs +9 -6
- package/dist/client/views/collection/cells/shared/asset-thumbnail.d.mts +7 -0
- package/dist/client/views/collection/cells/shared/asset-thumbnail.mjs +3 -2
- package/dist/client/views/collection/cells/shared/cell-helpers.mjs +3 -2
- package/dist/client/views/collection/cells/upload-cells.mjs +2 -1
- package/dist/client/views/collection/columns/build-columns.mjs +3 -1
- package/dist/client/views/collection/document-view.d.mts +30 -0
- package/dist/client/views/collection/document-view.mjs +377 -0
- package/dist/client/views/collection/field-context.mjs +3 -2
- package/dist/client/views/collection/field-renderer.mjs +13 -5
- package/dist/client/views/collection/form-view.mjs +221 -282
- package/dist/client/views/collection/list-view.mjs +592 -190
- package/dist/client/views/collection/outline.mjs +44 -19
- package/dist/client/views/collection/quick-filter-bar.mjs +45 -0
- package/dist/client/views/collection/table-view.mjs +61 -17
- package/dist/client/views/globals/global-form-view.mjs +12 -9
- package/dist/client/views/layout/admin-layout-provider.mjs +4 -3
- package/dist/client/views/layout/admin-layout.mjs +108 -21
- package/dist/client/views/layout/admin-router.mjs +19 -3
- package/dist/client/views/layout/admin-sidebar.mjs +70 -20
- package/dist/client/views/layout/admin-theme.mjs +5 -4
- package/dist/client/views/layout/admin-view-layout.d.mts +36 -0
- package/dist/client/views/pages/accept-invite-page.d.mts +2 -2
- package/dist/client/views/pages/dashboard-page.d.mts +2 -2
- package/dist/client/views/pages/forgot-password-page.d.mts +2 -2
- package/dist/client/views/pages/invite-page.d.mts +2 -2
- package/dist/client/views/pages/login-page.d.mts +2 -2
- package/dist/client/views/pages/reset-password-page.d.mts +2 -2
- package/dist/client/views/pages/setup-page.d.mts +2 -2
- package/dist/client.d.mts +17 -2
- package/dist/client.mjs +17 -2
- package/dist/components/rich-text/rich-text-renderer.d.mts +5 -5
- package/dist/components/rich-text/rich-text-renderer.mjs +5 -2
- package/dist/factories.d.mts +4 -2
- package/dist/factories.mjs +2 -2
- package/dist/index.d.mts +17 -3
- package/dist/index.mjs +17 -2
- package/dist/modules/admin.d.mts +1 -1
- package/dist/server/adapters/index.d.mts +2 -0
- package/dist/server/adapters/nextjs.d.mts +1 -0
- package/dist/server/augmentation/actions.d.mts +9 -3
- package/dist/server/augmentation/dashboard.d.mts +11 -11
- package/dist/server/augmentation/form-layout.d.mts +16 -6
- package/dist/server/augmentation/index.d.mts +7 -0
- package/dist/server/augmentation/sidebar.d.mts +8 -8
- package/dist/server/augmentation/views.d.mts +4 -1
- package/dist/server/auth-helpers.d.mts +1 -0
- package/dist/server/codegen/admin-client-template.mjs +7 -6
- package/dist/server/fields/blocks.mjs +4 -1
- package/dist/server/fields/index.d.mts +1 -1
- package/dist/server/fields/reactive-runtime.mjs +3 -0
- package/dist/server/fields/rich-text.d.mts +16 -17
- package/dist/server/fields/rich-text.mjs +18 -7
- package/dist/server/i18n/messages/cs.mjs +2 -0
- package/dist/server/i18n/messages/de.mjs +2 -0
- package/dist/server/i18n/messages/en.mjs +4 -0
- package/dist/server/i18n/messages/es.mjs +2 -0
- package/dist/server/i18n/messages/fr.mjs +2 -0
- package/dist/server/i18n/messages/pl.mjs +2 -0
- package/dist/server/i18n/messages/pt.mjs +2 -0
- package/dist/server/i18n/messages/sk.mjs +2 -0
- package/dist/server/modules/admin/.generated/module.d.mts +1 -1
- package/dist/server/modules/admin/auth-helpers.mjs +7 -1
- package/dist/server/modules/admin/block/block-builder.d.mts +0 -8
- package/dist/server/modules/admin/block/introspection.d.mts +2 -2
- package/dist/server/modules/admin/block/introspection.mjs +28 -4
- package/dist/server/modules/admin/block/prefetch.d.mts +11 -0
- package/dist/server/modules/admin/block/prefetch.mjs +108 -27
- package/dist/server/modules/admin/client/.generated/module.d.mts +68 -67
- package/dist/server/modules/admin/client/.generated/module.mjs +2 -0
- package/dist/server/modules/admin/client/views/collection-document.d.mts +6 -0
- package/dist/server/modules/admin/client/views/collection-document.mjs +10 -0
- package/dist/server/modules/admin/collections/account.d.mts +53 -52
- package/dist/server/modules/admin/collections/admin-locks.d.mts +57 -56
- package/dist/server/modules/admin/collections/admin-preferences.d.mts +38 -37
- package/dist/server/modules/admin/collections/admin-saved-views.d.mts +50 -49
- package/dist/server/modules/admin/collections/apikey.d.mts +76 -67
- package/dist/server/modules/admin/collections/assets.d.mts +37 -36
- package/dist/server/modules/admin/collections/session.d.mts +42 -41
- package/dist/server/modules/admin/collections/user.d.mts +57 -56
- package/dist/server/modules/admin/collections/verification.d.mts +34 -33
- package/dist/server/modules/admin/dto/admin-config.dto.mjs +34 -4
- package/dist/server/modules/admin/factories.mjs +4 -34
- package/dist/server/modules/admin/index.d.mts +3 -3
- package/dist/server/modules/admin/routes/admin-config.d.mts +4 -2
- package/dist/server/modules/admin/routes/admin-config.mjs +56 -24
- package/dist/server/modules/admin/routes/execute-action.d.mts +9 -9
- package/dist/server/modules/admin/routes/execute-action.mjs +35 -9
- package/dist/server/modules/admin/routes/locales.mjs +1 -1
- package/dist/server/modules/admin/routes/preview.d.mts +11 -11
- package/dist/server/modules/admin/routes/preview.mjs +6 -5
- package/dist/server/modules/admin/routes/reactive.d.mts +9 -9
- package/dist/server/modules/admin/routes/reactive.mjs +2 -2
- package/dist/server/modules/admin/routes/route-helpers.d.mts +11 -7
- package/dist/server/modules/admin/routes/route-helpers.mjs +1 -1
- 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/routes/widget-data.mjs +12 -4
- package/dist/server/modules/admin-preferences/collections/saved-views.d.mts +45 -45
- package/dist/server/modules/audit/.generated/module.d.mts +6 -6
- package/dist/server/modules/audit/collections/audit-log.d.mts +81 -80
- package/dist/server/modules/audit/jobs/audit-cleanup.d.mts +2 -2
- package/dist/server/plugin.mjs +10 -5
- package/dist/server/proxy-factories.d.mts +8 -1
- package/dist/server/proxy-factories.mjs +33 -1
- package/dist/server.d.mts +3 -1
- package/dist/shared/types/index.d.mts +1 -0
- package/dist/shared/types/saved-views.types.d.mts +14 -7
- package/dist/shared.d.mts +3 -2
- package/package.json +5 -4
|
@@ -1,7 +1,33 @@
|
|
|
1
1
|
import { useQuestpieQueryOptions } from "./use-questpie-query-options.mjs";
|
|
2
|
+
import { useEffect } from "react";
|
|
2
3
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
4
|
+
import { buildCollectionTopic } from "@questpie/tanstack-query";
|
|
3
5
|
|
|
4
6
|
//#region src/client/hooks/use-collection.ts
|
|
7
|
+
function useCollectionRealtimeInvalidation({ client, collection, options, realtime, queryClient }) {
|
|
8
|
+
const topicSignature = JSON.stringify(collection ? buildCollectionTopic(collection, options) : null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!collection || !realtime) return;
|
|
11
|
+
const realtimeApi = client?.realtime;
|
|
12
|
+
if (!realtimeApi?.subscribe) return;
|
|
13
|
+
const topic = JSON.parse(topicSignature);
|
|
14
|
+
if (!topic) return;
|
|
15
|
+
return realtimeApi.subscribe(topic, () => {
|
|
16
|
+
queryClient.invalidateQueries({ queryKey: [
|
|
17
|
+
"questpie",
|
|
18
|
+
"collections",
|
|
19
|
+
"collections",
|
|
20
|
+
collection
|
|
21
|
+
] });
|
|
22
|
+
});
|
|
23
|
+
}, [
|
|
24
|
+
client,
|
|
25
|
+
collection,
|
|
26
|
+
queryClient,
|
|
27
|
+
realtime,
|
|
28
|
+
topicSignature
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
5
31
|
/**
|
|
6
32
|
* Hook to fetch collection list with filters, sorting, pagination
|
|
7
33
|
*
|
|
@@ -14,24 +40,32 @@ import { useMutation, useQuery } from "@tanstack/react-query";
|
|
|
14
40
|
* ```
|
|
15
41
|
*/
|
|
16
42
|
function useCollectionList(collection, options, queryOptions, realtimeOptions) {
|
|
17
|
-
const { queryOpts, locale } = useQuestpieQueryOptions();
|
|
43
|
+
const { queryOpts, queryClient, locale, client } = useQuestpieQueryOptions();
|
|
18
44
|
const findOptions = {
|
|
19
45
|
...options,
|
|
20
46
|
locale
|
|
21
47
|
};
|
|
48
|
+
const baseQuery = collection ? queryOpts.collections[collection].find(findOptions, { realtime: realtimeOptions?.realtime }) : {
|
|
49
|
+
queryKey: [
|
|
50
|
+
"questpie",
|
|
51
|
+
"collections",
|
|
52
|
+
"__none__",
|
|
53
|
+
"find"
|
|
54
|
+
],
|
|
55
|
+
queryFn: () => ({
|
|
56
|
+
docs: [],
|
|
57
|
+
totalDocs: 0
|
|
58
|
+
})
|
|
59
|
+
};
|
|
60
|
+
useCollectionRealtimeInvalidation({
|
|
61
|
+
client,
|
|
62
|
+
collection: collection ? String(collection) : void 0,
|
|
63
|
+
options: findOptions,
|
|
64
|
+
realtime: realtimeOptions?.realtime,
|
|
65
|
+
queryClient
|
|
66
|
+
});
|
|
22
67
|
return useQuery({
|
|
23
|
-
...
|
|
24
|
-
queryKey: [
|
|
25
|
-
"questpie",
|
|
26
|
-
"collections",
|
|
27
|
-
"__none__",
|
|
28
|
-
"find"
|
|
29
|
-
],
|
|
30
|
-
queryFn: () => ({
|
|
31
|
-
docs: [],
|
|
32
|
-
totalDocs: 0
|
|
33
|
-
})
|
|
34
|
-
},
|
|
68
|
+
...baseQuery,
|
|
35
69
|
enabled: !!collection && (queryOptions?.enabled ?? true),
|
|
36
70
|
...queryOptions
|
|
37
71
|
});
|
|
@@ -54,21 +88,29 @@ function useCollectionList(collection, options, queryOptions, realtimeOptions) {
|
|
|
54
88
|
* ```
|
|
55
89
|
*/
|
|
56
90
|
function useCollectionCount(collection, options, queryOptions, realtimeOptions) {
|
|
57
|
-
const { queryOpts, locale } = useQuestpieQueryOptions();
|
|
91
|
+
const { queryOpts, queryClient, locale, client } = useQuestpieQueryOptions();
|
|
58
92
|
const countOptions = {
|
|
59
93
|
...options,
|
|
60
94
|
locale
|
|
61
95
|
};
|
|
96
|
+
const baseQuery = collection ? queryOpts.collections[collection].count(countOptions, { realtime: realtimeOptions?.realtime }) : {
|
|
97
|
+
queryKey: [
|
|
98
|
+
"questpie",
|
|
99
|
+
"collections",
|
|
100
|
+
"__none__",
|
|
101
|
+
"count"
|
|
102
|
+
],
|
|
103
|
+
queryFn: () => 0
|
|
104
|
+
};
|
|
105
|
+
useCollectionRealtimeInvalidation({
|
|
106
|
+
client,
|
|
107
|
+
collection: collection ? String(collection) : void 0,
|
|
108
|
+
options: countOptions,
|
|
109
|
+
realtime: realtimeOptions?.realtime,
|
|
110
|
+
queryClient
|
|
111
|
+
});
|
|
62
112
|
return useQuery({
|
|
63
|
-
...
|
|
64
|
-
queryKey: [
|
|
65
|
-
"questpie",
|
|
66
|
-
"collections",
|
|
67
|
-
"__none__",
|
|
68
|
-
"count"
|
|
69
|
-
],
|
|
70
|
-
queryFn: () => 0
|
|
71
|
-
},
|
|
113
|
+
...baseQuery,
|
|
72
114
|
enabled: !!collection && (queryOptions?.enabled ?? true),
|
|
73
115
|
...queryOptions
|
|
74
116
|
});
|
|
@@ -10,6 +10,8 @@ import { useFormContext, useWatch } from "react-hook-form";
|
|
|
10
10
|
* Watches form changes and triggers server-side reactive handlers.
|
|
11
11
|
* Supports batched RPC calls with debouncing.
|
|
12
12
|
*/
|
|
13
|
+
const EMPTY_REACTIVE_FIELD_STATE = {};
|
|
14
|
+
const ReactiveFieldStatesContext = React.createContext({});
|
|
13
15
|
/**
|
|
14
16
|
* Get sibling data for a field path (for fields inside arrays)
|
|
15
17
|
*/
|
|
@@ -66,6 +68,19 @@ function getChangedDeps(prevDeps, nextDeps) {
|
|
|
66
68
|
for (const [dep, value] of Object.entries(nextDeps)) if (prevDeps[dep] !== value) changed.push(dep);
|
|
67
69
|
return changed;
|
|
68
70
|
}
|
|
71
|
+
function mergeReactiveFieldState(base, reactive) {
|
|
72
|
+
return {
|
|
73
|
+
hidden: base.hidden === true || reactive?.hidden === true,
|
|
74
|
+
readOnly: base.readOnly === true || reactive?.readOnly === true,
|
|
75
|
+
disabled: base.disabled === true || reactive?.disabled === true
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function ReactiveFieldStatesProvider({ fieldStates, children }) {
|
|
79
|
+
return React.createElement(ReactiveFieldStatesContext.Provider, { value: fieldStates }, children);
|
|
80
|
+
}
|
|
81
|
+
function useReactiveFieldState(fieldPath) {
|
|
82
|
+
return React.useContext(ReactiveFieldStatesContext)[fieldPath] ?? EMPTY_REACTIVE_FIELD_STATE;
|
|
83
|
+
}
|
|
69
84
|
/**
|
|
70
85
|
* Hook to manage reactive field states.
|
|
71
86
|
* Watches form changes and triggers server-side handlers when dependencies change.
|
|
@@ -198,4 +213,4 @@ function useReactiveFields({ collection, mode = "collection", reactiveConfigs, d
|
|
|
198
213
|
}
|
|
199
214
|
|
|
200
215
|
//#endregion
|
|
201
|
-
export { useReactiveFields };
|
|
216
|
+
export { ReactiveFieldStatesProvider, mergeReactiveFieldState, useReactiveFieldState, useReactiveFields };
|
|
@@ -14,6 +14,13 @@ import * as React from "react";
|
|
|
14
14
|
* Server actions have their handlers stripped during serialization; this hook
|
|
15
15
|
* creates client-side wrappers that execute actions via the server API.
|
|
16
16
|
*/
|
|
17
|
+
var ServerActionValidationError = class extends Error {
|
|
18
|
+
constructor(message, fieldErrors) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.fieldErrors = fieldErrors;
|
|
21
|
+
this.name = "ServerActionValidationError";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
17
24
|
function getActionErrorMessage(response, t) {
|
|
18
25
|
if (response.error) return response.error;
|
|
19
26
|
if (response.result?.toast?.message) return response.result.toast.message;
|
|
@@ -106,7 +113,11 @@ function mapServerAction(serverAction, collection, fieldRegistry, client, locale
|
|
|
106
113
|
data,
|
|
107
114
|
locale
|
|
108
115
|
});
|
|
109
|
-
if (!response.success || response.result?.type === "error")
|
|
116
|
+
if (!response.success || response.result?.type === "error") {
|
|
117
|
+
const message = getActionErrorMessage(response, t);
|
|
118
|
+
if (response.result?.errors) throw new ServerActionValidationError(message, response.result.errors);
|
|
119
|
+
throw new Error(message);
|
|
120
|
+
}
|
|
110
121
|
await applyServerActionEffects(response.result, ctx);
|
|
111
122
|
return response.result?.toast?.message;
|
|
112
123
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/client/hooks/use-upload.d.ts
|
|
2
|
+
interface Asset {
|
|
3
|
+
id: string;
|
|
4
|
+
key: string;
|
|
5
|
+
filename: string;
|
|
6
|
+
mimeType: string;
|
|
7
|
+
size: number;
|
|
8
|
+
visibility: "public" | "private";
|
|
9
|
+
url?: string;
|
|
10
|
+
width?: number | null;
|
|
11
|
+
height?: number | null;
|
|
12
|
+
alt?: string | null;
|
|
13
|
+
caption?: string | null;
|
|
14
|
+
createdAt?: string;
|
|
15
|
+
updatedAt?: string;
|
|
16
|
+
}
|
|
17
|
+
interface UploadOptions {
|
|
18
|
+
to?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Optional destination path/folder forwarded to the collection's upload so a
|
|
21
|
+
* blob upload lands inside a folder (e.g. an `assets` row's required `path`).
|
|
22
|
+
*/
|
|
23
|
+
path?: string;
|
|
24
|
+
onProgress?: (progress: number) => void;
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
}
|
|
27
|
+
interface UploadManyOptions extends UploadOptions {
|
|
28
|
+
onProgress?: (progress: number, fileIndex?: number) => void;
|
|
29
|
+
}
|
|
30
|
+
interface UseUploadReturn {
|
|
31
|
+
upload: (file: File, options?: UploadOptions) => Promise<Asset>;
|
|
32
|
+
uploadMany: (files: File[], options?: UploadManyOptions) => Promise<Asset[]>;
|
|
33
|
+
isUploading: boolean;
|
|
34
|
+
progress: number;
|
|
35
|
+
error: Error | null;
|
|
36
|
+
reset: () => void;
|
|
37
|
+
}
|
|
38
|
+
declare function useUpload(): UseUploadReturn;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { Asset, useUpload };
|
|
@@ -29,7 +29,7 @@ function useUpload() {
|
|
|
29
29
|
}, [uploadCollections]);
|
|
30
30
|
const uploadMutation = useMutation({
|
|
31
31
|
mutationFn: async ({ file, options }) => {
|
|
32
|
-
const { to, onProgress, signal } = options ?? {};
|
|
32
|
+
const { to, path, onProgress, signal } = options ?? {};
|
|
33
33
|
const targetCollection = resolveTargetCollection(to);
|
|
34
34
|
if (!targetCollection) throw new Error(getMissingCollectionMessage());
|
|
35
35
|
const collectionApi = client.collections[targetCollection];
|
|
@@ -38,6 +38,7 @@ function useUpload() {
|
|
|
38
38
|
return {
|
|
39
39
|
asset: await collectionApi.upload(file, {
|
|
40
40
|
signal,
|
|
41
|
+
path,
|
|
41
42
|
onProgress: (p) => {
|
|
42
43
|
setProgress(p);
|
|
43
44
|
onProgress?.(p);
|
|
@@ -56,7 +57,7 @@ function useUpload() {
|
|
|
56
57
|
});
|
|
57
58
|
const uploadManyMutation = useMutation({
|
|
58
59
|
mutationFn: async ({ files, options }) => {
|
|
59
|
-
const { to, onProgress, signal } = options ?? {};
|
|
60
|
+
const { to, path, onProgress, signal } = options ?? {};
|
|
60
61
|
const targetCollection = resolveTargetCollection(to);
|
|
61
62
|
if (!targetCollection) throw new Error(getMissingCollectionMessage());
|
|
62
63
|
if (files.length === 0) return {
|
|
@@ -68,6 +69,7 @@ function useUpload() {
|
|
|
68
69
|
setProgress(0);
|
|
69
70
|
const results = await collectionApi.uploadMany(files, {
|
|
70
71
|
signal,
|
|
72
|
+
path,
|
|
71
73
|
onProgress: (p, fileIndex) => {
|
|
72
74
|
setProgress(p);
|
|
73
75
|
onProgress?.(p, fileIndex);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useAdminStore } from "../runtime/provider.mjs";
|
|
2
2
|
import { getAdminPreferenceQueryKey, useSetAdminPreference } from "./use-admin-preferences.mjs";
|
|
3
|
+
import { cloneFilters, filtersEqual, sortConfigEqual } from "../lib/view-filter-utils.mjs";
|
|
3
4
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
4
5
|
import { useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
|
|
5
6
|
|
|
@@ -102,7 +103,7 @@ function useViewState(defaultColumns, initialConfig, collectionName, userId) {
|
|
|
102
103
|
}
|
|
103
104
|
};
|
|
104
105
|
return {
|
|
105
|
-
filters: initialConfig?.filters ?? [],
|
|
106
|
+
filters: cloneFilters(initialConfig?.filters ?? []),
|
|
106
107
|
sortConfig: initialConfig?.sortConfig ?? null,
|
|
107
108
|
visibleColumns: defaultColumns,
|
|
108
109
|
groupBy: initialConfig?.groupBy ?? null,
|
|
@@ -273,17 +274,24 @@ function useViewState(defaultColumns, initialConfig, collectionName, userId) {
|
|
|
273
274
|
resetConfig: useCallback(() => {
|
|
274
275
|
setConfig({
|
|
275
276
|
...EMPTY_CONFIG,
|
|
276
|
-
|
|
277
|
+
filters: cloneFilters(initialConfig?.filters ?? []),
|
|
278
|
+
sortConfig: initialConfig?.sortConfig ?? null,
|
|
279
|
+
visibleColumns: defaultColumns,
|
|
280
|
+
groupBy: initialConfig?.groupBy ?? null,
|
|
281
|
+
realtime: initialConfig?.realtime,
|
|
282
|
+
includeDeleted: initialConfig?.includeDeleted ?? false
|
|
277
283
|
});
|
|
278
|
-
}, [
|
|
284
|
+
}, [
|
|
285
|
+
setConfig,
|
|
286
|
+
defaultColumns,
|
|
287
|
+
initialConfig
|
|
288
|
+
]),
|
|
279
289
|
hasChanges: useMemo(() => {
|
|
280
|
-
return config.filters
|
|
290
|
+
return !filtersEqual(config.filters, initialConfig?.filters ?? []) || !sortConfigEqual(config.sortConfig ?? null, initialConfig?.sortConfig ?? null) || (config.groupBy ?? null) !== (initialConfig?.groupBy ?? null) || (config.collapsedGroups?.length ?? 0) > 0 || config.realtime !== initialConfig?.realtime || (config.includeDeleted ?? false) !== (initialConfig?.includeDeleted ?? false) || config.pagination?.page !== 1 || config.pagination?.pageSize !== 25 || JSON.stringify([...config.visibleColumns].sort()) !== JSON.stringify([...defaultColumns].sort());
|
|
281
291
|
}, [
|
|
282
292
|
config,
|
|
283
293
|
defaultColumns,
|
|
284
|
-
initialConfig
|
|
285
|
-
initialConfig?.groupBy,
|
|
286
|
-
initialConfig?.realtime
|
|
294
|
+
initialConfig
|
|
287
295
|
]),
|
|
288
296
|
isLoading: false
|
|
289
297
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { I18nText } from "./types.mjs";
|
|
2
|
+
import "react";
|
|
3
|
+
import "date-fns";
|
|
4
|
+
|
|
5
|
+
//#region src/client/i18n/hooks.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Resolve I18nText to string
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* function Label({ text }: { text: I18nText }) {
|
|
13
|
+
* const resolve = useResolveText();
|
|
14
|
+
* return <span>{resolve(text)}</span>;
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare function useResolveText(): (text: I18nText | ((values: Record<string, any>) => I18nText) | undefined, fallback?: string, contextValues?: Record<string, any>) => string;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { useResolveText };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/client/lib/view-filter-utils.ts
|
|
2
|
+
function filterValueEqual(a, b) {
|
|
3
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
4
|
+
if (!Array.isArray(a) || !Array.isArray(b)) return false;
|
|
5
|
+
if (a.length !== b.length) return false;
|
|
6
|
+
return a.every((value, index) => value === b[index]);
|
|
7
|
+
}
|
|
8
|
+
return a === b;
|
|
9
|
+
}
|
|
10
|
+
function filtersEqual(a = [], b = []) {
|
|
11
|
+
if (a.length !== b.length) return false;
|
|
12
|
+
return a.every((filter, index) => {
|
|
13
|
+
const other = b[index];
|
|
14
|
+
return filter.id === other.id && filter.field === other.field && filter.operator === other.operator && filterValueEqual(filter.value, other.value);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function cloneFilters(filters) {
|
|
18
|
+
return filters.map((filter) => ({
|
|
19
|
+
...filter,
|
|
20
|
+
value: Array.isArray(filter.value) ? [...filter.value] : filter.value
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
function sortConfigEqual(a, b) {
|
|
24
|
+
if (a === b) return true;
|
|
25
|
+
if (!a || !b) return false;
|
|
26
|
+
return a.field === b.field && a.direction === b.direction;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { cloneFilters, filtersEqual, sortConfigEqual };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime55 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_runtime55.JSX.Element;
|
|
39
39
|
/**
|
|
40
40
|
* Get current block scope context.
|
|
41
41
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime56 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_runtime56.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_runtime57 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_runtime57.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_runtime57.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_runtime57.JSX.Element;
|
|
135
135
|
//#endregion
|
|
136
136
|
export { PreviewField, PreviewFieldProps, PreviewProvider, StandalonePreviewField, usePreviewContext };
|
|
@@ -19,6 +19,13 @@ const CONTENT_LOCALE_COOKIE = "questpie_content_locale";
|
|
|
19
19
|
/** Cookie max age (1 year) */
|
|
20
20
|
const LOCALE_COOKIE_MAX_AGE = 3600 * 24 * 365;
|
|
21
21
|
const LEGACY_LOCALE_COOKIE = "questpie_locale";
|
|
22
|
+
const PUBLIC_BRANDING_PATHS = [
|
|
23
|
+
"/login",
|
|
24
|
+
"/forgot-password",
|
|
25
|
+
"/reset-password",
|
|
26
|
+
"/accept-invite",
|
|
27
|
+
"/setup"
|
|
28
|
+
];
|
|
22
29
|
function setCookie(name, value) {
|
|
23
30
|
if (typeof document === "undefined") return;
|
|
24
31
|
document.cookie = `${name}=${value}; path=/; max-age=${LOCALE_COOKIE_MAX_AGE}; SameSite=Lax`;
|
|
@@ -201,13 +208,25 @@ function applyFavicon(href) {
|
|
|
201
208
|
}
|
|
202
209
|
link.href = href;
|
|
203
210
|
}
|
|
211
|
+
function isPublicBrandingPath(basePath) {
|
|
212
|
+
if (typeof window === "undefined") return false;
|
|
213
|
+
const currentPath = window.location.pathname.replace(/\/+$/, "");
|
|
214
|
+
const normalizedBase = basePath.replace(/\/+$/, "");
|
|
215
|
+
return PUBLIC_BRANDING_PATHS.some((path) => {
|
|
216
|
+
const fullPath = `${normalizedBase}${path}`.replace(/\/+$/, "");
|
|
217
|
+
return currentPath === fullPath || currentPath.startsWith(`${fullPath}/`);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
204
220
|
function BrandingSync() {
|
|
205
221
|
const store = useContext(AdminStoreContext);
|
|
206
222
|
useEffect(() => {
|
|
207
223
|
if (!store) return;
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
224
|
+
const state = store.getState();
|
|
225
|
+
const routes = state.client?.routes;
|
|
226
|
+
if (!routes) return;
|
|
227
|
+
const configRequest = isPublicBrandingPath(state.basePath) && typeof routes.getPublicAdminConfig === "function" ? routes.getPublicAdminConfig() : routes.getAdminConfig?.();
|
|
228
|
+
if (!configRequest) return;
|
|
229
|
+
configRequest.then((config) => {
|
|
211
230
|
const branding = config?.branding;
|
|
212
231
|
if (!branding) return;
|
|
213
232
|
const next = {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ScopePickerProps } from "./types.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime60 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/client/scope/picker.d.ts
|
|
5
5
|
|
|
@@ -48,6 +48,6 @@ declare function ScopePicker({
|
|
|
48
48
|
clearText,
|
|
49
49
|
className,
|
|
50
50
|
compact
|
|
51
|
-
}: ScopePickerProps):
|
|
51
|
+
}: ScopePickerProps): react_jsx_runtime60.JSX.Element;
|
|
52
52
|
//#endregion
|
|
53
53
|
export { ScopePicker };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ScopeContextValue, ScopeProviderProps } from "./types.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime61 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/client/scope/provider.d.ts
|
|
5
5
|
|
|
@@ -29,7 +29,7 @@ declare function ScopeProvider({
|
|
|
29
29
|
headerName,
|
|
30
30
|
storageKey,
|
|
31
31
|
defaultScope
|
|
32
|
-
}: ScopeProviderProps):
|
|
32
|
+
}: ScopeProviderProps): react_jsx_runtime61.JSX.Element;
|
|
33
33
|
/**
|
|
34
34
|
* Hook to access the current scope context.
|
|
35
35
|
*
|