From c4b7c5012ead56698dcf07d2c9039030d71a0117 Mon Sep 17 00:00:00 2001 From: James Brooks Date: Mon, 28 Jul 2025 23:15:36 +0100 Subject: [PATCH 1/4] Export `FormField` type from Scaffolder Signed-off-by: James Brooks --- .changeset/mighty-cycles-stay.md | 5 +++++ plugins/scaffolder/report-alpha.api.md | 12 +++++++----- plugins/scaffolder/src/alpha/index.ts | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 .changeset/mighty-cycles-stay.md diff --git a/.changeset/mighty-cycles-stay.md b/.changeset/mighty-cycles-stay.md new file mode 100644 index 0000000000..fa3dbcfe9c --- /dev/null +++ b/.changeset/mighty-cycles-stay.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': patch +--- + +Export `FormField` type. diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index 509cfa8497..a3196d45c1 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -281,6 +281,8 @@ export const formDecoratorsApi: ExtensionDefinition<{ // @alpha (undocumented) export const formDecoratorsApiRef: ApiRef; +export { FormField }; + export { formFieldsApiRef }; // @alpha @deprecated @@ -394,10 +396,10 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'ongoingTask.title': 'Run of'; readonly 'ongoingTask.contextMenu.cancel': 'Cancel'; readonly 'ongoingTask.contextMenu.startOver': 'Start Over'; - readonly 'ongoingTask.contextMenu.retry': 'Retry'; readonly 'ongoingTask.contextMenu.hideLogs': 'Hide Logs'; readonly 'ongoingTask.contextMenu.showLogs': 'Show Logs'; readonly 'ongoingTask.contextMenu.hideButtonBar': 'Hide Button Bar'; + readonly 'ongoingTask.contextMenu.retry': 'Retry'; readonly 'ongoingTask.contextMenu.showButtonBar': 'Show Button Bar'; readonly 'ongoingTask.subtitle': 'Task {{taskId}}'; readonly 'ongoingTask.pageTitle.hasTemplateName': 'Run of {{templateName}}'; @@ -415,8 +417,6 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'renderSchema.tableCell.description': 'Description'; readonly 'templatingExtensions.content.values.title': 'Values'; readonly 'templatingExtensions.content.values.notAvailable': 'There are no global template values defined.'; - readonly 'templatingExtensions.content.emptyState.title': 'No information to display'; - readonly 'templatingExtensions.content.emptyState.description': 'There are no templating extensions available or there was an issue communicating with the backend.'; readonly 'templatingExtensions.content.filters.title': 'Filters'; readonly 'templatingExtensions.content.filters.schema.input': 'Input'; readonly 'templatingExtensions.content.filters.schema.output': 'Output'; @@ -424,6 +424,8 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'templatingExtensions.content.filters.examples': 'Examples'; readonly 'templatingExtensions.content.filters.notAvailable': 'There are no template filters defined.'; readonly 'templatingExtensions.content.filters.metadataAbsent': 'Filter metadata unavailable'; + readonly 'templatingExtensions.content.emptyState.title': 'No information to display'; + readonly 'templatingExtensions.content.emptyState.description': 'There are no templating extensions available or there was an issue communicating with the backend.'; readonly 'templatingExtensions.content.searchFieldPlaceholder': 'Search for an extension'; readonly 'templatingExtensions.content.functions.title': 'Functions'; readonly 'templatingExtensions.content.functions.schema.output': 'Output'; @@ -480,8 +482,8 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'templateListPage.pageTitle': 'Create a new component'; readonly 'templateListPage.templateGroups.defaultTitle': 'Templates'; readonly 'templateListPage.templateGroups.otherTitle': 'Other Templates'; - readonly 'templateListPage.contentHeader.supportButtonTitle': 'Create new software components using standard templates. Different templates create different kinds of components (services, websites, documentation, ...).'; readonly 'templateListPage.contentHeader.registerExistingButtonTitle': 'Register Existing Component'; + readonly 'templateListPage.contentHeader.supportButtonTitle': 'Create new software components using standard templates. Different templates create different kinds of components (services, websites, documentation, ...).'; readonly 'templateListPage.additionalLinksForEntity.viewTechDocsTitle': 'View TechDocs'; readonly 'templateWizardPage.title': 'Create a new component'; readonly 'templateWizardPage.subtitle': 'Create new software components using standard templates in your organization'; @@ -494,8 +496,8 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'templateEditorToolbar.addToCatalogDialogTitle': 'Publish changes'; readonly 'templateEditorToolbar.addToCatalogDialogContent.stepsIntroduction': 'Follow the instructions below to create or update a template:'; readonly 'templateEditorToolbar.addToCatalogDialogContent.stepsListItems': 'Save the template files in a local directory\nCreate a pull request to a new or existing git repository\nIf the template already exists, the changes will be reflected in the software catalog once the pull request gets merged\nBut if you are creating a new template, follow the documentation linked below to register the new template repository in software catalog'; - readonly 'templateEditorToolbar.addToCatalogDialogActions.documentationUrl': 'https://backstage.io/docs/features/software-templates/adding-templates/'; readonly 'templateEditorToolbar.addToCatalogDialogActions.documentationButton': 'Go to the documentation'; + readonly 'templateEditorToolbar.addToCatalogDialogActions.documentationUrl': 'https://backstage.io/docs/features/software-templates/adding-templates/'; readonly 'templateEditorToolbarFileMenu.button': 'File'; readonly 'templateEditorToolbarFileMenu.options.openDirectory': 'Open template directory'; readonly 'templateEditorToolbarFileMenu.options.createDirectory': 'Create template directory'; diff --git a/plugins/scaffolder/src/alpha/index.ts b/plugins/scaffolder/src/alpha/index.ts index d239f44b4f..e7586ba733 100644 --- a/plugins/scaffolder/src/alpha/index.ts +++ b/plugins/scaffolder/src/alpha/index.ts @@ -30,4 +30,6 @@ export { type ScaffolderFormFieldsApi, } from '@backstage/plugin-scaffolder-react/alpha'; +export { type FormField } from '@internal/scaffolder'; + export { default } from './plugin'; From 62dc5a2bb970f26441b67083669da8ce25774705 Mon Sep 17 00:00:00 2001 From: James Brooks Date: Mon, 28 Jul 2025 23:46:19 +0100 Subject: [PATCH 2/4] Update API report Signed-off-by: James Brooks --- plugins/scaffolder/report-alpha.api.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index a3196d45c1..b14d47521d 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -396,10 +396,10 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'ongoingTask.title': 'Run of'; readonly 'ongoingTask.contextMenu.cancel': 'Cancel'; readonly 'ongoingTask.contextMenu.startOver': 'Start Over'; + readonly 'ongoingTask.contextMenu.retry': 'Retry'; readonly 'ongoingTask.contextMenu.hideLogs': 'Hide Logs'; readonly 'ongoingTask.contextMenu.showLogs': 'Show Logs'; readonly 'ongoingTask.contextMenu.hideButtonBar': 'Hide Button Bar'; - readonly 'ongoingTask.contextMenu.retry': 'Retry'; readonly 'ongoingTask.contextMenu.showButtonBar': 'Show Button Bar'; readonly 'ongoingTask.subtitle': 'Task {{taskId}}'; readonly 'ongoingTask.pageTitle.hasTemplateName': 'Run of {{templateName}}'; @@ -417,6 +417,8 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'renderSchema.tableCell.description': 'Description'; readonly 'templatingExtensions.content.values.title': 'Values'; readonly 'templatingExtensions.content.values.notAvailable': 'There are no global template values defined.'; + readonly 'templatingExtensions.content.emptyState.title': 'No information to display'; + readonly 'templatingExtensions.content.emptyState.description': 'There are no templating extensions available or there was an issue communicating with the backend.'; readonly 'templatingExtensions.content.filters.title': 'Filters'; readonly 'templatingExtensions.content.filters.schema.input': 'Input'; readonly 'templatingExtensions.content.filters.schema.output': 'Output'; @@ -424,8 +426,6 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'templatingExtensions.content.filters.examples': 'Examples'; readonly 'templatingExtensions.content.filters.notAvailable': 'There are no template filters defined.'; readonly 'templatingExtensions.content.filters.metadataAbsent': 'Filter metadata unavailable'; - readonly 'templatingExtensions.content.emptyState.title': 'No information to display'; - readonly 'templatingExtensions.content.emptyState.description': 'There are no templating extensions available or there was an issue communicating with the backend.'; readonly 'templatingExtensions.content.searchFieldPlaceholder': 'Search for an extension'; readonly 'templatingExtensions.content.functions.title': 'Functions'; readonly 'templatingExtensions.content.functions.schema.output': 'Output'; @@ -482,8 +482,8 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'templateListPage.pageTitle': 'Create a new component'; readonly 'templateListPage.templateGroups.defaultTitle': 'Templates'; readonly 'templateListPage.templateGroups.otherTitle': 'Other Templates'; - readonly 'templateListPage.contentHeader.registerExistingButtonTitle': 'Register Existing Component'; readonly 'templateListPage.contentHeader.supportButtonTitle': 'Create new software components using standard templates. Different templates create different kinds of components (services, websites, documentation, ...).'; + readonly 'templateListPage.contentHeader.registerExistingButtonTitle': 'Register Existing Component'; readonly 'templateListPage.additionalLinksForEntity.viewTechDocsTitle': 'View TechDocs'; readonly 'templateWizardPage.title': 'Create a new component'; readonly 'templateWizardPage.subtitle': 'Create new software components using standard templates in your organization'; @@ -496,8 +496,8 @@ export const scaffolderTranslationRef: TranslationRef< readonly 'templateEditorToolbar.addToCatalogDialogTitle': 'Publish changes'; readonly 'templateEditorToolbar.addToCatalogDialogContent.stepsIntroduction': 'Follow the instructions below to create or update a template:'; readonly 'templateEditorToolbar.addToCatalogDialogContent.stepsListItems': 'Save the template files in a local directory\nCreate a pull request to a new or existing git repository\nIf the template already exists, the changes will be reflected in the software catalog once the pull request gets merged\nBut if you are creating a new template, follow the documentation linked below to register the new template repository in software catalog'; - readonly 'templateEditorToolbar.addToCatalogDialogActions.documentationButton': 'Go to the documentation'; readonly 'templateEditorToolbar.addToCatalogDialogActions.documentationUrl': 'https://backstage.io/docs/features/software-templates/adding-templates/'; + readonly 'templateEditorToolbar.addToCatalogDialogActions.documentationButton': 'Go to the documentation'; readonly 'templateEditorToolbarFileMenu.button': 'File'; readonly 'templateEditorToolbarFileMenu.options.openDirectory': 'Open template directory'; readonly 'templateEditorToolbarFileMenu.options.createDirectory': 'Create template directory'; From c48a43fe53c0886d0ea15f774071d4509f09295f Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Tue, 29 Jul 2025 13:45:11 +0200 Subject: [PATCH 3/4] chore: small refactor and moving types around Signed-off-by: benjdlambert --- .../src/wiring/InternalFormField.ts | 10 ++++------ packages/scaffolder-internal/src/wiring/index.ts | 2 +- plugins/scaffolder-react/report-alpha.api.md | 7 ++++++- plugins/scaffolder-react/src/next/api/FormFieldsApi.ts | 4 ++-- plugins/scaffolder-react/src/next/api/index.ts | 2 +- plugins/scaffolder-react/src/next/api/types.ts | 5 +++++ .../src/next/blueprints/FormFieldBlueprint.tsx | 3 ++- plugins/scaffolder/report-alpha.api.md | 4 +--- plugins/scaffolder/src/alpha/index.ts | 2 -- plugins/scaffolder/src/components/Router/Router.tsx | 3 ++- 10 files changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/scaffolder-internal/src/wiring/InternalFormField.ts b/packages/scaffolder-internal/src/wiring/InternalFormField.ts index 5d7bf1ee7d..b711341ea5 100644 --- a/packages/scaffolder-internal/src/wiring/InternalFormField.ts +++ b/packages/scaffolder-internal/src/wiring/InternalFormField.ts @@ -17,12 +17,10 @@ import { OpaqueType } from '@internal/opaque'; import { z } from 'zod'; -import { FormFieldExtensionData } from '@backstage/plugin-scaffolder-react/alpha'; - -/** @alpha */ -export interface FormField { - readonly $$type: '@backstage/scaffolder/FormField'; -} +import { + FormFieldExtensionData, + FormField, +} from '@backstage/plugin-scaffolder-react/alpha'; /** @alpha */ export const OpaqueFormField = OpaqueType.create<{ diff --git a/packages/scaffolder-internal/src/wiring/index.ts b/packages/scaffolder-internal/src/wiring/index.ts index 37c8bd09cb..5195a1fa64 100644 --- a/packages/scaffolder-internal/src/wiring/index.ts +++ b/packages/scaffolder-internal/src/wiring/index.ts @@ -13,5 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { OpaqueFormField, type FormField } from './InternalFormField'; +export { OpaqueFormField } from './InternalFormField'; export { OpaqueFormDecorator } from './InternalFormDecorator'; diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md index 2014bff9be..213d9427d2 100644 --- a/plugins/scaffolder-react/report-alpha.api.md +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -18,7 +18,6 @@ import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import { FieldSchema } from '@backstage/plugin-scaffolder-react'; import { FieldValidation } from '@rjsf/utils'; -import { FormField } from '@internal/scaffolder'; import { FormProps } from '@backstage/plugin-scaffolder-react'; import { IconComponent } from '@backstage/core-plugin-api'; import { JsonObject } from '@backstage/types'; @@ -155,6 +154,12 @@ export const FormDecoratorBlueprint: ExtensionBlueprint<{ }; }>; +// @alpha (undocumented) +export interface FormField { + // (undocumented) + readonly $$type: '@backstage/scaffolder/FormField'; +} + // @alpha export const FormFieldBlueprint: ExtensionBlueprint<{ kind: 'scaffolder-form-field'; diff --git a/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts b/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts index 7712b91a18..7e8ea4f83c 100644 --- a/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts +++ b/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts @@ -20,9 +20,9 @@ import { createExtensionInput, } from '@backstage/frontend-plugin-api'; import { formFieldsApiRef } from './ref'; -import { ScaffolderFormFieldsApi } from './types'; +import { FormField, ScaffolderFormFieldsApi } from './types'; import { FormFieldBlueprint } from '../blueprints'; -import { FormField, OpaqueFormField } from '@internal/scaffolder'; +import { OpaqueFormField } from '@internal/scaffolder'; class DefaultScaffolderFormFieldsApi implements ScaffolderFormFieldsApi { constructor( diff --git a/plugins/scaffolder-react/src/next/api/index.ts b/plugins/scaffolder-react/src/next/api/index.ts index ecc62e5acf..52c40ad99a 100644 --- a/plugins/scaffolder-react/src/next/api/index.ts +++ b/plugins/scaffolder-react/src/next/api/index.ts @@ -16,4 +16,4 @@ export { formFieldsApi } from './FormFieldsApi'; export { formFieldsApiRef } from './ref'; -export type { ScaffolderFormFieldsApi } from './types'; +export type { ScaffolderFormFieldsApi, FormField } from './types'; diff --git a/plugins/scaffolder-react/src/next/api/types.ts b/plugins/scaffolder-react/src/next/api/types.ts index ea93ba86b2..9e028567f6 100644 --- a/plugins/scaffolder-react/src/next/api/types.ts +++ b/plugins/scaffolder-react/src/next/api/types.ts @@ -23,3 +23,8 @@ import { FormFieldExtensionData } from '../blueprints'; export interface ScaffolderFormFieldsApi { getFormFields(): Promise; } + +/** @alpha */ +export interface FormField { + readonly $$type: '@backstage/scaffolder/FormField'; +} diff --git a/plugins/scaffolder-react/src/next/blueprints/FormFieldBlueprint.tsx b/plugins/scaffolder-react/src/next/blueprints/FormFieldBlueprint.tsx index 4324a080f6..afbf2b501d 100644 --- a/plugins/scaffolder-react/src/next/blueprints/FormFieldBlueprint.tsx +++ b/plugins/scaffolder-react/src/next/blueprints/FormFieldBlueprint.tsx @@ -19,8 +19,9 @@ import { } from '@backstage/frontend-plugin-api'; import { z } from 'zod'; -import { OpaqueFormField, FormField } from '@internal/scaffolder'; +import { OpaqueFormField } from '@internal/scaffolder'; import { FormFieldExtensionData } from './types'; +import { FormField } from '../api'; const formFieldExtensionDataRef = createExtensionDataRef< () => Promise diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index b14d47521d..f4b560de47 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -14,7 +14,7 @@ import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; -import { FormField } from '@internal/scaffolder'; +import { FormField } from '@backstage/plugin-scaffolder-react/alpha'; import { formFieldsApiRef } from '@backstage/plugin-scaffolder-react/alpha'; import type { FormProps as FormProps_2 } from '@rjsf/core'; import { FormProps as FormProps_3 } from '@backstage/plugin-scaffolder-react'; @@ -281,8 +281,6 @@ export const formDecoratorsApi: ExtensionDefinition<{ // @alpha (undocumented) export const formDecoratorsApiRef: ApiRef; -export { FormField }; - export { formFieldsApiRef }; // @alpha @deprecated diff --git a/plugins/scaffolder/src/alpha/index.ts b/plugins/scaffolder/src/alpha/index.ts index e7586ba733..d239f44b4f 100644 --- a/plugins/scaffolder/src/alpha/index.ts +++ b/plugins/scaffolder/src/alpha/index.ts @@ -30,6 +30,4 @@ export { type ScaffolderFormFieldsApi, } from '@backstage/plugin-scaffolder-react/alpha'; -export { type FormField } from '@internal/scaffolder'; - export { default } from './plugin'; diff --git a/plugins/scaffolder/src/components/Router/Router.tsx b/plugins/scaffolder/src/components/Router/Router.tsx index d8dee73849..a57811a520 100644 --- a/plugins/scaffolder/src/components/Router/Router.tsx +++ b/plugins/scaffolder/src/components/Router/Router.tsx @@ -62,9 +62,10 @@ import { import { RequirePermission } from '@backstage/plugin-permission-react'; import { templateManagementPermission } from '@backstage/plugin-scaffolder-common/alpha'; import { useApp } from '@backstage/core-plugin-api'; -import { FormField, OpaqueFormField } from '@internal/scaffolder'; +import { OpaqueFormField } from '@internal/scaffolder'; import { useAsync, useMountEffect } from '@react-hookz/web'; import { TemplatingExtensionsPage } from '../TemplatingExtensionsPage'; +import { FormField } from '@backstage/plugin-scaffolder-react/alpha'; /** * The Props for the Scaffolder Router From cc3086bd003d9db0dd3873b38d218e3461782421 Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Tue, 29 Jul 2025 13:47:07 +0200 Subject: [PATCH 4/4] chore: update changeset Signed-off-by: benjdlambert --- .changeset/mighty-cycles-stay.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.changeset/mighty-cycles-stay.md b/.changeset/mighty-cycles-stay.md index fa3dbcfe9c..cb1bb3646e 100644 --- a/.changeset/mighty-cycles-stay.md +++ b/.changeset/mighty-cycles-stay.md @@ -1,5 +1,6 @@ --- '@backstage/plugin-scaffolder': patch +'@backstage/plugin-scaffolder-react': patch --- -Export `FormField` type. +Export `FormField` type from `/alpha` in `-react` package, and internal refactor.