diff --git a/examples/getstarted/config/admin.js b/examples/getstarted/config/admin.js index 16b79cca58..325d09e97c 100644 --- a/examples/getstarted/config/admin.js +++ b/examples/getstarted/config/admin.js @@ -18,4 +18,12 @@ module.exports = ({ env }) => ({ nps: env.bool('FLAG_NPS', true), promoteEE: env.bool('FLAG_PROMOTE_EE', true), }, + preview: { + enabled: env.bool('PREVIEW_ENABLED', true), + config: { + handler: (uid, { documentId, locale, status }) => { + return `/preview/${uid}/${documentId}/${locale}/${status}`; + }, + }, + }, }); diff --git a/packages/core/content-manager/server/src/preview/index.ts b/packages/core/content-manager/server/src/preview/index.ts index ff2ba6ee2e..8d4a8dcef0 100644 --- a/packages/core/content-manager/server/src/preview/index.ts +++ b/packages/core/content-manager/server/src/preview/index.ts @@ -4,6 +4,7 @@ import { FEATURE_ID } from './constants'; import { routes } from './routes'; import { controllers } from './controllers'; import { services } from './services'; +import { getService } from './utils'; /** * Check once if the feature is enabled before loading it, @@ -24,11 +25,8 @@ const getFeature = (): Partial => { // eslint-disable-next-line no-console -- TODO remove when we have real functionality console.log('Bootstrapping preview server'); - // eslint-disable-next-line @typescript-eslint/no-unused-vars -- TODO: Remove when implemented - const config = strapi.config.get('admin.preview'); - - // TODO: Validation - // TODO: Disable feature if config is not valid + const config = getService(strapi, 'preview-config'); + config.validate(); }, routes, controllers, diff --git a/packages/core/content-manager/server/src/preview/services/__tests__/preview-config.test.ts b/packages/core/content-manager/server/src/preview/services/__tests__/preview-config.test.ts new file mode 100644 index 0000000000..f04ffa1b3f --- /dev/null +++ b/packages/core/content-manager/server/src/preview/services/__tests__/preview-config.test.ts @@ -0,0 +1,55 @@ +import { createPreviewConfigService } from '../preview-config'; + +const getConfig = (enabled: boolean, handler: () => void) => { + return { + enabled, + config: { + handler, + }, + }; +}; + +describe('Preview Config', () => { + test('Is not enabled by default', () => { + const strapi = { + config: { + get: () => undefined, + }, + } as any; + + expect(createPreviewConfigService({ strapi }).isEnabled()).toBe(false); + }); + + test('Is enabled when configuration is set', () => { + const strapi = { + config: { + get: () => getConfig(true, () => {}), + }, + } as any; + + expect(createPreviewConfigService({ strapi }).isEnabled()).toBe(true); + }); + + describe('Validation', () => { + test('Passes on valid configuration', () => { + const strapi = { + config: { + get: () => getConfig(true, () => {}), + }, + } as any; + + createPreviewConfigService({ strapi }).validate(); + }); + + test('Fails on missing handler', () => { + const strapi = { + config: { + // @ts-expect-error - invalid handler + get: () => getConfig(true, 3), + }, + } as any; + + expect(() => createPreviewConfigService({ strapi }).validate()).toThrowError(); + }); + }); +}); diff --git a/packages/core/content-manager/server/src/preview/services/index.ts b/packages/core/content-manager/server/src/preview/services/index.ts index f1fa9b69db..f542aceffa 100644 --- a/packages/core/content-manager/server/src/preview/services/index.ts +++ b/packages/core/content-manager/server/src/preview/services/index.ts @@ -1,6 +1,9 @@ import type { Plugin } from '@strapi/types'; + import { createPreviewService } from './preview'; +import { createPreviewConfigService } from './preview-config'; export const services = { preview: createPreviewService, + 'preview-config': createPreviewConfigService, } satisfies Plugin.LoadedPlugin['services']; diff --git a/packages/core/content-manager/server/src/preview/services/preview-config.ts b/packages/core/content-manager/server/src/preview/services/preview-config.ts new file mode 100644 index 0000000000..1fc9007cd5 --- /dev/null +++ b/packages/core/content-manager/server/src/preview/services/preview-config.ts @@ -0,0 +1,69 @@ +import type { Core, UID } from '@strapi/types'; +import { errors } from '@strapi/utils'; + +export type HandlerParams = { + documentId: string; + locale: string; + status: 'published' | 'draft'; +}; + +export interface PreviewConfig { + enabled: boolean; + config: { + handler: (uid: UID.Schema, params: HandlerParams) => string | undefined; + }; +} + +/** + * Read configuration for static preview + */ +const createPreviewConfigService = ({ strapi }: { strapi: Core.Strapi }) => { + return { + isEnabled() { + const config = strapi.config.get('admin.preview') as PreviewConfig; + + if (!config) { + return false; + } + + return config?.enabled ?? true; + }, + + /** + * Validate if the configuration is valid + */ + validate() { + if (!this.isEnabled()) { + return; + } + + const handler = this.getPreviewHandler(); + + // Handler must be a function + if (typeof handler !== 'function') { + throw new errors.ValidationError( + 'Preview configuration is invalid. Handler must be a function' + ); + } + }, + + /** + * Utility to get the preview handler from the configuration + */ + getPreviewHandler(): PreviewConfig['config']['handler'] { + const config = strapi.config.get('admin.preview') as PreviewConfig; + + const emptyHandler = () => { + return undefined; + }; + + if (!this.isEnabled()) { + return emptyHandler; + } + + return config?.config?.handler || emptyHandler; + }, + }; +}; + +export { createPreviewConfigService };