convex-cms 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -101
- package/admin/src/components/BreakingChangesWarningDialog.tsx +5 -5
- package/admin/src/components/BulkOperationModal.tsx +14 -14
- package/admin/src/components/ContentEntryEditor.tsx +8 -8
- package/admin/src/components/ContentTypeFormModal.tsx +122 -82
- package/admin/src/components/Header.tsx +5 -2
- package/admin/src/components/SchemaDriftWarning.tsx +126 -0
- package/admin/src/components/TaxonomyEditor.tsx +2 -2
- package/admin/src/components/TermTree.tsx +3 -3
- package/admin/src/components/UploadDropzone.tsx +7 -7
- package/admin/src/components/VersionCompare.tsx +13 -13
- package/admin/src/components/VersionHistory.tsx +2 -2
- package/admin/src/components/VersionRollbackModal.tsx +5 -5
- package/admin/src/components/cmsds/CmsButton.tsx +2 -2
- package/admin/src/components/cmsds/CmsDialog.tsx +4 -1
- package/admin/src/components/cmsds/CmsStatusBadge.tsx +5 -5
- package/admin/src/components/fields/JsonField.tsx +1 -1
- package/admin/src/components/fields/ReferenceField.tsx +9 -9
- package/admin/src/components/fields/TagField.tsx +1 -1
- package/admin/src/contexts/SettingsConfigContext.tsx +10 -3
- package/admin/src/embed/index.tsx +29 -9
- package/admin/src/embed/pages/ContentTypeEntries.tsx +25 -0
- package/admin/src/embed/pages/Entry.tsx +114 -0
- package/admin/src/embed/pages/Media.tsx +3 -1
- package/admin/src/embed/pages/NewEntry.tsx +83 -0
- package/admin/src/embed/pages/index.ts +3 -0
- package/admin/src/pages/ContentPage.tsx +27 -20
- package/admin/src/pages/ContentTypeEntriesPage.tsx +466 -0
- package/admin/src/pages/ContentTypesPage.tsx +65 -19
- package/admin/src/pages/DashboardPage.tsx +3 -0
- package/admin/src/pages/SettingsPage.tsx +4 -4
- package/admin/src/pages/index.ts +1 -0
- package/admin/src/routes/__root.tsx +10 -10
- package/admin/src/routes/entries/$entryId.tsx +1 -1
- package/admin/src/routes/entries/type/$contentTypeId.tsx +1 -1
- package/admin/src/styles/globals.css +31 -5
- package/admin/src/styles/tailwind-config.css +25 -0
- package/admin/src/styles/theme.css +50 -0
- package/admin-dist/nitro.json +1 -1
- package/admin-dist/public/assets/CmsEmptyState-6-PLaXtD.js +1 -0
- package/admin-dist/public/assets/CmsPageHeader-SoF4Epu9.js +1 -0
- package/admin-dist/public/assets/CmsStatusBadge-D7kYaohx.js +1 -0
- package/admin-dist/public/assets/{CmsSurface-DBy5Lumx.js → CmsSurface-BvksBm6W.js} +1 -1
- package/admin-dist/public/assets/CmsToolbar-DlZPMe2B.js +1 -0
- package/admin-dist/public/assets/ContentEntryEditor-C6n9xLS9.js +4 -0
- package/admin-dist/public/assets/TaxonomyFilter-CFX1_g8s.js +1 -0
- package/admin-dist/public/assets/_contentTypeId-DTv8UoTp.js +1 -0
- package/admin-dist/public/assets/_entryId-D3lr5Dvy.js +1 -0
- package/admin-dist/public/assets/alert-BAHTL6ao.js +1 -0
- package/admin-dist/public/assets/badge-oJv4Eai8.js +1 -0
- package/admin-dist/public/assets/{circle-check-big-CpLxAvEj.js → circle-check-big-3OHxNDhO.js} +1 -1
- package/admin-dist/public/assets/command-DwgQs69u.js +1 -0
- package/admin-dist/public/assets/content-CKQ4QwW2.js +1 -0
- package/admin-dist/public/assets/content-types-BrttaLpc.js +1 -0
- package/admin-dist/public/assets/globals-CoCRjt0K.css +1 -0
- package/admin-dist/public/assets/index-DOkgTSx0.js +1 -0
- package/admin-dist/public/assets/main-DV6oxWnU.js +102 -0
- package/admin-dist/public/assets/media-B2i-mCbx.js +1 -0
- package/admin-dist/public/assets/new._contentTypeId-VF63rpic.js +1 -0
- package/admin-dist/public/assets/pencil-CX1CiTDD.js +1 -0
- package/admin-dist/public/assets/refresh-cw-Cm-YOeFI.js +1 -0
- package/admin-dist/public/assets/{rotate-ccw-BZpZtw0N.js → rotate-ccw-B45JsL5f.js} +1 -1
- package/admin-dist/public/assets/scroll-area-b3A1HHR7.js +1 -0
- package/admin-dist/public/assets/{search-BvgYr-c9.js → search-DKKh_DdH.js} +1 -1
- package/admin-dist/public/assets/settings-CGVDEV1r.js +1 -0
- package/admin-dist/public/assets/switch-BTMY8Qnk.js +1 -0
- package/admin-dist/public/assets/tabs-DUQwUoIb.js +1 -0
- package/admin-dist/public/assets/tanstack-adapter-f7AHmQ5L.js +1 -0
- package/admin-dist/public/assets/taxonomies-DvMppdiD.js +1 -0
- package/admin-dist/public/assets/trash-D7e0uKd9.js +1 -0
- package/admin-dist/public/assets/{useBreadcrumbLabel-D00rvqjw.js → useBreadcrumbLabel-CF2KYwsw.js} +1 -1
- package/admin-dist/public/assets/usePermissions-DWBImEOW.js +1 -0
- package/admin-dist/server/_chunks/_libs/@date-fns/tz.mjs +2 -2
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-avatar.mjs +1 -1
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-collection.mjs +1 -1
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-context.mjs +2 -2
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-dialog.mjs +2 -2
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-label.mjs +1 -1
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-menu.mjs +1 -1
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-popover.mjs +1 -1
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-primitive.mjs +6 -72
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-select.mjs +1 -1
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-separator.mjs +1 -1
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-slot.mjs +20 -435
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-visually-hidden.mjs +30 -3
- package/admin-dist/server/_chunks/_libs/@tanstack/history.mjs +0 -376
- package/admin-dist/server/_chunks/_libs/@tanstack/react-router.mjs +168 -383
- package/admin-dist/server/_chunks/_libs/@tanstack/router-core.mjs +451 -1195
- package/admin-dist/server/_chunks/_libs/react-dom.mjs +5 -5
- package/admin-dist/server/_chunks/_libs/react.mjs +2 -2
- package/admin-dist/server/_libs/cmdk.mjs +1 -1
- package/admin-dist/server/_libs/convex.mjs +3 -3
- package/admin-dist/server/_libs/cookie-es.mjs +1 -58
- package/admin-dist/server/_libs/date-fns.mjs +1 -1
- package/admin-dist/server/_libs/lucide-react.mjs +117 -103
- package/admin-dist/server/_libs/seroval-plugins.mjs +1 -58
- package/admin-dist/server/_libs/seroval.mjs +1 -1765
- package/admin-dist/server/_libs/zod.mjs +1 -1
- package/admin-dist/server/_ssr/CmsEmptyState-BM8DghTl.mjs +38 -0
- package/admin-dist/server/_ssr/{CmsPageHeader-ClNPU7Up.mjs → CmsPageHeader-BHUmrIWD.mjs} +1 -1
- package/admin-dist/server/_ssr/{CmsStatusBadge-CojMbrY7.mjs → CmsStatusBadge-D0Zb0oRl.mjs} +7 -7
- package/admin-dist/server/_ssr/{CmsSurface-Dcv440rp.mjs → CmsSurface-B2eBr-47.mjs} +1 -1
- package/admin-dist/server/_ssr/{CmsToolbar-BKv1nL6u.mjs → CmsToolbar-BCrwg7OL.mjs} +2 -3
- package/admin-dist/server/_ssr/{ContentEntryEditor-weiXSBdZ.mjs → ContentEntryEditor-Cjfm0uhr.mjs} +46 -49
- package/admin-dist/server/_ssr/{TaxonomyFilter-BPQ57Mwk.mjs → TaxonomyFilter-C4pD0kfM.mjs} +4 -5
- package/admin-dist/server/_ssr/{_contentTypeId-DyyauLOs.mjs → _contentTypeId-CiDiX-p7.mjs} +34 -43
- package/admin-dist/server/_ssr/{_entryId-9Cafwxmw.mjs → _entryId-9GxatOkL.mjs} +35 -47
- package/admin-dist/server/_ssr/_tanstack-start-manifest_v-CC7UrHKE.mjs +4 -0
- package/admin-dist/server/_ssr/badge-EI998zba.mjs +39 -0
- package/admin-dist/server/_ssr/{command-CEf8YBxY.mjs → command-BLAWQhUw.mjs} +2 -2
- package/admin-dist/server/_ssr/{config.server-D7JHDcDv.mjs → config.server-BOr7Jxr4.mjs} +5 -14
- package/admin-dist/server/_ssr/{content-ZFWVzO25.mjs → content-BHX39L4D.mjs} +63 -63
- package/admin-dist/server/_ssr/content-types-DCzrBhTH.mjs +459 -0
- package/admin-dist/server/_ssr/{index-BlSIlH4Z.mjs → index-DwM_5VNP.mjs} +114 -30
- package/admin-dist/server/_ssr/index.mjs +3459 -62
- package/admin-dist/server/_ssr/{media-CD2_NUMw.mjs → media-CbzgTRRQ.mjs} +31 -43
- package/admin-dist/server/_ssr/{new._contentTypeId-dmZy6PBX.mjs → new._contentTypeId-6Ph-Gtlw.mjs} +33 -45
- package/admin-dist/server/_ssr/router-vd1nySeP.mjs +3041 -0
- package/admin-dist/server/_ssr/{scroll-area-BH_1K-WT.mjs → scroll-area--B9snFTJ.mjs} +1 -1
- package/admin-dist/server/_ssr/{settings-DVdsoWoh.mjs → settings-DlTO2JSj.mjs} +34 -43
- package/admin-dist/server/_ssr/{switch-DX_X8vZl.mjs → switch-C05NgNW0.mjs} +1 -1
- package/admin-dist/server/_ssr/{tabs-4FWM0sn8.mjs → tabs-DAk2J5xy.mjs} +9 -10
- package/admin-dist/server/_ssr/{tanstack-adapter-D3ZcKtbY.mjs → tanstack-adapter-DWbaPByn.mjs} +15 -1
- package/admin-dist/server/_ssr/{taxonomies-BHFfO9Yr.mjs → taxonomies-B8nqce6u.mjs} +35 -44
- package/admin-dist/server/_ssr/{trash-9tUB2KwI.mjs → trash-zdlZgpTo.mjs} +30 -39
- package/admin-dist/server/_ssr/{useBreadcrumbLabel-DVme3DSb.mjs → useBreadcrumbLabel-DpEKyG1h.mjs} +1 -1
- package/admin-dist/server/_ssr/{usePermissions-zAQj-ruE.mjs → usePermissions-olYRd9S9.mjs} +1 -1
- package/admin-dist/server/index.mjs +168 -203
- package/dist/cli/templates/cmsClient.d.ts +1 -1
- package/dist/cli/templates/cmsClient.d.ts.map +1 -1
- package/dist/cli/templates/cmsClient.js +30 -11
- package/dist/cli/templates/cmsClient.js.map +1 -1
- package/dist/cli/templates/cmsConfig.d.ts +1 -1
- package/dist/cli/templates/cmsConfig.d.ts.map +1 -1
- package/dist/cli/templates/cmsConfig.js +3 -3
- package/dist/client/admin/contentLock.d.ts +4 -4
- package/dist/client/admin/contentLock.d.ts.map +1 -1
- package/dist/client/admin/contentLock.js +1 -1
- package/dist/client/admin/contentLock.js.map +1 -1
- package/dist/client/admin/contentTypes.d.ts +328 -290
- package/dist/client/admin/contentTypes.d.ts.map +1 -1
- package/dist/client/admin/contentTypes.js +307 -9
- package/dist/client/admin/contentTypes.js.map +1 -1
- package/dist/client/admin/entries.d.ts +18 -19
- package/dist/client/admin/entries.d.ts.map +1 -1
- package/dist/client/admin/entries.js +33 -8
- package/dist/client/admin/entries.js.map +1 -1
- package/dist/client/admin/index.d.ts +694 -642
- package/dist/client/admin/index.d.ts.map +1 -1
- package/dist/client/admin/index.js +45 -5
- package/dist/client/admin/index.js.map +1 -1
- package/dist/client/admin/media.d.ts.map +1 -1
- package/dist/client/admin/taxonomies.d.ts.map +1 -1
- package/dist/client/admin/trash.d.ts +3 -4
- package/dist/client/admin/trash.d.ts.map +1 -1
- package/dist/client/admin/types.d.ts +185 -4
- package/dist/client/admin/types.d.ts.map +1 -1
- package/dist/client/admin/validators.d.ts +2009 -25
- package/dist/client/admin/validators.d.ts.map +1 -1
- package/dist/client/admin/validators.js +15 -4
- package/dist/client/admin/validators.js.map +1 -1
- package/dist/client/admin/versions.d.ts +1 -1
- package/dist/client/admin/versions.d.ts.map +1 -1
- package/dist/client/agentTools.d.ts +1 -4
- package/dist/client/agentTools.d.ts.map +1 -1
- package/dist/client/agentTools.js +9 -21
- package/dist/client/agentTools.js.map +1 -1
- package/dist/client/config.d.ts +10 -0
- package/dist/client/config.d.ts.map +1 -1
- package/dist/client/config.js +1 -0
- package/dist/client/config.js.map +1 -1
- package/dist/client/defineContent.d.ts +338 -0
- package/dist/client/defineContent.d.ts.map +1 -0
- package/dist/client/defineContent.js +368 -0
- package/dist/client/defineContent.js.map +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/queryBuilder.d.ts +0 -15
- package/dist/client/queryBuilder.d.ts.map +1 -1
- package/dist/client/queryBuilder.js +0 -23
- package/dist/client/queryBuilder.js.map +1 -1
- package/dist/client/registry.d.ts +77 -0
- package/dist/client/registry.d.ts.map +1 -0
- package/dist/client/registry.js +95 -0
- package/dist/client/registry.js.map +1 -0
- package/dist/client/schema/defineContentType.d.ts +36 -24
- package/dist/client/schema/defineContentType.d.ts.map +1 -1
- package/dist/client/schema/defineContentType.js +176 -128
- package/dist/client/schema/defineContentType.js.map +1 -1
- package/dist/client/schema/typedClient.d.ts.map +1 -1
- package/dist/client/schema/typedClient.js +2 -10
- package/dist/client/schema/typedClient.js.map +1 -1
- package/dist/client/schema/types.d.ts +16 -9
- package/dist/client/schema/types.d.ts.map +1 -1
- package/dist/client/schema/types.js.map +1 -1
- package/dist/client/utils/toSlug.d.ts +60 -0
- package/dist/client/utils/toSlug.d.ts.map +1 -0
- package/dist/client/utils/toSlug.js +31 -0
- package/dist/client/utils/toSlug.js.map +1 -0
- package/dist/client/wrapper.d.ts +2 -2
- package/dist/client/wrapper.d.ts.map +1 -1
- package/dist/client/wrapper.js +22 -30
- package/dist/client/wrapper.js.map +1 -1
- package/dist/component/_generated/component.d.ts +24 -28
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/authorizationHooks.d.ts +1 -1
- package/dist/component/authorizationHooks.d.ts.map +1 -1
- package/dist/component/authorizationHooks.js +2 -2
- package/dist/component/authorizationHooks.js.map +1 -1
- package/dist/component/bulkOperations.d.ts.map +1 -1
- package/dist/component/bulkOperations.js +7 -4
- package/dist/component/bulkOperations.js.map +1 -1
- package/dist/component/contentEntries.d.ts +18 -56
- package/dist/component/contentEntries.d.ts.map +1 -1
- package/dist/component/contentEntries.js +45 -137
- package/dist/component/contentEntries.js.map +1 -1
- package/dist/component/contentEntryMutations.d.ts +14 -14
- package/dist/component/contentEntryMutations.d.ts.map +1 -1
- package/dist/component/contentEntryMutations.js +40 -43
- package/dist/component/contentEntryMutations.js.map +1 -1
- package/dist/component/contentEntryValidation.d.ts +3 -3
- package/dist/component/contentEntryValidation.js +6 -9
- package/dist/component/contentEntryValidation.js.map +1 -1
- package/dist/component/contentLock.d.ts +7 -7
- package/dist/component/contentLock.js +3 -3
- package/dist/component/contentLock.js.map +1 -1
- package/dist/component/contentTypeMigration.d.ts +1 -1
- package/dist/component/contentTypeMigration.js +2 -2
- package/dist/component/contentTypeMigration.js.map +1 -1
- package/dist/component/contentTypeMutations.d.ts.map +1 -1
- package/dist/component/contentTypeMutations.js +7 -6
- package/dist/component/contentTypeMutations.js.map +1 -1
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/convex.config.js +1 -1
- package/dist/component/convex.config.js.map +1 -1
- package/dist/component/eventEmitter.d.ts +0 -1
- package/dist/component/eventEmitter.d.ts.map +1 -1
- package/dist/component/eventEmitter.js.map +1 -1
- package/dist/component/exportImport.d.ts +37 -37
- package/dist/component/exportImport.d.ts.map +1 -1
- package/dist/component/exportImport.js +34 -34
- package/dist/component/exportImport.js.map +1 -1
- package/dist/component/lib/deepReferenceResolver.d.ts +2 -2
- package/dist/component/lib/deepReferenceResolver.d.ts.map +1 -1
- package/dist/component/lib/deepReferenceResolver.js +13 -8
- package/dist/component/lib/deepReferenceResolver.js.map +1 -1
- package/dist/component/lib/ragContentChunker.d.ts +3 -3
- package/dist/component/lib/ragContentChunker.d.ts.map +1 -1
- package/dist/component/lib/ragContentChunker.js +4 -4
- package/dist/component/lib/ragContentChunker.js.map +1 -1
- package/dist/component/lib/referenceResolver.d.ts.map +1 -1
- package/dist/component/lib/referenceResolver.js +10 -17
- package/dist/component/lib/referenceResolver.js.map +1 -1
- package/dist/component/mediaAssetMutations.js +4 -4
- package/dist/component/mediaAssetMutations.js.map +1 -1
- package/dist/component/ragContentIndexer.d.ts +2 -2
- package/dist/component/ragContentIndexer.d.ts.map +1 -1
- package/dist/component/ragContentIndexer.js +44 -48
- package/dist/component/ragContentIndexer.js.map +1 -1
- package/dist/component/roles.d.ts +3 -3
- package/dist/component/scheduledPublish.d.ts +4 -4
- package/dist/component/scheduledPublish.js +3 -3
- package/dist/component/scheduledPublish.js.map +1 -1
- package/dist/component/schema.d.ts +18 -18
- package/dist/component/schema.js +5 -5
- package/dist/component/schema.js.map +1 -1
- package/dist/component/trash.d.ts +6 -9
- package/dist/component/trash.d.ts.map +1 -1
- package/dist/component/trash.js +12 -36
- package/dist/component/trash.js.map +1 -1
- package/dist/component/userContext.d.ts +1 -2
- package/dist/component/userContext.d.ts.map +1 -1
- package/dist/component/userContext.js +1 -2
- package/dist/component/userContext.js.map +1 -1
- package/dist/component/validators.d.ts +27 -33
- package/dist/component/validators.d.ts.map +1 -1
- package/dist/component/validators.js +3 -5
- package/dist/component/validators.js.map +1 -1
- package/dist/component/versionMutations.d.ts +1 -1
- package/dist/component/webhookTrigger.d.ts +14 -14
- package/dist/test.d.ts +30 -30
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +24 -24
- package/dist/test.js.map +1 -1
- package/package.json +1 -1
- package/admin-dist/public/assets/CmsEmptyState-Do_erIgn.js +0 -5
- package/admin-dist/public/assets/CmsPageHeader-qDwPGi48.js +0 -1
- package/admin-dist/public/assets/CmsStatusBadge-Dd9uToHE.js +0 -1
- package/admin-dist/public/assets/CmsToolbar-D1-Y-7SK.js +0 -1
- package/admin-dist/public/assets/ContentEntryEditor-CWBiIx52.js +0 -4
- package/admin-dist/public/assets/TaxonomyFilter-CdYQawxb.js +0 -1
- package/admin-dist/public/assets/_contentTypeId-D9VMP6Gs.js +0 -1
- package/admin-dist/public/assets/_entryId-2FlCfqE7.js +0 -1
- package/admin-dist/public/assets/alert-GxZx0y5c.js +0 -1
- package/admin-dist/public/assets/badge-BAlGIjop.js +0 -1
- package/admin-dist/public/assets/command-di7XCqcv.js +0 -1
- package/admin-dist/public/assets/content-D8zELsDG.js +0 -1
- package/admin-dist/public/assets/content-types-BmzD0krT.js +0 -2
- package/admin-dist/public/assets/globals-BvFfH-v9.css +0 -1
- package/admin-dist/public/assets/index-zqfj4T_v.js +0 -1
- package/admin-dist/public/assets/label-B6PPtKR5.js +0 -1
- package/admin-dist/public/assets/link-2-W2fVnVOf.js +0 -1
- package/admin-dist/public/assets/list-F8O0lZXC.js +0 -1
- package/admin-dist/public/assets/main-dZT72bAG.js +0 -97
- package/admin-dist/public/assets/media-CETueFbV.js +0 -1
- package/admin-dist/public/assets/new._contentTypeId-BV2-TyyR.js +0 -1
- package/admin-dist/public/assets/plus-AABQIF0N.js +0 -1
- package/admin-dist/public/assets/scroll-area-CDfk-zrz.js +0 -1
- package/admin-dist/public/assets/select-BuiHcMzS.js +0 -1
- package/admin-dist/public/assets/settings-DBxbYDvn.js +0 -1
- package/admin-dist/public/assets/switch-DiJvolcs.js +0 -1
- package/admin-dist/public/assets/tabs-Cgz6G_Xy.js +0 -1
- package/admin-dist/public/assets/tanstack-adapter-BknsSgra.js +0 -1
- package/admin-dist/public/assets/taxonomies-DOErsLl5.js +0 -1
- package/admin-dist/public/assets/textarea-CgggMxUX.js +0 -1
- package/admin-dist/public/assets/trash-BU4ANuaW.js +0 -1
- package/admin-dist/public/assets/triangle-alert-lvCbwp0s.js +0 -1
- package/admin-dist/public/assets/usePermissions-D7tQowaF.js +0 -1
- package/admin-dist/server/_libs/h3-v2.mjs +0 -277
- package/admin-dist/server/_ssr/CmsButton-DbzfJru_.mjs +0 -125
- package/admin-dist/server/_ssr/CmsEmptyState-CuvcXr3Z.mjs +0 -290
- package/admin-dist/server/_ssr/_tanstack-start-manifest_v-Dk-FIYPN.mjs +0 -4
- package/admin-dist/server/_ssr/content-types-D25lUE-j.mjs +0 -1312
- package/admin-dist/server/_ssr/label-PblVvdRv.mjs +0 -22
- package/admin-dist/server/_ssr/router-x6Ab8T4s.mjs +0 -1622
- package/admin-dist/server/_ssr/select-CrfEkFJw.mjs +0 -142
- package/admin-dist/server/_ssr/textarea-CZVaroMc.mjs +0 -18
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Content Type Entries Page Component
|
|
3
|
+
*
|
|
4
|
+
* Lists entries for a specific content type with search, filtering, and actions.
|
|
5
|
+
* Used by both CLI routes and embed pages.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useState, useMemo, useEffect, useCallback } from "react";
|
|
9
|
+
import { useQuery, useMutation } from "convex/react";
|
|
10
|
+
import { usePermissions } from "~/hooks";
|
|
11
|
+
import { CmsPageHeader } from "~/components/cmsds/CmsPageHeader";
|
|
12
|
+
import { CmsToolbar } from "~/components/cmsds/CmsToolbar";
|
|
13
|
+
import { CmsButton } from "~/components/cmsds/CmsButton";
|
|
14
|
+
import { CmsStatusBadge, type ContentStatus } from "~/components/cmsds/CmsStatusBadge";
|
|
15
|
+
import { CmsEmptyState } from "~/components/cmsds/CmsEmptyState";
|
|
16
|
+
import { CmsConfirmDialog } from "~/components/cmsds/CmsDialog";
|
|
17
|
+
import { Input } from "~/components/ui/input";
|
|
18
|
+
import {
|
|
19
|
+
Select,
|
|
20
|
+
SelectContent,
|
|
21
|
+
SelectItem,
|
|
22
|
+
SelectTrigger,
|
|
23
|
+
SelectValue,
|
|
24
|
+
} from "~/components/ui/select";
|
|
25
|
+
import {
|
|
26
|
+
Search,
|
|
27
|
+
Plus,
|
|
28
|
+
FileText,
|
|
29
|
+
ChevronUp,
|
|
30
|
+
ChevronDown,
|
|
31
|
+
ArrowUpDown,
|
|
32
|
+
} from "lucide-react";
|
|
33
|
+
import type { AdminNavigation } from "~/lib/navigation";
|
|
34
|
+
import type { CmsAdminApi } from "~/embed/contexts/ApiContext";
|
|
35
|
+
|
|
36
|
+
type SortField = "title" | "status" | "updatedAt" | "createdAt";
|
|
37
|
+
type SortDirection = "asc" | "desc";
|
|
38
|
+
|
|
39
|
+
export interface ContentTypeEntriesPageProps {
|
|
40
|
+
api: CmsAdminApi;
|
|
41
|
+
navigation: AdminNavigation;
|
|
42
|
+
contentTypeId: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function ContentTypeEntriesPage({
|
|
46
|
+
api,
|
|
47
|
+
navigation,
|
|
48
|
+
contentTypeId,
|
|
49
|
+
}: ContentTypeEntriesPageProps) {
|
|
50
|
+
const [selectedStatus, setSelectedStatus] = useState<ContentStatus | "all">("all");
|
|
51
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
52
|
+
const [debouncedSearch, setDebouncedSearch] = useState("");
|
|
53
|
+
const [sortField, setSortField] = useState<SortField>("updatedAt");
|
|
54
|
+
const [sortDirection, setSortDirection] = useState<SortDirection>("desc");
|
|
55
|
+
const [currentPage, setCurrentPage] = useState(0);
|
|
56
|
+
const pageSize = 25;
|
|
57
|
+
|
|
58
|
+
const { canCreate, canUpdate, canDelete } = usePermissions();
|
|
59
|
+
|
|
60
|
+
const deleteEntry = useMutation(api.deleteEntry);
|
|
61
|
+
|
|
62
|
+
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
|
|
63
|
+
const [entryToDelete, setEntryToDelete] = useState<{ _id: string; title: string } | null>(null);
|
|
64
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
65
|
+
const [deleteError, setDeleteError] = useState<string | null>(null);
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
const timer = setTimeout(() => {
|
|
69
|
+
setDebouncedSearch(searchQuery);
|
|
70
|
+
setCurrentPage(0);
|
|
71
|
+
}, 300);
|
|
72
|
+
return () => clearTimeout(timer);
|
|
73
|
+
}, [searchQuery]);
|
|
74
|
+
|
|
75
|
+
const contentType = useQuery(api.getContentType, { id: contentTypeId });
|
|
76
|
+
|
|
77
|
+
const entriesResult = useQuery(api.listEntries, {
|
|
78
|
+
contentTypeName: contentType?.name,
|
|
79
|
+
status: selectedStatus === "all" ? undefined : selectedStatus,
|
|
80
|
+
search: debouncedSearch || undefined,
|
|
81
|
+
paginationOpts: { numItems: 250, cursor: null },
|
|
82
|
+
});
|
|
83
|
+
const allEntries = entriesResult?.page ?? [];
|
|
84
|
+
|
|
85
|
+
const getEntryTitle = useCallback(
|
|
86
|
+
(entry: { data: Record<string, unknown> }) => {
|
|
87
|
+
const titleField = contentType?.titleField ?? "title";
|
|
88
|
+
const title = entry.data[titleField];
|
|
89
|
+
return typeof title === "string" && title ? title : "Untitled";
|
|
90
|
+
},
|
|
91
|
+
[contentType?.titleField]
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const sortedEntries = useMemo(() => {
|
|
95
|
+
const entries = [...allEntries];
|
|
96
|
+
|
|
97
|
+
entries.sort((a, b) => {
|
|
98
|
+
let comparison = 0;
|
|
99
|
+
|
|
100
|
+
switch (sortField) {
|
|
101
|
+
case "title": {
|
|
102
|
+
const titleA = getEntryTitle(a).toLowerCase();
|
|
103
|
+
const titleB = getEntryTitle(b).toLowerCase();
|
|
104
|
+
comparison = titleA.localeCompare(titleB);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case "status":
|
|
108
|
+
comparison = a.status.localeCompare(b.status);
|
|
109
|
+
break;
|
|
110
|
+
case "updatedAt": {
|
|
111
|
+
const updatedA = a.lastPublishedAt ?? a._creationTime ?? 0;
|
|
112
|
+
const updatedB = b.lastPublishedAt ?? b._creationTime ?? 0;
|
|
113
|
+
comparison = updatedA - updatedB;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "createdAt":
|
|
117
|
+
comparison = (a._creationTime ?? 0) - (b._creationTime ?? 0);
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
comparison = 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return sortDirection === "desc" ? -comparison : comparison;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return entries;
|
|
127
|
+
}, [allEntries, sortField, sortDirection, getEntryTitle]);
|
|
128
|
+
|
|
129
|
+
const paginatedEntries = useMemo(() => {
|
|
130
|
+
const start = currentPage * pageSize;
|
|
131
|
+
return sortedEntries.slice(start, start + pageSize);
|
|
132
|
+
}, [sortedEntries, currentPage, pageSize]);
|
|
133
|
+
|
|
134
|
+
const totalPages = Math.ceil(sortedEntries.length / pageSize);
|
|
135
|
+
|
|
136
|
+
const formatDate = (timestamp: number) => {
|
|
137
|
+
return new Date(timestamp).toLocaleDateString("en-US", {
|
|
138
|
+
year: "numeric",
|
|
139
|
+
month: "short",
|
|
140
|
+
day: "numeric",
|
|
141
|
+
hour: "2-digit",
|
|
142
|
+
minute: "2-digit",
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const handleSort = (field: SortField) => {
|
|
147
|
+
if (sortField === field) {
|
|
148
|
+
setSortDirection(sortDirection === "asc" ? "desc" : "asc");
|
|
149
|
+
} else {
|
|
150
|
+
setSortField(field);
|
|
151
|
+
setSortDirection("desc");
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const getSortIcon = (field: SortField) => {
|
|
156
|
+
if (sortField !== field) {
|
|
157
|
+
return <ArrowUpDown className="size-3.5 text-muted-foreground/50" />;
|
|
158
|
+
}
|
|
159
|
+
return sortDirection === "asc" ? (
|
|
160
|
+
<ChevronUp className="size-3.5" />
|
|
161
|
+
) : (
|
|
162
|
+
<ChevronDown className="size-3.5" />
|
|
163
|
+
);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const handleDeleteClick = useCallback(
|
|
167
|
+
(entry: { _id: string; data: Record<string, unknown> }) => {
|
|
168
|
+
const title = getEntryTitle(entry);
|
|
169
|
+
setEntryToDelete({ _id: entry._id, title });
|
|
170
|
+
setDeleteError(null);
|
|
171
|
+
setDeleteModalOpen(true);
|
|
172
|
+
},
|
|
173
|
+
[getEntryTitle]
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const handleDeleteConfirm = useCallback(async () => {
|
|
177
|
+
if (!entryToDelete) return;
|
|
178
|
+
|
|
179
|
+
setIsDeleting(true);
|
|
180
|
+
setDeleteError(null);
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
await deleteEntry({
|
|
184
|
+
id: entryToDelete._id,
|
|
185
|
+
hardDelete: false,
|
|
186
|
+
});
|
|
187
|
+
setDeleteModalOpen(false);
|
|
188
|
+
setEntryToDelete(null);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
const message = error instanceof Error ? error.message : "Failed to delete entry";
|
|
191
|
+
setDeleteError(message);
|
|
192
|
+
} finally {
|
|
193
|
+
setIsDeleting(false);
|
|
194
|
+
}
|
|
195
|
+
}, [entryToDelete, deleteEntry]);
|
|
196
|
+
|
|
197
|
+
const handleDeleteModalClose = useCallback(
|
|
198
|
+
(open: boolean) => {
|
|
199
|
+
if (!open && !isDeleting) {
|
|
200
|
+
setDeleteModalOpen(false);
|
|
201
|
+
setEntryToDelete(null);
|
|
202
|
+
setDeleteError(null);
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
[isDeleting]
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const clearFilters = useCallback(() => {
|
|
209
|
+
setSearchQuery("");
|
|
210
|
+
setDebouncedSearch("");
|
|
211
|
+
setSelectedStatus("all");
|
|
212
|
+
setCurrentPage(0);
|
|
213
|
+
}, []);
|
|
214
|
+
|
|
215
|
+
if (contentType === undefined || entriesResult === undefined) {
|
|
216
|
+
return (
|
|
217
|
+
<div className="space-y-6 p-6">
|
|
218
|
+
<div className="flex flex-col items-center justify-center py-12">
|
|
219
|
+
<div className="size-8 animate-spin rounded-full border-2 border-muted border-t-primary" />
|
|
220
|
+
<p className="mt-4 text-sm text-muted-foreground">Loading entries...</p>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (contentType === null) {
|
|
227
|
+
return (
|
|
228
|
+
<div className="space-y-6 p-6">
|
|
229
|
+
<CmsEmptyState
|
|
230
|
+
icon={<FileText className="size-6" />}
|
|
231
|
+
title="Content Type Not Found"
|
|
232
|
+
description="The content type you're looking for doesn't exist or has been deleted."
|
|
233
|
+
action={{
|
|
234
|
+
label: "Back to Content Types",
|
|
235
|
+
onClick: () => navigation.navigate("/content-types"),
|
|
236
|
+
}}
|
|
237
|
+
/>
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const hasFilters = searchQuery || selectedStatus !== "all";
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
<div className="space-y-6 p-6">
|
|
246
|
+
<CmsPageHeader
|
|
247
|
+
title={contentType.displayName}
|
|
248
|
+
description={contentType.description}
|
|
249
|
+
actions={
|
|
250
|
+
canCreate("contentEntries") && (
|
|
251
|
+
<CmsButton onClick={() => navigation.navigateToNewEntry(contentTypeId)}>
|
|
252
|
+
<Plus className="size-4" />
|
|
253
|
+
Create {contentType.displayName}
|
|
254
|
+
</CmsButton>
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
/>
|
|
258
|
+
|
|
259
|
+
<CmsToolbar
|
|
260
|
+
left={
|
|
261
|
+
<div className="flex items-center gap-3">
|
|
262
|
+
<div className="relative">
|
|
263
|
+
<Search className="absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
|
264
|
+
<Input
|
|
265
|
+
type="search"
|
|
266
|
+
placeholder="Search entries..."
|
|
267
|
+
value={searchQuery}
|
|
268
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
269
|
+
className="w-64 pl-9"
|
|
270
|
+
/>
|
|
271
|
+
</div>
|
|
272
|
+
<Select
|
|
273
|
+
value={selectedStatus}
|
|
274
|
+
onValueChange={(value) => {
|
|
275
|
+
setSelectedStatus(value as ContentStatus | "all");
|
|
276
|
+
setCurrentPage(0);
|
|
277
|
+
}}
|
|
278
|
+
>
|
|
279
|
+
<SelectTrigger className="w-36">
|
|
280
|
+
<SelectValue placeholder="All Statuses" />
|
|
281
|
+
</SelectTrigger>
|
|
282
|
+
<SelectContent>
|
|
283
|
+
<SelectItem value="all">All Statuses</SelectItem>
|
|
284
|
+
<SelectItem value="draft">Draft</SelectItem>
|
|
285
|
+
<SelectItem value="published">Published</SelectItem>
|
|
286
|
+
<SelectItem value="scheduled">Scheduled</SelectItem>
|
|
287
|
+
<SelectItem value="archived">Archived</SelectItem>
|
|
288
|
+
</SelectContent>
|
|
289
|
+
</Select>
|
|
290
|
+
</div>
|
|
291
|
+
}
|
|
292
|
+
right={
|
|
293
|
+
<span className="text-sm text-muted-foreground">
|
|
294
|
+
{sortedEntries.length} {sortedEntries.length === 1 ? "entry" : "entries"}
|
|
295
|
+
</span>
|
|
296
|
+
}
|
|
297
|
+
/>
|
|
298
|
+
|
|
299
|
+
{sortedEntries.length === 0 ? (
|
|
300
|
+
<CmsEmptyState
|
|
301
|
+
icon={<FileText className="size-6" />}
|
|
302
|
+
title={hasFilters ? "No matching entries" : `No ${contentType.displayName} entries yet`}
|
|
303
|
+
description={
|
|
304
|
+
hasFilters
|
|
305
|
+
? "Try adjusting your search or filter criteria."
|
|
306
|
+
: `Click "Create ${contentType.displayName}" to add your first entry.`
|
|
307
|
+
}
|
|
308
|
+
action={
|
|
309
|
+
hasFilters
|
|
310
|
+
? { label: "Clear Filters", onClick: clearFilters, variant: "secondary" }
|
|
311
|
+
: undefined
|
|
312
|
+
}
|
|
313
|
+
/>
|
|
314
|
+
) : (
|
|
315
|
+
<>
|
|
316
|
+
<div className="rounded-lg border bg-card">
|
|
317
|
+
<table className="w-full">
|
|
318
|
+
<thead>
|
|
319
|
+
<tr className="border-b">
|
|
320
|
+
<th className="p-3 text-left">
|
|
321
|
+
<button
|
|
322
|
+
className="flex items-center gap-1.5 text-sm font-medium text-muted-foreground hover:text-foreground"
|
|
323
|
+
onClick={() => handleSort("title")}
|
|
324
|
+
>
|
|
325
|
+
Title
|
|
326
|
+
{getSortIcon("title")}
|
|
327
|
+
</button>
|
|
328
|
+
</th>
|
|
329
|
+
<th className="p-3 text-left">
|
|
330
|
+
<button
|
|
331
|
+
className="flex items-center gap-1.5 text-sm font-medium text-muted-foreground hover:text-foreground"
|
|
332
|
+
onClick={() => handleSort("status")}
|
|
333
|
+
>
|
|
334
|
+
Status
|
|
335
|
+
{getSortIcon("status")}
|
|
336
|
+
</button>
|
|
337
|
+
</th>
|
|
338
|
+
<th className="p-3 text-left">
|
|
339
|
+
<button
|
|
340
|
+
className="flex items-center gap-1.5 text-sm font-medium text-muted-foreground hover:text-foreground"
|
|
341
|
+
onClick={() => handleSort("updatedAt")}
|
|
342
|
+
>
|
|
343
|
+
Updated
|
|
344
|
+
{getSortIcon("updatedAt")}
|
|
345
|
+
</button>
|
|
346
|
+
</th>
|
|
347
|
+
<th className="p-3 text-left text-sm font-medium text-muted-foreground">
|
|
348
|
+
Actions
|
|
349
|
+
</th>
|
|
350
|
+
</tr>
|
|
351
|
+
</thead>
|
|
352
|
+
<tbody>
|
|
353
|
+
{paginatedEntries.map((entry) => (
|
|
354
|
+
<tr
|
|
355
|
+
key={entry._id}
|
|
356
|
+
className="border-b last:border-0 transition-colors hover:bg-muted/50"
|
|
357
|
+
>
|
|
358
|
+
<td className="p-3">
|
|
359
|
+
<button
|
|
360
|
+
type="button"
|
|
361
|
+
onClick={() => navigation.navigateToEntry(entry._id)}
|
|
362
|
+
className="text-left font-medium text-foreground hover:text-primary hover:underline"
|
|
363
|
+
>
|
|
364
|
+
{getEntryTitle(entry)}
|
|
365
|
+
</button>
|
|
366
|
+
<p className="text-xs text-muted-foreground">{entry.slug}</p>
|
|
367
|
+
</td>
|
|
368
|
+
<td className="p-3">
|
|
369
|
+
<CmsStatusBadge status={entry.status as ContentStatus} />
|
|
370
|
+
</td>
|
|
371
|
+
<td className="p-3 text-sm text-muted-foreground">
|
|
372
|
+
{formatDate(entry.lastPublishedAt ?? entry._creationTime)}
|
|
373
|
+
</td>
|
|
374
|
+
<td className="p-3">
|
|
375
|
+
<div className="flex items-center gap-2">
|
|
376
|
+
<CmsButton
|
|
377
|
+
variant="outline"
|
|
378
|
+
size="sm"
|
|
379
|
+
onClick={() => navigation.navigateToEntry(entry._id)}
|
|
380
|
+
>
|
|
381
|
+
{canUpdate("contentEntries") ? "Edit" : "View"}
|
|
382
|
+
</CmsButton>
|
|
383
|
+
{canDelete("contentEntries") && (
|
|
384
|
+
<CmsButton
|
|
385
|
+
variant="danger"
|
|
386
|
+
size="sm"
|
|
387
|
+
onClick={() => handleDeleteClick(entry)}
|
|
388
|
+
>
|
|
389
|
+
Delete
|
|
390
|
+
</CmsButton>
|
|
391
|
+
)}
|
|
392
|
+
</div>
|
|
393
|
+
</td>
|
|
394
|
+
</tr>
|
|
395
|
+
))}
|
|
396
|
+
</tbody>
|
|
397
|
+
</table>
|
|
398
|
+
</div>
|
|
399
|
+
|
|
400
|
+
{totalPages > 1 && (
|
|
401
|
+
<div className="flex items-center justify-center gap-2">
|
|
402
|
+
<CmsButton
|
|
403
|
+
variant="outline"
|
|
404
|
+
size="sm"
|
|
405
|
+
onClick={() => setCurrentPage(0)}
|
|
406
|
+
disabled={currentPage === 0}
|
|
407
|
+
>
|
|
408
|
+
First
|
|
409
|
+
</CmsButton>
|
|
410
|
+
<CmsButton
|
|
411
|
+
variant="outline"
|
|
412
|
+
size="sm"
|
|
413
|
+
onClick={() => setCurrentPage((p) => Math.max(0, p - 1))}
|
|
414
|
+
disabled={currentPage === 0}
|
|
415
|
+
>
|
|
416
|
+
Previous
|
|
417
|
+
</CmsButton>
|
|
418
|
+
<span className="px-3 text-sm text-muted-foreground">
|
|
419
|
+
Page {currentPage + 1} of {totalPages}
|
|
420
|
+
</span>
|
|
421
|
+
<CmsButton
|
|
422
|
+
variant="outline"
|
|
423
|
+
size="sm"
|
|
424
|
+
onClick={() => setCurrentPage((p) => Math.min(totalPages - 1, p + 1))}
|
|
425
|
+
disabled={currentPage >= totalPages - 1}
|
|
426
|
+
>
|
|
427
|
+
Next
|
|
428
|
+
</CmsButton>
|
|
429
|
+
<CmsButton
|
|
430
|
+
variant="outline"
|
|
431
|
+
size="sm"
|
|
432
|
+
onClick={() => setCurrentPage(totalPages - 1)}
|
|
433
|
+
disabled={currentPage >= totalPages - 1}
|
|
434
|
+
>
|
|
435
|
+
Last
|
|
436
|
+
</CmsButton>
|
|
437
|
+
</div>
|
|
438
|
+
)}
|
|
439
|
+
</>
|
|
440
|
+
)}
|
|
441
|
+
|
|
442
|
+
{sortedEntries.length > 0 && (
|
|
443
|
+
<p className="text-center text-sm text-muted-foreground">
|
|
444
|
+
Showing {paginatedEntries.length} of {sortedEntries.length}{" "}
|
|
445
|
+
{sortedEntries.length === 1 ? "entry" : "entries"}
|
|
446
|
+
</p>
|
|
447
|
+
)}
|
|
448
|
+
|
|
449
|
+
<CmsConfirmDialog
|
|
450
|
+
open={deleteModalOpen}
|
|
451
|
+
onOpenChange={handleDeleteModalClose}
|
|
452
|
+
title="Delete Entry"
|
|
453
|
+
description={
|
|
454
|
+
entryToDelete
|
|
455
|
+
? `Are you sure you want to delete "${entryToDelete.title}"? It will be moved to the trash and can be restored within the retention period.`
|
|
456
|
+
: "Are you sure you want to delete this entry?"
|
|
457
|
+
}
|
|
458
|
+
confirmLabel="Delete"
|
|
459
|
+
variant="danger"
|
|
460
|
+
onConfirm={handleDeleteConfirm}
|
|
461
|
+
isLoading={isDeleting}
|
|
462
|
+
error={deleteError}
|
|
463
|
+
/>
|
|
464
|
+
</div>
|
|
465
|
+
);
|
|
466
|
+
}
|
|
@@ -25,6 +25,7 @@ interface ContentTypeWithCount {
|
|
|
25
25
|
singleton?: boolean;
|
|
26
26
|
entryCount?: number;
|
|
27
27
|
_creationTime: number;
|
|
28
|
+
source?: "code" | "database";
|
|
28
29
|
}
|
|
29
30
|
import { CmsPageHeader } from "~/components/cmsds/CmsPageHeader";
|
|
30
31
|
import { CmsToolbar } from "~/components/cmsds/CmsToolbar";
|
|
@@ -51,6 +52,8 @@ import {
|
|
|
51
52
|
FolderOpen,
|
|
52
53
|
AlignLeft,
|
|
53
54
|
Pencil,
|
|
55
|
+
Code2,
|
|
56
|
+
Eye,
|
|
54
57
|
} from "lucide-react";
|
|
55
58
|
import type { AdminNavigation } from "~/lib/navigation";
|
|
56
59
|
import { CmsAdminApi } from "~/embed/contexts/ApiContext";
|
|
@@ -252,6 +255,16 @@ export function ContentTypesPage({ api, navigation }: ContentTypesPageProps) {
|
|
|
252
255
|
<FileType className="size-5" />
|
|
253
256
|
</div>
|
|
254
257
|
<div className="flex items-center gap-1.5">
|
|
258
|
+
{contentType.source === "code" && (
|
|
259
|
+
<Badge
|
|
260
|
+
variant="secondary"
|
|
261
|
+
className="border-violet-200 bg-violet-50 text-xs font-normal text-violet-700"
|
|
262
|
+
title="Managed by code - edit in your codebase"
|
|
263
|
+
>
|
|
264
|
+
<Code2 className="mr-1 size-3" />
|
|
265
|
+
Code
|
|
266
|
+
</Badge>
|
|
267
|
+
)}
|
|
255
268
|
{!contentType.isActive && (
|
|
256
269
|
<Badge variant="secondary" className="text-xs font-normal">
|
|
257
270
|
Inactive
|
|
@@ -260,19 +273,30 @@ export function ContentTypesPage({ api, navigation }: ContentTypesPageProps) {
|
|
|
260
273
|
{contentType.singleton && (
|
|
261
274
|
<Badge
|
|
262
275
|
variant="secondary"
|
|
263
|
-
className="border-
|
|
276
|
+
className="border-diff-modified-border bg-diff-modified-bg text-xs font-normal text-diff-modified-foreground"
|
|
264
277
|
>
|
|
265
278
|
Singleton
|
|
266
279
|
</Badge>
|
|
267
280
|
)}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
281
|
+
{contentType.source === "code" ? (
|
|
282
|
+
<button
|
|
283
|
+
className="rounded p-1.5 text-muted-foreground opacity-0 transition-all hover:bg-muted hover:text-foreground group-hover:opacity-100"
|
|
284
|
+
title="View content type (managed by code)"
|
|
285
|
+
aria-label="View content type"
|
|
286
|
+
onClick={() => setEditingContentType(contentType)}
|
|
287
|
+
>
|
|
288
|
+
<Eye className="size-4" />
|
|
289
|
+
</button>
|
|
290
|
+
) : (
|
|
291
|
+
<button
|
|
292
|
+
onClick={() => setEditingContentType(contentType)}
|
|
293
|
+
className="rounded p-1.5 text-muted-foreground opacity-0 transition-all hover:bg-muted hover:text-foreground group-hover:opacity-100"
|
|
294
|
+
title="Edit content type"
|
|
295
|
+
aria-label="Edit content type"
|
|
296
|
+
>
|
|
297
|
+
<Pencil className="size-4" />
|
|
298
|
+
</button>
|
|
299
|
+
)}
|
|
276
300
|
</div>
|
|
277
301
|
</div>
|
|
278
302
|
|
|
@@ -383,12 +407,22 @@ export function ContentTypesPage({ api, navigation }: ContentTypesPageProps) {
|
|
|
383
407
|
</td>
|
|
384
408
|
<td className="p-3">
|
|
385
409
|
<div className="flex items-center gap-1.5">
|
|
410
|
+
{contentType.source === "code" && (
|
|
411
|
+
<Badge
|
|
412
|
+
variant="secondary"
|
|
413
|
+
className="border-violet-200 bg-violet-50 text-xs font-normal text-violet-700"
|
|
414
|
+
title="Managed by code"
|
|
415
|
+
>
|
|
416
|
+
<Code2 className="mr-1 size-3" />
|
|
417
|
+
Code
|
|
418
|
+
</Badge>
|
|
419
|
+
)}
|
|
386
420
|
<Badge
|
|
387
421
|
variant={contentType.isActive ? "default" : "secondary"}
|
|
388
422
|
className={cn(
|
|
389
423
|
"text-xs font-normal",
|
|
390
424
|
contentType.isActive &&
|
|
391
|
-
"border-
|
|
425
|
+
"border-diff-added-border bg-diff-added-bg text-diff-added-foreground",
|
|
392
426
|
)}
|
|
393
427
|
>
|
|
394
428
|
{contentType.isActive ? "Active" : "Inactive"}
|
|
@@ -396,7 +430,7 @@ export function ContentTypesPage({ api, navigation }: ContentTypesPageProps) {
|
|
|
396
430
|
{contentType.singleton && (
|
|
397
431
|
<Badge
|
|
398
432
|
variant="secondary"
|
|
399
|
-
className="border-
|
|
433
|
+
className="border-diff-modified-border bg-diff-modified-bg text-xs font-normal text-diff-modified-foreground"
|
|
400
434
|
>
|
|
401
435
|
Singleton
|
|
402
436
|
</Badge>
|
|
@@ -408,14 +442,26 @@ export function ContentTypesPage({ api, navigation }: ContentTypesPageProps) {
|
|
|
408
442
|
</td>
|
|
409
443
|
<td className="p-3">
|
|
410
444
|
<div className="flex items-center gap-2">
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
445
|
+
{contentType.source === "code" ? (
|
|
446
|
+
<CmsButton
|
|
447
|
+
variant="outline"
|
|
448
|
+
size="sm"
|
|
449
|
+
onClick={() => setEditingContentType(contentType)}
|
|
450
|
+
title="View content type (managed by code)"
|
|
451
|
+
>
|
|
452
|
+
<Eye className="size-3.5" />
|
|
453
|
+
View
|
|
454
|
+
</CmsButton>
|
|
455
|
+
) : (
|
|
456
|
+
<CmsButton
|
|
457
|
+
variant="outline"
|
|
458
|
+
size="sm"
|
|
459
|
+
onClick={() => setEditingContentType(contentType)}
|
|
460
|
+
>
|
|
461
|
+
<Pencil className="size-3.5" />
|
|
462
|
+
Edit
|
|
463
|
+
</CmsButton>
|
|
464
|
+
)}
|
|
419
465
|
<CmsButton
|
|
420
466
|
variant="outline"
|
|
421
467
|
size="sm"
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "~/components/ui/card";
|
|
16
16
|
import { Skeleton } from "~/components/ui/skeleton";
|
|
17
17
|
import { CmsPageHeader } from "~/components/cmsds";
|
|
18
|
+
import { SchemaDriftWarning } from "~/components/SchemaDriftWarning";
|
|
18
19
|
import { FileText, Image, Layers, Settings, TrendingUp } from "lucide-react";
|
|
19
20
|
import type { AdminNavigation } from "~/lib/navigation";
|
|
20
21
|
import type { CmsAdminApi } from "~/embed/contexts/ApiContext";
|
|
@@ -36,6 +37,8 @@ export function DashboardPage({ api, navigation }: DashboardPageProps) {
|
|
|
36
37
|
description="Welcome to Convex CMS Admin. Manage your content, media, and publishing workflows."
|
|
37
38
|
/>
|
|
38
39
|
|
|
40
|
+
<SchemaDriftWarning api={api} />
|
|
41
|
+
|
|
39
42
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
|
40
43
|
<DashboardCard
|
|
41
44
|
title="Content Entries"
|
|
@@ -135,7 +135,7 @@ export function SettingsPage({
|
|
|
135
135
|
const adminConfig = useAdminConfig();
|
|
136
136
|
|
|
137
137
|
const isConfigured = useMemo(() => {
|
|
138
|
-
return
|
|
138
|
+
return api.getSettings != null;
|
|
139
139
|
}, [api]);
|
|
140
140
|
|
|
141
141
|
const settings = useQuery(
|
|
@@ -371,7 +371,7 @@ export function SettingsPage({
|
|
|
371
371
|
{feedbackStatus === "saved" && (
|
|
372
372
|
<Badge
|
|
373
373
|
variant="secondary"
|
|
374
|
-
className="gap-1 bg-
|
|
374
|
+
className="gap-1 bg-diff-added-bg text-diff-added-foreground"
|
|
375
375
|
>
|
|
376
376
|
<Check className="size-3" />
|
|
377
377
|
Settings saved successfully
|
|
@@ -517,9 +517,9 @@ export function SettingsPage({
|
|
|
517
517
|
{canEdit && api.resetSettings && (
|
|
518
518
|
<CmsSurface
|
|
519
519
|
elevation="base"
|
|
520
|
-
className="border-
|
|
520
|
+
className="border-destructive/50 p-6"
|
|
521
521
|
>
|
|
522
|
-
<h2 className="mb-4 text-lg font-semibold text-
|
|
522
|
+
<h2 className="mb-4 text-lg font-semibold text-destructive">
|
|
523
523
|
Danger Zone
|
|
524
524
|
</h2>
|
|
525
525
|
<div className="flex items-center justify-between">
|
package/admin/src/pages/index.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
export { ContentPage, type ContentPageProps } from "./ContentPage";
|
|
9
|
+
export { ContentTypeEntriesPage, type ContentTypeEntriesPageProps } from "./ContentTypeEntriesPage";
|
|
9
10
|
export { ContentTypesPage, type ContentTypesPageProps } from "./ContentTypesPage";
|
|
10
11
|
export { DashboardPage } from "./DashboardPage";
|
|
11
12
|
export { MediaPage, type MediaPageProps } from "./MediaPage";
|