From 5c71a35d1c91bc38aadd629c3e92cf40fb42aa4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20de=20Alba?= Date: Fri, 17 Jan 2025 15:51:50 +0100 Subject: [PATCH] Route registry (#6600) --- packages/coresandbox/src/index.ts | 10 +++ packages/registry/news/6600.feature | 1 + packages/registry/src/index.ts | 16 ++++ packages/registry/src/registry.test.tsx | 97 +++++++++++++++++++++++++ packages/types/news/6600.feature | 1 + packages/types/src/config/index.d.ts | 18 +++++ packages/types/src/utils.d.ts | 8 ++ 7 files changed, 151 insertions(+) create mode 100644 packages/registry/news/6600.feature create mode 100644 packages/types/news/6600.feature diff --git a/packages/coresandbox/src/index.ts b/packages/coresandbox/src/index.ts index a27e22cd2d..ec4979d483 100644 --- a/packages/coresandbox/src/index.ts +++ b/packages/coresandbox/src/index.ts @@ -235,6 +235,16 @@ const applyConfig = (config: ConfigType) => { predicates: [ContentTypeCondition(['Document']), RouteCondition('/hello')], }); + config.registerRoute({ + type: 'route', + path: '/hello', + file: 'src/components/Views/NewsAndEvents/asd.tsx', + options: { + id: 'hello', + index: true, + }, + }); + return config; }; diff --git a/packages/registry/news/6600.feature b/packages/registry/news/6600.feature new file mode 100644 index 0000000000..946395b56f --- /dev/null +++ b/packages/registry/news/6600.feature @@ -0,0 +1 @@ +Added route registry. @sneridagh diff --git a/packages/registry/src/index.ts b/packages/registry/src/index.ts index 5394254281..2254fa42b6 100644 --- a/packages/registry/src/index.ts +++ b/packages/registry/src/index.ts @@ -13,6 +13,7 @@ import type { UtilitiesConfig, ViewsConfig, WidgetsConfig, + ReactRouterRouteEntry, } from '@plone/types'; export type ConfigData = { @@ -22,6 +23,7 @@ export type ConfigData = { widgets: WidgetsConfig | Record; addonReducers?: AddonReducersConfig; addonRoutes?: AddonRoutesConfig; + routes?: Array; slots: SlotsConfig | Record; components: ComponentsConfig | Record; utilities: UtilitiesConfig | Record; @@ -126,6 +128,14 @@ class Config { this._data.addonRoutes = addonRoutes; } + get routes() { + return this._data.routes; + } + + set routes(routes) { + this._data.routes = routes; + } + get slots() { return this._data.slots; } @@ -494,6 +504,12 @@ class Config { return utilities; } + + registerRoute(options: ReactRouterRouteEntry) { + const route = this._data.routes || []; + route.push(options); + this._data.routes = route; + } } const instance = new Config(); diff --git a/packages/registry/src/registry.test.tsx b/packages/registry/src/registry.test.tsx index 90ad418249..02df01d9d6 100644 --- a/packages/registry/src/registry.test.tsx +++ b/packages/registry/src/registry.test.tsx @@ -1073,3 +1073,100 @@ describe('Utilities registry', () => { ).toEqual([]); }); }); + +describe('Routes registry', () => { + afterEach(() => { + config.set('routes', []); + }); + + it('registers a simple route', () => { + config.registerRoute({ + type: 'route', + path: '/login', + file: 'login.tsx', + }); + + expect(config.routes).toEqual([ + { + type: 'route', + path: '/login', + file: 'login.tsx', + }, + ]); + }); + + it('registers a simple route with options', () => { + config.registerRoute({ + type: 'route', + path: '/login', + file: 'login.tsx', + options: { id: 'login', caseSensitive: true }, + }); + + expect(config.routes).toEqual([ + { + type: 'route', + path: '/login', + file: 'login.tsx', + options: { id: 'login', caseSensitive: true }, + }, + ]); + }); + + it('registers a nested route', () => { + config.registerRoute({ + type: 'route', + path: '/login', + file: 'login.tsx', + children: [ + { + type: 'route', + path: '/login/ok', + file: 'ok.tsx', + }, + ], + }); + + expect(config.routes).toEqual([ + { + type: 'route', + path: '/login', + file: 'login.tsx', + children: [ + { + type: 'route', + path: '/login/ok', + file: 'ok.tsx', + }, + ], + }, + ]); + }); + + it('registers a couple of routes', () => { + config.registerRoute({ + type: 'route', + path: '/login', + file: 'login.tsx', + }); + + config.registerRoute({ + type: 'route', + path: '/logout', + file: 'logout.tsx', + }); + + expect(config.routes).toEqual([ + { + type: 'route', + path: '/login', + file: 'login.tsx', + }, + { + type: 'route', + path: '/logout', + file: 'logout.tsx', + }, + ]); + }); +}); diff --git a/packages/types/news/6600.feature b/packages/types/news/6600.feature new file mode 100644 index 0000000000..cfa4d841ba --- /dev/null +++ b/packages/types/news/6600.feature @@ -0,0 +1 @@ +Added typings for the route registry. @sneridagh diff --git a/packages/types/src/config/index.d.ts b/packages/types/src/config/index.d.ts index 58be498702..1ae06e1fdc 100644 --- a/packages/types/src/config/index.d.ts +++ b/packages/types/src/config/index.d.ts @@ -13,6 +13,24 @@ export type AddonRoutesConfig = { component: React.ComponentType; }[]; +export type AddonRoutesEntry = { + path: string; + exact: boolean; + component: React.ComponentType; +}; + +export type ReactRouterRouteEntry = { + type: 'route' | 'index' | 'layout' | 'prefix'; + path: string; + file: string; + options?: { + id?: string; + index?: boolean; + caseSensitive?: boolean; + }; + children?: ReactRouterRouteEntry[]; +}; + export type ComponentsConfig = Record< string, { component: React.ComponentType } diff --git a/packages/types/src/utils.d.ts b/packages/types/src/utils.d.ts index 220a792ceb..a564760a68 100644 --- a/packages/types/src/utils.d.ts +++ b/packages/types/src/utils.d.ts @@ -2,3 +2,11 @@ * Get the type of the elements in an array */ export type ArrayElement = A extends readonly (infer T)[] ? T : never; + +export type RequireAtLeastOne = Pick< + T, + Exclude +> & + { + [K in Keys]-?: Required> & Partial>>; + }[Keys];