@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
|
@@ -16,7 +16,7 @@ import { DashboardGrid } from "../dashboard/dashboard-grid.mjs";
|
|
|
16
16
|
import { Icon } from "@iconify/react";
|
|
17
17
|
import * as React from "react";
|
|
18
18
|
import { useQueryClient } from "@tanstack/react-query";
|
|
19
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
20
20
|
|
|
21
21
|
//#region src/client/views/layout/admin-router.tsx
|
|
22
22
|
/**
|
|
@@ -201,16 +201,30 @@ function UnknownViewState({ viewKind, viewId }) {
|
|
|
201
201
|
*/
|
|
202
202
|
function RouterSkeleton() {
|
|
203
203
|
return /* @__PURE__ */ jsxs("div", {
|
|
204
|
-
className: "qa-router-skeleton
|
|
204
|
+
className: "qa-router-skeleton min-w-0 space-y-4",
|
|
205
|
+
"aria-busy": "true",
|
|
205
206
|
children: [
|
|
206
|
-
/* @__PURE__ */ jsx(
|
|
207
|
-
|
|
207
|
+
/* @__PURE__ */ jsx("span", {
|
|
208
|
+
className: "sr-only",
|
|
209
|
+
children: "Loading admin view"
|
|
210
|
+
}),
|
|
211
|
+
/* @__PURE__ */ jsx(AdminViewHeader, {
|
|
212
|
+
title: /* @__PURE__ */ jsx(Skeleton, {
|
|
213
|
+
variant: "text",
|
|
214
|
+
className: "h-7 w-44 max-w-full"
|
|
215
|
+
}),
|
|
216
|
+
description: /* @__PURE__ */ jsx(Skeleton, {
|
|
217
|
+
variant: "text",
|
|
218
|
+
className: "h-4 w-64 max-w-full"
|
|
219
|
+
}),
|
|
220
|
+
actions: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Skeleton, { className: "size-8" }), /* @__PURE__ */ jsx(Skeleton, { className: "size-8" })] })
|
|
221
|
+
}),
|
|
208
222
|
/* @__PURE__ */ jsxs("div", {
|
|
209
|
-
className: "
|
|
223
|
+
className: "grid gap-3",
|
|
210
224
|
children: [
|
|
211
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-
|
|
212
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-
|
|
213
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-
|
|
225
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" }),
|
|
226
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" }),
|
|
227
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" })
|
|
214
228
|
]
|
|
215
229
|
})
|
|
216
230
|
]
|
|
@@ -363,7 +377,7 @@ function DefaultDashboard() {
|
|
|
363
377
|
children: /* @__PURE__ */ jsxs("div", { children: [
|
|
364
378
|
/* @__PURE__ */ jsxs("div", {
|
|
365
379
|
className: "mb-4 flex items-center gap-3",
|
|
366
|
-
children: [/* @__PURE__ */ jsx("div", { className: "bg-primary
|
|
380
|
+
children: [/* @__PURE__ */ jsx("div", { className: "bg-primary size-2 rounded-full" }), /* @__PURE__ */ jsx("h3", {
|
|
367
381
|
className: "text-muted-foreground font-chrome chrome-meta text-xs font-medium",
|
|
368
382
|
children: t("dashboard.systemStatus")
|
|
369
383
|
})]
|
|
@@ -386,7 +400,7 @@ function DefaultNotFound() {
|
|
|
386
400
|
return /* @__PURE__ */ jsxs("div", {
|
|
387
401
|
className: "qa-not-found container",
|
|
388
402
|
children: [/* @__PURE__ */ jsx("h1", {
|
|
389
|
-
className: "mb-4 text-2xl font-
|
|
403
|
+
className: "mb-4 text-2xl font-semibold",
|
|
390
404
|
children: t("error.pageNotFound")
|
|
391
405
|
}), /* @__PURE__ */ jsx("p", {
|
|
392
406
|
className: "text-muted-foreground",
|
|
@@ -402,10 +416,10 @@ function RestrictedAccess({ type, name, navigate, basePath }) {
|
|
|
402
416
|
className: "mx-auto max-w-lg p-8 text-center",
|
|
403
417
|
children: /* @__PURE__ */ jsxs("div", { children: [
|
|
404
418
|
/* @__PURE__ */ jsx("div", {
|
|
405
|
-
className: "bg-muted mx-auto mb-6 flex
|
|
419
|
+
className: "bg-muted mx-auto mb-6 flex size-16 items-center justify-center rounded-full",
|
|
406
420
|
children: /* @__PURE__ */ jsx(Icon, {
|
|
407
421
|
icon: "ph:lock-simple",
|
|
408
|
-
className: "text-muted-foreground
|
|
422
|
+
className: "text-muted-foreground size-8"
|
|
409
423
|
})
|
|
410
424
|
}),
|
|
411
425
|
/* @__PURE__ */ jsx("h1", {
|
|
@@ -424,7 +438,7 @@ function RestrictedAccess({ type, name, navigate, basePath }) {
|
|
|
424
438
|
onClick: () => navigate(basePath),
|
|
425
439
|
children: [/* @__PURE__ */ jsx(Icon, {
|
|
426
440
|
icon: "ph:arrow-left",
|
|
427
|
-
className: "
|
|
441
|
+
className: "size-4"
|
|
428
442
|
}), t("error.backToDashboard")]
|
|
429
443
|
})
|
|
430
444
|
] })
|
|
@@ -434,26 +448,35 @@ function RestrictedAccess({ type, name, navigate, basePath }) {
|
|
|
434
448
|
function LazyPageRenderer({ config }) {
|
|
435
449
|
const { t } = useTranslation();
|
|
436
450
|
const component = config.component;
|
|
437
|
-
const [
|
|
438
|
-
|
|
439
|
-
|
|
451
|
+
const [pageState, setPageState] = React.useState(() => {
|
|
452
|
+
const Component = getCachedComponent(component) ?? null;
|
|
453
|
+
return {
|
|
454
|
+
source: component,
|
|
455
|
+
Component,
|
|
456
|
+
loading: Component == null,
|
|
457
|
+
error: null
|
|
458
|
+
};
|
|
459
|
+
});
|
|
440
460
|
React.useEffect(() => {
|
|
441
461
|
let mounted = true;
|
|
442
462
|
async function load() {
|
|
443
463
|
try {
|
|
444
464
|
const cachedComponent = getCachedComponent(component);
|
|
445
465
|
if (cachedComponent) {
|
|
446
|
-
if (mounted) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
466
|
+
if (mounted) setPageState({
|
|
467
|
+
source: component,
|
|
468
|
+
Component: cachedComponent,
|
|
469
|
+
loading: false,
|
|
470
|
+
error: null
|
|
471
|
+
});
|
|
451
472
|
return;
|
|
452
473
|
}
|
|
453
|
-
if (mounted) {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
474
|
+
if (mounted) setPageState({
|
|
475
|
+
source: component,
|
|
476
|
+
Component: null,
|
|
477
|
+
loading: true,
|
|
478
|
+
error: null
|
|
479
|
+
});
|
|
457
480
|
if (typeof component === "function") {
|
|
458
481
|
const result = component();
|
|
459
482
|
let isThenable = false;
|
|
@@ -467,21 +490,44 @@ function LazyPageRenderer({ config }) {
|
|
|
467
490
|
if (mod.default) resolved = mod.default;
|
|
468
491
|
else resolved = mod;
|
|
469
492
|
cacheComponent(component, resolved);
|
|
470
|
-
|
|
493
|
+
setPageState({
|
|
494
|
+
source: component,
|
|
495
|
+
Component: resolved,
|
|
496
|
+
loading: false,
|
|
497
|
+
error: null
|
|
498
|
+
});
|
|
471
499
|
}
|
|
472
|
-
} else if (mounted)
|
|
500
|
+
} else if (mounted) setPageState({
|
|
501
|
+
source: component,
|
|
502
|
+
Component: component,
|
|
503
|
+
loading: false,
|
|
504
|
+
error: null
|
|
505
|
+
});
|
|
473
506
|
} else if (component) {
|
|
474
|
-
if (mounted)
|
|
475
|
-
|
|
476
|
-
|
|
507
|
+
if (mounted) setPageState({
|
|
508
|
+
source: component,
|
|
509
|
+
Component: component,
|
|
510
|
+
loading: false,
|
|
511
|
+
error: null
|
|
512
|
+
});
|
|
513
|
+
} else if (mounted) setPageState({
|
|
514
|
+
source: component,
|
|
515
|
+
Component: null,
|
|
516
|
+
loading: false,
|
|
517
|
+
error: null
|
|
518
|
+
});
|
|
477
519
|
} catch (err) {
|
|
478
520
|
if (mounted) {
|
|
479
521
|
let resolvedError;
|
|
480
522
|
if (err instanceof Error) resolvedError = err;
|
|
481
523
|
else resolvedError = new Error(t("error.failedToLoad"));
|
|
482
|
-
|
|
524
|
+
setPageState({
|
|
525
|
+
source: component,
|
|
526
|
+
Component: null,
|
|
527
|
+
loading: false,
|
|
528
|
+
error: resolvedError
|
|
529
|
+
});
|
|
483
530
|
}
|
|
484
|
-
if (mounted) setLoading(false);
|
|
485
531
|
}
|
|
486
532
|
}
|
|
487
533
|
load();
|
|
@@ -489,21 +535,22 @@ function LazyPageRenderer({ config }) {
|
|
|
489
535
|
mounted = false;
|
|
490
536
|
};
|
|
491
537
|
}, [component, t]);
|
|
492
|
-
if (loading) {
|
|
538
|
+
if (!(pageState.source === component) || pageState.loading) {
|
|
493
539
|
const path = config.path?.replace(/^\//, "") ?? "";
|
|
494
540
|
return AUTH_ROUTE_SEGMENTS.has(path) ? /* @__PURE__ */ jsx(AuthPageSkeleton, {}) : /* @__PURE__ */ jsx(RouterSkeleton, {});
|
|
495
541
|
}
|
|
496
|
-
if (error) return /* @__PURE__ */ jsxs("div", {
|
|
542
|
+
if (pageState.error) return /* @__PURE__ */ jsxs("div", {
|
|
497
543
|
className: "container",
|
|
498
544
|
children: [/* @__PURE__ */ jsx("h1", {
|
|
499
|
-
className: "text-destructive mb-4 text-2xl font-
|
|
545
|
+
className: "text-destructive mb-4 text-2xl font-semibold",
|
|
500
546
|
children: t("error.unexpectedError")
|
|
501
547
|
}), /* @__PURE__ */ jsx("p", {
|
|
502
548
|
className: "text-muted-foreground",
|
|
503
|
-
children: error.message
|
|
549
|
+
children: pageState.error.message
|
|
504
550
|
})]
|
|
505
551
|
});
|
|
506
|
-
|
|
552
|
+
const PageComponent = pageState.Component;
|
|
553
|
+
return PageComponent ? /* @__PURE__ */ jsx(PageComponent, {}) : /* @__PURE__ */ jsx(DefaultNotFound, {});
|
|
507
554
|
}
|
|
508
555
|
/**
|
|
509
556
|
* AdminRouter Component
|
|
@@ -5,7 +5,7 @@ import { useSafeContentLocales } from "../../runtime/content-locales-provider.mj
|
|
|
5
5
|
import { ComponentRenderer } from "../../components/component-renderer.mjs";
|
|
6
6
|
import { Button } from "../../components/ui/button.mjs";
|
|
7
7
|
import { getFlagUrl } from "../../utils/locale-to-flag.mjs";
|
|
8
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "../../components/ui/dropdown-menu.mjs";
|
|
8
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "../../components/ui/dropdown-menu.mjs";
|
|
9
9
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../../components/ui/tooltip.mjs";
|
|
10
10
|
import { useAdminConfig } from "../../hooks/use-admin-config.mjs";
|
|
11
11
|
import { useLazyComponent } from "../../utils/use-lazy-component.mjs";
|
|
@@ -222,7 +222,7 @@ function isRouteActive(activeRoute, itemHref, basePath, exact = false) {
|
|
|
222
222
|
/**
|
|
223
223
|
* Menu button styles - QUESTPIE design: clean, technical look
|
|
224
224
|
*/
|
|
225
|
-
const menuButtonStyles = cn("item-surface font-chrome flex w-full items-center gap-2
|
|
225
|
+
const menuButtonStyles = cn("item-surface font-chrome flex w-full items-center gap-2 p-2 text-[13px] font-medium transition-[background-color,color,border-color,transform] duration-[var(--motion-duration-base)] ease-[var(--motion-ease-standard)] active:scale-[0.96] motion-reduce:transition-none motion-reduce:active:scale-100", "text-sidebar-foreground/75 hover:bg-sidebar-accent hover:text-sidebar-foreground", "focus-visible:ring-sidebar-ring focus-visible:ring-1 focus-visible:outline-none", "group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-2");
|
|
226
226
|
const menuButtonActiveStyles = cn("border-transparent bg-[var(--sidebar-active-background)] text-[var(--sidebar-active-foreground)]");
|
|
227
227
|
function NavItem({ item, isActive, LinkComponent, renderNavItem, useActiveProps, className, depth = 0 }) {
|
|
228
228
|
const { state, isMobile, setOpenMobile } = useSidebar();
|
|
@@ -423,7 +423,7 @@ function UserFooter({ theme = "system", setTheme, showThemeToggle }) {
|
|
|
423
423
|
const setContentLocale = useAdminStore(selectSetContentLocale);
|
|
424
424
|
const hasMultipleContentLocales = (contentLocales?.locales?.length ?? 0) > 1;
|
|
425
425
|
const shouldShowThemeToggle = !!setTheme && showThemeToggle !== false;
|
|
426
|
-
const themeOptions = [
|
|
426
|
+
const themeOptions = React.useMemo(() => [
|
|
427
427
|
{
|
|
428
428
|
value: "light",
|
|
429
429
|
label: t("ui.themeLight"),
|
|
@@ -439,7 +439,10 @@ function UserFooter({ theme = "system", setTheme, showThemeToggle }) {
|
|
|
439
439
|
label: t("ui.themeSystem"),
|
|
440
440
|
icon: "ph:monitor"
|
|
441
441
|
}
|
|
442
|
-
];
|
|
442
|
+
], [t]);
|
|
443
|
+
const handleThemeChange = React.useCallback((value) => {
|
|
444
|
+
setTheme?.(value);
|
|
445
|
+
}, [setTheme]);
|
|
443
446
|
const closeSidebarOnMobile = React.useCallback(() => {
|
|
444
447
|
if (isMobile) setOpenMobile(false);
|
|
445
448
|
}, [isMobile, setOpenMobile]);
|
|
@@ -527,23 +530,21 @@ function UserFooter({ theme = "system", setTheme, showThemeToggle }) {
|
|
|
527
530
|
className: "size-4"
|
|
528
531
|
}), t("auth.myAccount")]
|
|
529
532
|
}),
|
|
530
|
-
shouldShowThemeToggle && /* @__PURE__ */ jsxs(
|
|
531
|
-
|
|
532
|
-
children:
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
]
|
|
546
|
-
}, option.value)) })] }),
|
|
533
|
+
shouldShowThemeToggle && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
534
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
535
|
+
/* @__PURE__ */ jsx(DropdownMenuLabel, { children: t("ui.toggleTheme") }),
|
|
536
|
+
/* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
|
|
537
|
+
value: theme,
|
|
538
|
+
onValueChange: handleThemeChange,
|
|
539
|
+
children: themeOptions.map((option) => /* @__PURE__ */ jsxs(DropdownMenuRadioItem, {
|
|
540
|
+
value: option.value,
|
|
541
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
542
|
+
icon: option.icon,
|
|
543
|
+
className: "size-4"
|
|
544
|
+
}), /* @__PURE__ */ jsx("span", { children: option.label })]
|
|
545
|
+
}, option.value))
|
|
546
|
+
})
|
|
547
|
+
] }),
|
|
547
548
|
hasMultipleUiLocales && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Icon, { icon: "ph:globe" }), t("locale.uiLanguage")] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: uiLocaleOptions.map((locale) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
548
549
|
onClick: () => setUiLocale(locale.code),
|
|
549
550
|
children: [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime19 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/components/rich-text/rich-text-renderer.d.ts
|
|
4
4
|
/**
|
|
@@ -98,6 +98,6 @@ declare function RichTextRenderer({
|
|
|
98
98
|
content,
|
|
99
99
|
styles: customStyles,
|
|
100
100
|
className
|
|
101
|
-
}: RichTextRendererProps):
|
|
101
|
+
}: RichTextRendererProps): react_jsx_runtime19.JSX.Element | null;
|
|
102
102
|
//#endregion
|
|
103
103
|
export { RichTextRenderer, RichTextStyles, TipTapDoc, TipTapNode };
|
|
@@ -1,5 +1,47 @@
|
|
|
1
|
+
import { categoryRecordEntry, importStatement, sortedValues } from "questpie/codegen";
|
|
2
|
+
|
|
1
3
|
//#region src/server/codegen/admin-client-template.ts
|
|
2
4
|
/**
|
|
5
|
+
* Admin Client Template Generator
|
|
6
|
+
*
|
|
7
|
+
* Custom generator for the `admin-client` codegen target.
|
|
8
|
+
* Produces `questpie/admin/.generated/client.ts` — a plain admin config
|
|
9
|
+
* object that merges module defaults with user-discovered files.
|
|
10
|
+
*
|
|
11
|
+
* ## Architecture
|
|
12
|
+
*
|
|
13
|
+
* The admin-client target works identically to the server target:
|
|
14
|
+
*
|
|
15
|
+
* 1. **Package mode** (`generatePackageModules`): discovers files from
|
|
16
|
+
* `modules/admin/client/` → generates `modules/admin/client/.generated/module.ts`
|
|
17
|
+
* using the standard `generateModuleTemplate()` primitive.
|
|
18
|
+
*
|
|
19
|
+
* 2. **Root app mode** (`runAllTargets`): user has `admin/modules.ts` that imports
|
|
20
|
+
* module packages → this template imports `_mod` and merges generically with
|
|
21
|
+
* user-discovered files from `admin/{blocks,views,fields,...}/`.
|
|
22
|
+
*
|
|
23
|
+
* ## How to create an admin-client module (for third-party packages)
|
|
24
|
+
*
|
|
25
|
+
* 1. Create wrapper files in `modules/<name>/client/{fields,views,...}/`
|
|
26
|
+
* 2. Run `questpie generate` — generates `client/.generated/module.ts`
|
|
27
|
+
* 3. Create `client/index.ts` that re-exports the generated module
|
|
28
|
+
* 4. Add `"./client/module"` to `package.json` exports
|
|
29
|
+
*
|
|
30
|
+
* ## How users extend admin
|
|
31
|
+
*
|
|
32
|
+
* Add files in `questpie/admin/{views,fields,pages,widgets,blocks,components}/`.
|
|
33
|
+
* They are discovered automatically and merged over module defaults.
|
|
34
|
+
*
|
|
35
|
+
* ## Category key strategies
|
|
36
|
+
*
|
|
37
|
+
* - Default: use file key — `"bookingCta": _block_bookingCta`
|
|
38
|
+
* - `keyFromProperty: "name"`: use runtime key — `[_view_kanban.name]: _view_kanban`
|
|
39
|
+
*
|
|
40
|
+
* The strategy is declared per-category in `CategoryDeclaration.keyFromProperty`.
|
|
41
|
+
*
|
|
42
|
+
* @see PLAN-PLUGIN-CONSISTENCY.md §6.2 (admin-client target)
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
3
45
|
* Generate the admin client config file.
|
|
4
46
|
*
|
|
5
47
|
* Called by `runAllTargets()` for the `admin-client` target.
|
|
@@ -18,7 +60,7 @@ function generateAdminClientTemplate(ctx) {
|
|
|
18
60
|
lines.push(" */");
|
|
19
61
|
lines.push("");
|
|
20
62
|
if (modulesFile) {
|
|
21
|
-
lines.push(
|
|
63
|
+
lines.push(importStatement(modulesFile));
|
|
22
64
|
lines.push(`const _mergedModules = Array.isArray(${modulesFile.varName})`);
|
|
23
65
|
lines.push(`\t? ${modulesFile.varName}.reduce((acc: any, m: any) => {`);
|
|
24
66
|
lines.push(" for (const [k, v] of Object.entries(m)) acc[k] = typeof v === \"object\" && v !== null && !Array.isArray(v) ? { ...acc[k], ...v } : v;");
|
|
@@ -27,15 +69,15 @@ function generateAdminClientTemplate(ctx) {
|
|
|
27
69
|
}
|
|
28
70
|
const categoryFiles = /* @__PURE__ */ new Map();
|
|
29
71
|
for (const [cat, fileMap] of ctx.discovered.categories) if (fileMap.size > 0) {
|
|
30
|
-
const sorted =
|
|
72
|
+
const sorted = sortedValues(fileMap);
|
|
31
73
|
categoryFiles.set(cat, sorted);
|
|
32
|
-
for (const file of sorted) lines.push(
|
|
74
|
+
for (const file of sorted) lines.push(importStatement(file));
|
|
33
75
|
}
|
|
34
76
|
const singleFiles = /* @__PURE__ */ new Map();
|
|
35
77
|
for (const [key, file] of ctx.discovered.singles) {
|
|
36
78
|
if (key === "modules") continue;
|
|
37
79
|
singleFiles.set(key, file);
|
|
38
|
-
lines.push(
|
|
80
|
+
lines.push(importStatement(file));
|
|
39
81
|
}
|
|
40
82
|
for (const imp of ctx.extraImports) lines.push(`import ${imp.name} from "${imp.path}";`);
|
|
41
83
|
lines.push("");
|
|
@@ -52,11 +94,11 @@ function generateAdminClientTemplate(ctx) {
|
|
|
52
94
|
const files = categoryFiles.get(cat);
|
|
53
95
|
const catDecl = ctx.target.categories?.[cat];
|
|
54
96
|
if (modulesFile && files && files.length > 0) {
|
|
55
|
-
const entries =
|
|
97
|
+
const entries = files.map((f) => categoryRecordEntry(f, catDecl)).join(", ");
|
|
56
98
|
lines.push(`\t${cat}: { ..._mergedModules.${cat}, ${entries} },`);
|
|
57
99
|
} else if (modulesFile && (!files || files.length === 0)) lines.push(`\t${cat}: { ..._mergedModules.${cat} },`);
|
|
58
100
|
else if (files && files.length > 0) {
|
|
59
|
-
const entries =
|
|
101
|
+
const entries = files.map((f) => categoryRecordEntry(f, catDecl)).join(", ");
|
|
60
102
|
lines.push(`\t${cat}: { ${entries} },`);
|
|
61
103
|
}
|
|
62
104
|
}
|
|
@@ -73,32 +115,6 @@ function generateAdminClientTemplate(ctx) {
|
|
|
73
115
|
lines.push("");
|
|
74
116
|
return { code: lines.join("\n") };
|
|
75
117
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Generate category entries string based on the category's key strategy.
|
|
78
|
-
*
|
|
79
|
-
* When `keyFromProperty` is set (e.g., views with `keyFromProperty: "name"`),
|
|
80
|
-
* uses runtime property as key: `[_view_kanban.name]: _view_kanban`.
|
|
81
|
-
*
|
|
82
|
-
* Otherwise uses the file-derived key: `"bookingCta": _block_bookingCta`.
|
|
83
|
-
*/
|
|
84
|
-
function generateCategoryEntries(files, catDecl) {
|
|
85
|
-
const keyProp = catDecl?.keyFromProperty;
|
|
86
|
-
return files.map((f) => {
|
|
87
|
-
if (keyProp) return `[${f.varName}.${keyProp}]: ${f.varName}`;
|
|
88
|
-
if (catDecl?.keyFromSource === "basename") return `${JSON.stringify(getSourceBasename(f))}: ${f.varName}`;
|
|
89
|
-
return `${JSON.stringify(f.key)}: ${f.varName}`;
|
|
90
|
-
}).join(", ");
|
|
91
|
-
}
|
|
92
|
-
function getSourceBasename(file) {
|
|
93
|
-
return (file.source.replaceAll("\\", "/").split("/").pop() ?? file.key).replace(/\.[^.]+$/, "");
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Generate an import line for a discovered file.
|
|
97
|
-
*/
|
|
98
|
-
function generateImportLine(file) {
|
|
99
|
-
if (file.exportType === "named" && file.namedExportName) return `import { ${file.namedExportName} as ${file.varName} } from "${file.importPath}";`;
|
|
100
|
-
return `import ${file.varName} from "${file.importPath}";`;
|
|
101
|
-
}
|
|
102
118
|
|
|
103
119
|
//#endregion
|
|
104
120
|
export { generateAdminClientTemplate };
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import * as
|
|
3
|
-
import * as
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
1
|
+
import * as questpie_shared40 from "questpie/shared";
|
|
2
|
+
import * as questpie242 from "questpie";
|
|
3
|
+
import * as questpie_src_server_modules_core_fields_email_js6 from "questpie/src/server/modules/core/fields/email.js";
|
|
4
|
+
import * as questpie_src_server_modules_core_fields_json_js6 from "questpie/src/server/modules/core/fields/json.js";
|
|
5
|
+
import * as drizzle_orm_pg_core61 from "drizzle-orm/pg-core";
|
|
6
|
+
import * as drizzle_orm43 from "drizzle-orm";
|
|
7
7
|
|
|
8
8
|
//#region src/server/modules/admin/collections/account.d.ts
|
|
9
|
-
declare const _default:
|
|
10
|
-
readonly text: typeof
|
|
11
|
-
readonly textarea: typeof
|
|
12
|
-
readonly email: typeof
|
|
13
|
-
readonly url: typeof
|
|
14
|
-
readonly number: typeof
|
|
15
|
-
readonly boolean: typeof
|
|
16
|
-
readonly date: typeof
|
|
17
|
-
readonly datetime: typeof
|
|
18
|
-
readonly time: typeof
|
|
19
|
-
readonly select: typeof
|
|
20
|
-
readonly upload: typeof
|
|
21
|
-
readonly relation: typeof
|
|
22
|
-
readonly object: typeof
|
|
23
|
-
readonly json: typeof
|
|
24
|
-
readonly from: typeof
|
|
9
|
+
declare const _default: questpie242.CollectionBuilder<questpie_shared40.Override<questpie242.EmptyCollectionState<"account", undefined, {
|
|
10
|
+
readonly text: typeof questpie242.text;
|
|
11
|
+
readonly textarea: typeof questpie242.textarea;
|
|
12
|
+
readonly email: typeof questpie_src_server_modules_core_fields_email_js6.email;
|
|
13
|
+
readonly url: typeof questpie242.url;
|
|
14
|
+
readonly number: typeof questpie242.number;
|
|
15
|
+
readonly boolean: typeof questpie242.boolean;
|
|
16
|
+
readonly date: typeof questpie242.date;
|
|
17
|
+
readonly datetime: typeof questpie242.datetime;
|
|
18
|
+
readonly time: typeof questpie242.time;
|
|
19
|
+
readonly select: typeof questpie242.select;
|
|
20
|
+
readonly upload: typeof questpie242.upload;
|
|
21
|
+
readonly relation: typeof questpie242.relation;
|
|
22
|
+
readonly object: typeof questpie242.object;
|
|
23
|
+
readonly json: typeof questpie_src_server_modules_core_fields_json_js6.json;
|
|
24
|
+
readonly from: typeof questpie242.from;
|
|
25
25
|
}>, {
|
|
26
26
|
name: "account";
|
|
27
27
|
fields: Record<string, any> & {
|
|
28
|
-
readonly userId:
|
|
29
|
-
readonly accountId:
|
|
30
|
-
readonly providerId:
|
|
31
|
-
readonly accessToken:
|
|
32
|
-
readonly refreshToken:
|
|
33
|
-
readonly accessTokenExpiresAt:
|
|
34
|
-
readonly refreshTokenExpiresAt:
|
|
35
|
-
readonly scope:
|
|
36
|
-
readonly idToken:
|
|
37
|
-
readonly password:
|
|
28
|
+
readonly userId: drizzle_orm43.NotNull<drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>>;
|
|
29
|
+
readonly accountId: drizzle_orm43.NotNull<drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>>;
|
|
30
|
+
readonly providerId: drizzle_orm43.NotNull<drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>>;
|
|
31
|
+
readonly accessToken: drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>;
|
|
32
|
+
readonly refreshToken: drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>;
|
|
33
|
+
readonly accessTokenExpiresAt: drizzle_orm_pg_core61.PgTimestampBuilder;
|
|
34
|
+
readonly refreshTokenExpiresAt: drizzle_orm_pg_core61.PgTimestampBuilder;
|
|
35
|
+
readonly scope: drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>;
|
|
36
|
+
readonly idToken: drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>;
|
|
37
|
+
readonly password: drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>;
|
|
38
38
|
};
|
|
39
39
|
virtuals: undefined;
|
|
40
|
-
relations: Record<string,
|
|
40
|
+
relations: Record<string, questpie242.RelationConfig>;
|
|
41
41
|
indexes: Record<string, any>;
|
|
42
42
|
title: "providerId";
|
|
43
|
-
options:
|
|
43
|
+
options: questpie242.CollectionOptions & {
|
|
44
44
|
timestamps: true;
|
|
45
45
|
};
|
|
46
46
|
hooks: Record<string, any>;
|
|
47
47
|
access: Record<string, any>;
|
|
48
48
|
searchable: undefined;
|
|
49
49
|
fieldDefinitions: {
|
|
50
|
-
readonly userId:
|
|
50
|
+
readonly userId: questpie242.FieldWithMethods<Omit<questpie242.TextFieldState, "notNull" | "column"> & {
|
|
51
51
|
notNull: true;
|
|
52
|
-
column:
|
|
53
|
-
},
|
|
54
|
-
readonly accountId:
|
|
52
|
+
column: drizzle_orm43.NotNull<drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>>;
|
|
53
|
+
}, questpie242.TextFieldMethods>;
|
|
54
|
+
readonly accountId: questpie242.FieldWithMethods<Omit<questpie242.TextFieldState, "notNull" | "column"> & {
|
|
55
55
|
notNull: true;
|
|
56
|
-
column:
|
|
57
|
-
},
|
|
58
|
-
readonly providerId:
|
|
56
|
+
column: drizzle_orm43.NotNull<drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>>;
|
|
57
|
+
}, questpie242.TextFieldMethods>;
|
|
58
|
+
readonly providerId: questpie242.FieldWithMethods<Omit<questpie242.TextFieldState, "notNull" | "column"> & {
|
|
59
59
|
notNull: true;
|
|
60
|
-
column:
|
|
61
|
-
},
|
|
62
|
-
readonly accessToken:
|
|
63
|
-
readonly refreshToken:
|
|
64
|
-
readonly accessTokenExpiresAt:
|
|
65
|
-
readonly refreshTokenExpiresAt:
|
|
66
|
-
readonly scope:
|
|
67
|
-
readonly idToken:
|
|
68
|
-
readonly password:
|
|
60
|
+
column: drizzle_orm43.NotNull<drizzle_orm_pg_core61.PgVarcharBuilder<[string, ...string[]]>>;
|
|
61
|
+
}, questpie242.TextFieldMethods>;
|
|
62
|
+
readonly accessToken: questpie242.FieldWithMethods<questpie242.TextFieldState, questpie242.TextFieldMethods>;
|
|
63
|
+
readonly refreshToken: questpie242.FieldWithMethods<questpie242.TextFieldState, questpie242.TextFieldMethods>;
|
|
64
|
+
readonly accessTokenExpiresAt: questpie242.FieldWithMethods<questpie242.DatetimeFieldState, questpie242.DatetimeFieldMethods>;
|
|
65
|
+
readonly refreshTokenExpiresAt: questpie242.FieldWithMethods<questpie242.DatetimeFieldState, questpie242.DatetimeFieldMethods>;
|
|
66
|
+
readonly scope: questpie242.FieldWithMethods<questpie242.TextFieldState, questpie242.TextFieldMethods>;
|
|
67
|
+
readonly idToken: questpie242.FieldWithMethods<questpie242.TextFieldState, questpie242.TextFieldMethods>;
|
|
68
|
+
readonly password: questpie242.FieldWithMethods<questpie242.TextFieldState, questpie242.TextFieldMethods>;
|
|
69
69
|
};
|
|
70
70
|
upload: undefined;
|
|
71
71
|
output: {};
|