diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index e01844e233..2216dc9d01 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -45,8 +45,8 @@ import { NewRelicPage } from '@backstage/plugin-newrelic';
import {
ScaffolderPage,
scaffolderPlugin,
- OwnerPicker,
- RepoUrlPicker,
+ OwnerPickerFieldExtension,
+ RepoUrlPickerFieldExtension,
} from '@backstage/plugin-scaffolder';
import { SearchPage, SearchPageNext } from '@backstage/plugin-search';
import { TechRadarPage } from '@backstage/plugin-tech-radar';
@@ -112,15 +112,10 @@ const routes = (
} />
} />
-
-
-
-
- }
- />
+ }>
+
+
+
} />
;
- // Register Custom Fields
- registerCustomField(field: CustomField): void;
- getCustomFields(): {
- components: Map;
- validators: Map void>;
- };
-
streamLogs({
taskId,
after,
@@ -102,7 +95,6 @@ export class ScaffolderClient implements ScaffolderApi {
private readonly discoveryApi: DiscoveryApi;
private readonly identityApi: IdentityApi;
private readonly scmIntegrationsApi: ScmIntegrationRegistry;
- private readonly customFields: Map = new Map();
constructor(options: {
discoveryApi: DiscoveryApi;
@@ -151,24 +143,6 @@ export class ScaffolderClient implements ScaffolderApi {
return schema;
}
- registerCustomField(field: CustomField) {
- this.customFields.set(field.name, field);
- }
-
- getCustomFields() {
- return [...this.customFields.entries()].reduce(
- (previous, [name, field]) => {
- previous.components.set(name, field.component);
- previous.validators.set(name, field.validation);
- return previous;
- },
- {
- components: new Map(),
- validators: new Map(),
- },
- );
- }
-
/**
* Executes the scaffolding of a component, given a template and its
* parameter values.
diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/components/Router.tsx
index fab5eb50c8..8abdc7c09f 100644
--- a/plugins/scaffolder/src/components/Router.tsx
+++ b/plugins/scaffolder/src/components/Router.tsx
@@ -15,21 +15,38 @@
*/
import React from 'react';
-import { Routes, Route } from 'react-router';
+import { Routes, Route, useOutlet } from 'react-router';
import { ScaffolderPage } from './ScaffolderPage';
import { TemplatePage } from './TemplatePage';
import { TaskPage } from './TaskPage';
import { ActionsPage } from './ActionsPage';
+import { getComponentData } from '@backstage/core';
+import { FieldExtensionOptions } from '../extensions';
export const Router = () => {
+ const children = useOutlet();
+ const fieldExtensions = React.Children.map(children ?? [], child => {
+ if (!React.isValidElement(child)) {
+ return null;
+ }
+
+ const data = getComponentData>(
+ child,
+ 'scaffolder.extensions.field.v1',
+ );
+
+ return data;
+ }).filter(Boolean);
+
return (
- <>
-
- } />
- } />
- } />
- } />
-
- >
+
+ } />
+ }
+ />
+ } />
+ } />
+
);
};
diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx
index 0aad67a1c0..00d4fbae16 100644
--- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx
+++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx
@@ -34,6 +34,7 @@ import { scaffolderApiRef } from '../../api';
import { rootRouteRef } from '../../routes';
import { MultistepJsonForm } from '../MultistepJsonForm';
import { JsonObject, JsonValue } from '@backstage/config';
+import { FieldExtensionOptions } from '../../extensions';
const useTemplateParameterSchema = (templateName: string) => {
const scaffolderApi = useApi(scaffolderApiRef);
@@ -132,7 +133,11 @@ const storePathValidator = (
return errors;
};
-export const TemplatePage = () => {
+export const TemplatePage = ({
+ customFieldExtensions = [],
+}: {
+ customFieldExtensions: FieldExtensionOptions[];
+}) => {
const errorApi = useApi(errorApiRef);
const scaffolderApi = useApi(scaffolderApiRef);
const { templateName } = useParams();
@@ -141,7 +146,6 @@ export const TemplatePage = () => {
const { schema, loading, error } = useTemplateParameterSchema(templateName);
const [formState, setFormState] = useState({});
const handleFormReset = () => setFormState({});
-
const handleChange = useCallback(
(e: IChangeEvent) => setFormState(e.formData),
[setFormState],
@@ -166,7 +170,14 @@ export const TemplatePage = () => {
return ;
}
- const { components, validators } = scaffolderApi.getCustomFields();
+ const customFieldComponents = Object.fromEntries(
+ customFieldExtensions.map(({ name, component }) => [name, component]),
+ );
+
+ const customFieldValidators = Object.fromEntries(
+ customFieldExtensions.map(({ name, validation }) => [name, validation]),
+ );
+
return (
{
>
{
return {
...step,
- validate: createValidator(step.schema, validators),
+ validate: createValidator(step.schema, customFieldValidators),
};
})}
/>
diff --git a/plugins/scaffolder/src/extensions/index.tsx b/plugins/scaffolder/src/extensions/index.tsx
index acc3de38a0..307bdd8aeb 100644
--- a/plugins/scaffolder/src/extensions/index.tsx
+++ b/plugins/scaffolder/src/extensions/index.tsx
@@ -24,7 +24,7 @@ export type FieldExtensionOptions = {
export function createScaffolderFieldExtension(
options: FieldExtensionOptions,
-): Extension {
+): Extension<() => null> {
return {
expose() {
const FieldExtensionDataHolder: any = () => null;
diff --git a/plugins/scaffolder/src/index.ts b/plugins/scaffolder/src/index.ts
index 66eff47e5d..bda87eee5f 100644
--- a/plugins/scaffolder/src/index.ts
+++ b/plugins/scaffolder/src/index.ts
@@ -18,8 +18,8 @@ export {
scaffolderPlugin,
scaffolderPlugin as plugin,
ScaffolderPage,
- OwnerPicker,
- RepoUrlPicker,
+ OwnerPickerFieldExtension,
+ RepoUrlPickerFieldExtension,
} from './plugin';
export type { ScaffolderApi } from './api';
export { ScaffolderClient, scaffolderApiRef } from './api';