Added a context parameter to validator functions, letting them have access to the API holder
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder': patch
|
||||
---
|
||||
|
||||
Added a `context` parameter to validator functions, letting them have access to
|
||||
the API holder.
|
||||
|
||||
If you have implemented custom validators and use `createScaffolderFieldExtension`,
|
||||
your `validation` function can now optionally accept a third parameter,
|
||||
`context: { apiHolder: ApiHolder }`.
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
```ts
|
||||
|
||||
import { ApiHolder } from '@backstage/core-plugin-api';
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
@@ -24,9 +25,21 @@ import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
// @public (undocumented)
|
||||
export function createScaffolderFieldExtension<T = any>(options: FieldExtensionOptions<T>): Extension<() => null>;
|
||||
|
||||
// @public (undocumented)
|
||||
export type CustomFieldValidator<T> = ((data: T, field: FieldValidation) => void) | ((data: T, field: FieldValidation, context: {
|
||||
apiHolder: ApiHolder;
|
||||
}) => void);
|
||||
|
||||
// @public (undocumented)
|
||||
export const EntityPickerFieldExtension: () => null;
|
||||
|
||||
// @public (undocumented)
|
||||
export type FieldExtensionOptions<T = any> = {
|
||||
name: string;
|
||||
component: (props: FieldProps<T>) => JSX.Element | null;
|
||||
validation?: CustomFieldValidator<T>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const OwnerPickerFieldExtension: () => null;
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
import { JsonObject, JsonValue } from '@backstage/config';
|
||||
import { LinearProgress } from '@material-ui/core';
|
||||
import { FieldValidation, FormValidation, IChangeEvent } from '@rjsf/core';
|
||||
import { FormValidation, IChangeEvent } from '@rjsf/core';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { generatePath, Navigate, useNavigate } from 'react-router';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useAsync } from 'react-use';
|
||||
import { scaffolderApiRef } from '../../api';
|
||||
import { FieldExtensionOptions } from '../../extensions';
|
||||
import { CustomFieldValidator, FieldExtensionOptions } from '../../extensions';
|
||||
import { rootRouteRef } from '../../routes';
|
||||
import { MultistepJsonForm } from '../MultistepJsonForm';
|
||||
|
||||
@@ -32,7 +32,13 @@ import {
|
||||
Lifecycle,
|
||||
Page,
|
||||
} from '@backstage/core-components';
|
||||
import { errorApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
ApiHolder,
|
||||
errorApiRef,
|
||||
useApi,
|
||||
useApiHolder,
|
||||
useRouteRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
const useTemplateParameterSchema = (templateName: string) => {
|
||||
const scaffolderApi = useApi(scaffolderApiRef);
|
||||
@@ -54,10 +60,10 @@ function isObject(obj: unknown): obj is JsonObject {
|
||||
|
||||
export const createValidator = (
|
||||
rootSchema: JsonObject,
|
||||
validators: Record<
|
||||
string,
|
||||
undefined | ((value: JsonValue, validation: FieldValidation) => void)
|
||||
>,
|
||||
validators: Record<string, undefined | CustomFieldValidator<unknown>>,
|
||||
context: {
|
||||
apiHolder: ApiHolder;
|
||||
},
|
||||
) => {
|
||||
function validate(
|
||||
schema: JsonObject,
|
||||
@@ -86,7 +92,11 @@ export const createValidator = (
|
||||
const fieldName =
|
||||
isObject(propSchema) && (propSchema['ui:field'] as string);
|
||||
if (fieldName && typeof validators[fieldName] === 'function') {
|
||||
validators[fieldName]!(propData as JsonValue, propValidation);
|
||||
validators[fieldName]!(
|
||||
propData as JsonValue,
|
||||
propValidation,
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +113,7 @@ export const TemplatePage = ({
|
||||
}: {
|
||||
customFieldExtensions?: FieldExtensionOptions[];
|
||||
}) => {
|
||||
const apiHolder = useApiHolder();
|
||||
const errorApi = useApi(errorApiRef);
|
||||
const scaffolderApi = useApi(scaffolderApiRef);
|
||||
const { templateName } = useParams();
|
||||
@@ -171,7 +182,11 @@ export const TemplatePage = ({
|
||||
steps={schema.steps.map(step => {
|
||||
return {
|
||||
...step,
|
||||
validate: createValidator(step.schema, customFieldValidators),
|
||||
validate: createValidator(
|
||||
step.schema,
|
||||
customFieldValidators,
|
||||
{ apiHolder },
|
||||
),
|
||||
};
|
||||
})}
|
||||
/>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { repoPickerValidation } from './validation';
|
||||
import { FieldValidation } from '@rjsf/core';
|
||||
|
||||
@@ -22,7 +23,7 @@ describe('RepoPicker Validation', () => {
|
||||
addError: jest.fn(),
|
||||
} as unknown) as FieldValidation);
|
||||
|
||||
it('validaties when no repo', () => {
|
||||
it('validates when no repo', () => {
|
||||
const mockFieldValidation = fieldValidator();
|
||||
|
||||
repoPickerValidation('github.com?owner=a', mockFieldValidation);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FieldValidation } from '@rjsf/core';
|
||||
|
||||
export const repoPickerValidation = (
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { FieldExtensionOptions } from './types';
|
||||
import { CustomFieldValidator, FieldExtensionOptions } from './types';
|
||||
import { Extension, attachComponentData } from '@backstage/core-plugin-api';
|
||||
|
||||
export const FIELD_EXTENSION_WRAPPER_KEY = 'scaffolder.extensions.wrapper.v1';
|
||||
@@ -46,6 +46,6 @@ attachComponentData(
|
||||
true,
|
||||
);
|
||||
|
||||
export type { FieldExtensionOptions };
|
||||
export type { CustomFieldValidator, FieldExtensionOptions };
|
||||
|
||||
export { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default';
|
||||
|
||||
@@ -13,10 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ApiHolder } from '@backstage/core-plugin-api';
|
||||
import { FieldValidation, FieldProps } from '@rjsf/core';
|
||||
|
||||
export type CustomFieldValidator<T> =
|
||||
| ((data: T, field: FieldValidation) => void)
|
||||
| ((
|
||||
data: T,
|
||||
field: FieldValidation,
|
||||
context: { apiHolder: ApiHolder },
|
||||
) => void);
|
||||
|
||||
export type FieldExtensionOptions<T = any> = {
|
||||
name: string;
|
||||
component: (props: FieldProps<T>) => JSX.Element | null;
|
||||
validation?: (data: T, field: FieldValidation) => void;
|
||||
validation?: CustomFieldValidator<T>;
|
||||
};
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
export { scaffolderApiRef, ScaffolderClient } from './api';
|
||||
export type { ScaffolderApi } from './api';
|
||||
export {
|
||||
createScaffolderFieldExtension,
|
||||
export { createScaffolderFieldExtension } from './extensions';
|
||||
export type {
|
||||
ScaffolderFieldExtensions,
|
||||
CustomFieldValidator,
|
||||
FieldExtensionOptions,
|
||||
} from './extensions';
|
||||
export {
|
||||
EntityPickerFieldExtension,
|
||||
|
||||
Reference in New Issue
Block a user