@vexcms/next 0.1.0-alpha.26 → 0.1.0-alpha.28
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/HydrationBoundaryClient.d.ts +17 -0
- package/dist/HydrationBoundaryClient.d.ts.map +1 -0
- package/dist/HydrationBoundaryClient.js +9 -0
- package/dist/HydrationBoundaryClient.js.map +1 -0
- package/dist/NextAdminLayout.d.ts +21 -13
- package/dist/NextAdminLayout.d.ts.map +1 -1
- package/dist/NextAdminLayout.js +1 -1
- package/dist/NextAdminLayoutClient.d.ts +10 -4
- package/dist/NextAdminLayoutClient.d.ts.map +1 -1
- package/dist/NextAdminLayoutClient.js +104 -7
- package/dist/NextAdminLayoutClient.js.map +1 -1
- package/dist/NextAdminPage.d.ts +52 -5
- package/dist/NextAdminPage.d.ts.map +1 -1
- package/dist/NextAdminPage.js +1 -1
- package/dist/auth/VexAdminAuthAdapterContext.d.ts +66 -0
- package/dist/auth/VexAdminAuthAdapterContext.d.ts.map +1 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +12 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/chunk-JB3GMZPF.js +525 -0
- package/dist/chunk-JB3GMZPF.js.map +1 -0
- package/dist/chunk-NE2VUFS2.js +15 -0
- package/dist/chunk-NE2VUFS2.js.map +1 -0
- package/dist/chunk-T7DNJLSX.js +21 -0
- package/dist/chunk-T7DNJLSX.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/navigation/index.d.ts +3 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/useNextNavigate.d.ts +19 -0
- package/dist/navigation/useNextNavigate.d.ts.map +1 -0
- package/dist/navigation/useNextNavigationBlocker.d.ts +32 -0
- package/dist/navigation/useNextNavigationBlocker.d.ts.map +1 -0
- package/dist/serverQueryClient.d.ts +48 -0
- package/dist/serverQueryClient.d.ts.map +1 -0
- package/package.json +11 -4
- package/dist/chunk-DDH2TJTP.js +0 -195
- package/dist/chunk-DDH2TJTP.js.map +0 -1
- package/dist/chunk-UMJTAD5A.js +0 -22
- package/dist/chunk-UMJTAD5A.js.map +0 -1
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
// src/NextAdminPage.tsx
|
|
2
|
+
import {
|
|
3
|
+
ADMIN_COOKIE_NAME,
|
|
4
|
+
adminCollectionCookieName,
|
|
5
|
+
appendLivePreviewParams,
|
|
6
|
+
buildGetArgs,
|
|
7
|
+
buildGlobalGetArgs,
|
|
8
|
+
buildListViewFindQueryArgs,
|
|
9
|
+
buildListViewSearchQueryArgs,
|
|
10
|
+
collectListViewFilterRelationshipValues,
|
|
11
|
+
CRUD_ACTIONS,
|
|
12
|
+
parseListViewUrlState,
|
|
13
|
+
parseListViewConfigCookies,
|
|
14
|
+
parseListViewSkeletonRowCountCookie,
|
|
15
|
+
parseLocalSavedListViewsIndexCookie,
|
|
16
|
+
PERMISSION_SCOPES,
|
|
17
|
+
readLivePreviewLayoutCookie,
|
|
18
|
+
readLivePreviewPanelCookie,
|
|
19
|
+
resolveFieldPermissions,
|
|
20
|
+
resolveListViewQueryState,
|
|
21
|
+
resolveLivePreviewSettings,
|
|
22
|
+
resolveListViewSearchField,
|
|
23
|
+
vexConvexApi
|
|
24
|
+
} from "@vexcms/core";
|
|
25
|
+
import {
|
|
26
|
+
AdminNotFound,
|
|
27
|
+
AdminTopNav,
|
|
28
|
+
adminHref,
|
|
29
|
+
CollectionEditView,
|
|
30
|
+
CollectionListView,
|
|
31
|
+
CollectionsIndexView,
|
|
32
|
+
DashboardView,
|
|
33
|
+
GlobalEditView,
|
|
34
|
+
GlobalsListView,
|
|
35
|
+
MediaCollectionEditView,
|
|
36
|
+
MediaCollectionListView,
|
|
37
|
+
VexAuthProvider
|
|
38
|
+
} from "@vexcms/react";
|
|
39
|
+
import { dehydrate } from "@tanstack/react-query";
|
|
40
|
+
import { fetchQuery } from "convex/nextjs";
|
|
41
|
+
import { cookies } from "next/headers";
|
|
42
|
+
import { notFound } from "next/navigation";
|
|
43
|
+
import { HydrationBoundaryClient } from "./HydrationBoundaryClient";
|
|
44
|
+
|
|
45
|
+
// src/serverQueryClient.ts
|
|
46
|
+
import { defaultShouldDehydrateQuery, hashKey, QueryClient } from "@tanstack/react-query";
|
|
47
|
+
import { getFunctionName } from "convex/server";
|
|
48
|
+
import { convexToJson } from "convex/values";
|
|
49
|
+
import { cache } from "react";
|
|
50
|
+
function convexServerQueryKey(funcRef, args) {
|
|
51
|
+
return ["convexQuery", getFunctionName(funcRef), args];
|
|
52
|
+
}
|
|
53
|
+
function serverQueryKeyHashFn(queryKey) {
|
|
54
|
+
if (queryKey.length >= 2 && queryKey[0] === "convexQuery") {
|
|
55
|
+
return `convexQuery|${getFunctionName(queryKey[1])}|${JSON.stringify(convexToJson(queryKey[2]))}`;
|
|
56
|
+
}
|
|
57
|
+
return hashKey(queryKey);
|
|
58
|
+
}
|
|
59
|
+
var getServerQueryClient = cache(() => {
|
|
60
|
+
return new QueryClient({
|
|
61
|
+
defaultOptions: {
|
|
62
|
+
queries: {
|
|
63
|
+
// Matches `apps/*/src/components/providers/convex.tsx`'s client `QueryClient`, so a
|
|
64
|
+
// Convex query's dehydrated key hashes identically on both sides — required for
|
|
65
|
+
// hydration to find it rather than silently re-fetching.
|
|
66
|
+
queryKeyHashFn: serverQueryKeyHashFn,
|
|
67
|
+
retry: false
|
|
68
|
+
},
|
|
69
|
+
dehydrate: {
|
|
70
|
+
// `pending`: TanStack's own default only dehydrates settled queries — required for
|
|
71
|
+
// the "don't await the prefetch" half of the pattern, see above. `error`: a Convex
|
|
72
|
+
// query that genuinely fails (e.g. `UNINDEXED_SORT`) settles to "error" by the time
|
|
73
|
+
// `dehydrate()` runs (several awaits/microtasks after the un-awaited `prefetchQuery`
|
|
74
|
+
// call) — WITHOUT this, `defaultShouldDehydrateQuery` excludes it entirely (only
|
|
75
|
+
// "success" dehydrates by default), so the client's `useSuspenseQuery` would silently
|
|
76
|
+
// re-fetch from scratch and hit the identical error a second time — functionally fine
|
|
77
|
+
// (the client already handles its own error the same way, `ListViewQueryError`), but a
|
|
78
|
+
// wasted round trip; including "error" here lets the dehydrated failure reach the
|
|
79
|
+
// client directly, no second Convex call needed.
|
|
80
|
+
shouldDehydrateQuery: (query) => defaultShouldDehydrateQuery(query) || query.state.status === "pending" || query.state.status === "error",
|
|
81
|
+
// Next.js detects dynamic rendering via a thrown error during render; redacting it
|
|
82
|
+
// here (TanStack's own default) would hide that signal from Next.js.
|
|
83
|
+
shouldRedactErrors: () => false
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// src/NextAdminPage.tsx
|
|
90
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
91
|
+
function renderAdminShell(props) {
|
|
92
|
+
return /* @__PURE__ */ jsx(VexAuthProvider, { value: props.auth, children: /* @__PURE__ */ jsxs(HydrationBoundaryClient, { state: dehydrate(props.queryClient), children: [
|
|
93
|
+
/* @__PURE__ */ jsx(AdminTopNav, { activeSlug: props.activeSlug, activeDocID: props.activeDocID }),
|
|
94
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 p-6 pt-0", children: props.children })
|
|
95
|
+
] }) });
|
|
96
|
+
}
|
|
97
|
+
async function resolveInitialPreviewUrl(props) {
|
|
98
|
+
const url = await fetchQuery(
|
|
99
|
+
vexConvexApi.livePreviewUrl,
|
|
100
|
+
props.args,
|
|
101
|
+
props.token ? { token: props.token } : void 0
|
|
102
|
+
);
|
|
103
|
+
if (!url) return void 0;
|
|
104
|
+
return appendLivePreviewParams({ url, collectionSlug: props.slug });
|
|
105
|
+
}
|
|
106
|
+
var warnedMissingAuth = false;
|
|
107
|
+
function warnIfAuthMissing(props) {
|
|
108
|
+
if (props.authPromise !== void 0) return;
|
|
109
|
+
if (!props.access || !props.access.enabled) return;
|
|
110
|
+
if (warnedMissingAuth) return;
|
|
111
|
+
if (process.env.NODE_ENV === "production") return;
|
|
112
|
+
warnedMissingAuth = true;
|
|
113
|
+
console.warn(
|
|
114
|
+
"[vexcms] NextAdminPage: config.access is enabled but no `authPromise` prop was passed. Every caller is being treated as anonymous (fail-closed) until you pass `authPromise={getUserOrg()}` from your own session source \u2014 see Decision 44 (.agent/docs/specs/2026-10-26-list-view-overhaul/spec.md)."
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
async function NextAdminPage(props) {
|
|
118
|
+
const { path = [] } = await props.params;
|
|
119
|
+
const [section, collectionSlug, documentId] = path;
|
|
120
|
+
const cookieStore = await cookies();
|
|
121
|
+
warnIfAuthMissing({ access: props.config.access, authPromise: props.authPromise });
|
|
122
|
+
const token = props.tokenPromise ? await props.tokenPromise : void 0;
|
|
123
|
+
const authPromise = props.authPromise ?? Promise.resolve({ user: null });
|
|
124
|
+
if (path.length === 0) {
|
|
125
|
+
const auth2 = await authPromise;
|
|
126
|
+
return renderAdminShell({
|
|
127
|
+
auth: auth2,
|
|
128
|
+
queryClient: getServerQueryClient(),
|
|
129
|
+
children: /* @__PURE__ */ jsx(DashboardView, {})
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (section !== "collections" && section !== "globals") {
|
|
133
|
+
notFound();
|
|
134
|
+
}
|
|
135
|
+
if (section === "globals") {
|
|
136
|
+
if (!collectionSlug) {
|
|
137
|
+
const auth3 = await authPromise;
|
|
138
|
+
return renderAdminShell({
|
|
139
|
+
auth: auth3,
|
|
140
|
+
activeSlug: "globals",
|
|
141
|
+
queryClient: getServerQueryClient(),
|
|
142
|
+
children: /* @__PURE__ */ jsx(GlobalsListView, {})
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const globalConfig = props.config.globals.find((g) => g.slug === collectionSlug);
|
|
146
|
+
if (!globalConfig) {
|
|
147
|
+
const auth3 = await authPromise;
|
|
148
|
+
return renderAdminShell({
|
|
149
|
+
auth: auth3,
|
|
150
|
+
activeSlug: "globals",
|
|
151
|
+
queryClient: getServerQueryClient(),
|
|
152
|
+
children: /* @__PURE__ */ jsx(
|
|
153
|
+
AdminNotFound,
|
|
154
|
+
{
|
|
155
|
+
variant: "global",
|
|
156
|
+
detail: `Global "${collectionSlug}" doesn't exist.`,
|
|
157
|
+
backHref: adminHref({ type: "globals" }, props.config.basePath),
|
|
158
|
+
backLabel: "Back to globals"
|
|
159
|
+
}
|
|
160
|
+
)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
const globalQueryClient = getServerQueryClient();
|
|
164
|
+
const globalArgs = buildGlobalGetArgs({ global: globalConfig });
|
|
165
|
+
const globalDocPromise = fetchQuery(
|
|
166
|
+
vexConvexApi.globals.get,
|
|
167
|
+
globalArgs,
|
|
168
|
+
token ? { token } : void 0
|
|
169
|
+
).catch(() => null);
|
|
170
|
+
const globalLivePreview = resolveLivePreviewSettings({
|
|
171
|
+
config: props.config.admin.livePreview,
|
|
172
|
+
kind: "global",
|
|
173
|
+
slug: globalConfig.slug,
|
|
174
|
+
admin: globalConfig.admin.livePreview
|
|
175
|
+
});
|
|
176
|
+
const previewUrlPromise = globalLivePreview === void 0 ? Promise.resolve(void 0) : resolveInitialPreviewUrl({
|
|
177
|
+
args: { collection: globalConfig.slug, kind: "global", values: {} },
|
|
178
|
+
slug: globalConfig.slug,
|
|
179
|
+
token
|
|
180
|
+
});
|
|
181
|
+
const [auth2, initialPreviewUrl, globalDoc] = await Promise.all([
|
|
182
|
+
authPromise,
|
|
183
|
+
previewUrlPromise,
|
|
184
|
+
globalDocPromise
|
|
185
|
+
]);
|
|
186
|
+
if (!globalDoc) {
|
|
187
|
+
return renderAdminShell({
|
|
188
|
+
auth: auth2,
|
|
189
|
+
activeSlug: "globals",
|
|
190
|
+
queryClient: globalQueryClient,
|
|
191
|
+
children: /* @__PURE__ */ jsx(
|
|
192
|
+
AdminNotFound,
|
|
193
|
+
{
|
|
194
|
+
variant: "document",
|
|
195
|
+
detail: "This document doesn't exist, or you don't have access to view it.",
|
|
196
|
+
backHref: `${props.config.basePath}/globals`,
|
|
197
|
+
backLabel: "Back to Globals"
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
await globalQueryClient.prefetchQuery({
|
|
203
|
+
queryKey: convexServerQueryKey(vexConvexApi.globals.get, globalArgs),
|
|
204
|
+
queryFn: () => globalDoc
|
|
205
|
+
}).catch(() => void 0);
|
|
206
|
+
return renderAdminShell({
|
|
207
|
+
auth: auth2,
|
|
208
|
+
activeSlug: "globals",
|
|
209
|
+
activeDocID: globalConfig.slug,
|
|
210
|
+
queryClient: globalQueryClient,
|
|
211
|
+
children: /* @__PURE__ */ jsx(
|
|
212
|
+
GlobalEditView,
|
|
213
|
+
{
|
|
214
|
+
global: globalConfig.slug,
|
|
215
|
+
initialData: globalDoc,
|
|
216
|
+
initialPreviewPanelOpen: globalLivePreview !== void 0 && readLivePreviewPanelCookie({
|
|
217
|
+
cookieValue: cookieStore.get(ADMIN_COOKIE_NAME)?.value,
|
|
218
|
+
defaultOpen: globalLivePreview.defaultOpen
|
|
219
|
+
}),
|
|
220
|
+
initialPreviewPanelSize: readLivePreviewLayoutCookie({
|
|
221
|
+
cookieValue: cookieStore.get(ADMIN_COOKIE_NAME)?.value
|
|
222
|
+
}),
|
|
223
|
+
initialPreviewUrl
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
if (!collectionSlug) {
|
|
229
|
+
const auth2 = await authPromise;
|
|
230
|
+
return renderAdminShell({
|
|
231
|
+
auth: auth2,
|
|
232
|
+
activeSlug: "collections",
|
|
233
|
+
queryClient: getServerQueryClient(),
|
|
234
|
+
children: /* @__PURE__ */ jsx(CollectionsIndexView, {})
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
const collection = props.config.collections.find((c) => c.slug === collectionSlug);
|
|
238
|
+
const mediaCollection = props.config.mediaCollections.find((mc) => mc.slug === collectionSlug);
|
|
239
|
+
if (!collection && !mediaCollection) {
|
|
240
|
+
const auth2 = await authPromise;
|
|
241
|
+
return renderAdminShell({
|
|
242
|
+
auth: auth2,
|
|
243
|
+
activeSlug: collectionSlug,
|
|
244
|
+
queryClient: getServerQueryClient(),
|
|
245
|
+
children: /* @__PURE__ */ jsx(
|
|
246
|
+
AdminNotFound,
|
|
247
|
+
{
|
|
248
|
+
variant: "collection",
|
|
249
|
+
detail: `Collection "${collectionSlug}" doesn't exist.`,
|
|
250
|
+
backHref: adminHref({ type: "collections" }, props.config.basePath),
|
|
251
|
+
backLabel: "Back to collections"
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (mediaCollection && documentId) {
|
|
257
|
+
const mediaEditQueryClient = getServerQueryClient();
|
|
258
|
+
const mediaEditArgs = buildGetArgs({ id: documentId, collection: mediaCollection });
|
|
259
|
+
const mediaDocPromise = fetchQuery(
|
|
260
|
+
vexConvexApi.get,
|
|
261
|
+
mediaEditArgs,
|
|
262
|
+
token ? { token } : void 0
|
|
263
|
+
).catch(() => null);
|
|
264
|
+
const [auth2, mediaDoc] = await Promise.all([authPromise, mediaDocPromise]);
|
|
265
|
+
if (!mediaDoc) {
|
|
266
|
+
return renderAdminShell({
|
|
267
|
+
auth: auth2,
|
|
268
|
+
activeSlug: mediaCollection.slug,
|
|
269
|
+
queryClient: mediaEditQueryClient,
|
|
270
|
+
children: /* @__PURE__ */ jsx(
|
|
271
|
+
AdminNotFound,
|
|
272
|
+
{
|
|
273
|
+
variant: "document",
|
|
274
|
+
detail: "This document doesn't exist, or you don't have access to view it.",
|
|
275
|
+
backHref: `${props.config.basePath}/collections/${mediaCollection.slug}`,
|
|
276
|
+
backLabel: `Back to ${mediaCollection.labels.plural}`
|
|
277
|
+
}
|
|
278
|
+
)
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
await mediaEditQueryClient.prefetchQuery({
|
|
282
|
+
queryKey: convexServerQueryKey(vexConvexApi.get, mediaEditArgs),
|
|
283
|
+
queryFn: () => mediaDoc
|
|
284
|
+
}).catch(() => void 0);
|
|
285
|
+
return renderAdminShell({
|
|
286
|
+
auth: auth2,
|
|
287
|
+
activeSlug: mediaCollection.slug,
|
|
288
|
+
activeDocID: documentId,
|
|
289
|
+
queryClient: mediaEditQueryClient,
|
|
290
|
+
children: /* @__PURE__ */ jsx(MediaCollectionEditView, { collection: mediaCollection.slug, documentId, initialData: mediaDoc })
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
if (mediaCollection) {
|
|
294
|
+
const numItems2 = Math.max(
|
|
295
|
+
mediaCollection.admin.view.state.serverPageSize,
|
|
296
|
+
mediaCollection.admin.view.state.pageSize
|
|
297
|
+
);
|
|
298
|
+
const auth2 = await authPromise;
|
|
299
|
+
const mediaQueryClient = getServerQueryClient();
|
|
300
|
+
const mediaArgs = buildListViewFindQueryArgs({
|
|
301
|
+
collection: mediaCollection,
|
|
302
|
+
where: void 0,
|
|
303
|
+
sort: void 0,
|
|
304
|
+
drafts: void 0,
|
|
305
|
+
depth: 1,
|
|
306
|
+
numItems: numItems2
|
|
307
|
+
});
|
|
308
|
+
void mediaQueryClient.prefetchQuery({
|
|
309
|
+
queryKey: convexServerQueryKey(vexConvexApi.findPaginated, mediaArgs),
|
|
310
|
+
queryFn: () => fetchQuery(vexConvexApi.findPaginated, mediaArgs, token ? { token } : void 0)
|
|
311
|
+
}).catch(() => void 0);
|
|
312
|
+
return renderAdminShell({
|
|
313
|
+
auth: auth2,
|
|
314
|
+
activeSlug: mediaCollection.slug,
|
|
315
|
+
queryClient: mediaQueryClient,
|
|
316
|
+
children: /* @__PURE__ */ jsx(MediaCollectionListView, { collection: mediaCollection.slug })
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if (collection && documentId) {
|
|
320
|
+
const collectionEditQueryClient = getServerQueryClient();
|
|
321
|
+
const collectionEditArgs = buildGetArgs({ id: documentId, collection });
|
|
322
|
+
const collectionDocPromise = fetchQuery(
|
|
323
|
+
vexConvexApi.get,
|
|
324
|
+
collectionEditArgs,
|
|
325
|
+
token ? { token } : void 0
|
|
326
|
+
).catch(() => null);
|
|
327
|
+
const collectionLivePreview = resolveLivePreviewSettings({
|
|
328
|
+
config: props.config.admin.livePreview,
|
|
329
|
+
kind: "collection",
|
|
330
|
+
slug: collection.slug,
|
|
331
|
+
admin: collection.admin.livePreview
|
|
332
|
+
});
|
|
333
|
+
const previewUrlPromise = collectionLivePreview === void 0 ? Promise.resolve(void 0) : resolveInitialPreviewUrl({
|
|
334
|
+
args: { collection: collection.slug, kind: "collection", documentId, values: {} },
|
|
335
|
+
slug: collection.slug,
|
|
336
|
+
token
|
|
337
|
+
});
|
|
338
|
+
const [auth2, initialPreviewUrl, currentDocument] = await Promise.all([
|
|
339
|
+
authPromise,
|
|
340
|
+
previewUrlPromise,
|
|
341
|
+
collectionDocPromise
|
|
342
|
+
]);
|
|
343
|
+
if (!currentDocument) {
|
|
344
|
+
return renderAdminShell({
|
|
345
|
+
auth: auth2,
|
|
346
|
+
activeSlug: collection.slug,
|
|
347
|
+
queryClient: collectionEditQueryClient,
|
|
348
|
+
children: /* @__PURE__ */ jsx(
|
|
349
|
+
AdminNotFound,
|
|
350
|
+
{
|
|
351
|
+
variant: "document",
|
|
352
|
+
detail: "This document doesn't exist, or you don't have access to view it.",
|
|
353
|
+
backHref: `${props.config.basePath}/collections/${collection.slug}`,
|
|
354
|
+
backLabel: `Back to ${collection.labels.plural}`
|
|
355
|
+
}
|
|
356
|
+
)
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
await collectionEditQueryClient.prefetchQuery({
|
|
360
|
+
queryKey: convexServerQueryKey(vexConvexApi.get, collectionEditArgs),
|
|
361
|
+
queryFn: () => currentDocument
|
|
362
|
+
}).catch(() => void 0);
|
|
363
|
+
return renderAdminShell({
|
|
364
|
+
auth: auth2,
|
|
365
|
+
activeSlug: collection.slug,
|
|
366
|
+
activeDocID: documentId,
|
|
367
|
+
queryClient: collectionEditQueryClient,
|
|
368
|
+
children: /* @__PURE__ */ jsx(
|
|
369
|
+
CollectionEditView,
|
|
370
|
+
{
|
|
371
|
+
collection: collection.slug,
|
|
372
|
+
documentId,
|
|
373
|
+
initialData: currentDocument,
|
|
374
|
+
initialPreviewPanelOpen: collectionLivePreview !== void 0 && readLivePreviewPanelCookie({
|
|
375
|
+
cookieValue: cookieStore.get(adminCollectionCookieName({ collection: collection.slug }))?.value,
|
|
376
|
+
defaultOpen: collectionLivePreview.defaultOpen
|
|
377
|
+
}),
|
|
378
|
+
initialPreviewPanelSize: readLivePreviewLayoutCookie({
|
|
379
|
+
cookieValue: cookieStore.get(adminCollectionCookieName({ collection: collection.slug }))?.value
|
|
380
|
+
}),
|
|
381
|
+
initialPreviewUrl
|
|
382
|
+
}
|
|
383
|
+
)
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
if (!collection) {
|
|
387
|
+
throw new Error("invalid collection slug");
|
|
388
|
+
}
|
|
389
|
+
const params = parseListViewUrlState({
|
|
390
|
+
searchParams: toSearchParams(await props.searchParams ?? {}),
|
|
391
|
+
collection
|
|
392
|
+
});
|
|
393
|
+
const [viewSource, viewId] = params.view?.split(":") ?? [];
|
|
394
|
+
const configView = viewSource === "config" ? collection.admin.views.find((view) => view.viewId === viewId) : void 0;
|
|
395
|
+
const listViewsPromise = fetchQuery(
|
|
396
|
+
vexConvexApi.listViews,
|
|
397
|
+
{ collection: collection.slug },
|
|
398
|
+
token ? { token } : void 0
|
|
399
|
+
);
|
|
400
|
+
const peekArgs = params.peek === void 0 ? void 0 : buildGetArgs({ id: params.peek, collection });
|
|
401
|
+
const peekPromise = peekArgs === void 0 ? Promise.resolve(void 0) : (
|
|
402
|
+
// Same args as `useVexDocQuery`'s client query inside `ListViewPeek` (Design Decision
|
|
403
|
+
// 27/39), so the hydrated peek opens with no re-fetch.
|
|
404
|
+
fetchQuery(vexConvexApi.get, peekArgs, token ? { token } : void 0)
|
|
405
|
+
);
|
|
406
|
+
const queryClient = getServerQueryClient();
|
|
407
|
+
if (peekArgs !== void 0) {
|
|
408
|
+
void queryClient.prefetchQuery({
|
|
409
|
+
queryKey: convexServerQueryKey(vexConvexApi.get, peekArgs),
|
|
410
|
+
queryFn: () => peekPromise
|
|
411
|
+
}).catch(() => void 0);
|
|
412
|
+
}
|
|
413
|
+
const [auth, sharedView] = await Promise.all([
|
|
414
|
+
authPromise,
|
|
415
|
+
viewSource === "shared" ? listViewsPromise.catch(() => []).then((views) => views.find((view) => view.viewId === viewId)) : Promise.resolve(void 0)
|
|
416
|
+
]);
|
|
417
|
+
const fieldPermissions = resolveFieldPermissions({
|
|
418
|
+
access: props.config.access,
|
|
419
|
+
user: auth.user,
|
|
420
|
+
organization: auth.organization,
|
|
421
|
+
resource: collection.slug,
|
|
422
|
+
action: CRUD_ACTIONS.read,
|
|
423
|
+
scope: PERMISSION_SCOPES.any
|
|
424
|
+
});
|
|
425
|
+
const resolved = resolveListViewQueryState({ collection, params, configView, sharedView, fieldPermissions });
|
|
426
|
+
const relationshipFilterValues = collectListViewFilterRelationshipValues({ where: resolved.where, collection });
|
|
427
|
+
const distinctFilterValues = [
|
|
428
|
+
...new Map(relationshipFilterValues.map((v) => [`${v.targetCollection}:${v.id}`, v])).values()
|
|
429
|
+
];
|
|
430
|
+
const filterValueTitlesPromise = Promise.allSettled(
|
|
431
|
+
distinctFilterValues.map(async (v) => {
|
|
432
|
+
const targetCollectionConfig = props.config.collections.find((c) => c.slug === v.targetCollection) ?? props.config.mediaCollections.find((c) => c.slug === v.targetCollection);
|
|
433
|
+
if (targetCollectionConfig === void 0) return [v.id, null];
|
|
434
|
+
const doc = await fetchQuery(
|
|
435
|
+
vexConvexApi.get,
|
|
436
|
+
buildGetArgs({ id: v.id, collection: targetCollectionConfig }),
|
|
437
|
+
token ? { token } : void 0
|
|
438
|
+
);
|
|
439
|
+
if (doc === null) return [v.id, null];
|
|
440
|
+
const titleField = targetCollectionConfig.admin.useAsTitle;
|
|
441
|
+
const title = doc[titleField];
|
|
442
|
+
return [v.id, typeof title === "string" && title !== "" ? title : String(doc._id)];
|
|
443
|
+
})
|
|
444
|
+
);
|
|
445
|
+
const numItems = Math.max(collection.admin.view.state.serverPageSize, resolved.pageSize);
|
|
446
|
+
const drafts = collection.versions.drafts ? true : void 0;
|
|
447
|
+
const resolvedSearchField = resolveListViewSearchField({
|
|
448
|
+
collection,
|
|
449
|
+
qf: resolved.searchField,
|
|
450
|
+
fieldPermissions
|
|
451
|
+
});
|
|
452
|
+
const isSearchActive = resolved.search.trim() !== "" && resolvedSearchField !== void 0;
|
|
453
|
+
if (isSearchActive) {
|
|
454
|
+
const args = buildListViewSearchQueryArgs({
|
|
455
|
+
collection,
|
|
456
|
+
where: resolved.where,
|
|
457
|
+
search: resolved.search,
|
|
458
|
+
searchField: resolvedSearchField,
|
|
459
|
+
drafts,
|
|
460
|
+
numItems
|
|
461
|
+
});
|
|
462
|
+
void queryClient.prefetchQuery({
|
|
463
|
+
queryKey: convexServerQueryKey(vexConvexApi.search, args),
|
|
464
|
+
queryFn: () => fetchQuery(vexConvexApi.search, args, token ? { token } : void 0)
|
|
465
|
+
}).catch(() => void 0);
|
|
466
|
+
} else {
|
|
467
|
+
const args = buildListViewFindQueryArgs({
|
|
468
|
+
collection,
|
|
469
|
+
where: resolved.where,
|
|
470
|
+
sort: resolved.sort,
|
|
471
|
+
drafts,
|
|
472
|
+
depth: 1,
|
|
473
|
+
numItems
|
|
474
|
+
});
|
|
475
|
+
void queryClient.prefetchQuery({
|
|
476
|
+
queryKey: convexServerQueryKey(vexConvexApi.findPaginated, args),
|
|
477
|
+
queryFn: () => fetchQuery(vexConvexApi.findPaginated, args, token ? { token } : void 0)
|
|
478
|
+
}).catch(() => void 0);
|
|
479
|
+
}
|
|
480
|
+
const listViewsPrefetch = queryClient.prefetchQuery({
|
|
481
|
+
queryKey: convexServerQueryKey(vexConvexApi.listViews, { collection: collection.slug }),
|
|
482
|
+
queryFn: () => listViewsPromise
|
|
483
|
+
}).catch(() => void 0);
|
|
484
|
+
await listViewsPrefetch;
|
|
485
|
+
const skeletonRowCountEntry = parseListViewSkeletonRowCountCookie({
|
|
486
|
+
cookieValue: cookieStore.get(adminCollectionCookieName({ collection: collection.slug }))?.value
|
|
487
|
+
})[viewId ?? "default"];
|
|
488
|
+
const filterValueTitleResults = await filterValueTitlesPromise;
|
|
489
|
+
const initialFilterValueTitles = Object.fromEntries(
|
|
490
|
+
filterValueTitleResults.map(
|
|
491
|
+
(result, index) => result.status === "fulfilled" ? result.value : [distinctFilterValues[index].id, null]
|
|
492
|
+
)
|
|
493
|
+
);
|
|
494
|
+
return renderAdminShell({
|
|
495
|
+
auth,
|
|
496
|
+
activeSlug: collection.slug,
|
|
497
|
+
queryClient,
|
|
498
|
+
children: /* @__PURE__ */ jsx(
|
|
499
|
+
CollectionListView,
|
|
500
|
+
{
|
|
501
|
+
collection: collection.slug,
|
|
502
|
+
initialLocalIndex: parseLocalSavedListViewsIndexCookie({
|
|
503
|
+
cookieValue: cookieStore.get(adminCollectionCookieName({ collection: collection.slug }))?.value
|
|
504
|
+
}),
|
|
505
|
+
initialPreferences: parseListViewConfigCookies({ cookies: cookieStore, collectionSlug: collection.slug }),
|
|
506
|
+
initialSkeletonRowCount: skeletonRowCountEntry?.n,
|
|
507
|
+
initialSkeletonDone: skeletonRowCountEntry?.done,
|
|
508
|
+
initialFilterValueTitles
|
|
509
|
+
}
|
|
510
|
+
)
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
function toSearchParams(raw) {
|
|
514
|
+
const params = new URLSearchParams();
|
|
515
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
516
|
+
if (value === void 0) continue;
|
|
517
|
+
for (const entry of Array.isArray(value) ? value : [value]) params.append(key, entry);
|
|
518
|
+
}
|
|
519
|
+
return params;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export {
|
|
523
|
+
NextAdminPage
|
|
524
|
+
};
|
|
525
|
+
//# sourceMappingURL=chunk-JB3GMZPF.js.map
|