betterstart-cli 0.0.95 → 0.0.97
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/assets/adapters/next/integrations/_shared/actions/object-key.ts +16 -0
- package/dist/assets/adapters/next/integrations/r2/actions/r2.ts +6 -14
- package/dist/assets/adapters/next/integrations/r2/integration.ts +4 -0
- package/dist/assets/adapters/next/integrations/railway-bucket/actions/railway-bucket.ts +7 -15
- package/dist/assets/adapters/next/integrations/railway-bucket/integration.ts +4 -0
- package/dist/assets/adapters/next/integrations/vercel-blob/actions/vercel-blob.ts +2 -10
- package/dist/assets/adapters/next/integrations/vercel-blob/integration.ts +4 -0
- package/dist/assets/adapters/next/templates/init/api/upload-route.ts +37 -13
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-header.tsx +6 -6
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-branding-skeleton.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-user-menu-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-user-menu.tsx +8 -8
- package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar.tsx +4 -4
- package/dist/assets/adapters/next/templates/init/components/layouts/content-skeleton.tsx +4 -4
- package/dist/assets/adapters/next/templates/init/components/layouts/sidebar-branding.tsx +4 -4
- package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-grid.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table-pagination.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/delete-dialog.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/copyable-code-block.tsx +5 -5
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/plain-code-fallback.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode-integrate.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/entity-filters-bar.tsx +5 -5
- package/dist/assets/adapters/next/templates/init/components/shared/entity-metadata.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-version-item.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-current-row.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/media/edit-media-dialog-content.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-drawer.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-filters-bar.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-gallery-dialog.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-item.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-pagination.tsx +4 -4
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-preview.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/components/shared/page-header.tsx +4 -4
- package/dist/assets/adapters/next/templates/init/components/shared/search-input.tsx +5 -5
- package/dist/assets/adapters/next/templates/init/components/shared/sort-indicator.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/sort-order-dialog.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/sort-order-drag-overlay-item.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/components/shared/sort-order-item.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-color-highlight.ts +10 -64
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-source-mode.tsx +11 -4
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-heading-dropdown-menu.ts +0 -1
- package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-list-dropdown-menu.ts +0 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/audit/get-audit-logs.ts +5 -10
- package/dist/assets/adapters/next/templates/init/lib/actions/forms/index.ts +1 -5
- package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +6 -6
- package/dist/assets/adapters/next/templates/init/lib/actions/media/get-media.ts +4 -1
- package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +5 -5
- package/dist/assets/adapters/next/templates/init/lib/actions/profile/index.ts +1 -5
- package/dist/assets/adapters/next/templates/init/lib/actions/upload/index.ts +1 -5
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhook-deliveries.ts +1 -10
- package/dist/assets/adapters/next/templates/init/lib/actions/webhooks/get-webhooks.ts +1 -10
- package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +4 -1
- package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +1 -1
- package/dist/assets/adapters/next/templates/init/pages/admin-layout.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/auth-gate-rsc.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/dashboard-page.tsx +6 -6
- package/dist/assets/adapters/next/templates/init/pages/forgot-password-form.tsx +4 -4
- package/dist/assets/adapters/next/templates/init/pages/login-form.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/pages/media/media-page-content.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/pages/media/media-page-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/minimal-account-shell.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/pages/profile/profile-page.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/reset-password-form.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-columns.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-detail-drawer.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-detail-row.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-page-content.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-page-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/audit-log/audit-log-table.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-page-content.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-page-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/forms/forms-settings-table.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhook-endpoint-dialog.tsx +3 -3
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-columns.tsx +6 -6
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-columns.tsx +7 -7
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-page-content.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-logs-table.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-page-content.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-page-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/settings/webhooks/webhooks-table.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/pages/users/columns.tsx +4 -4
- package/dist/assets/adapters/next/templates/init/pages/users/users-page-content.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/users/users-page-skeleton.tsx +1 -1
- package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +5 -5
- package/dist/assets/adapters/next/templates/init/types/table-meta.ts +1 -1
- package/dist/assets/adapters/next/templates/init/utils/date/date.ts +15 -0
- package/dist/assets/adapters/next/templates/init/utils/editor/content-editor.ts +98 -25
- package/dist/assets/adapters/next/templates/init/utils/editor/markdown.ts +5 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/editor-toolbar.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/index.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/main-toolbar-content.tsx +4 -4
- package/dist/assets/shared-assets/react-admin/custom/content-editor/math-bubble-menu.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/math-editor-controls.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/mobile-toolbar-content.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/remove-table-part-icon.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/selection-bubble-menu.tsx +5 -5
- package/dist/assets/shared-assets/react-admin/custom/content-editor/slash-command-menu.tsx +6 -6
- package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode.tsx +11 -9
- package/dist/assets/shared-assets/react-admin/custom/content-editor/table-add-controls.tsx +3 -3
- package/dist/assets/shared-assets/react-admin/custom/content-editor/table-bubble-menu.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/blockquote-button/blockquote-button.tsx +1 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/code-block-button/code-block-button.tsx +1 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-button/color-highlight-button.tsx +2 -3
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover-content.tsx +4 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover.tsx +3 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/source-color-highlight-popover.tsx +5 -3
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +2 -1
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-main.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-popover.tsx +1 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/mark-button/mark-button.tsx +1 -2
- package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/undo-redo-button/undo-redo-button.tsx +1 -2
- package/dist/assets/shared-assets/react-admin/custom/date-picker.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/custom/gallery-field.tsx +6 -6
- package/dist/assets/shared-assets/react-admin/custom/icon-picker.tsx +10 -8
- package/dist/assets/shared-assets/react-admin/custom/icons-column-skeleton.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/custom/media-field-empty-state.tsx +5 -5
- package/dist/assets/shared-assets/react-admin/custom/media-field.tsx +7 -7
- package/dist/assets/shared-assets/react-admin/custom/nested-object-list-field.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/custom/placeholder-card.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/placeholder.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/progressive-blur.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/custom/sortable-gallery-item.tsx +3 -3
- package/dist/assets/shared-assets/react-admin/custom/upload-dropzone.tsx +6 -6
- package/dist/assets/shared-assets/react-admin/schema.json +1143 -876
- package/dist/assets/shared-assets/react-admin/ui/accordion.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/alert-dialog.tsx +4 -4
- package/dist/assets/shared-assets/react-admin/ui/badge.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/button-group.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/button.tsx +6 -6
- package/dist/assets/shared-assets/react-admin/ui/card.tsx +5 -5
- package/dist/assets/shared-assets/react-admin/ui/checkbox.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/combobox.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/command.tsx +0 -1
- package/dist/assets/shared-assets/react-admin/ui/context-menu.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/ui/dialog.tsx +3 -3
- package/dist/assets/shared-assets/react-admin/ui/drawer.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/dropdown-menu.tsx +3 -3
- package/dist/assets/shared-assets/react-admin/ui/field.tsx +0 -1
- package/dist/assets/shared-assets/react-admin/ui/input-group.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/ui/input.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/menubar.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/ui/pagination.tsx +0 -1
- package/dist/assets/shared-assets/react-admin/ui/scroll-area.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/select.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/ui/sidebar.tsx +4 -4
- package/dist/assets/shared-assets/react-admin/ui/table.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/tabs.tsx +2 -2
- package/dist/assets/shared-assets/react-admin/ui/textarea.tsx +1 -1
- package/dist/assets/shared-assets/react-admin/ui/tooltip.tsx +1 -1
- package/dist/{chunk-3CLINNJL.js → chunk-MJWUGEMK.js} +32 -8
- package/dist/chunk-MJWUGEMK.js.map +1 -0
- package/dist/cli.js +8554 -9062
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{template-reader-PVN53GS7.js → template-reader-R2JIWUNK.js} +2 -2
- package/package.json +3 -3
- package/dist/chunk-3CLINNJL.js.map +0 -1
- /package/dist/{template-reader-PVN53GS7.js.map → template-reader-R2JIWUNK.js.map} +0 -0
|
@@ -24,7 +24,7 @@ export function EntityVersionItem({
|
|
|
24
24
|
const authorLabel = author?.name || author?.email || 'System'
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
|
-
<div className="flex items-center justify-between gap-3 rounded-sm border border-border
|
|
27
|
+
<div className="flex items-center justify-between gap-3 rounded-sm border border-border px-3 py-3 shadow-input">
|
|
28
28
|
<div className="flex min-w-0 items-center gap-3">
|
|
29
29
|
<Avatar size="sm">
|
|
30
30
|
{author?.image ? <AvatarImage src={author.image} alt={authorLabel} /> : null}
|
|
@@ -22,7 +22,7 @@ export function EntityVersionsCurrentRow({ updatedAt, author }: EntityVersionsCu
|
|
|
22
22
|
const authorLabel = author?.name || author?.email || 'System'
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
|
-
<div className="flex items-center justify-between gap-3 rounded-sm border border-border
|
|
25
|
+
<div className="flex items-center justify-between gap-3 rounded-sm border border-border bg-card px-3 py-3 shadow-input">
|
|
26
26
|
<div className="flex min-w-0 items-center gap-3">
|
|
27
27
|
<Avatar size="sm">
|
|
28
28
|
{author?.image ? <AvatarImage src={author.image} alt={authorLabel} /> : null}
|
|
@@ -95,7 +95,7 @@ export function EditMediaDialogContent({
|
|
|
95
95
|
ref={handleDrawerContainerRef}
|
|
96
96
|
className="pointer-events-none absolute inset-3 z-20 overflow-hidden rounded-sm"
|
|
97
97
|
/>
|
|
98
|
-
<div className="relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden
|
|
98
|
+
<div className="relative z-10 flex min-h-0 flex-1 flex-col gap-3 overflow-hidden">
|
|
99
99
|
<DrawerHeader>
|
|
100
100
|
<DrawerTitle>Media file</DrawerTitle>
|
|
101
101
|
</DrawerHeader>
|
|
@@ -103,7 +103,7 @@ export function EditMediaDialogContent({
|
|
|
103
103
|
<form
|
|
104
104
|
id={formId}
|
|
105
105
|
onSubmit={form.handleSubmit(handleSave)}
|
|
106
|
-
className="flex flex-1 flex-col gap-4 overflow-y-auto px-6 pb-4
|
|
106
|
+
className="flex flex-1 flex-col gap-4 overflow-y-auto px-6 pt-px pb-4"
|
|
107
107
|
>
|
|
108
108
|
<Card>
|
|
109
109
|
<CardContent className="p-0">
|
|
@@ -112,7 +112,7 @@ export function EditMediaDialogContent({
|
|
|
112
112
|
</div>
|
|
113
113
|
</CardContent>
|
|
114
114
|
|
|
115
|
-
<CardFooter className="grid w-full pt-5
|
|
115
|
+
<CardFooter className="grid w-full gap-1 pt-5 pb-3">
|
|
116
116
|
<div className="grid w-full gap-2">
|
|
117
117
|
<div className="flex w-full min-w-0 items-center gap-x-2">
|
|
118
118
|
<div className="flex min-w-0 flex-1 items-center gap-x-2 text-muted-foreground">
|
package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-drawer.tsx
CHANGED
|
@@ -110,7 +110,7 @@ export function MediaDeleteDrawer({
|
|
|
110
110
|
>
|
|
111
111
|
<div
|
|
112
112
|
ref={contentRef}
|
|
113
|
-
className="max-h-[calc(100vh-8rem)] overflow-y-auto px-4
|
|
113
|
+
className="max-h-[calc(100vh-8rem)] overflow-y-auto px-4 pt-4 pb-4"
|
|
114
114
|
>
|
|
115
115
|
<div aria-hidden="true" className="mx-auto mb-5 h-1.5 w-20 rounded-sm bg-muted" />
|
|
116
116
|
<div className="mb-3 flex size-10 items-center justify-center rounded-sm bg-destructive/10 text-foreground">
|
package/dist/assets/adapters/next/templates/init/components/shared/media/media-filters-bar.tsx
CHANGED
|
@@ -48,13 +48,13 @@ export function MediaFiltersBar({
|
|
|
48
48
|
return (
|
|
49
49
|
<div
|
|
50
50
|
className={cn(
|
|
51
|
-
'sticky z-9 flex flex-col gap-1
|
|
51
|
+
'sticky top-14 z-9 flex h-16 flex-col gap-1 overflow-clip bg-background px-4 transition-shadow xl:flex-row xl:items-center xl:justify-between',
|
|
52
52
|
{
|
|
53
53
|
'shadow-modal/3': hasScrolled
|
|
54
54
|
}
|
|
55
55
|
)}
|
|
56
56
|
>
|
|
57
|
-
<div className="flex flex-1 items-center gap-1
|
|
57
|
+
<div className="flex w-full flex-1 items-center gap-1">
|
|
58
58
|
<SearchInput
|
|
59
59
|
value={search}
|
|
60
60
|
placeholder={contentType === 'all' ? 'Search media...' : `Search ${contentType}s...`}
|
package/dist/assets/adapters/next/templates/init/components/shared/media/media-gallery-dialog.tsx
CHANGED
|
@@ -99,7 +99,7 @@ export function MediaGalleryDialog({
|
|
|
99
99
|
onOpenChange(next)
|
|
100
100
|
}}
|
|
101
101
|
>
|
|
102
|
-
<DialogContent className="flex
|
|
102
|
+
<DialogContent className="flex h-[80svh] max-h-[700px] min-h-0 flex-col gap-0 overflow-hidden sm:max-w-3xl">
|
|
103
103
|
<DialogHeader>
|
|
104
104
|
<DialogTitle>Select file</DialogTitle>
|
|
105
105
|
<DialogDescription>
|
|
@@ -122,7 +122,7 @@ export function MediaGalleryDialog({
|
|
|
122
122
|
<TabsUi.TabsTrigger value="url">Import from URL</TabsUi.TabsTrigger>
|
|
123
123
|
</TabsUi.TabsList>
|
|
124
124
|
|
|
125
|
-
<TabsUi.TabsContent value="upload" className="min-h-0
|
|
125
|
+
<TabsUi.TabsContent value="upload" className="h-full min-h-0 flex-1">
|
|
126
126
|
<UploadDropzone
|
|
127
127
|
onFilesSelected={upload}
|
|
128
128
|
progress={progress}
|
package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-item.tsx
CHANGED
|
@@ -22,19 +22,19 @@ export const MediaGridItem = React.memo(function MediaGridItem({
|
|
|
22
22
|
}: MediaGridItemProps) {
|
|
23
23
|
return (
|
|
24
24
|
<Card
|
|
25
|
-
className={cn('relative
|
|
25
|
+
className={cn('group relative', {
|
|
26
26
|
'cursor-pointer': Boolean(onClick)
|
|
27
27
|
})}
|
|
28
28
|
onClick={onClick ? () => onClick(item) : undefined}
|
|
29
29
|
>
|
|
30
30
|
<CardContent
|
|
31
31
|
aria-pressed={isSelectMode && onClick ? selected : undefined}
|
|
32
|
-
className={cn('
|
|
32
|
+
className={cn('flex flex-col p-2', {
|
|
33
33
|
'hover:border-highlight': Boolean(onClick),
|
|
34
34
|
'border-highlight': selected
|
|
35
35
|
})}
|
|
36
36
|
>
|
|
37
|
-
<div className="flex size-full
|
|
37
|
+
<div className="flex aspect-square size-full overflow-hidden rounded-sm border border-border bg-background">
|
|
38
38
|
<MediaPreview media={item} isFilled />
|
|
39
39
|
</div>
|
|
40
40
|
|
package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-pagination.tsx
CHANGED
|
@@ -60,7 +60,7 @@ export function MediaGridPagination({
|
|
|
60
60
|
return (
|
|
61
61
|
<div
|
|
62
62
|
className={cn(
|
|
63
|
-
'pointer-events-none fixed right-0 bottom-0 left-(--admin-shell-content-left) z-10
|
|
63
|
+
'pointer-events-none fixed right-0 bottom-0 left-(--admin-shell-content-left) isolate z-10 flex flex-col transition-[left] duration-200 ease-linear',
|
|
64
64
|
{
|
|
65
65
|
static: isMinimal
|
|
66
66
|
},
|
|
@@ -69,9 +69,9 @@ export function MediaGridPagination({
|
|
|
69
69
|
>
|
|
70
70
|
<div
|
|
71
71
|
className={cn(
|
|
72
|
-
'pointer-events-auto flex
|
|
72
|
+
'pointer-events-auto flex h-(--admin-shell-bottom-bar-height) items-center justify-between border-t border-border/80 bg-background px-4 py-2 [--admin-shell-bottom-bar-height:53px]',
|
|
73
73
|
{
|
|
74
|
-
'border-none p-0
|
|
74
|
+
'border-none bg-transparent p-0': isMinimal
|
|
75
75
|
}
|
|
76
76
|
)}
|
|
77
77
|
>
|
|
@@ -79,7 +79,7 @@ export function MediaGridPagination({
|
|
|
79
79
|
<div className="flex items-center gap-2">
|
|
80
80
|
<span className="text-sm text-muted-foreground">{perPage}</span>
|
|
81
81
|
<Select value={pageSizeValue} onValueChange={handlePageSizeChange}>
|
|
82
|
-
<SelectTrigger className="w-25
|
|
82
|
+
<SelectTrigger className="h-8 w-25">
|
|
83
83
|
<SelectValue>{pageSize}</SelectValue>
|
|
84
84
|
</SelectTrigger>
|
|
85
85
|
<SelectContent>
|
|
@@ -17,7 +17,7 @@ export function MediaPreview({ media, isFilled = false, showMetadata = false }:
|
|
|
17
17
|
|
|
18
18
|
if (media.contentType.startsWith('image/') && !hasImageFailed) {
|
|
19
19
|
return (
|
|
20
|
-
<div className="flex size-full flex-col items-center justify-center overflow-hidden
|
|
20
|
+
<div className="relative flex size-full flex-col items-center justify-center overflow-hidden">
|
|
21
21
|
<Image
|
|
22
22
|
src={media.url}
|
|
23
23
|
alt={media.alt || media.filename}
|
|
@@ -35,7 +35,7 @@ export function MediaPreview({ media, isFilled = false, showMetadata = false }:
|
|
|
35
35
|
/>
|
|
36
36
|
|
|
37
37
|
{showMetadata && (
|
|
38
|
-
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-10 flex w-full items-center bg-[linear-gradient(to_top,color-mix(in_oklab,var(--primary)_86%,transparent)_0%,color-mix(in_oklab,var(--primary)_52%,transparent)_48%,transparent_100%)] px-3 py-2 text-left text-xs font-medium
|
|
38
|
+
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-10 flex w-full items-center justify-between gap-4 bg-[linear-gradient(to_top,color-mix(in_oklab,var(--primary)_86%,transparent)_0%,color-mix(in_oklab,var(--primary)_52%,transparent)_48%,transparent_100%)] px-3 py-2 text-left text-xs font-medium text-white">
|
|
39
39
|
<p className="truncate">{media.filename}</p>
|
|
40
40
|
<p className="shrink-0">
|
|
41
41
|
{media.contentType} · {(media.size / 1024).toFixed(1)} KB
|
|
@@ -48,7 +48,7 @@ export function MediaPreview({ media, isFilled = false, showMetadata = false }:
|
|
|
48
48
|
|
|
49
49
|
if (media.contentType.startsWith('image/')) {
|
|
50
50
|
return (
|
|
51
|
-
<div className="flex size-full items-center justify-center
|
|
51
|
+
<div className="flex size-full items-center justify-center border border-border/80 bg-background text-muted-foreground/30">
|
|
52
52
|
<ImageOff strokeWidth={1} className="size-12" />
|
|
53
53
|
</div>
|
|
54
54
|
)
|
package/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx
CHANGED
|
@@ -90,9 +90,9 @@ export function MediaUrlImporter({ onImportFromUrl, accept, className }: MediaUr
|
|
|
90
90
|
|
|
91
91
|
return (
|
|
92
92
|
<Card className={cn('flex items-center justify-center', className)}>
|
|
93
|
-
<CardContent className="
|
|
94
|
-
<div className="flex w-full flex-col
|
|
95
|
-
<InputGroup className="
|
|
93
|
+
<CardContent className="h-full w-full">
|
|
94
|
+
<div className="flex h-full w-full flex-col items-center justify-center gap-3 text-center">
|
|
95
|
+
<InputGroup className="mx-auto max-w-2xl bg-background">
|
|
96
96
|
<InputGroupInput
|
|
97
97
|
type="url"
|
|
98
98
|
name="url"
|
|
@@ -23,7 +23,7 @@ export function PageHeader({
|
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<>
|
|
26
|
-
<header className="fixed
|
|
26
|
+
<header className="fixed top-0 right-0 left-(--admin-shell-content-left) z-200 grid h-14 grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-center border-t border-b border-border/80 bg-sidebar px-4 transition-[left] duration-200 ease-linear">
|
|
27
27
|
<div className="flex w-full items-center justify-start gap-2">
|
|
28
28
|
{hasBackButton && (
|
|
29
29
|
<Button variant="ghost" size="icon" onClick={() => router.back()}>
|
|
@@ -35,9 +35,9 @@ export function PageHeader({
|
|
|
35
35
|
<h2 className="truncate text-sm font-medium tracking-tight">{title}</h2>
|
|
36
36
|
</div>
|
|
37
37
|
<div className="flex w-full min-w-0 items-center justify-end gap-2">
|
|
38
|
-
{children
|
|
39
|
-
{search
|
|
40
|
-
{actions
|
|
38
|
+
{children}
|
|
39
|
+
{search}
|
|
40
|
+
{actions}
|
|
41
41
|
</div>
|
|
42
42
|
</header>
|
|
43
43
|
<div className="h-14 shrink-0" aria-hidden="true" />
|
|
@@ -40,16 +40,16 @@ export function SearchInput({
|
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
42
|
<Form {...form}>
|
|
43
|
-
<form onSubmit={form.handleSubmit(onSubmit)} className="flex items-center
|
|
43
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="flex w-full items-center">
|
|
44
44
|
<FormField
|
|
45
45
|
control={form.control}
|
|
46
46
|
name="search"
|
|
47
47
|
render={({ field }) => (
|
|
48
48
|
<FormItem className="w-full">
|
|
49
49
|
<div className="relative w-full">
|
|
50
|
-
<Search className="
|
|
50
|
+
<Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-foreground" />
|
|
51
51
|
<FormControl>
|
|
52
|
-
<Input {...field} placeholder={placeholder} className="pl-9
|
|
52
|
+
<Input {...field} placeholder={placeholder} className="w-full pl-9" />
|
|
53
53
|
</FormControl>
|
|
54
54
|
|
|
55
55
|
{value ? (
|
|
@@ -63,7 +63,7 @@ export function SearchInput({
|
|
|
63
63
|
onSearch(null)
|
|
64
64
|
}}
|
|
65
65
|
aria-label="Clear search"
|
|
66
|
-
className="absolute
|
|
66
|
+
className="absolute top-1/2 right-2 size-7 -translate-y-1/2 text-foreground"
|
|
67
67
|
>
|
|
68
68
|
<X className="size-4" />
|
|
69
69
|
</Button>
|
|
@@ -72,7 +72,7 @@ export function SearchInput({
|
|
|
72
72
|
type="submit"
|
|
73
73
|
variant="ghost"
|
|
74
74
|
size="icon-sm"
|
|
75
|
-
className="absolute
|
|
75
|
+
className="absolute top-1/2 right-2 size-7 -translate-y-1/2 text-foreground"
|
|
76
76
|
disabled={isPending}
|
|
77
77
|
>
|
|
78
78
|
<CornerDownLeft className="size-4" />
|
|
@@ -18,7 +18,7 @@ export function SortIndicator({ direction }: { direction: false | 'asc' | 'desc'
|
|
|
18
18
|
<Icon
|
|
19
19
|
aria-hidden="true"
|
|
20
20
|
className={cn(
|
|
21
|
-
'size-4 shrink-0 text-muted-foreground opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-
|
|
21
|
+
'size-4 shrink-0 text-muted-foreground opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-hover/resize-header:opacity-100 group-focus-visible:opacity-100',
|
|
22
22
|
{
|
|
23
23
|
'text-foreground': direction !== false
|
|
24
24
|
}
|
|
@@ -194,7 +194,7 @@ export function SortOrderDialog({
|
|
|
194
194
|
onAnimationEnd={handleDrawerAnimationEnd}
|
|
195
195
|
>
|
|
196
196
|
<DrawerContent className="h-full w-full overflow-hidden">
|
|
197
|
-
<div className="relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden
|
|
197
|
+
<div className="relative z-10 flex min-h-0 flex-1 flex-col gap-3 overflow-hidden">
|
|
198
198
|
<DrawerHeader>
|
|
199
199
|
<DrawerTitle>{title}</DrawerTitle>
|
|
200
200
|
{description ? <DrawerDescription>{description}</DrawerDescription> : null}
|
package/dist/assets/adapters/next/templates/init/components/shared/sort-order-drag-overlay-item.tsx
CHANGED
|
@@ -6,7 +6,7 @@ export function DragOverlayItem({ label }: { label: string }) {
|
|
|
6
6
|
<Button
|
|
7
7
|
type="button"
|
|
8
8
|
variant="outline"
|
|
9
|
-
className="shrink-0
|
|
9
|
+
className="w-full shrink-0 cursor-grabbing touch-none justify-start gap-2 px-2 font-normal"
|
|
10
10
|
>
|
|
11
11
|
<GripVertical strokeWidth={1} />
|
|
12
12
|
<span className="min-w-0 truncate text-sm">{label}</span>
|
|
@@ -16,9 +16,9 @@ export function SortableItem({ id, label }: SortOrderItemData) {
|
|
|
16
16
|
type="button"
|
|
17
17
|
variant="outline"
|
|
18
18
|
className={cn(
|
|
19
|
-
'shrink-0
|
|
19
|
+
'w-full shrink-0 cursor-grab touch-none justify-start gap-2 px-2 font-normal active:cursor-grabbing',
|
|
20
20
|
{
|
|
21
|
-
'opacity-50
|
|
21
|
+
'z-20 opacity-50': isDragging
|
|
22
22
|
}
|
|
23
23
|
)}
|
|
24
24
|
{...attributes}
|
package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-color-highlight.ts
CHANGED
|
@@ -4,6 +4,11 @@ import { useIsBreakpoint } from '@admin/hooks/content-editor/use-is-breakpoint'
|
|
|
4
4
|
// --- Hooks ---
|
|
5
5
|
import { useTiptapEditor } from '@admin/hooks/content-editor/use-tiptap-editor'
|
|
6
6
|
// --- Lib ---
|
|
7
|
+
import {
|
|
8
|
+
CONTENT_EDITOR_HIGHLIGHT_COLOR_OPTIONS,
|
|
9
|
+
CONTENT_EDITOR_HIGHLIGHT_COLORS,
|
|
10
|
+
type ContentEditorHighlightColorOption
|
|
11
|
+
} from '@admin/utils/editor/content-editor'
|
|
7
12
|
import {
|
|
8
13
|
isExtensionAvailable,
|
|
9
14
|
isMarkInSchema,
|
|
@@ -16,69 +21,10 @@ import { useCallback, useEffect, useState } from 'react'
|
|
|
16
21
|
import { useHotkeys } from 'react-hotkeys-hook'
|
|
17
22
|
|
|
18
23
|
export const COLOR_HIGHLIGHT_SHORTCUT_KEY = 'mod+shift+h'
|
|
19
|
-
export const HIGHLIGHT_COLORS =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
colorValue: '#ffffff',
|
|
24
|
-
border: 'var(--tt-bg-color-contrast)'
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
label: 'Gray background',
|
|
28
|
-
value: 'var(--tt-color-highlight-gray)',
|
|
29
|
-
colorValue: '#f8f8f7',
|
|
30
|
-
border: 'var(--tt-color-highlight-gray-contrast)'
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
label: 'Brown background',
|
|
34
|
-
value: 'var(--tt-color-highlight-brown)',
|
|
35
|
-
colorValue: '#f4eeee',
|
|
36
|
-
border: 'var(--tt-color-highlight-brown-contrast)'
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
label: 'Orange background',
|
|
40
|
-
value: 'var(--tt-color-highlight-orange)',
|
|
41
|
-
colorValue: '#fbecdd',
|
|
42
|
-
border: 'var(--tt-color-highlight-orange-contrast)'
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
label: 'Yellow background',
|
|
46
|
-
value: 'var(--tt-color-highlight-yellow)',
|
|
47
|
-
colorValue: '#fef9c3',
|
|
48
|
-
border: 'var(--tt-color-highlight-yellow-contrast)'
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
label: 'Green background',
|
|
52
|
-
value: 'var(--tt-color-highlight-green)',
|
|
53
|
-
colorValue: '#dcfce7',
|
|
54
|
-
border: 'var(--tt-color-highlight-green-contrast)'
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
label: 'Blue background',
|
|
58
|
-
value: 'var(--tt-color-highlight-blue)',
|
|
59
|
-
colorValue: '#e0f2fe',
|
|
60
|
-
border: 'var(--tt-color-highlight-blue-contrast)'
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
label: 'Purple background',
|
|
64
|
-
value: 'var(--tt-color-highlight-purple)',
|
|
65
|
-
colorValue: '#f3e8ff',
|
|
66
|
-
border: 'var(--tt-color-highlight-purple-contrast)'
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
label: 'Pink background',
|
|
70
|
-
value: 'var(--tt-color-highlight-pink)',
|
|
71
|
-
colorValue: '#fcf1f6',
|
|
72
|
-
border: 'var(--tt-color-highlight-pink-contrast)'
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
label: 'Red background',
|
|
76
|
-
value: 'var(--tt-color-highlight-red)',
|
|
77
|
-
colorValue: '#ffe4e6',
|
|
78
|
-
border: 'var(--tt-color-highlight-red-contrast)'
|
|
79
|
-
}
|
|
80
|
-
]
|
|
81
|
-
export type HighlightColor = (typeof HIGHLIGHT_COLORS)[number]
|
|
24
|
+
export const HIGHLIGHT_COLORS = CONTENT_EDITOR_HIGHLIGHT_COLORS.map(
|
|
25
|
+
(name) => CONTENT_EDITOR_HIGHLIGHT_COLOR_OPTIONS[name]
|
|
26
|
+
)
|
|
27
|
+
export type HighlightColor = ContentEditorHighlightColorOption
|
|
82
28
|
|
|
83
29
|
export type HighlightMode = 'mark' | 'node'
|
|
84
30
|
|
|
@@ -133,7 +79,7 @@ export function pickHighlightColorsByValue(values: string[]) {
|
|
|
133
79
|
const colorMap = new Map(HIGHLIGHT_COLORS.map((color) => [color.value, color]))
|
|
134
80
|
return values
|
|
135
81
|
.map((value) => colorMap.get(value))
|
|
136
|
-
.filter((color): color is
|
|
82
|
+
.filter((color): color is ContentEditorHighlightColorOption => !!color)
|
|
137
83
|
}
|
|
138
84
|
|
|
139
85
|
/**
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from '@admin/utils/editor/markdown'
|
|
27
27
|
import { createMarkdownTextFromUrl } from '@admin/utils/editor/source-media'
|
|
28
28
|
import { sanitizeUrl } from '@admin/utils/editor/tiptap'
|
|
29
|
-
import { redo, undo } from '@codemirror/commands'
|
|
29
|
+
import { redo, redoDepth, undo, undoDepth } from '@codemirror/commands'
|
|
30
30
|
import { markdown } from '@codemirror/lang-markdown'
|
|
31
31
|
import { Decoration, EditorView, type ViewUpdate, WidgetType } from '@codemirror/view'
|
|
32
32
|
import { type QueryClient, QueryClientProvider, useQueryClient } from '@tanstack/react-query'
|
|
@@ -147,6 +147,8 @@ export function useContentEditorSourceMode({
|
|
|
147
147
|
} | null>(null)
|
|
148
148
|
const [markdownLinkUrl, setMarkdownLinkUrl] = React.useState<string | null>(null)
|
|
149
149
|
const [isMarkdownLinkActive, setIsMarkdownLinkActive] = React.useState(false)
|
|
150
|
+
const [canUndoMarkdownChange, setCanUndoMarkdownChange] = React.useState(false)
|
|
151
|
+
const [canRedoMarkdownChange, setCanRedoMarkdownChange] = React.useState(false)
|
|
150
152
|
const { resolvedTheme } = useTheme()
|
|
151
153
|
const editorTheme = React.useMemo(
|
|
152
154
|
() =>
|
|
@@ -313,8 +315,11 @@ export function useContentEditorSourceMode({
|
|
|
313
315
|
[onChange, onSelectionChange]
|
|
314
316
|
)
|
|
315
317
|
|
|
316
|
-
const
|
|
318
|
+
const handleEditorUpdate = React.useCallback(
|
|
317
319
|
(viewUpdate: ViewUpdate) => {
|
|
320
|
+
setCanUndoMarkdownChange(undoDepth(viewUpdate.state) > 0)
|
|
321
|
+
setCanRedoMarkdownChange(redoDepth(viewUpdate.state) > 0)
|
|
322
|
+
|
|
318
323
|
if (!viewUpdate.selectionSet) return
|
|
319
324
|
syncMarkdownLinkState(viewUpdate.view)
|
|
320
325
|
onSelectionChange?.(viewUpdate.state.selection.main.from)
|
|
@@ -348,7 +353,7 @@ export function useContentEditorSourceMode({
|
|
|
348
353
|
() => [
|
|
349
354
|
markdown(),
|
|
350
355
|
EditorView.lineWrapping,
|
|
351
|
-
EditorView.updateListener.of(
|
|
356
|
+
EditorView.updateListener.of(handleEditorUpdate),
|
|
352
357
|
EditorView.theme({
|
|
353
358
|
'&': {
|
|
354
359
|
backgroundColor: 'var(--background)',
|
|
@@ -397,7 +402,7 @@ export function useContentEditorSourceMode({
|
|
|
397
402
|
}),
|
|
398
403
|
...mediaGalleryExtensions
|
|
399
404
|
],
|
|
400
|
-
[
|
|
405
|
+
[handleEditorUpdate, mediaGalleryExtensions]
|
|
401
406
|
)
|
|
402
407
|
|
|
403
408
|
const insertInline = React.useCallback(
|
|
@@ -614,6 +619,8 @@ export function useContentEditorSourceMode({
|
|
|
614
619
|
applyHighlight,
|
|
615
620
|
applyStrike,
|
|
616
621
|
applyUnderline,
|
|
622
|
+
canRedoMarkdownChange,
|
|
623
|
+
canUndoMarkdownChange,
|
|
617
624
|
codeMirrorExtensions,
|
|
618
625
|
editorRef,
|
|
619
626
|
editorTheme,
|
package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-list-dropdown-menu.ts
CHANGED
|
@@ -8,7 +8,6 @@ import type { Editor } from '@tiptap/react'
|
|
|
8
8
|
// --- Icons ---
|
|
9
9
|
import { ListIcon, ListOrderedIcon, ListTodoIcon } from 'lucide-react'
|
|
10
10
|
import { useEffect, useMemo, useState } from 'react'
|
|
11
|
-
|
|
12
11
|
import { canToggleList, isListActive, type ListType, listIcons } from './use-list'
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { requireRole, UserRole } from '@admin/auth/middleware'
|
|
4
4
|
import db from '@admin/db'
|
|
5
5
|
import { auditLog } from '@admin/db/schema'
|
|
6
|
+
import { getExclusiveDateUpperBound } from '@admin/utils/date/date'
|
|
6
7
|
import { and, asc, desc, eq, gte, ilike, lt, or, sql } from 'drizzle-orm'
|
|
7
8
|
import type { AuditLogEntry, AuditLogPage, AuditLogQuery } from './types'
|
|
8
9
|
|
|
@@ -47,15 +48,6 @@ function getAuditLogOrderBy(query: AuditLogQuery) {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
function getExclusiveDateUpperBound(value: string | undefined): string | null {
|
|
51
|
-
if (!value) return null
|
|
52
|
-
const date = new Date(value)
|
|
53
|
-
if (Number.isNaN(date.getTime())) return null
|
|
54
|
-
|
|
55
|
-
date.setUTCDate(date.getUTCDate() + 1)
|
|
56
|
-
return date.toISOString()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
51
|
async function queryAuditLogs(query: AuditLogQuery = {}): Promise<AuditLogPage> {
|
|
60
52
|
const page = clampPage(query.page)
|
|
61
53
|
const pageSize = normalizePageSize(query.pageSize)
|
|
@@ -102,7 +94,10 @@ async function queryAuditLogs(query: AuditLogQuery = {}): Promise<AuditLogPage>
|
|
|
102
94
|
.orderBy(...orderBy)
|
|
103
95
|
const [rows, countResult] = await Promise.all([
|
|
104
96
|
pageSize ? orderedQuery.limit(pageSize).offset(offset) : orderedQuery,
|
|
105
|
-
db
|
|
97
|
+
db
|
|
98
|
+
.select({ count: sql<number>`count(*)` })
|
|
99
|
+
.from(auditLog)
|
|
100
|
+
.where(where)
|
|
106
101
|
])
|
|
107
102
|
const total = Number(countResult[0]?.count ?? 0)
|
|
108
103
|
const resolvedPageSize = pageSize ?? total
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
export { getAllFormSettings } from './get-all-form-settings'
|
|
2
2
|
export { getFormSettings } from './get-form-settings'
|
|
3
|
-
export type {
|
|
4
|
-
FormSettingsData,
|
|
5
|
-
FormSettingsResult,
|
|
6
|
-
UpsertFormSettingsInput
|
|
7
|
-
} from './types'
|
|
3
|
+
export type { FormSettingsData, FormSettingsResult, UpsertFormSettingsInput } from './types'
|
|
8
4
|
export { upsertFormSettings } from './upsert-form-settings'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use server'
|
|
2
2
|
|
|
3
3
|
import { getAuditRequestMetadata } from '@admin/actions/audit/request-metadata'
|
|
4
|
-
import {
|
|
4
|
+
import { requireRole, UserRole } from '@admin/auth/middleware'
|
|
5
5
|
import db from '@admin/db'
|
|
6
6
|
import { adminMedia } from '@admin/db/schema'
|
|
7
7
|
import { runAdminEventHooks } from '@admin/lib/lifecycle-hooks'
|
|
@@ -11,9 +11,9 @@ import { getMediaById } from './get-media-by-id'
|
|
|
11
11
|
import { type CreateMediaInput, type CreateMediaResult, mediaCacheTags } from './types'
|
|
12
12
|
|
|
13
13
|
export async function createMedia(data: CreateMediaInput): Promise<CreateMediaResult> {
|
|
14
|
+
const actor = await requireRole([UserRole.ADMIN, UserRole.EDITOR])
|
|
15
|
+
|
|
14
16
|
try {
|
|
15
|
-
const session = await getSession()
|
|
16
|
-
const actorId = session?.user?.id ?? null
|
|
17
17
|
const now = new Date().toISOString()
|
|
18
18
|
const auditRequestMetadata = await getAuditRequestMetadata()
|
|
19
19
|
const [row] = await db
|
|
@@ -22,8 +22,8 @@ export async function createMedia(data: CreateMediaInput): Promise<CreateMediaRe
|
|
|
22
22
|
...data,
|
|
23
23
|
createdAt: now,
|
|
24
24
|
updatedAt: now,
|
|
25
|
-
createdBy:
|
|
26
|
-
updatedBy:
|
|
25
|
+
createdBy: actor.id,
|
|
26
|
+
updatedBy: actor.id
|
|
27
27
|
})
|
|
28
28
|
.returning({ id: adminMedia.id })
|
|
29
29
|
if (row?.id) {
|
|
@@ -38,7 +38,7 @@ export async function createMedia(data: CreateMediaInput): Promise<CreateMediaRe
|
|
|
38
38
|
targetType: 'media',
|
|
39
39
|
targetId: media.id,
|
|
40
40
|
targetLabel: media.filename,
|
|
41
|
-
user:
|
|
41
|
+
user: actor,
|
|
42
42
|
timestamp: now,
|
|
43
43
|
sourceType: 'admin_ui' as const,
|
|
44
44
|
changedFields: getTouchedFieldNames(data as unknown as Record<string, unknown>),
|
|
@@ -57,7 +57,10 @@ export async function getMedia(params: GetMediaParams = {}) {
|
|
|
57
57
|
|
|
58
58
|
const [items, countResult] = await Promise.all([
|
|
59
59
|
itemsQuery,
|
|
60
|
-
db
|
|
60
|
+
db
|
|
61
|
+
.select({ count: sql<number>`count(*)` })
|
|
62
|
+
.from(adminMedia)
|
|
63
|
+
.where(where)
|
|
61
64
|
])
|
|
62
65
|
|
|
63
66
|
const result: GetMediaResult = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use server'
|
|
2
2
|
|
|
3
3
|
import { getAuditRequestMetadata } from '@admin/actions/audit/request-metadata'
|
|
4
|
-
import {
|
|
4
|
+
import { requireRole, UserRole } from '@admin/auth/middleware'
|
|
5
5
|
import db from '@admin/db'
|
|
6
6
|
import { adminMedia } from '@admin/db/schema'
|
|
7
7
|
import { runAdminEventHooks } from '@admin/lib/lifecycle-hooks'
|
|
@@ -15,9 +15,9 @@ export async function updateMedia(
|
|
|
15
15
|
id: string,
|
|
16
16
|
data: { alt?: string; tags?: string[] }
|
|
17
17
|
): Promise<UpdateMediaResult> {
|
|
18
|
+
const actor = await requireRole([UserRole.ADMIN, UserRole.EDITOR])
|
|
19
|
+
|
|
18
20
|
try {
|
|
19
|
-
const session = await getSession()
|
|
20
|
-
const actorId = session?.user?.id ?? null
|
|
21
21
|
const now = new Date().toISOString()
|
|
22
22
|
const auditRequestMetadata = await getAuditRequestMetadata()
|
|
23
23
|
const [previousMedia] = await db.select().from(adminMedia).where(eq(adminMedia.id, id)).limit(1)
|
|
@@ -26,7 +26,7 @@ export async function updateMedia(
|
|
|
26
26
|
.set({
|
|
27
27
|
...data,
|
|
28
28
|
updatedAt: now,
|
|
29
|
-
updatedBy:
|
|
29
|
+
updatedBy: actor.id
|
|
30
30
|
})
|
|
31
31
|
.where(eq(adminMedia.id, id))
|
|
32
32
|
updateTag(mediaCacheTags.all)
|
|
@@ -37,7 +37,7 @@ export async function updateMedia(
|
|
|
37
37
|
targetType: 'media',
|
|
38
38
|
targetId: id,
|
|
39
39
|
targetLabel: previousMedia?.filename ?? id,
|
|
40
|
-
user:
|
|
40
|
+
user: actor,
|
|
41
41
|
timestamp: now,
|
|
42
42
|
sourceType: 'admin_ui' as const,
|
|
43
43
|
changedFields: getChangedFieldNames(
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export { changeOwnPassword } from './change-own-password'
|
|
2
2
|
export { invalidateUsersCache } from './invalidate-users-cache'
|
|
3
3
|
export { isEmailConfigured } from './is-email-configured'
|
|
4
|
-
export type {
|
|
5
|
-
ChangeOwnPasswordInput,
|
|
6
|
-
ChangeOwnPasswordResult,
|
|
7
|
-
UpdateEmailResult
|
|
8
|
-
} from './types'
|
|
4
|
+
export type { ChangeOwnPasswordInput, ChangeOwnPasswordResult, UpdateEmailResult } from './types'
|
|
9
5
|
export { updateEmail } from './update-email'
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
export type {
|
|
2
|
-
FileValidationConfig,
|
|
3
|
-
RemoteUploadOptions,
|
|
4
|
-
UploadResult
|
|
5
|
-
} from './types'
|
|
1
|
+
export type { FileValidationConfig, RemoteUploadOptions, UploadResult } from './types'
|
|
6
2
|
export { uploadFile } from './upload-file'
|
|
7
3
|
export { uploadFiles } from './upload-files'
|
|
8
4
|
export { uploadImageFromUrl } from './upload-image-from-url'
|