From ef818fd5c8107e4e11e9c854971053cdfabd1749 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Wed, 28 Aug 2024 13:56:52 -0400 Subject: [PATCH] fix(ui): admin.dependencies components not added to client config (#7928) --- docs/admin/components.mdx | 42 +++++++++++++++++++ packages/payload/src/config/client.ts | 3 +- .../Config/createClientConfig/index.tsx | 24 +++++++++++ .../components/AfterDashboardClient/index.tsx | 17 ++++++++ test/admin/components/TestComponent.tsx | 6 +++ test/admin/config.ts | 14 ++++++- 6 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 test/admin/components/AfterDashboardClient/index.tsx create mode 100644 test/admin/components/TestComponent.tsx diff --git a/docs/admin/components.mdx b/docs/admin/components.mdx index b87003be2b..b9e8b09ade 100644 --- a/docs/admin/components.mdx +++ b/docs/admin/components.mdx @@ -196,6 +196,48 @@ import { MyFieldComponent } from 'my-external-package/client' which is a valid way to access MyFieldComponent that can be resolved by the consuming project. +### Custom Components from unknown locations + +By default, any component paths from known locations are added to the import map. However, if you need to add any components from unknown locations to the import map, you can do so by adding them to the `admin.dependencies` array in your Payload Config. This is mostly only relevant for plugin authors and not for regular Payload users. + +Example: + +```ts +export default { + // ... + admin: { + // ... + dependencies: { + myTestComponent: { // myTestComponent is the key - can be anything + path: '/components/TestComponent.js#TestComponent', + type: 'component', + clientProps: { + test: 'hello', + }, + }, + }, + } +} +``` + +This way, `TestComponent` is added to the import map, no matter if it's referenced in a known location or not. On the client, you can then use the component like this: + +```tsx +'use client' + +import { RenderComponent, useConfig } from '@payloadcms/ui' +import React from 'react' + +export const CustomView = () => { + const { config } = useConfig() + return ( +
+ +
+ ) +} +``` + ## Root Components Root Components are those that effect the [Admin Panel](./overview) generally, such as the logo or the main nav. diff --git a/packages/payload/src/config/client.ts b/packages/payload/src/config/client.ts index 60c059e9d1..76d7f4c929 100644 --- a/packages/payload/src/config/client.ts +++ b/packages/payload/src/config/client.ts @@ -39,8 +39,9 @@ export type ClientConfig = { Logo: MappedComponent } } + dependencies?: Record livePreview?: Omit - } & Omit + } & Omit collections: ClientCollectionConfig[] custom?: Record globals: ClientGlobalConfig[] diff --git a/packages/ui/src/providers/Config/createClientConfig/index.tsx b/packages/ui/src/providers/Config/createClientConfig/index.tsx index 58d1e63d2a..ddc1cdf156 100644 --- a/packages/ui/src/providers/Config/createClientConfig/index.tsx +++ b/packages/ui/src/providers/Config/createClientConfig/index.tsx @@ -6,6 +6,7 @@ import { type EditViewProps, type ImportMap, type Payload, + type PayloadComponent, type SanitizedConfig, deepCopyObjectSimple, serverOnlyConfigProperties, @@ -113,6 +114,29 @@ export const createClientConfig = async ({ 'config.admin.components.graphics.Logo', ) } + + if (config.admin?.dependencies) { + clientConfig.admin.dependencies = {} + for (const key in config.admin.dependencies) { + const dependency = config.admin.dependencies[key] + + if (dependency.type === 'component') { + const payloadComponent: PayloadComponent = { + clientProps: dependency.clientProps, + path: dependency.path, + serverProps: dependency.serverProps, + } + + clientConfig.admin.dependencies[key] = createMappedComponent( + payloadComponent, + undefined, + undefined, + `config.admin.dependencies.${key}`, + ) + continue + } + } + } } if ( diff --git a/test/admin/components/AfterDashboardClient/index.tsx b/test/admin/components/AfterDashboardClient/index.tsx new file mode 100644 index 0000000000..39f614cc34 --- /dev/null +++ b/test/admin/components/AfterDashboardClient/index.tsx @@ -0,0 +1,17 @@ +'use client' +import type { PayloadClientReactComponent, SanitizedConfig } from 'payload' + +import { RenderComponent, useConfig } from '@payloadcms/ui' +import React from 'react' + +export const AfterDashboardClient: PayloadClientReactComponent< + SanitizedConfig['admin']['components']['afterDashboard'][0] +> = () => { + const { config } = useConfig() + return ( +
+

Admin Dependency test component:

+ +
+ ) +} diff --git a/test/admin/components/TestComponent.tsx b/test/admin/components/TestComponent.tsx new file mode 100644 index 0000000000..764c31119a --- /dev/null +++ b/test/admin/components/TestComponent.tsx @@ -0,0 +1,6 @@ +'use client' +import React from 'react' + +export const TestComponent: React.FC = () => { + return
Test Component
+} diff --git a/test/admin/config.ts b/test/admin/config.ts index 428466b335..86d6dccf8f 100644 --- a/test/admin/config.ts +++ b/test/admin/config.ts @@ -41,7 +41,10 @@ export default buildConfigWithDefaults({ }, components: { actions: ['/components/AdminButton/index.js#AdminButton'], - afterDashboard: ['/components/AfterDashboard/index.js#AfterDashboard'], + afterDashboard: [ + '/components/AfterDashboard/index.js#AfterDashboard', + '/components/AfterDashboardClient/index.js#AfterDashboardClient', + ], afterNavLinks: ['/components/AfterNavLinks/index.js#AfterNavLinks'], beforeLogin: ['/components/BeforeLogin/index.js#BeforeLogin'], logout: { @@ -104,6 +107,15 @@ export default buildConfigWithDefaults({ titleSuffix: '- Custom Title Suffix', }, routes: customAdminRoutes, + dependencies: { + myTestComponent: { + path: '/components/TestComponent.js#TestComponent', + type: 'component', + clientProps: { + test: 'hello', + }, + }, + }, }, collections: [ UploadCollection,