From 88746203aa6c7b171d381896bc07d77b11d44b1e Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 14 Oct 2024 09:06:16 +0200 Subject: [PATCH] chore: hooks -> decorators Signed-off-by: blam --- .../scaffolder-backend/src/service/router.ts | 3 +- .../src/Template.v1beta3.schema.json | 4 +- .../src/TemplateEntityV1beta3.ts | 2 +- plugins/scaffolder-react/report.api.md | 2 +- .../src/next/components/Workflow/Workflow.tsx | 24 +++++------ ... => createScaffolderFormDecorator.test.ts} | 14 +++---- ...ok.ts => createScaffolderFormDecorator.ts} | 14 +++---- .../src/next/extensions/index.ts | 2 +- plugins/scaffolder-react/src/types.ts | 2 +- .../{FormHooksApi.ts => FormDecoratorsApi.ts} | 18 +++++---- plugins/scaffolder/src/alpha/api/ref.ts | 6 +-- plugins/scaffolder/src/alpha/api/types.ts | 6 +-- .../TemplateWizardPage/TemplateWizardPage.tsx | 6 +-- ...ks.test.tsx => useFormDecorators.test.tsx} | 40 ++++++++++--------- .../{useFormHooks.ts => useFormDecorators.ts} | 33 ++++++++------- 15 files changed, 91 insertions(+), 85 deletions(-) rename plugins/scaffolder-react/src/next/extensions/{createScaffolderFormHook.test.ts => createScaffolderFormDecorator.test.ts} (74%) rename plugins/scaffolder-react/src/next/extensions/{createScaffolderFormHook.ts => createScaffolderFormDecorator.ts} (83%) rename plugins/scaffolder/src/alpha/api/{FormHooksApi.ts => FormDecoratorsApi.ts} (57%) rename plugins/scaffolder/src/alpha/hooks/{useFormHooks.test.tsx => useFormDecorators.test.tsx} (68%) rename plugins/scaffolder/src/alpha/hooks/{useFormHooks.ts => useFormDecorators.ts} (57%) diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index c5457fe603..3bde8d19ae 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -475,7 +475,8 @@ export async function createRouter( description: schema.description, schema, })), - EXPERIMENTAL_formHooks: template.spec.EXPERIMENTAL_formHooks, + EXPERIMENTAL_formDecorators: + template.spec.EXPERIMENTAL_formDecorators, }); }, ) diff --git a/plugins/scaffolder-common/src/Template.v1beta3.schema.json b/plugins/scaffolder-common/src/Template.v1beta3.schema.json index a0392f63d9..9ab9c0ab5a 100644 --- a/plugins/scaffolder-common/src/Template.v1beta3.schema.json +++ b/plugins/scaffolder-common/src/Template.v1beta3.schema.json @@ -173,9 +173,9 @@ } } }, - "EXPERIMENTAL_formHooks": { + "EXPERIMENTAL_formDecorators": { "type": "object", - "description": "A list of hooks and their inputs that the form should trigger before submitting the job", + "description": "A list of decorators and their inputs that the form should trigger before submitting the job", "properties": { "id": { "type": "string", diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index 942de02bad..c5b576b5c2 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -59,7 +59,7 @@ export interface TemplateEntityV1beta3 extends Entity { /** * Form hooks to be run */ - EXPERIMENTAL_formHooks?: { id: string; input?: JsonObject }[]; + EXPERIMENTAL_formDecorators?: { id: string; input?: JsonObject }[]; /** * This is a JSONSchema or an array of JSONSchema's which is used to render a form in the frontend diff --git a/plugins/scaffolder-react/report.api.md b/plugins/scaffolder-react/report.api.md index 1c19729ee4..1ac2fd279b 100644 --- a/plugins/scaffolder-react/report.api.md +++ b/plugins/scaffolder-react/report.api.md @@ -538,7 +538,7 @@ export type TemplateParameterSchema = { description?: string; schema: JsonObject; }>; - EXPERIMENTAL_formHooks?: { + EXPERIMENTAL_formDecorators?: { id: string; input?: JsonObject; }[]; diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index 0d271095e7..785696436c 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -35,7 +35,7 @@ import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { useTemplateTimeSavedMinutes } from '../../hooks/useTemplateTimeSaved'; import { JsonValue } from '@backstage/types'; // eslint-disable-next-line @backstage/no-relative-monorepo-imports -import { useFormHooks } from '../../../../../scaffolder/src/alpha/hooks/useFormHooks'; +import { useFormDecorators } from '../../../../../scaffolder/src/alpha/hooks/useFormDecorators'; const useStyles = makeStyles({ markdown: { @@ -89,24 +89,24 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { const sortedManifest = useFilteredSchemaProperties(manifest); const minutesSaved = useTemplateTimeSavedMinutes(templateRef); const { setSecrets } = useTemplateSecrets(); - const formHooks = useFormHooks(); + const formDecorators = useFormDecorators(); const workflowOnCreate = useCallback( async (formState: Record) => { - if (manifest?.EXPERIMENTAL_formHooks && formHooks?.size) { - // for each of the form hooks, go and call the hook with the context + if (manifest?.EXPERIMENTAL_formDecorators && formDecorators?.size) { + // for each of the form decorators, go and call the decorator with the context await Promise.all( - manifest.EXPERIMENTAL_formHooks.map(async hook => { - const formHook = formHooks.get(hook.id); - if (!formHook) { + manifest.EXPERIMENTAL_formDecorators.map(async decorator => { + const formDecorator = formDecorators.get(decorator.id); + if (!formDecorator) { // eslint-disable-next-line no-console - console.error('Failed to find form hook', hook.id); + console.error('Failed to find form decorator', decorator.id); return; } - await formHook.fn({ + await formDecorator.fn({ setSecrets, - input: hook.input, + input: decorator.input, }); }), ); @@ -121,8 +121,8 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { }); }, [ - manifest?.EXPERIMENTAL_formHooks, - formHooks, + manifest?.EXPERIMENTAL_formDecorators, + formDecorators, onCreate, analytics, templateName, diff --git a/plugins/scaffolder-react/src/next/extensions/createScaffolderFormHook.test.ts b/plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.test.ts similarity index 74% rename from plugins/scaffolder-react/src/next/extensions/createScaffolderFormHook.test.ts rename to plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.test.ts index f694092af3..55d59cc249 100644 --- a/plugins/scaffolder-react/src/next/extensions/createScaffolderFormHook.test.ts +++ b/plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.test.ts @@ -13,21 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createScaffolderFormHook } from './createScaffolderFormHook'; +import { createScaffolderFormDecorator } from './createScaffolderFormDecorator'; -describe('createScaffolderFormHook', () => { - it('should return a hook', () => { - const hook = createScaffolderFormHook({ +describe('createScaffolderFormDecorator', () => { + it('should return a decorator', () => { + const decorator = createScaffolderFormDecorator({ id: 'test', deps: {}, fn: async () => {}, }); - expect(hook).toMatchInlineSnapshot(); + expect(decorator).toMatchInlineSnapshot(); }); it('should allow passing schema and be typesafe', () => { - const hook = createScaffolderFormHook({ + const decorator = createScaffolderFormDecorator({ id: 'test', deps: {}, schema: { @@ -46,6 +46,6 @@ describe('createScaffolderFormHook', () => { }, }); - expect(hook).toMatchInlineSnapshot(); + expect(decorator).toMatchInlineSnapshot(); }); }); diff --git a/plugins/scaffolder-react/src/next/extensions/createScaffolderFormHook.ts b/plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.ts similarity index 83% rename from plugins/scaffolder-react/src/next/extensions/createScaffolderFormHook.ts rename to plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.ts index 261a003745..fc70fc4d52 100644 --- a/plugins/scaffolder-react/src/next/extensions/createScaffolderFormHook.ts +++ b/plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.ts @@ -16,12 +16,12 @@ import { AnyApiRef } from '@backstage/core-plugin-api'; import { z } from 'zod'; -export type ScaffolderFormHookContext = { +export type ScaffolderFormDecoratorContext = { input: TInput; setSecrets: (input: Record) => void; }; -export type ScaffolderFormHook< +export type ScaffolderFormDecorator< TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } = {}, TDeps extends { [key in string]: AnyApiRef } = { [key in string]: AnyApiRef }, TInput extends {} = { @@ -35,7 +35,7 @@ export type ScaffolderFormHook< }; deps?: TDeps; fn: ( - ctx: ScaffolderFormHookContext, + ctx: ScaffolderFormDecoratorContext, deps: TDeps extends { [key in string]: AnyApiRef } ? { [key in keyof TDeps]: TDeps[key]['T'] } : never, @@ -43,11 +43,11 @@ export type ScaffolderFormHook< }; /** - * Method for creating hooks which can be used to collect + * Method for creating decorators which can be used to collect * secrets from the user before submitting to the backend. * @public */ -export function createScaffolderFormHook< +export function createScaffolderFormDecorator< TDeps extends { [key in string]: AnyApiRef }, TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType }, TInput extends {} = { @@ -60,12 +60,12 @@ export function createScaffolderFormHook< }; deps?: TDeps; fn: ( - ctx: ScaffolderFormHookContext, + ctx: ScaffolderFormDecoratorContext, deps: TDeps extends { [key in string]: AnyApiRef } ? { [key in keyof TDeps]: TDeps[key]['T'] } : never, ) => Promise; -}): ScaffolderFormHook { +}): ScaffolderFormDecorator { return { ...options, version: 'v1', diff --git a/plugins/scaffolder-react/src/next/extensions/index.ts b/plugins/scaffolder-react/src/next/extensions/index.ts index fff3dfbf4a..73bfa749f6 100644 --- a/plugins/scaffolder-react/src/next/extensions/index.ts +++ b/plugins/scaffolder-react/src/next/extensions/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './createScaffolderFormHook'; +export * from './createScaffolderFormDecorator'; diff --git a/plugins/scaffolder-react/src/types.ts b/plugins/scaffolder-react/src/types.ts index c75d830369..5f557198c6 100644 --- a/plugins/scaffolder-react/src/types.ts +++ b/plugins/scaffolder-react/src/types.ts @@ -33,5 +33,5 @@ export type TemplateParameterSchema = { description?: string; schema: JsonObject; }>; - EXPERIMENTAL_formHooks?: { id: string; input?: JsonObject }[]; + EXPERIMENTAL_formDecorators?: { id: string; input?: JsonObject }[]; }; diff --git a/plugins/scaffolder/src/alpha/api/FormHooksApi.ts b/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts similarity index 57% rename from plugins/scaffolder/src/alpha/api/FormHooksApi.ts rename to plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts index c8ea5d6cfa..38170f899a 100644 --- a/plugins/scaffolder/src/alpha/api/FormHooksApi.ts +++ b/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts @@ -14,21 +14,23 @@ * limitations under the License. */ -import { ScaffolderFormHooksApi } from './types'; -import { ScaffolderFormHook } from '@backstage/plugin-scaffolder-react/alpha'; +import { ScaffolderFormDecoratorsApi } from './types'; +import { ScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha'; -export class DefaultScaffolderFormHooksApi implements ScaffolderFormHooksApi { +export class DefaultScaffolderFormDecoratorsApi + implements ScaffolderFormDecoratorsApi +{ constructor( private readonly options: { - hooks: Array; + decorators: Array; }, ) {} - static create(options: { hooks: ScaffolderFormHook[] }) { - return new DefaultScaffolderFormHooksApi(options); + static create(options: { decorators: ScaffolderFormDecorator[] }) { + return new DefaultScaffolderFormDecoratorsApi(options); } - async getFormHooks(): Promise { - return this.options.hooks; + async getFormDecorators(): Promise { + return this.options.decorators; } } diff --git a/plugins/scaffolder/src/alpha/api/ref.ts b/plugins/scaffolder/src/alpha/api/ref.ts index d977f5a817..121f394dce 100644 --- a/plugins/scaffolder/src/alpha/api/ref.ts +++ b/plugins/scaffolder/src/alpha/api/ref.ts @@ -15,12 +15,12 @@ */ import { createApiRef } from '@backstage/frontend-plugin-api'; -import { ScaffolderFormFieldsApi, ScaffolderFormHooksApi } from './types'; +import { ScaffolderFormFieldsApi, ScaffolderFormDecoratorsApi } from './types'; export const formFieldsApiRef = createApiRef({ id: 'plugin.scaffolder.form-fields', }); -export const formHooksApiRef = createApiRef({ - id: 'plugin.scaffolder.form-hooks', +export const formDecoratorsApiRef = createApiRef({ + id: 'plugin.scaffolder.form-decorators', }); diff --git a/plugins/scaffolder/src/alpha/api/types.ts b/plugins/scaffolder/src/alpha/api/types.ts index 98c47f72a9..28ce8dab3d 100644 --- a/plugins/scaffolder/src/alpha/api/types.ts +++ b/plugins/scaffolder/src/alpha/api/types.ts @@ -16,13 +16,13 @@ import { FormFieldExtensionData, - ScaffolderFormHook, + ScaffolderFormDecorator, } from '@backstage/plugin-scaffolder-react/alpha'; export interface ScaffolderFormFieldsApi { getFormFields(): Promise; } -export interface ScaffolderFormHooksApi { - getFormHooks(): Promise; +export interface ScaffolderFormDecoratorsApi { + getFormDecorators(): Promise; } diff --git a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx index 70436bbd3e..b5e24a7d52 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx @@ -36,10 +36,7 @@ import { } from '@backstage/plugin-scaffolder-react'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; -import { - ScaffolderFormHook, - Workflow, -} from '@backstage/plugin-scaffolder-react/alpha'; +import { Workflow } from '@backstage/plugin-scaffolder-react/alpha'; import { JsonValue } from '@backstage/types'; import { Header, Page } from '@backstage/core-components'; @@ -68,7 +65,6 @@ export type TemplateWizardPageProps = { title?: string; subtitle?: string; }; - EXPERIMENTAL_formHooks?: ScaffolderFormHook[]; }; export const TemplateWizardPage = (props: TemplateWizardPageProps) => { diff --git a/plugins/scaffolder/src/alpha/hooks/useFormHooks.test.tsx b/plugins/scaffolder/src/alpha/hooks/useFormDecorators.test.tsx similarity index 68% rename from plugins/scaffolder/src/alpha/hooks/useFormHooks.test.tsx rename to plugins/scaffolder/src/alpha/hooks/useFormDecorators.test.tsx index d6ede80831..cdc3eef918 100644 --- a/plugins/scaffolder/src/alpha/hooks/useFormHooks.test.tsx +++ b/plugins/scaffolder/src/alpha/hooks/useFormDecorators.test.tsx @@ -13,24 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { DefaultScaffolderFormHooksApi } from '../api/FormHooksApi'; -import { createScaffolderFormHook } from '@backstage/plugin-scaffolder-react/alpha'; +import { DefaultScaffolderFormDecoratorsApi } from '../api/FormDecoratorsApi'; +import { createScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha'; import { createApiRef } from '@backstage/core-plugin-api'; import { TestApiProvider, withLogCollector } from '@backstage/test-utils'; import { renderHook } from '@testing-library/react'; -import { useFormHooks } from './useFormHooks'; +import { useFormDecorators } from './useFormDecorators'; import React from 'react'; -import { formHooksApiRef } from '../api/ref'; +import { formDecoratorsApiRef } from '../api/ref'; -describe('useFormHooks', () => { +describe('useFormDecorators', () => { const mockApiRef = createApiRef<{ test: (input: string) => void; }>({ id: 'test' }); const mockApiImplementation = { test: jest.fn() }; - const mockHook = createScaffolderFormHook({ + const mockDecorator = createScaffolderFormDecorator({ id: 'test', deps: { mockApiRef }, schema: { @@ -43,16 +43,18 @@ describe('useFormHooks', () => { }, }); - it('should wrap up the form hooks', async () => { - const renderedHook = renderHook(() => useFormHooks(), { + it('should wrap up the form decorators', async () => { + const renderedHook = renderHook(() => useFormDecorators(), { wrapper: ({ children }) => ( @@ -65,10 +67,10 @@ describe('useFormHooks', () => { expect(result.size).toBe(1); - const testHook = result.get('test')!; - expect(testHook).toBeDefined(); + const testDecorator = result.get('test')!; + expect(testDecorator).toBeDefined(); - await testHook.fn({ + await testDecorator.fn({ setSecrets: () => {}, input: { test: 'input value' }, }); @@ -78,14 +80,16 @@ describe('useFormHooks', () => { it('should skip failing deps', async () => { const { error } = await withLogCollector(async () => { - const renderedHook = renderHook(() => useFormHooks(), { + const renderedHook = renderHook(() => useFormDecorators(), { wrapper: ({ children }) => ( diff --git a/plugins/scaffolder/src/alpha/hooks/useFormHooks.ts b/plugins/scaffolder/src/alpha/hooks/useFormDecorators.ts similarity index 57% rename from plugins/scaffolder/src/alpha/hooks/useFormHooks.ts rename to plugins/scaffolder/src/alpha/hooks/useFormDecorators.ts index 85f25cfbd4..293c81996d 100644 --- a/plugins/scaffolder/src/alpha/hooks/useFormHooks.ts +++ b/plugins/scaffolder/src/alpha/hooks/useFormDecorators.ts @@ -14,40 +14,43 @@ * limitations under the License. */ import { useApi, useApiHolder } from '@backstage/core-plugin-api'; -import { formHooksApiRef } from '../api/ref'; +import { formDecoratorsApiRef } from '../api/ref'; import useAsync from 'react-use/esm/useAsync'; import { useMemo } from 'react'; -import { ScaffolderFormHookContext } from '@backstage/plugin-scaffolder-react/alpha'; +import { ScaffolderFormDecoratorContext } from '@backstage/plugin-scaffolder-react/alpha'; /** @internal */ -type BoundFieldHook = { - fn: (ctx: ScaffolderFormHookContext) => Promise; +type BoundFieldDecorator = { + fn: (ctx: ScaffolderFormDecoratorContext) => Promise; }; -export const useFormHooks = () => { - const formHooksApi = useApi(formHooksApiRef); - const { value: hooks } = useAsync(() => formHooksApi.getFormHooks(), []); +export const useFormDecorators = () => { + const formDecoratorsApi = useApi(formDecoratorsApiRef); + const { value: decorators } = useAsync( + () => formDecoratorsApi.getFormDecorators(), + [], + ); const apiHolder = useApiHolder(); return useMemo(() => { - const hooksMap = new Map(); + const decoratorsMap = new Map(); - for (const hook of hooks ?? []) { + for (const decorator of decorators ?? []) { try { - const resolvedDeps = Object.entries(hook.deps ?? {}).map( + const resolvedDeps = Object.entries(decorator.deps ?? {}).map( ([key, value]) => { const api = apiHolder.get(value); if (!api) { throw new Error( - `Failed to resolve apiRef ${value.id} for form hook ${hook.id} it will be disabled`, + `Failed to resolve apiRef ${value.id} for form decorator ${decorator.id} it will be disabled`, ); } return [key, api]; }, ); - hooksMap.set(hook.id, { - fn: ctx => hook.fn(ctx, Object.fromEntries(resolvedDeps)), + decoratorsMap.set(decorator.id, { + fn: ctx => decorator.fn(ctx, Object.fromEntries(resolvedDeps)), }); } catch (ex) { // eslint-disable-next-line no-console @@ -55,6 +58,6 @@ export const useFormHooks = () => { return undefined; } } - return hooksMap; - }, [apiHolder, hooks]); + return decoratorsMap; + }, [apiHolder, decorators]); };