diff --git a/plugins/scaffolder-react/api-report.md b/plugins/scaffolder-react/api-report.md index cc6a725012..f2076f8f95 100644 --- a/plugins/scaffolder-react/api-report.md +++ b/plugins/scaffolder-react/api-report.md @@ -65,6 +65,11 @@ export function createScaffolderFieldExtension< options: FieldExtensionOptions, ): Extension>; +// @public +export function createScaffolderLayout( + options: LayoutOptions, +): Extension>; + // @public export type CustomFieldExtensionSchema = { returnValue: JSONSchema7; @@ -122,6 +127,9 @@ export type FormProps = Pick< 'transformErrors' | 'noHtml5Validate' >; +// @public +export type LayoutComponent<_TInputProps> = () => null; + // @public export interface LayoutOptions

{ // (undocumented) @@ -289,6 +297,9 @@ export interface ScaffolderGetIntegrationsListResponse { }[]; } +// @public +export const ScaffolderLayouts: React.ComponentType; + // @public (undocumented) export type ScaffolderOutputLink = { title?: string; diff --git a/plugins/scaffolder-react/src/extensions/index.tsx b/plugins/scaffolder-react/src/extensions/index.tsx index 33442f6697..d70f5e36c5 100644 --- a/plugins/scaffolder-react/src/extensions/index.tsx +++ b/plugins/scaffolder-react/src/extensions/index.tsx @@ -25,7 +25,8 @@ import { Extension, attachComponentData } from '@backstage/core-plugin-api'; import { FIELD_EXTENSION_KEY, FIELD_EXTENSION_WRAPPER_KEY } from './keys'; /** - * A type used to wrap up the FieldExtension to embed the ReturnValue and the InputProps + * The type used to wrap up the Layout and embed the input props + * * @public */ export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null; diff --git a/plugins/scaffolder-react/src/next/index.ts b/plugins/scaffolder-react/src/next/index.ts index a75aa812d3..4674c1f70a 100644 --- a/plugins/scaffolder-react/src/next/index.ts +++ b/plugins/scaffolder-react/src/next/index.ts @@ -15,6 +15,7 @@ */ export * from './components'; export * from './extensions'; +export * from './layouts'; export * from './types'; export * from './lib'; export * from './hooks'; diff --git a/plugins/scaffolder-react/src/next/layouts/index.tsx b/plugins/scaffolder-react/src/next/layouts/index.tsx index 560748af59..0b1533c7c8 100644 --- a/plugins/scaffolder-react/src/next/layouts/index.tsx +++ b/plugins/scaffolder-react/src/next/layouts/index.tsx @@ -18,6 +18,10 @@ import { LAYOUTS_KEY, LAYOUTS_WRAPPER_KEY } from './keys'; */ import { attachComponentData, Extension } from '@backstage/core-plugin-api'; +/** + * A type used to wrap up the FieldExtension to embed the ReturnValue and the InputProps + * @public + */ export type LayoutComponent<_TInputProps> = () => null; /** diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index a67ce10dec..1fb72b0fac 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -10,22 +10,23 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import { createScaffolderFieldExtension as createScaffolderFieldExtension_2 } from '@backstage/plugin-scaffolder-react'; +import { createScaffolderLayout as createScaffolderLayout_2 } from '@backstage/plugin-scaffolder-react'; import { CustomFieldExtensionSchema as CustomFieldExtensionSchema_2 } from '@backstage/plugin-scaffolder-react'; import { CustomFieldValidator as CustomFieldValidator_2 } from '@backstage/plugin-scaffolder-react'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; -import { Extension } from '@backstage/core-plugin-api'; import { ExternalRouteRef } from '@backstage/core-plugin-api'; import { FetchApi } from '@backstage/core-plugin-api'; import { FieldExtensionComponent as FieldExtensionComponent_2 } from '@backstage/plugin-scaffolder-react'; import { FieldExtensionComponentProps as FieldExtensionComponentProps_2 } from '@backstage/plugin-scaffolder-react'; import { FieldExtensionOptions as FieldExtensionOptions_2 } from '@backstage/plugin-scaffolder-react'; import { FieldValidation } from '@rjsf/core'; -import type { FormProps as FormProps_2 } from '@rjsf/core'; -import { FormProps as FormProps_3 } from '@backstage/plugin-scaffolder-react'; -import type { FormProps as FormProps_4 } from '@rjsf/core-v5'; +import { FormProps as FormProps_2 } from '@backstage/plugin-scaffolder-react'; +import type { FormProps as FormProps_3 } from '@rjsf/core-v5'; import { IdentityApi } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; +import { LayoutOptions as LayoutOptions_2 } from '@backstage/plugin-scaffolder-react'; +import { LayoutTemplate as LayoutTemplate_2 } from '@backstage/plugin-scaffolder-react'; import { ListActionsResponse as ListActionsResponse_2 } from '@backstage/plugin-scaffolder-react'; import { LogEvent as LogEvent_2 } from '@backstage/plugin-scaffolder-react'; import { Observable } from '@backstage/types'; @@ -57,10 +58,8 @@ import { z } from 'zod'; // @public @deprecated (undocumented) export const createScaffolderFieldExtension: typeof createScaffolderFieldExtension_2; -// @public -export function createScaffolderLayout( - options: LayoutOptions, -): Extension>; +// @public @deprecated (undocumented) +export const createScaffolderLayout: typeof createScaffolderLayout_2; // @public @deprecated (undocumented) export type CustomFieldExtensionSchema = CustomFieldExtensionSchema_2; @@ -158,23 +157,15 @@ export interface FieldSchema { // @alpha @deprecated export type FormProps = Pick< - FormProps_4, + FormProps_3, 'transformErrors' | 'noHtml5Validate' >; -// @public -export type LayoutComponent<_TInputProps> = () => null; +// @public @deprecated (undocumented) +export type LayoutOptions = LayoutOptions_2; -// @public -export interface LayoutOptions

{ - // (undocumented) - component: LayoutTemplate

; - // (undocumented) - name: string; -} - -// @public -export type LayoutTemplate = FormProps_2['ObjectFieldTemplate']; +// @public @deprecated (undocumented) +export type LayoutTemplate = LayoutTemplate_2; // @public @deprecated (undocumented) export type ListActionsResponse = ListActionsResponse_2; @@ -208,7 +199,7 @@ export type NextRouterProps = { TaskPageComponent?: React_2.ComponentType<{}>; }; groups?: TemplateGroupFilter[]; - FormProps?: FormProps_3; + FormProps?: FormProps_2; }; // @alpha @@ -454,8 +445,8 @@ export type ScaffolderGetIntegrationsListOptions = export type ScaffolderGetIntegrationsListResponse = ScaffolderGetIntegrationsListResponse_2; -// @public -export const ScaffolderLayouts: React.ComponentType; +// @public @deprecated (undocumented) +export const ScaffolderLayouts: ComponentType<{}>; // @public @deprecated (undocumented) export type ScaffolderOutputlink = ScaffolderOutputLink; diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx index 3a1196bc0e..a74b65b885 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx +++ b/plugins/scaffolder/src/components/MultistepJsonForm/MultistepJsonForm.tsx @@ -35,10 +35,12 @@ import React, { ComponentType, useState } from 'react'; import { transformSchemaToProps } from './schema'; import cloneDeep from 'lodash/cloneDeep'; import * as fieldOverrides from './FieldOverrides'; -import { LayoutOptions } from '../../layouts'; import { ReviewStepProps } from '../types'; import { ReviewStep } from './ReviewStep'; -import { extractSchemaFromStep } from '@backstage/plugin-scaffolder-react'; +import { + extractSchemaFromStep, + type LayoutOptions, +} from '@backstage/plugin-scaffolder-react'; import { selectedTemplateRouteRef } from '../../routes'; const Form = withTheme(MuiTheme); diff --git a/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts b/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts index 5d74b0fc81..c3c90ae86a 100644 --- a/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts +++ b/plugins/scaffolder/src/components/MultistepJsonForm/schema.ts @@ -16,7 +16,7 @@ import { JsonObject } from '@backstage/types'; import { FormProps, UiSchema } from '@rjsf/core'; -import { LayoutOptions } from '../../layouts'; +import type { LayoutOptions } from '@backstage/plugin-scaffolder-react'; function isObject(value: unknown): value is JsonObject { return typeof value === 'object' && value !== null && !Array.isArray(value); @@ -120,7 +120,8 @@ export function transformSchemaToProps( )?.component; if (Layout) { - uiSchema['ui:ObjectFieldTemplate'] = Layout; + uiSchema['ui:ObjectFieldTemplate'] = + Layout as unknown as FormProps['ObjectFieldTemplate']; } } diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/components/Router.tsx index 6a2da406e0..ccc2bd283b 100644 --- a/plugins/scaffolder/src/components/Router.tsx +++ b/plugins/scaffolder/src/components/Router.tsx @@ -24,18 +24,14 @@ import { TaskPage } from './TaskPage'; import { ActionsPage } from './ActionsPage'; import { TemplateEditorPage } from './TemplateEditorPage'; import { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from '../extensions/default'; -import { - useElementFilter, - useRouteRef, - useRouteRefParams, -} from '@backstage/core-plugin-api'; +import { useRouteRef, useRouteRefParams } from '@backstage/core-plugin-api'; import { FieldExtensionOptions, SecretsContextProvider, useCustomFieldExtensions, + useCustomLayouts, } from '@backstage/plugin-scaffolder-react'; import { ListTasksPage } from './ListTasksPage'; -import { LayoutOptions, LAYOUTS_KEY, LAYOUTS_WRAPPER_KEY } from '../layouts'; import { ReviewStepProps } from './types'; import { actionsRouteRef, @@ -104,16 +100,7 @@ export const Router = (props: RouterProps) => { ), ] as FieldExtensionOptions[]; - // todo(blam): this should also be moved to a hook in -react - const customLayouts = useElementFilter(outlet, elements => - elements - .selectByComponentData({ - key: LAYOUTS_WRAPPER_KEY, - }) - .findComponentData({ - key: LAYOUTS_KEY, - }), - ); + const customLayouts = useCustomLayouts(outlet); /** * This component can be deleted once the older routes have been deprecated. diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditor.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditor.tsx index dc67f687bb..e07434aff7 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditor.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditor.tsx @@ -15,8 +15,10 @@ */ import { makeStyles } from '@material-ui/core'; import React, { useState } from 'react'; -import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; -import type { LayoutOptions } from '../../layouts'; +import type { + FieldExtensionOptions, + LayoutOptions, +} from '@backstage/plugin-scaffolder-react'; import { TemplateDirectoryAccess } from '../../lib/filesystem'; import { DirectoryEditorProvider } from './DirectoryEditorContext'; import { DryRunProvider } from './DryRunContext'; diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx index c62112a89c..315028219b 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorForm.tsx @@ -19,11 +19,11 @@ import { makeStyles } from '@material-ui/core/styles'; import React, { Component, ReactNode, useMemo, useState } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; import yaml from 'yaml'; -import { +import type { FieldExtensionOptions, + LayoutOptions, TemplateParameterSchema, } from '@backstage/plugin-scaffolder-react'; -import { LayoutOptions } from '../../layouts'; import { MultistepJsonForm } from '../MultistepJsonForm'; import { createValidator } from '../TemplatePage'; import { useDirectoryEditor } from './DirectoryEditorContext'; diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx index 20691a8e85..ebb763e145 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateEditorPage.tsx @@ -23,8 +23,10 @@ import { CustomFieldExplorer } from './CustomFieldExplorer'; import { TemplateEditorIntro } from './TemplateEditorIntro'; import { TemplateEditor } from './TemplateEditor'; import { TemplateFormPreviewer } from './TemplateFormPreviewer'; -import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; -import type { LayoutOptions } from '../../layouts'; +import { + type FieldExtensionOptions, + type LayoutOptions, +} from '@backstage/plugin-scaffolder-react'; type Selection = | { diff --git a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateFormPreviewer.tsx b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateFormPreviewer.tsx index 884305bf64..a7e3c6a697 100644 --- a/plugins/scaffolder/src/components/TemplateEditorPage/TemplateFormPreviewer.tsx +++ b/plugins/scaffolder/src/components/TemplateEditorPage/TemplateFormPreviewer.tsx @@ -32,8 +32,10 @@ import CloseIcon from '@material-ui/icons/Close'; import React, { useCallback, useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; import yaml from 'yaml'; -import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; -import { LayoutOptions } from '../../layouts'; +import { + type FieldExtensionOptions, + type LayoutOptions, +} from '@backstage/plugin-scaffolder-react'; import { TemplateEditorForm } from './TemplateEditorForm'; import { TemplateEditorTextArea } from './TemplateEditorTextArea'; diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index 0f484ff404..c615649f93 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -20,7 +20,8 @@ import React, { ComponentType, useCallback, useState } from 'react'; import { Navigate, useNavigate } from 'react-router-dom'; import useAsync from 'react-use/lib/useAsync'; import { - FieldExtensionOptions, + type FieldExtensionOptions, + type LayoutOptions, scaffolderApiRef, useTemplateSecrets, } from '@backstage/plugin-scaffolder-react'; @@ -37,7 +38,6 @@ import { useRouteRefParams, } from '@backstage/core-plugin-api'; import { stringifyEntityRef } from '@backstage/catalog-model'; -import { LayoutOptions } from '../../layouts'; import { ReviewStepProps } from '../types'; import { rootRouteRef, diff --git a/plugins/scaffolder/src/deprecated.ts b/plugins/scaffolder/src/deprecated.ts index 201f7ac7d7..f08a83c594 100644 --- a/plugins/scaffolder/src/deprecated.ts +++ b/plugins/scaffolder/src/deprecated.ts @@ -25,6 +25,10 @@ import { ScaffolderFieldExtensions as ScaffolderFieldExtensionsTemp, useTemplateSecrets as useTemplateSecretsTemp, scaffolderApiRef as scaffolderApiRefTemp, + createScaffolderLayout as createScaffolderLayoutTemp, + ScaffolderLayouts as ScaffolderLayoutsTemp, + type LayoutOptions as LayoutOptionsTemp, + type LayoutTemplate as LayoutTemplateTemp, type ScaffolderApi as ScaffolderApiTemp, type ScaffolderUseTemplateSecrets as ScaffolderUseTemplateSecretsTemp, type TemplateParameterSchema as TemplateParameterSchemaTemp, @@ -188,3 +192,23 @@ export type ScaffolderTaskOutput = ScaffolderTaskOutputTemp; * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderTaskStatus} instead as this has now been moved. */ export type ScaffolderTaskStatus = ScaffolderTaskStatusTemp; +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-react#createScaffolderLayout} instead as this has now been moved. + */ +export const createScaffolderLayout = createScaffolderLayoutTemp; +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-react#ScaffolderLayouts} instead as this has now been moved. + */ +export const ScaffolderLayouts = ScaffolderLayoutsTemp; +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-react#LayoutTemplate} instead as this has now been moved. + */ +export type LayoutTemplate = LayoutTemplateTemp; +/** + * @public + * @deprecated use import from {@link @backstage/plugin-scaffolder-react#LayoutOptions} instead as this has now been moved. + */ +export type LayoutOptions = LayoutOptionsTemp; diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts index 0e2b293982..aa78874f9d 100644 --- a/plugins/scaffolder/src/index.ts +++ b/plugins/scaffolder/src/index.ts @@ -21,14 +21,6 @@ */ export { ScaffolderClient } from './api'; -export { - createScaffolderLayout, - ScaffolderLayouts, - type LayoutOptions, - type LayoutTemplate, - type LayoutComponent, -} from './layouts'; - export { EntityPickerFieldExtension, EntityNamePickerFieldExtension, diff --git a/plugins/scaffolder/src/layouts/index.tsx b/plugins/scaffolder/src/layouts/index.tsx deleted file mode 100644 index ce1dac9bdf..0000000000 --- a/plugins/scaffolder/src/layouts/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { attachComponentData, Extension } from '@backstage/core-plugin-api'; -import type { LayoutOptions } from './types'; - -export const LAYOUTS_KEY = 'scaffolder.layout.v1'; -export const LAYOUTS_WRAPPER_KEY = 'scaffolder.layouts.wrapper.v1'; - -/** - * The type used to wrap up the Layout and embed the input props - * - * @public - */ -export type LayoutComponent<_TInputProps> = () => null; - -/** - * Method for creating custom Layouts that can be used in the scaffolder frontend form - * - * @public - */ -export function createScaffolderLayout( - options: LayoutOptions, -): Extension> { - return { - expose() { - const LayoutDataHolder: any = () => null; - - attachComponentData(LayoutDataHolder, LAYOUTS_KEY, options); - - return LayoutDataHolder; - }, - }; -} - -/** - * The wrapping component for defining scaffolder layouts as children - * - * @public - */ -export const ScaffolderLayouts: React.ComponentType = (): JSX.Element | null => - null; - -attachComponentData(ScaffolderLayouts, LAYOUTS_WRAPPER_KEY, true); - -export type { LayoutOptions, LayoutTemplate } from './types'; diff --git a/plugins/scaffolder/src/layouts/types.ts b/plugins/scaffolder/src/layouts/types.ts deleted file mode 100644 index dd17134dc5..0000000000 --- a/plugins/scaffolder/src/layouts/types.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import type { FormProps } from '@rjsf/core'; - -/** - * The field template from `@rjsf/core` which is a react component that gets passed `@rjsf/core` field related props. - * - * @public - */ -export type LayoutTemplate = FormProps['ObjectFieldTemplate']; - -/** - * The type of layouts that is passed to the TemplateForms - * - * @public - */ -export interface LayoutOptions

{ - name: string; - component: LayoutTemplate

; -} diff --git a/plugins/scaffolder/src/next/Router/Router.test.tsx b/plugins/scaffolder/src/next/Router/Router.test.tsx index 573b4ac8b8..9565572a2f 100644 --- a/plugins/scaffolder/src/next/Router/Router.test.tsx +++ b/plugins/scaffolder/src/next/Router/Router.test.tsx @@ -23,7 +23,10 @@ import { ScaffolderFieldExtensions, } from '@backstage/plugin-scaffolder-react'; import { scaffolderPlugin } from '../../plugin'; -import { createScaffolderLayout, ScaffolderLayouts } from '../../layouts'; +import { + createScaffolderLayout, + ScaffolderLayouts, +} from '@backstage/plugin-scaffolder-react'; jest.mock('../TemplateListPage', () => ({ TemplateListPage: jest.fn(() => null),