feat(scaffolder): add missing form fields for the nfs

Signed-off-by: Hellgren Heikki <heikki.hellgren@op.fi>
This commit is contained in:
Hellgren Heikki
2025-09-24 10:23:35 +03:00
parent 9e76ddb8f9
commit 075e0648b8
18 changed files with 496 additions and 12 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Added missing form fields for the new frontend system.
+123 -3
View File
@@ -226,6 +226,126 @@ const _default: OverridableFrontendPlugin<
routeRef?: RouteRef;
};
}>;
'scaffolder-form-field:scaffolder/entity-name-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'entity-name-picker';
config: {};
configInput: {};
output: ExtensionDataRef<
() => Promise<FormField>,
'scaffolder.form-field-loader',
{}
>;
inputs: {};
params: {
field: () => Promise<FormField>;
};
}>;
'scaffolder-form-field:scaffolder/entity-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'entity-picker';
config: {};
configInput: {};
output: ExtensionDataRef<
() => Promise<FormField>,
'scaffolder.form-field-loader',
{}
>;
inputs: {};
params: {
field: () => Promise<FormField>;
};
}>;
'scaffolder-form-field:scaffolder/entity-tags-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'entity-tags-picker';
config: {};
configInput: {};
output: ExtensionDataRef<
() => Promise<FormField>,
'scaffolder.form-field-loader',
{}
>;
inputs: {};
params: {
field: () => Promise<FormField>;
};
}>;
'scaffolder-form-field:scaffolder/multi-entity-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'multi-entity-picker';
config: {};
configInput: {};
output: ExtensionDataRef<
() => Promise<FormField>,
'scaffolder.form-field-loader',
{}
>;
inputs: {};
params: {
field: () => Promise<FormField>;
};
}>;
'scaffolder-form-field:scaffolder/my-groups-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'my-groups-picker';
config: {};
configInput: {};
output: ExtensionDataRef<
() => Promise<FormField>,
'scaffolder.form-field-loader',
{}
>;
inputs: {};
params: {
field: () => Promise<FormField>;
};
}>;
'scaffolder-form-field:scaffolder/owned-entity-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'owned-entity-picker';
config: {};
configInput: {};
output: ExtensionDataRef<
() => Promise<FormField>,
'scaffolder.form-field-loader',
{}
>;
inputs: {};
params: {
field: () => Promise<FormField>;
};
}>;
'scaffolder-form-field:scaffolder/owner-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'owner-picker';
config: {};
configInput: {};
output: ExtensionDataRef<
() => Promise<FormField>,
'scaffolder.form-field-loader',
{}
>;
inputs: {};
params: {
field: () => Promise<FormField>;
};
}>;
'scaffolder-form-field:scaffolder/repo-branch-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'repo-branch-picker';
config: {};
configInput: {};
output: ExtensionDataRef<
() => Promise<FormField>,
'scaffolder.form-field-loader',
{}
>;
inputs: {};
params: {
field: () => Promise<FormField>;
};
}>;
'scaffolder-form-field:scaffolder/repo-url-picker': ExtensionDefinition<{
kind: 'scaffolder-form-field';
name: 'repo-url-picker';
@@ -402,10 +522,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}}';
@@ -488,8 +608,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';
@@ -502,8 +622,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';
+72 -3
View File
@@ -70,6 +70,15 @@ export const EntityNamePickerFieldExtension: FieldExtensionComponent_2<
any
>;
// @public (undocumented)
export const EntityNamePickerFieldSchema: FieldSchema_2<string, any>;
// @public (undocumented)
export const entityNamePickerValidation: (
value: string,
validation: FieldValidation,
) => void;
// @public
export const EntityPickerFieldExtension: FieldExtensionComponent_2<
string,
@@ -228,6 +237,39 @@ export const MultiEntityPickerFieldExtension: FieldExtensionComponent_2<
}
>;
// @public (undocumented)
export const MultiEntityPickerFieldSchema: FieldSchema_2<
string[],
{
defaultKind?: string | undefined;
defaultNamespace?: string | false | undefined;
catalogFilter?:
| Record<
string,
| string
| string[]
| {
exists?: boolean | undefined;
}
>
| Record<
string,
| string
| string[]
| {
exists?: boolean | undefined;
}
>[]
| undefined;
allowArbitraryValues?: boolean | undefined;
}
>;
// @public
export type MultiEntityPickerUiOptions = NonNullable<
(typeof MultiEntityPickerFieldSchema.TProps.uiSchema)['ui:options']
>;
// @public
export const MyGroupsPickerFieldExtension: FieldExtensionComponent_2<
string,
@@ -380,9 +422,9 @@ export const RepoBranchPickerFieldExtension: FieldExtensionComponent_2<
| {
azure?: string[] | undefined;
github?: string[] | undefined;
gitlab?: string[] | undefined;
bitbucket?: string[] | undefined;
gerrit?: string[] | undefined;
gitlab?: string[] | undefined;
gitea?: string[] | undefined;
}
| undefined;
@@ -391,6 +433,33 @@ export const RepoBranchPickerFieldExtension: FieldExtensionComponent_2<
}
>;
// @public (undocumented)
export const RepoBranchPickerFieldSchema: FieldSchema_2<
string,
{
requestUserCredentials?:
| {
secretsKey: string;
additionalScopes?:
| {
azure?: string[] | undefined;
github?: string[] | undefined;
bitbucket?: string[] | undefined;
gerrit?: string[] | undefined;
gitlab?: string[] | undefined;
gitea?: string[] | undefined;
}
| undefined;
}
| undefined;
}
>;
// @public
export type RepoBranchPickerUiOptions = NonNullable<
(typeof RepoBranchPickerFieldSchema.TProps.uiSchema)['ui:options']
>;
// @public
export const repoPickerValidation: (
value: string,
@@ -416,9 +485,9 @@ export const RepoUrlPickerFieldExtension: FieldExtensionComponent_2<
| {
azure?: string[] | undefined;
github?: string[] | undefined;
gitlab?: string[] | undefined;
bitbucket?: string[] | undefined;
gerrit?: string[] | undefined;
gitlab?: string[] | undefined;
gitea?: string[] | undefined;
}
| undefined;
@@ -443,9 +512,9 @@ export const RepoUrlPickerFieldSchema: FieldSchema_2<
| {
azure?: string[] | undefined;
github?: string[] | undefined;
gitlab?: string[] | undefined;
bitbucket?: string[] | undefined;
gerrit?: string[] | undefined;
gitlab?: string[] | undefined;
gitea?: string[] | undefined;
}
| undefined;
+64 -3
View File
@@ -19,13 +19,13 @@ import {
convertLegacyRouteRef,
} from '@backstage/core-compat-api';
import {
NavItemBlueprint,
PageBlueprint,
ApiBlueprint,
createExtensionInput,
discoveryApiRef,
fetchApiRef,
identityApiRef,
createExtensionInput,
NavItemBlueprint,
PageBlueprint,
} from '@backstage/frontend-plugin-api';
import { rootRouteRef } from '../routes';
import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
@@ -72,6 +72,67 @@ export const repoUrlPickerFormField = FormFieldBlueprint.make({
},
});
export const entityNamePickerFormField = FormFieldBlueprint.make({
name: 'entity-name-picker',
params: {
field: () =>
import('./fields/EntityNamePicker').then(m => m.EntityNamePicker),
},
});
export const entityPickerFormField = FormFieldBlueprint.make({
name: 'entity-picker',
params: {
field: () => import('./fields/EntityPicker').then(m => m.EntityPicker),
},
});
export const ownerPickerFormField = FormFieldBlueprint.make({
name: 'owner-picker',
params: {
field: () => import('./fields/OwnerPicker').then(m => m.OwnerPicker),
},
});
export const entityTagsPickerFormField = FormFieldBlueprint.make({
name: 'entity-tags-picker',
params: {
field: () =>
import('./fields/EntityTagsPicker').then(m => m.EntityTagsPicker),
},
});
export const multiEntityPickerFormField = FormFieldBlueprint.make({
name: 'multi-entity-picker',
params: {
field: () =>
import('./fields/MultiEntityPicker').then(m => m.MultiEntityPicker),
},
});
export const myGroupsPickerFormField = FormFieldBlueprint.make({
name: 'my-groups-picker',
params: {
field: () => import('./fields/MyGroupsPicker').then(m => m.MyGroupsPicker),
},
});
export const ownedEntityPickerFormField = FormFieldBlueprint.make({
name: 'owned-entity-picker',
params: {
field: () =>
import('./fields/OwnedEntityPicker').then(m => m.OwnedEntityPicker),
},
});
export const repoBranchPickerFormField = FormFieldBlueprint.make({
name: 'repo-branch-picker',
params: {
field: () =>
import('./fields/RepoBranchPicker').then(m => m.RepoBranchPicker),
},
});
export const scaffolderApi = ApiBlueprint.make({
params: defineParams =>
defineParams({
@@ -0,0 +1,28 @@
/*
* Copyright 2024 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 { createFormField } from '@backstage/plugin-scaffolder-react/alpha';
import { EntityNamePicker as Component } from '../../components/fields/EntityNamePicker/EntityNamePicker';
import {
EntityNamePickerFieldSchema,
entityNamePickerValidation,
} from '../../components';
export const EntityNamePicker = createFormField({
component: Component,
name: 'EntityNamePicker',
validation: entityNamePickerValidation,
schema: EntityNamePickerFieldSchema,
});
@@ -0,0 +1,24 @@
/*
* Copyright 2024 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 { createFormField } from '@backstage/plugin-scaffolder-react/alpha';
import { EntityPicker as Component } from '../../components/fields/EntityPicker/EntityPicker';
import { EntityPickerFieldSchema } from '../../components';
export const EntityPicker = createFormField({
component: Component,
name: 'EntityPicker',
schema: EntityPickerFieldSchema,
});
@@ -0,0 +1,24 @@
/*
* Copyright 2024 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 { createFormField } from '@backstage/plugin-scaffolder-react/alpha';
import { EntityTagsPicker as Component } from '../../components/fields/EntityTagsPicker/EntityTagsPicker';
import { EntityTagsPickerFieldSchema } from '../../components';
export const EntityTagsPicker = createFormField({
component: Component,
name: 'EntityTagsPicker',
schema: EntityTagsPickerFieldSchema,
});
@@ -0,0 +1,24 @@
/*
* Copyright 2024 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 { createFormField } from '@backstage/plugin-scaffolder-react/alpha';
import { MultiEntityPicker as Component } from '../../components/fields/MultiEntityPicker/MultiEntityPicker';
import { MultiEntityPickerFieldSchema } from '../../components';
export const MultiEntityPicker = createFormField({
component: Component,
name: 'MultiEntityPicker',
schema: MultiEntityPickerFieldSchema,
});
@@ -0,0 +1,24 @@
/*
* Copyright 2024 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 { createFormField } from '@backstage/plugin-scaffolder-react/alpha';
import { MyGroupsPicker as Component } from '../../components/fields/MyGroupsPicker/MyGroupsPicker';
import { MyGroupsPickerFieldSchema } from '../../components';
export const MyGroupsPicker = createFormField({
component: Component,
name: 'MyGroupsPicker',
schema: MyGroupsPickerFieldSchema,
});
@@ -0,0 +1,24 @@
/*
* Copyright 2024 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 { createFormField } from '@backstage/plugin-scaffolder-react/alpha';
import { OwnedEntityPicker as Component } from '../../components/fields/OwnedEntityPicker/OwnedEntityPicker';
import { OwnedEntityPickerFieldSchema } from '../../components';
export const OwnedEntityPicker = createFormField({
component: Component,
name: 'OwnedEntityPicker',
schema: OwnedEntityPickerFieldSchema,
});
@@ -0,0 +1,24 @@
/*
* Copyright 2024 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 { createFormField } from '@backstage/plugin-scaffolder-react/alpha';
import { OwnerPicker as Component } from '../../components/fields/OwnerPicker/OwnerPicker';
import { OwnerPickerFieldSchema } from '../../components';
export const OwnerPicker = createFormField({
component: Component,
name: 'OwnerPicker',
schema: OwnerPickerFieldSchema,
});
@@ -0,0 +1,24 @@
/*
* Copyright 2024 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 { createFormField } from '@backstage/plugin-scaffolder-react/alpha';
import { RepoBranchPicker as Component } from '../../components/fields/RepoBranchPicker/RepoBranchPicker';
import { RepoBranchPickerFieldSchema } from '../../components';
export const RepoBranchPicker = createFormField({
component: Component,
name: 'RepoBranchPicker',
schema: RepoBranchPickerFieldSchema,
});
+18 -2
View File
@@ -17,10 +17,10 @@
import { convertLegacyRouteRefs } from '@backstage/core-compat-api';
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
import {
rootRouteRef,
actionsRouteRef,
editRouteRef,
registerComponentRouteRef,
rootRouteRef,
scaffolderListTaskRouteRef,
scaffolderTaskRouteRef,
selectedTemplateRouteRef,
@@ -28,10 +28,18 @@ import {
viewTechDocRouteRef,
} from '../routes';
import {
entityNamePickerFormField,
entityPickerFormField,
entityTagsPickerFormField,
multiEntityPickerFormField,
myGroupsPickerFormField,
ownedEntityPickerFormField,
ownerPickerFormField,
repoBranchPickerFormField,
repoUrlPickerFormField,
scaffolderApi,
scaffolderNavItem,
scaffolderPage,
scaffolderApi,
} from './extensions';
import { isTemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import { formFieldsApi } from '@backstage/plugin-scaffolder-react/alpha';
@@ -73,5 +81,13 @@ export default createFrontendPlugin({
formDecoratorsApi,
formFieldsApi,
repoUrlPickerFormField,
entityNamePickerFormField,
entityPickerFormField,
ownerPickerFormField,
entityTagsPickerFormField,
multiEntityPickerFormField,
myGroupsPickerFormField,
ownedEntityPickerFormField,
repoBranchPickerFormField,
],
});
@@ -14,3 +14,4 @@
* limitations under the License.
*/
export { entityNamePickerValidation } from './validation';
export { EntityNamePickerFieldSchema } from './schema';
@@ -15,7 +15,10 @@
*/
import { makeFieldSchema } from '@backstage/plugin-scaffolder-react';
const EntityNamePickerFieldSchema = makeFieldSchema({
/**
* @public
*/
export const EntityNamePickerFieldSchema = makeFieldSchema({
output: z => z.string(),
});
@@ -17,6 +17,9 @@
import { FieldValidation } from '@rjsf/utils';
import { KubernetesValidatorFunctions } from '@backstage/catalog-model';
/**
* @public
*/
export const entityNamePickerValidation = (
value: string,
validation: FieldValidation,
@@ -16,6 +16,9 @@
import { z as zod } from 'zod';
import { makeFieldSchema } from '@backstage/plugin-scaffolder-react';
/**
* @public
*/
export const entityQueryFilterExpressionSchema = zod.record(
zod
.string()
@@ -23,6 +26,9 @@ export const entityQueryFilterExpressionSchema = zod.record(
.or(zod.array(zod.string())),
);
/**
* @public
*/
export const MultiEntityPickerFieldSchema = makeFieldSchema({
output: z => z.array(z.string()),
uiOptions: z =>
@@ -54,6 +60,7 @@ export const MultiEntityPickerFieldSchema = makeFieldSchema({
/**
* The input props that can be specified under `ui:options` for the
* `EntityPicker` field extension.
* @public
*/
export type MultiEntityPickerUiOptions = NonNullable<
(typeof MultiEntityPickerFieldSchema.TProps.uiSchema)['ui:options']
@@ -14,10 +14,13 @@
* limitations under the License.
*/
export * from './EntityPicker';
export * from './EntityNamePicker';
export * from './OwnerPicker';
export * from './RepoUrlPicker';
export * from './OwnedEntityPicker';
export * from './EntityTagsPicker';
export * from './RepoBranchPicker';
export * from './MultiEntityPicker';
export * from './MyGroupsPicker';
export { type FieldSchema, makeFieldSchemaFromZod } from './utils';