@aphexcms/cms-core 2.0.10 → 2.1.0
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/api/api-keys.d.ts +4 -0
- package/dist/api/api-keys.d.ts.map +1 -1
- package/dist/api/assets.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -0
- package/dist/api/roles.d.ts +22 -0
- package/dist/api/roles.d.ts.map +1 -0
- package/dist/api/roles.js +26 -0
- package/dist/api/schemas/api-keys.d.ts +50 -4
- package/dist/api/schemas/api-keys.d.ts.map +1 -1
- package/dist/api/schemas/api-keys.js +22 -3
- package/dist/api/schemas/organizations.d.ts +4 -22
- package/dist/api/schemas/organizations.d.ts.map +1 -1
- package/dist/api/schemas/organizations.js +13 -2
- package/dist/api/schemas/roles.d.ts +77 -0
- package/dist/api/schemas/roles.d.ts.map +1 -0
- package/dist/api/schemas/roles.js +42 -0
- package/dist/app-augment.d.ts +32 -0
- package/dist/app-augment.d.ts.map +1 -0
- package/dist/app-augment.js +18 -0
- package/dist/auth/auth-hooks.d.ts +2 -1
- package/dist/auth/auth-hooks.d.ts.map +1 -1
- package/dist/auth/auth-hooks.js +22 -2
- package/dist/client/index.d.ts +4 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -2
- package/dist/components/AdminApp.svelte +300 -140
- package/dist/components/AdminApp.svelte.d.ts +8 -0
- package/dist/components/AdminApp.svelte.d.ts.map +1 -1
- package/dist/components/admin/DocumentEditor.svelte +633 -350
- package/dist/components/admin/DocumentEditor.svelte.d.ts +2 -0
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
- package/dist/components/admin/DocumentVersionPanel.svelte +46 -20
- package/dist/components/admin/DocumentVersionPanel.svelte.d.ts.map +1 -1
- package/dist/components/admin/MediaBrowser.svelte +70 -30
- package/dist/components/admin/MediaBrowser.svelte.d.ts.map +1 -1
- package/dist/components/admin/ObjectModal.svelte +70 -95
- package/dist/components/admin/ObjectModal.svelte.d.ts +1 -2
- package/dist/components/admin/ObjectModal.svelte.d.ts.map +1 -1
- package/dist/components/admin/PermissionsDebug.svelte +119 -0
- package/dist/components/admin/PermissionsDebug.svelte.d.ts +4 -0
- package/dist/components/admin/PermissionsDebug.svelte.d.ts.map +1 -0
- package/dist/components/admin/SchemaField.svelte +3 -1
- package/dist/components/admin/SchemaField.svelte.d.ts.map +1 -1
- package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte +8 -10
- package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ArrayField.svelte +104 -108
- package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/FileField.svelte +22 -17
- package/dist/components/admin/fields/FileField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ImageField.svelte +21 -15
- package/dist/components/admin/fields/ImageField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ReferenceField.svelte +142 -112
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/TextareaField.svelte +4 -3
- package/dist/components/admin/fields/TextareaField.svelte.d.ts +2 -2
- package/dist/components/admin/fields/TextareaField.svelte.d.ts.map +1 -1
- package/dist/components/layout/Sidebar.svelte +21 -11
- package/dist/components/layout/Sidebar.svelte.d.ts.map +1 -1
- package/dist/components/layout/sidebar/NavMain.svelte +1 -0
- package/dist/db/interfaces/document.d.ts.map +1 -1
- package/dist/db/interfaces/index.d.ts +3 -1
- package/dist/db/interfaces/index.d.ts.map +1 -1
- package/dist/db/interfaces/organization.d.ts +1 -1
- package/dist/db/interfaces/organization.d.ts.map +1 -1
- package/dist/db/interfaces/role.d.ts +25 -0
- package/dist/db/interfaces/role.d.ts.map +1 -0
- package/dist/db/interfaces/role.js +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +5 -0
- package/dist/field-access.d.ts +30 -0
- package/dist/field-access.d.ts.map +1 -0
- package/dist/field-access.js +79 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +19 -13
- package/dist/lib/api/api-keys.d.ts +4 -0
- package/dist/lib/api/api-keys.d.ts.map +1 -1
- package/dist/lib/api/api-keys.js.map +1 -1
- package/dist/lib/api/assets.d.ts.map +1 -1
- package/dist/lib/api/assets.js.map +1 -1
- package/dist/lib/api/index.d.ts +1 -0
- package/dist/lib/api/index.d.ts.map +1 -1
- package/dist/lib/api/index.js +1 -0
- package/dist/lib/api/index.js.map +1 -1
- package/dist/lib/api/roles.d.ts +22 -0
- package/dist/lib/api/roles.d.ts.map +1 -0
- package/dist/lib/api/roles.js +27 -0
- package/dist/lib/api/roles.js.map +1 -0
- package/dist/lib/api/schemas/api-keys.d.ts +50 -4
- package/dist/lib/api/schemas/api-keys.d.ts.map +1 -1
- package/dist/lib/api/schemas/api-keys.js +22 -3
- package/dist/lib/api/schemas/api-keys.js.map +1 -1
- package/dist/lib/api/schemas/organizations.d.ts +4 -22
- package/dist/lib/api/schemas/organizations.d.ts.map +1 -1
- package/dist/lib/api/schemas/organizations.js +13 -2
- package/dist/lib/api/schemas/organizations.js.map +1 -1
- package/dist/lib/api/schemas/roles.d.ts +77 -0
- package/dist/lib/api/schemas/roles.d.ts.map +1 -0
- package/dist/lib/api/schemas/roles.js +43 -0
- package/dist/lib/api/schemas/roles.js.map +1 -0
- package/dist/lib/app-augment.d.ts +32 -0
- package/dist/lib/app-augment.d.ts.map +1 -0
- package/dist/lib/app-augment.js +19 -0
- package/dist/lib/app-augment.js.map +1 -0
- package/dist/lib/auth/auth-hooks.d.ts +2 -1
- package/dist/lib/auth/auth-hooks.d.ts.map +1 -1
- package/dist/lib/auth/auth-hooks.js +22 -2
- package/dist/lib/auth/auth-hooks.js.map +1 -1
- package/dist/lib/client/index.d.ts +4 -2
- package/dist/lib/client/index.d.ts.map +1 -1
- package/dist/lib/client/index.js +6 -2
- package/dist/lib/client/index.js.map +1 -1
- package/dist/lib/db/interfaces/document.d.ts.map +1 -1
- package/dist/lib/db/interfaces/index.d.ts +3 -1
- package/dist/lib/db/interfaces/index.d.ts.map +1 -1
- package/dist/lib/db/interfaces/organization.d.ts +1 -1
- package/dist/lib/db/interfaces/organization.d.ts.map +1 -1
- package/dist/lib/db/interfaces/role.d.ts +25 -0
- package/dist/lib/db/interfaces/role.d.ts.map +1 -0
- package/dist/lib/db/interfaces/role.js +2 -0
- package/dist/lib/db/interfaces/role.js.map +1 -0
- package/dist/lib/engine.d.ts.map +1 -1
- package/dist/lib/engine.js +5 -0
- package/dist/lib/engine.js.map +1 -1
- package/dist/lib/field-access.d.ts +30 -0
- package/dist/lib/field-access.d.ts.map +1 -0
- package/dist/lib/field-access.js +80 -0
- package/dist/lib/field-access.js.map +1 -0
- package/dist/lib/hooks.d.ts +2 -0
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/hooks.js +19 -13
- package/dist/lib/hooks.js.map +1 -1
- package/dist/lib/local-api/collection-api.d.ts +2 -0
- package/dist/lib/local-api/collection-api.d.ts.map +1 -1
- package/dist/lib/local-api/collection-api.js +98 -30
- package/dist/lib/local-api/collection-api.js.map +1 -1
- package/dist/lib/local-api/index.d.ts.map +1 -1
- package/dist/lib/local-api/index.js.map +1 -1
- package/dist/lib/local-api/permissions.d.ts +26 -26
- package/dist/lib/local-api/permissions.d.ts.map +1 -1
- package/dist/lib/local-api/permissions.js +122 -80
- package/dist/lib/local-api/permissions.js.map +1 -1
- package/dist/lib/permissions-context.svelte.d.ts +44 -0
- package/dist/lib/permissions-context.svelte.d.ts.map +1 -0
- package/dist/lib/permissions-context.svelte.js +80 -0
- package/dist/lib/permissions-context.svelte.js.map +1 -0
- package/dist/lib/routes/assets.d.ts.map +1 -1
- package/dist/lib/routes/assets.js.map +1 -1
- package/dist/lib/routes/document-versions.d.ts.map +1 -1
- package/dist/lib/routes/document-versions.js.map +1 -1
- package/dist/lib/routes/organizations-by-id.d.ts.map +1 -1
- package/dist/lib/routes/organizations-by-id.js +6 -3
- package/dist/lib/routes/organizations-by-id.js.map +1 -1
- package/dist/lib/routes/organizations-invitations.d.ts.map +1 -1
- package/dist/lib/routes/organizations-invitations.js +17 -7
- package/dist/lib/routes/organizations-invitations.js.map +1 -1
- package/dist/lib/routes/organizations-members.d.ts.map +1 -1
- package/dist/lib/routes/organizations-members.js +15 -7
- package/dist/lib/routes/organizations-members.js.map +1 -1
- package/dist/lib/routes/organizations.d.ts.map +1 -1
- package/dist/lib/routes/organizations.js +3 -0
- package/dist/lib/routes/organizations.js.map +1 -1
- package/dist/lib/routes/roles-by-name.d.ts +4 -0
- package/dist/lib/routes/roles-by-name.d.ts.map +1 -0
- package/dist/lib/routes/roles-by-name.js +112 -0
- package/dist/lib/routes/roles-by-name.js.map +1 -0
- package/dist/lib/routes/roles.d.ts +4 -0
- package/dist/lib/routes/roles.d.ts.map +1 -0
- package/dist/lib/routes/roles.js +91 -0
- package/dist/lib/routes/roles.js.map +1 -0
- package/dist/lib/routes-exports.d.ts +2 -0
- package/dist/lib/routes-exports.d.ts.map +1 -1
- package/dist/lib/routes-exports.js +3 -0
- package/dist/lib/routes-exports.js.map +1 -1
- package/dist/lib/save-state-context.svelte.d.ts +8 -0
- package/dist/lib/save-state-context.svelte.d.ts.map +1 -0
- package/dist/lib/save-state-context.svelte.js +9 -0
- package/dist/lib/save-state-context.svelte.js.map +1 -0
- package/dist/lib/schema-utils/validator.d.ts.map +1 -1
- package/dist/lib/schema-utils/validator.js +14 -0
- package/dist/lib/schema-utils/validator.js.map +1 -1
- package/dist/lib/server/index.d.ts +1 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +1 -0
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/services/index.d.ts +1 -0
- package/dist/lib/services/index.d.ts.map +1 -1
- package/dist/lib/services/index.js +1 -0
- package/dist/lib/services/index.js.map +1 -1
- package/dist/lib/services/roles-service.d.ts +35 -0
- package/dist/lib/services/roles-service.d.ts.map +1 -0
- package/dist/lib/services/roles-service.js +91 -0
- package/dist/lib/services/roles-service.js.map +1 -0
- package/dist/lib/services/version-service.d.ts.map +1 -1
- package/dist/lib/services/version-service.js.map +1 -1
- package/dist/lib/types/auth.d.ts +43 -9
- package/dist/lib/types/auth.d.ts.map +1 -1
- package/dist/lib/types/auth.js +31 -26
- package/dist/lib/types/auth.js.map +1 -1
- package/dist/lib/types/capabilities.d.ts +104 -0
- package/dist/lib/types/capabilities.d.ts.map +1 -0
- package/dist/lib/types/capabilities.js +217 -0
- package/dist/lib/types/capabilities.js.map +1 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js +1 -0
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/organization.d.ts +13 -4
- package/dist/lib/types/organization.d.ts.map +1 -1
- package/dist/lib/types/schemas.d.ts +71 -0
- package/dist/lib/types/schemas.d.ts.map +1 -1
- package/dist/lib/types/sidebar.d.ts +1 -1
- package/dist/lib/types/sidebar.d.ts.map +1 -1
- package/dist/lib/utils/mime-detect.d.ts.map +1 -1
- package/dist/lib/utils/mime-detect.js +28 -6
- package/dist/lib/utils/mime-detect.js.map +1 -1
- package/dist/local-api/collection-api.d.ts +2 -0
- package/dist/local-api/collection-api.d.ts.map +1 -1
- package/dist/local-api/collection-api.js +98 -30
- package/dist/local-api/index.d.ts.map +1 -1
- package/dist/local-api/permissions.d.ts +26 -26
- package/dist/local-api/permissions.d.ts.map +1 -1
- package/dist/local-api/permissions.js +122 -80
- package/dist/permissions-context.svelte.d.ts +44 -0
- package/dist/permissions-context.svelte.d.ts.map +1 -0
- package/dist/permissions-context.svelte.js +79 -0
- package/dist/plugins/README.md +20 -20
- package/dist/routes/assets.d.ts.map +1 -1
- package/dist/routes/document-versions.d.ts.map +1 -1
- package/dist/routes/organizations-by-id.d.ts.map +1 -1
- package/dist/routes/organizations-by-id.js +6 -3
- package/dist/routes/organizations-invitations.d.ts.map +1 -1
- package/dist/routes/organizations-invitations.js +17 -7
- package/dist/routes/organizations-members.d.ts.map +1 -1
- package/dist/routes/organizations-members.js +15 -7
- package/dist/routes/organizations.d.ts.map +1 -1
- package/dist/routes/organizations.js +3 -0
- package/dist/routes/roles-by-name.d.ts +4 -0
- package/dist/routes/roles-by-name.d.ts.map +1 -0
- package/dist/routes/roles-by-name.js +111 -0
- package/dist/routes/roles.d.ts +4 -0
- package/dist/routes/roles.d.ts.map +1 -0
- package/dist/routes/roles.js +90 -0
- package/dist/routes-exports.d.ts +2 -0
- package/dist/routes-exports.d.ts.map +1 -1
- package/dist/routes-exports.js +3 -0
- package/dist/save-state-context.svelte.d.ts +8 -0
- package/dist/save-state-context.svelte.d.ts.map +1 -0
- package/dist/save-state-context.svelte.js +8 -0
- package/dist/schema-utils/validator.d.ts.map +1 -1
- package/dist/schema-utils/validator.js +14 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +1 -0
- package/dist/services/roles-service.d.ts +35 -0
- package/dist/services/roles-service.d.ts.map +1 -0
- package/dist/services/roles-service.js +90 -0
- package/dist/services/version-service.d.ts.map +1 -1
- package/dist/types/auth.d.ts +43 -9
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/auth.js +31 -26
- package/dist/types/capabilities.d.ts +104 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +216 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/organization.d.ts +13 -4
- package/dist/types/organization.d.ts.map +1 -1
- package/dist/types/schemas.d.ts +71 -0
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/sidebar.d.ts +1 -1
- package/dist/types/sidebar.d.ts.map +1 -1
- package/dist/utils/mime-detect.d.ts.map +1 -1
- package/dist/utils/mime-detect.js +28 -6
- package/package.json +6 -2
|
@@ -9,6 +9,8 @@ interface Props {
|
|
|
9
9
|
onAutoSaved?: (documentId: string, title: string) => void;
|
|
10
10
|
onDeleted?: () => void;
|
|
11
11
|
onPublished?: (documentId: string) => void;
|
|
12
|
+
onUnpublished?: (documentId: string) => void;
|
|
13
|
+
onRestored?: (documentId: string) => void;
|
|
12
14
|
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
13
15
|
onOpenVersionHistory?: (documentId: string) => void;
|
|
14
16
|
externalVersionPreview?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentEditor.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentEditor.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"DocumentEditor.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentEditor.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAaxD,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,sBAAsB,CAAC,EAAE;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,CAAC;IACT,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AA+5CF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
documentId: string;
|
|
9
9
|
onClose: () => void;
|
|
10
10
|
onRestored?: () => void;
|
|
11
|
-
onPreviewVersion?: (
|
|
11
|
+
onPreviewVersion?: (
|
|
12
|
+
version: {
|
|
13
|
+
versionNumber: number;
|
|
14
|
+
data: Record<string, any>;
|
|
15
|
+
eventType: string;
|
|
16
|
+
createdAt?: string;
|
|
17
|
+
} | null
|
|
18
|
+
) => void;
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
let { documentId, onClose, onRestored, onPreviewVersion }: Props = $props();
|
|
@@ -57,20 +64,20 @@
|
|
|
57
64
|
toast.error('Failed to load version');
|
|
58
65
|
}
|
|
59
66
|
}
|
|
60
|
-
|
|
61
67
|
</script>
|
|
62
68
|
|
|
63
69
|
<div class="flex h-full flex-col">
|
|
64
70
|
<!-- Header -->
|
|
65
71
|
<div class="border-border bg-background flex h-14 items-center justify-between border-b px-3">
|
|
66
72
|
<h3 class="text-sm font-medium">History</h3>
|
|
67
|
-
<Button
|
|
68
|
-
class="hover:bg-muted rounded p-1 transition-colors"
|
|
69
|
-
variant="ghost"
|
|
70
|
-
onclick={onClose}
|
|
71
|
-
>
|
|
73
|
+
<Button class="hover:bg-muted rounded p-1 transition-colors" variant="ghost" onclick={onClose}>
|
|
72
74
|
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
73
|
-
<path
|
|
75
|
+
<path
|
|
76
|
+
stroke-linecap="round"
|
|
77
|
+
stroke-linejoin="round"
|
|
78
|
+
stroke-width="2"
|
|
79
|
+
d="M6 18L18 6M6 6l12 12"
|
|
80
|
+
/>
|
|
74
81
|
</svg>
|
|
75
82
|
</Button>
|
|
76
83
|
</div>
|
|
@@ -79,9 +86,14 @@
|
|
|
79
86
|
<div class="border-border flex border-b">
|
|
80
87
|
{#each [{ value: 'all', label: 'All' }, { value: 'publish', label: 'Published' }, { value: 'draft', label: 'Drafts' }] as tab}
|
|
81
88
|
<Button
|
|
82
|
-
|
|
83
|
-
class="rounded-none
|
|
84
|
-
|
|
89
|
+
variant="ghost"
|
|
90
|
+
class="flex-1 cursor-pointer rounded-none px-2 py-2 text-xs font-medium transition-colors {filter ===
|
|
91
|
+
tab.value
|
|
92
|
+
? 'border-primary text-foreground border-b-2'
|
|
93
|
+
: 'text-muted-foreground hover:text-foreground'}"
|
|
94
|
+
onclick={() => {
|
|
95
|
+
filter = tab.value as any;
|
|
96
|
+
}}
|
|
85
97
|
>
|
|
86
98
|
{tab.label}
|
|
87
99
|
</Button>
|
|
@@ -96,28 +108,42 @@
|
|
|
96
108
|
</div>
|
|
97
109
|
{:else if filteredVersions.length === 0}
|
|
98
110
|
<div class="p-4 text-center">
|
|
99
|
-
<span class="text-muted-foreground text-xs"
|
|
111
|
+
<span class="text-muted-foreground text-xs"
|
|
112
|
+
>No {filter === 'all' ? '' : filter} versions</span
|
|
113
|
+
>
|
|
100
114
|
</div>
|
|
101
115
|
{:else}
|
|
102
116
|
{#each filteredVersions as version, i}
|
|
103
117
|
<div
|
|
104
118
|
data-version-id={i}
|
|
105
|
-
class="w-full border-b
|
|
119
|
+
class="hover:bg-muted w-full cursor-pointer border-b px-3 py-2.5 text-left transition-colors {previewVersion?.versionNumber ===
|
|
120
|
+
version.versionNumber
|
|
121
|
+
? 'bg-muted border-l-primary border-l-2'
|
|
122
|
+
: ''}"
|
|
106
123
|
onclick={() => previewVersionData(version)}
|
|
107
124
|
>
|
|
108
125
|
<div class="flex items-center justify-between">
|
|
109
126
|
<span class="text-muted-foreground text-[11px]">
|
|
110
|
-
{new Date(version.createdAt).toLocaleString(undefined, {
|
|
127
|
+
{new Date(version.createdAt).toLocaleString(undefined, {
|
|
128
|
+
month: 'short',
|
|
129
|
+
day: 'numeric',
|
|
130
|
+
hour: 'numeric',
|
|
131
|
+
minute: '2-digit',
|
|
132
|
+
hour12: true
|
|
133
|
+
})}
|
|
111
134
|
</span>
|
|
112
|
-
<Badge
|
|
135
|
+
<Badge
|
|
136
|
+
variant={version.eventType === 'publish' ? 'default' : 'secondary'}
|
|
137
|
+
class="px-1.5 py-0 text-[9px]"
|
|
138
|
+
>
|
|
113
139
|
{version.eventType}
|
|
114
140
|
</Badge>
|
|
115
141
|
</div>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
142
|
+
{#if version.createdByName}
|
|
143
|
+
<p class="text-muted-foreground mt-0.5 truncate text-[10px]">
|
|
144
|
+
{version.createdByName}
|
|
145
|
+
</p>
|
|
146
|
+
{/if}
|
|
121
147
|
</div>
|
|
122
148
|
{/each}
|
|
123
149
|
{/if}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentVersionPanel.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentVersionPanel.svelte.ts"],"names":[],"mappings":"AASC,UAAU,KAAK;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,gBAAgB,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"DocumentVersionPanel.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentVersionPanel.svelte.ts"],"names":[],"mappings":"AASC,UAAU,KAAK;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAClB,OAAO,EAAE;QACR,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,KACJ,IAAI,CAAC;CACV;AA4HF,QAAA,MAAM,oBAAoB,2CAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
import { copyUrlToClipboard, downloadFile } from '../../utils/asset-actions';
|
|
34
34
|
import { cmsLogger } from '../../utils/logger';
|
|
35
35
|
import { SvelteSet } from 'svelte/reactivity';
|
|
36
|
+
import { confirmDialog } from './confirm-dialog/confirm-dialog.svelte';
|
|
37
|
+
import { usePermissions } from '../../permissions-context.svelte';
|
|
36
38
|
|
|
37
39
|
interface Props {
|
|
38
40
|
/** When true, shows a "Select" button for picking an asset */
|
|
@@ -71,6 +73,10 @@
|
|
|
71
73
|
let viewMode = $state<'grid' | 'list'>('grid');
|
|
72
74
|
let sortOrder = $state<'newest' | 'oldest' | 'name-asc' | 'name-desc'>('newest');
|
|
73
75
|
|
|
76
|
+
const perms = usePermissions();
|
|
77
|
+
const canUpload = $derived(perms.can('asset.upload'));
|
|
78
|
+
const canDeleteAssets = $derived(perms.can('asset.delete'));
|
|
79
|
+
|
|
74
80
|
let selectedAsset = $state<Asset | null>(null);
|
|
75
81
|
let lightboxOpen = $state(false);
|
|
76
82
|
let currentPage = $state(1);
|
|
@@ -292,7 +298,13 @@
|
|
|
292
298
|
}
|
|
293
299
|
|
|
294
300
|
const count = selectedIds.size;
|
|
295
|
-
|
|
301
|
+
const confirmed = await confirmDialog({
|
|
302
|
+
title: `Delete ${count} asset${count > 1 ? 's' : ''}?`,
|
|
303
|
+
description: 'This cannot be undone.',
|
|
304
|
+
confirmText: 'Delete',
|
|
305
|
+
variant: 'destructive'
|
|
306
|
+
});
|
|
307
|
+
if (!confirmed) return;
|
|
296
308
|
|
|
297
309
|
isBulkDeleting = true;
|
|
298
310
|
try {
|
|
@@ -428,7 +440,13 @@
|
|
|
428
440
|
);
|
|
429
441
|
return;
|
|
430
442
|
}
|
|
431
|
-
|
|
443
|
+
const confirmed = await confirmDialog({
|
|
444
|
+
title: 'Delete asset?',
|
|
445
|
+
description: `"${asset.originalFilename}" will be permanently deleted. This cannot be undone.`,
|
|
446
|
+
confirmText: 'Delete',
|
|
447
|
+
variant: 'destructive'
|
|
448
|
+
});
|
|
449
|
+
if (!confirmed) return;
|
|
432
450
|
try {
|
|
433
451
|
const result = await assets.delete(asset.id);
|
|
434
452
|
if (result.success) {
|
|
@@ -566,16 +584,18 @@
|
|
|
566
584
|
<!-- Header -->
|
|
567
585
|
<div class="border-border flex items-center justify-between border-b px-4 py-3 sm:px-6 sm:py-4">
|
|
568
586
|
<h2 class="text-base font-semibold sm:text-lg">Browse Assets</h2>
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
587
|
+
{#if canUpload}
|
|
588
|
+
<Button
|
|
589
|
+
size="sm"
|
|
590
|
+
onclick={() => {
|
|
591
|
+
showUploadModal = true;
|
|
592
|
+
uploadQueue = [];
|
|
593
|
+
}}
|
|
594
|
+
>
|
|
595
|
+
<Upload size={16} class="sm:mr-2" />
|
|
596
|
+
<span class="hidden sm:inline">Upload assets</span>
|
|
597
|
+
</Button>
|
|
598
|
+
{/if}
|
|
579
599
|
</div>
|
|
580
600
|
|
|
581
601
|
<!-- Toolbar -->
|
|
@@ -641,8 +661,9 @@
|
|
|
641
661
|
</button>
|
|
642
662
|
</div>
|
|
643
663
|
|
|
644
|
-
<!-- Select mode toggle
|
|
645
|
-
|
|
664
|
+
<!-- Select mode toggle — only useful when the user can actually act on
|
|
665
|
+
the selection (delete). Hidden otherwise so it doesn't dead-end. -->
|
|
666
|
+
{#if !selectable && canDeleteAssets}
|
|
646
667
|
<button
|
|
647
668
|
onclick={toggleSelectMode}
|
|
648
669
|
class="rounded p-1.5 transition-colors {isSelectMode
|
|
@@ -703,15 +724,17 @@
|
|
|
703
724
|
<span class="text-sm font-medium">
|
|
704
725
|
{selectedIds.size} selected
|
|
705
726
|
</span>
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
727
|
+
{#if canDeleteAssets}
|
|
728
|
+
<Button
|
|
729
|
+
variant="destructive"
|
|
730
|
+
size="sm"
|
|
731
|
+
onclick={bulkDelete}
|
|
732
|
+
disabled={isBulkDeleting}
|
|
733
|
+
>
|
|
734
|
+
<Trash2 size={14} class="mr-1.5" />
|
|
735
|
+
{isBulkDeleting ? 'Deleting...' : 'Delete'}
|
|
736
|
+
</Button>
|
|
737
|
+
{/if}
|
|
715
738
|
<button
|
|
716
739
|
onclick={() => (selectedIds = new Set())}
|
|
717
740
|
class="text-muted-foreground hover:text-foreground text-sm transition-colors"
|
|
@@ -805,12 +828,25 @@
|
|
|
805
828
|
{#if selectable}
|
|
806
829
|
<!-- Info button to view details without selecting -->
|
|
807
830
|
<button
|
|
808
|
-
onclick={(e) => {
|
|
809
|
-
|
|
831
|
+
onclick={(e) => {
|
|
832
|
+
e.stopPropagation();
|
|
833
|
+
openAssetDetail(asset);
|
|
834
|
+
}}
|
|
835
|
+
class="bg-background/80 absolute top-1.5 right-1.5 rounded p-1 opacity-0 transition-opacity group-hover:opacity-100"
|
|
810
836
|
title="View details"
|
|
811
837
|
>
|
|
812
|
-
<svg
|
|
813
|
-
|
|
838
|
+
<svg
|
|
839
|
+
class="h-3.5 w-3.5"
|
|
840
|
+
fill="none"
|
|
841
|
+
viewBox="0 0 24 24"
|
|
842
|
+
stroke="currentColor"
|
|
843
|
+
>
|
|
844
|
+
<path
|
|
845
|
+
stroke-linecap="round"
|
|
846
|
+
stroke-linejoin="round"
|
|
847
|
+
stroke-width="2"
|
|
848
|
+
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
849
|
+
/>
|
|
814
850
|
</svg>
|
|
815
851
|
</button>
|
|
816
852
|
{:else if isSelectMode}
|
|
@@ -1042,7 +1078,9 @@
|
|
|
1042
1078
|
{#snippet failed(error, reset)}
|
|
1043
1079
|
<div class="border-destructive/30 bg-destructive/5 rounded-md border p-4 text-center">
|
|
1044
1080
|
<p class="text-destructive font-medium">Media browser encountered an error</p>
|
|
1045
|
-
<p class="text-muted-foreground mt-1 text-sm">
|
|
1081
|
+
<p class="text-muted-foreground mt-1 text-sm">
|
|
1082
|
+
{error instanceof Error ? error.message : 'Unknown error'}
|
|
1083
|
+
</p>
|
|
1046
1084
|
<button
|
|
1047
1085
|
class="bg-primary text-primary-foreground mt-3 rounded px-4 py-2 text-sm"
|
|
1048
1086
|
onclick={reset}
|
|
@@ -1077,7 +1115,7 @@
|
|
|
1077
1115
|
{selectedAsset.originalFilename}
|
|
1078
1116
|
</p>
|
|
1079
1117
|
<div class="flex items-center gap-1">
|
|
1080
|
-
{#if !selectable}
|
|
1118
|
+
{#if !selectable && canDeleteAssets}
|
|
1081
1119
|
<Button
|
|
1082
1120
|
variant="ghost"
|
|
1083
1121
|
size="sm"
|
|
@@ -1105,7 +1143,9 @@
|
|
|
1105
1143
|
<Button
|
|
1106
1144
|
size="sm"
|
|
1107
1145
|
class="w-full"
|
|
1108
|
-
onclick={() => {
|
|
1146
|
+
onclick={() => {
|
|
1147
|
+
if (selectedAsset && onSelect) onSelect(selectedAsset);
|
|
1148
|
+
}}
|
|
1109
1149
|
>
|
|
1110
1150
|
Select
|
|
1111
1151
|
</Button>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaBrowser.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/MediaBrowser.svelte.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"MediaBrowser.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/MediaBrowser.svelte.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAS9C,UAAU,KAAK;IACd,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAClC,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IAC7C,oCAAoC;IACpC,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACnC,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAgqCF,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -1,70 +1,33 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
3
|
-
import * as Card from '@aphexcms/ui/shadcn/card';
|
|
4
3
|
import type { SchemaType } from '../../types/schemas.js';
|
|
5
4
|
import SchemaField from './SchemaField.svelte';
|
|
6
|
-
import {
|
|
5
|
+
import { getSaveStateContext } from '../../save-state-context.svelte';
|
|
6
|
+
|
|
7
|
+
const saveState = getSaveStateContext();
|
|
7
8
|
|
|
8
9
|
interface Props {
|
|
9
10
|
open: boolean;
|
|
10
11
|
schema: SchemaType;
|
|
11
12
|
value: Record<string, any>;
|
|
12
13
|
onClose: () => void;
|
|
13
|
-
|
|
14
|
-
onUpdate?: (value: Record<string, any>) => void; // For real-time updates
|
|
14
|
+
onUpdate: (value: Record<string, any>) => void;
|
|
15
15
|
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
16
16
|
readonly?: boolean;
|
|
17
|
-
organizationId?: string;
|
|
17
|
+
organizationId?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
// TODO: add onUpdate to auto save
|
|
21
20
|
let {
|
|
22
21
|
open,
|
|
23
22
|
schema,
|
|
24
23
|
value,
|
|
25
24
|
onClose,
|
|
26
|
-
|
|
25
|
+
onUpdate,
|
|
27
26
|
onOpenReference,
|
|
28
27
|
readonly = false,
|
|
29
28
|
organizationId
|
|
30
29
|
}: Props = $props();
|
|
31
30
|
|
|
32
|
-
// Initialize editing data with defaults and existing values
|
|
33
|
-
function initializeData() {
|
|
34
|
-
const initialData: Record<string, any> = {};
|
|
35
|
-
|
|
36
|
-
if (schema?.fields) {
|
|
37
|
-
schema.fields.forEach((field: any) => {
|
|
38
|
-
if ('initialValue' in field && field.initialValue !== undefined) {
|
|
39
|
-
// Only use literal initialValue (skip functions to keep this synchronous)
|
|
40
|
-
if (typeof field.initialValue !== 'function') {
|
|
41
|
-
initialData[field.name] = field.initialValue;
|
|
42
|
-
} else {
|
|
43
|
-
// Function-based initialValues are skipped for nested items
|
|
44
|
-
// They will use field type defaults instead
|
|
45
|
-
initialData[field.name] = getDefaultValueForFieldType(field.type);
|
|
46
|
-
}
|
|
47
|
-
} else {
|
|
48
|
-
initialData[field.name] = getDefaultValueForFieldType(field.type);
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return { ...initialData, ...value };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Local state for editing
|
|
57
|
-
let editingData = $state<Record<string, any>>(initializeData());
|
|
58
|
-
|
|
59
|
-
function handleSave() {
|
|
60
|
-
onSave(editingData);
|
|
61
|
-
onClose();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function handleCancel() {
|
|
65
|
-
onClose();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
31
|
// Handle backdrop click
|
|
69
32
|
function handleBackdropClick(e: MouseEvent) {
|
|
70
33
|
if (e.target === e.currentTarget) {
|
|
@@ -81,65 +44,77 @@
|
|
|
81
44
|
</script>
|
|
82
45
|
|
|
83
46
|
{#if open}
|
|
84
|
-
<!-- Backdrop -
|
|
47
|
+
<!-- Backdrop: full-editor overlay -->
|
|
85
48
|
<div
|
|
86
|
-
class="bg-background/80
|
|
49
|
+
class="bg-background/80 absolute inset-0 z-50 backdrop-blur-xs"
|
|
87
50
|
onclick={handleBackdropClick}
|
|
88
51
|
onkeydown={handleKeydown}
|
|
89
52
|
role="button"
|
|
90
53
|
tabindex="-1"
|
|
91
|
-
>
|
|
92
|
-
<!-- Modal Content -->
|
|
93
|
-
<Card.Root class="flex max-h-[85vh] w-full max-w-2xl flex-col overflow-hidden shadow-lg">
|
|
94
|
-
<Card.Header class="border-b">
|
|
95
|
-
<div class="flex items-center justify-between">
|
|
96
|
-
<div>
|
|
97
|
-
<Card.Title>{schema.title}</Card.Title>
|
|
98
|
-
{#if schema.description}
|
|
99
|
-
<Card.Description>{schema.description}</Card.Description>
|
|
100
|
-
{/if}
|
|
101
|
-
</div>
|
|
102
|
-
<Button variant="ghost" size="icon" onclick={onClose}>
|
|
103
|
-
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
104
|
-
<path
|
|
105
|
-
stroke-linecap="round"
|
|
106
|
-
stroke-linejoin="round"
|
|
107
|
-
stroke-width="2"
|
|
108
|
-
d="M6 18L18 6M6 6l12 12"
|
|
109
|
-
/>
|
|
110
|
-
</svg>
|
|
111
|
-
</Button>
|
|
112
|
-
</div>
|
|
113
|
-
</Card.Header>
|
|
54
|
+
></div>
|
|
114
55
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
56
|
+
<!-- Panel: centered dialog with max-width and max-height -->
|
|
57
|
+
<div
|
|
58
|
+
class="border-border bg-background absolute top-1/2 left-1/2 z-50 flex max-h-[calc(100%-4rem)] w-[calc(100%-2rem)] max-w-3xl -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-lg border shadow-lg"
|
|
59
|
+
>
|
|
60
|
+
<div
|
|
61
|
+
class="border-border bg-background flex items-center justify-between gap-3 border-b px-4 py-2"
|
|
62
|
+
>
|
|
63
|
+
<span class="text-sm font-medium">Edit {schema.title}</span>
|
|
64
|
+
<div class="flex items-center gap-2">
|
|
65
|
+
{#if saveState}
|
|
66
|
+
{#if saveState.saving}
|
|
67
|
+
<span
|
|
68
|
+
class="text-muted-foreground inline-flex items-center gap-1.5 text-[10px] font-medium tracking-wider whitespace-nowrap uppercase"
|
|
69
|
+
>
|
|
70
|
+
<span class="bg-muted-foreground/60 h-1.5 w-1.5 animate-pulse rounded-full"></span>
|
|
71
|
+
Saving
|
|
72
|
+
</span>
|
|
73
|
+
{:else if saveState.hasUnsavedChanges}
|
|
74
|
+
<span
|
|
75
|
+
class="text-muted-foreground inline-flex items-center gap-1.5 text-[10px] font-medium tracking-wider whitespace-nowrap uppercase"
|
|
76
|
+
>
|
|
77
|
+
<span class="bg-muted-foreground/60 h-1.5 w-1.5 rounded-full"></span>
|
|
78
|
+
Unsaved
|
|
79
|
+
</span>
|
|
80
|
+
{:else if saveState.savedAgoText}
|
|
81
|
+
<span
|
|
82
|
+
class="text-muted-foreground inline-flex items-center gap-1.5 text-[10px] font-medium tracking-wider whitespace-nowrap uppercase"
|
|
83
|
+
>
|
|
84
|
+
<span class="bg-muted-foreground/60 h-1.5 w-1.5 rounded-full"></span>
|
|
85
|
+
Auto-saved
|
|
86
|
+
</span>
|
|
131
87
|
{/if}
|
|
132
|
-
</div>
|
|
133
|
-
</Card.Content>
|
|
134
|
-
|
|
135
|
-
<Card.Footer class="flex justify-end gap-2 border-t">
|
|
136
|
-
{#if readonly}
|
|
137
|
-
<Button onclick={onClose}>Close</Button>
|
|
138
|
-
{:else}
|
|
139
|
-
<Button variant="outline" onclick={handleCancel}>Cancel</Button>
|
|
140
|
-
<Button onclick={handleSave}>Save Changes</Button>
|
|
141
88
|
{/if}
|
|
142
|
-
|
|
143
|
-
|
|
89
|
+
<Button variant="ghost" size="icon" class="h-7 w-7" onclick={onClose}>
|
|
90
|
+
<svg class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
91
|
+
<path
|
|
92
|
+
stroke-linecap="round"
|
|
93
|
+
stroke-linejoin="round"
|
|
94
|
+
stroke-width="2"
|
|
95
|
+
d="M6 18L18 6M6 6l12 12"
|
|
96
|
+
/>
|
|
97
|
+
</svg>
|
|
98
|
+
</Button>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div class="bg-background flex-1 space-y-3 overflow-auto p-4">
|
|
103
|
+
{#if schema.fields}
|
|
104
|
+
{#each schema.fields as field, index (index)}
|
|
105
|
+
<SchemaField
|
|
106
|
+
{field}
|
|
107
|
+
value={(value ?? {})[field.name]}
|
|
108
|
+
documentData={value ?? {}}
|
|
109
|
+
onUpdate={(newValue) => {
|
|
110
|
+
onUpdate({ ...value, [field.name]: newValue });
|
|
111
|
+
}}
|
|
112
|
+
{onOpenReference}
|
|
113
|
+
{readonly}
|
|
114
|
+
{organizationId}
|
|
115
|
+
/>
|
|
116
|
+
{/each}
|
|
117
|
+
{/if}
|
|
118
|
+
</div>
|
|
144
119
|
</div>
|
|
145
120
|
{/if}
|
|
@@ -4,8 +4,7 @@ interface Props {
|
|
|
4
4
|
schema: SchemaType;
|
|
5
5
|
value: Record<string, any>;
|
|
6
6
|
onClose: () => void;
|
|
7
|
-
|
|
8
|
-
onUpdate?: (value: Record<string, any>) => void;
|
|
7
|
+
onUpdate: (value: Record<string, any>) => void;
|
|
9
8
|
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
10
9
|
readonly?: boolean;
|
|
11
10
|
organizationId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectModal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/ObjectModal.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ObjectModal.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/ObjectModal.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKxD,UAAU,KAAK;IACd,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAC/C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAqFF,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Shield, X, Copy } from '@lucide/svelte';
|
|
3
|
+
import { toast } from 'svelte-sonner';
|
|
4
|
+
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
5
|
+
import { Badge } from '@aphexcms/ui/shadcn/badge';
|
|
6
|
+
import { usePermissions } from '../../permissions-context.svelte';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A floating dev panel that surfaces the caller's resolved RBAC state so
|
|
10
|
+
* you can see exactly what the client thinks you can do. Mirrors the
|
|
11
|
+
* server-side capability set hydrated by the auth hook.
|
|
12
|
+
*
|
|
13
|
+
* Mount once near the root of your admin layout. Hidden by default —
|
|
14
|
+
* clicking the shield toggles the panel open.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const perms = usePermissions();
|
|
18
|
+
let open = $state(false);
|
|
19
|
+
|
|
20
|
+
const capabilities = $derived([...perms.capabilities].sort());
|
|
21
|
+
const grouped = $derived.by(() => {
|
|
22
|
+
const groups = new Map<string, string[]>();
|
|
23
|
+
for (const cap of capabilities) {
|
|
24
|
+
const prefix = cap.includes('.') ? (cap.split('.')[0] ?? 'other') : 'other';
|
|
25
|
+
if (!groups.has(prefix)) groups.set(prefix, []);
|
|
26
|
+
groups.get(prefix)!.push(cap);
|
|
27
|
+
}
|
|
28
|
+
return Array.from(groups.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
async function copyJSON() {
|
|
32
|
+
const payload = {
|
|
33
|
+
role: perms.role,
|
|
34
|
+
capabilities
|
|
35
|
+
};
|
|
36
|
+
try {
|
|
37
|
+
await navigator.clipboard.writeText(JSON.stringify(payload, null, 2));
|
|
38
|
+
toast.success('Copied RBAC snapshot');
|
|
39
|
+
} catch {
|
|
40
|
+
toast.error('Copy failed');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
{#if open}
|
|
46
|
+
<div
|
|
47
|
+
class="bg-background fixed right-4 bottom-4 z-50 w-80 overflow-hidden rounded-lg border shadow-lg"
|
|
48
|
+
role="dialog"
|
|
49
|
+
aria-label="Permissions debug"
|
|
50
|
+
>
|
|
51
|
+
<div class="border-b px-3 py-2">
|
|
52
|
+
<div class="flex items-center justify-between gap-2">
|
|
53
|
+
<div class="flex items-center gap-2">
|
|
54
|
+
<Shield class="h-3.5 w-3.5" />
|
|
55
|
+
<span class="text-sm font-semibold">RBAC</span>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="flex items-center gap-1">
|
|
58
|
+
<Button
|
|
59
|
+
variant="ghost"
|
|
60
|
+
size="sm"
|
|
61
|
+
class="h-6 w-6 p-0"
|
|
62
|
+
onclick={copyJSON}
|
|
63
|
+
title="Copy JSON"
|
|
64
|
+
>
|
|
65
|
+
<Copy class="h-3 w-3" />
|
|
66
|
+
</Button>
|
|
67
|
+
<Button
|
|
68
|
+
variant="ghost"
|
|
69
|
+
size="sm"
|
|
70
|
+
class="h-6 w-6 p-0"
|
|
71
|
+
onclick={() => (open = false)}
|
|
72
|
+
title="Close"
|
|
73
|
+
>
|
|
74
|
+
<X class="h-3 w-3" />
|
|
75
|
+
</Button>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="mt-1 flex items-center gap-1.5 text-xs">
|
|
79
|
+
<span class="text-muted-foreground">role:</span>
|
|
80
|
+
{#if perms.role}
|
|
81
|
+
<Badge variant="secondary" class="text-[10px]">{perms.role}</Badge>
|
|
82
|
+
{:else}
|
|
83
|
+
<span class="text-muted-foreground italic">none</span>
|
|
84
|
+
{/if}
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<div class="max-h-80 space-y-3 overflow-y-auto p-3">
|
|
89
|
+
{#if capabilities.length === 0}
|
|
90
|
+
<p class="text-muted-foreground py-4 text-center text-xs">No capabilities granted.</p>
|
|
91
|
+
{:else}
|
|
92
|
+
{#each grouped as [prefix, caps] (prefix)}
|
|
93
|
+
<div class="space-y-1">
|
|
94
|
+
<p class="text-muted-foreground text-[10px] font-semibold tracking-wider uppercase">
|
|
95
|
+
{prefix}
|
|
96
|
+
</p>
|
|
97
|
+
<div class="flex flex-wrap gap-1">
|
|
98
|
+
{#each caps as cap (cap)}
|
|
99
|
+
<Badge variant="outline" class="font-mono text-[10px]">
|
|
100
|
+
{cap.split('.').slice(1).join('.') || cap}
|
|
101
|
+
</Badge>
|
|
102
|
+
{/each}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
{/each}
|
|
106
|
+
{/if}
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
{:else}
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
112
|
+
onclick={() => (open = true)}
|
|
113
|
+
class="bg-background hover:bg-muted fixed right-4 bottom-4 z-50 flex h-9 w-9 items-center justify-center rounded-full border shadow-sm transition-colors"
|
|
114
|
+
title="Show permissions"
|
|
115
|
+
aria-label="Show permissions debug"
|
|
116
|
+
>
|
|
117
|
+
<Shield class="h-4 w-4" />
|
|
118
|
+
</button>
|
|
119
|
+
{/if}
|