@backstage/plugin-scaffolder-react 1.5.6-next.2 → 1.6.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # @backstage/plugin-scaffolder-react
2
2
 
3
+ ## 1.6.0-next.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3fdffbb699: Release design improvements for the `Scaffolder` plugin and support v5 of `@rjsf/*` libraries.
8
+
9
+ This change should be non-breaking. If you're seeing typescript issues after migrating please [open an issue](https://github.com/backstage/backstage/issues/new/choose)
10
+
11
+ The `next` versions like `createNextFieldExtension` and `NextScaffolderPage` have been promoted to the public interface under `createScaffolderFieldExtension` and `ScaffolderPage`, so any older imports which are no longer found will need updating from `@backstage/plugin-scaffolder/alpha` or `@backstage/plugin-scaffolder-react/alpha` will need to be imported from `@backstage/plugin-scaffolder` and `@backstage/plugin-scaffolder-react` respectively.
12
+
13
+ The legacy versions are now available in `/alpha` under `createLegacyFieldExtension` and `LegacyScaffolderPage` if you're running into issues, but be aware that these will be removed in a next mainline release.
14
+
15
+ ### Patch Changes
16
+
17
+ - 6c2b872153: Add official support for React 18.
18
+ - Updated dependencies
19
+ - @backstage/core-components@0.13.7-next.0
20
+ - @backstage/plugin-scaffolder-common@1.4.3-next.0
21
+ - @backstage/plugin-catalog-react@1.9.0-next.0
22
+ - @backstage/core-plugin-api@1.8.0-next.0
23
+ - @backstage/version-bridge@1.0.7-next.0
24
+ - @backstage/theme@0.4.4-next.0
25
+ - @backstage/catalog-client@1.4.5
26
+ - @backstage/catalog-model@1.4.3
27
+ - @backstage/errors@1.2.3
28
+ - @backstage/types@1.1.1
29
+
30
+ ## 1.5.6
31
+
32
+ ### Patch Changes
33
+
34
+ - 9a1fce352e: Updated dependency `@testing-library/jest-dom` to `^6.0.0`.
35
+ - f95af4e540: Updated dependency `@testing-library/dom` to `^9.0.0`.
36
+ - Updated dependencies
37
+ - @backstage/plugin-catalog-react@1.8.5
38
+ - @backstage/core-plugin-api@1.7.0
39
+ - @backstage/core-components@0.13.6
40
+ - @backstage/catalog-model@1.4.3
41
+ - @backstage/errors@1.2.3
42
+ - @backstage/version-bridge@1.0.6
43
+ - @backstage/theme@0.4.3
44
+ - @backstage/catalog-client@1.4.5
45
+ - @backstage/types@1.1.1
46
+ - @backstage/plugin-scaffolder-common@1.4.2
47
+
3
48
  ## 1.5.6-next.2
4
49
 
5
50
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-react",
3
- "version": "1.5.6-next.2",
3
+ "version": "1.6.0-next.0",
4
4
  "main": "../dist/alpha.esm.js",
5
5
  "module": "../dist/alpha.esm.js",
6
6
  "types": "../dist/alpha.d.ts"
package/dist/alpha.d.ts CHANGED
@@ -1,60 +1,12 @@
1
1
  /// <reference types="react" />
2
2
  import { JsonObject, JsonValue } from '@backstage/types';
3
3
  import * as React from 'react';
4
- import React__default, { PropsWithChildren, ReactNode, ReactElement } from 'react';
5
- import { ApiHolder, Extension, IconComponent } from '@backstage/core-plugin-api';
6
- import { FieldProps, UiSchema, UIOptionsType, FieldValidation } from '@rjsf/utils';
7
- import { CustomFieldExtensionSchema, FieldExtensionComponent, TemplateParameterSchema, LayoutOptions, ScaffolderTaskOutput, ScaffolderStep } from '@backstage/plugin-scaffolder-react';
8
- import { FormProps as FormProps$1 } from '@rjsf/core-v5';
4
+ import React__default, { ComponentType, ReactNode, PropsWithChildren, ReactElement } from 'react';
5
+ import { UiSchema, FieldValidation } from '@rjsf/utils';
6
+ import { TemplateParameterSchema, FieldExtensionOptions, FormProps, ReviewStepProps, LayoutOptions, CustomFieldValidator, TemplateGroupFilter, ScaffolderTaskOutput, ScaffolderRJSFFormProps, ScaffolderStep, CustomFieldExtensionSchema, ScaffolderRJSFFieldProps, FieldExtensionComponent } from '@backstage/plugin-scaffolder-react';
7
+ import { ApiHolder, IconComponent, Extension } from '@backstage/core-plugin-api';
9
8
  import { TemplateEntityV1beta3, TaskStep } from '@backstage/plugin-scaffolder-common';
10
9
 
11
- /**
12
- * Type for Field Extension Props for RJSF v5
13
- *
14
- * @alpha
15
- */
16
- interface NextFieldExtensionComponentProps<TFieldReturnValue, TUiOptions = {}> extends PropsWithChildren<FieldProps<TFieldReturnValue>> {
17
- uiSchema?: NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
18
- }
19
- /**
20
- * Type for Field Extension UiSchema
21
- *
22
- * @alpha
23
- */
24
- interface NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions> extends UiSchema<TFieldReturnValue> {
25
- 'ui:options'?: TUiOptions & UIOptionsType;
26
- }
27
- /**
28
- * Field validation type for Custom Field Extensions.
29
- *
30
- * @alpha
31
- */
32
- type NextCustomFieldValidator<TFieldReturnValue, TUiOptions = unknown> = (data: TFieldReturnValue, field: FieldValidation, context: {
33
- apiHolder: ApiHolder;
34
- formData: JsonObject;
35
- schema: JsonObject;
36
- uiSchema?: NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
37
- }) => void | Promise<void>;
38
- /**
39
- * Type for the Custom Field Extension with the
40
- * name and components and validation function.
41
- *
42
- * @alpha
43
- */
44
- type NextFieldExtensionOptions<TFieldReturnValue = unknown, TUiOptions = unknown> = {
45
- name: string;
46
- component: (props: NextFieldExtensionComponentProps<TFieldReturnValue, TUiOptions>) => JSX.Element | null;
47
- validation?: NextCustomFieldValidator<TFieldReturnValue, TUiOptions>;
48
- schema?: CustomFieldExtensionSchema;
49
- };
50
-
51
- /**
52
- * Method for creating field extensions that can be used in the scaffolder
53
- * frontend form.
54
- * @alpha
55
- */
56
- declare function createNextScaffolderFieldExtension<TReturnValue = unknown, TInputProps extends UIOptionsType = {}>(options: NextFieldExtensionOptions<TReturnValue, TInputProps>): Extension<FieldExtensionComponent<TReturnValue, TInputProps>>;
57
-
58
10
  /**
59
11
  * This is the parsed template schema that is returned from the {@link useTemplateSchema} hook.
60
12
  * @alpha
@@ -90,25 +42,19 @@ type ReviewStateProps = {
90
42
  */
91
43
  declare const ReviewState: (props: ReviewStateProps) => React__default.JSX.Element;
92
44
 
93
- /**
94
- * Any `@rjsf/core` form properties that are publicly exposed to the `NextScaffolderpage`
95
- *
96
- * @alpha
97
- */
98
- type FormProps = Pick<FormProps$1, 'transformErrors' | 'noHtml5Validate'>;
99
-
100
45
  /**
101
46
  * The Props for {@link Stepper} component
102
47
  * @alpha
103
48
  */
104
49
  type StepperProps = {
105
50
  manifest: TemplateParameterSchema;
106
- extensions: NextFieldExtensionOptions<any, any>[];
51
+ extensions: FieldExtensionOptions<any, any>[];
107
52
  templateName?: string;
108
- FormProps?: FormProps;
53
+ formProps?: FormProps;
109
54
  initialState?: Record<string, JsonValue>;
110
55
  onCreate: (values: Record<string, JsonValue>) => Promise<void>;
111
56
  components?: {
57
+ ReviewStepComponent?: ComponentType<ReviewStepProps>;
112
58
  ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element;
113
59
  createButtonText?: ReactNode;
114
60
  reviewButtonText?: ReactNode;
@@ -121,6 +67,15 @@ type StepperProps = {
121
67
  */
122
68
  declare const Stepper: (stepperProps: StepperProps) => React__default.JSX.Element;
123
69
 
70
+ /** @alpha */
71
+ type FormValidation = {
72
+ [name: string]: FieldValidation | FormValidation;
73
+ };
74
+ /** @alpha */
75
+ declare const createAsyncValidators: (rootSchema: JsonObject, validators: Record<string, undefined | CustomFieldValidator<unknown, unknown>>, context: {
76
+ apiHolder: ApiHolder;
77
+ }) => (formData: JsonObject) => Promise<FormValidation>;
78
+
124
79
  /**
125
80
  * The Props for the {@link TemplateCard} component
126
81
  * @alpha
@@ -165,13 +120,6 @@ interface TemplateGroupProps {
165
120
  */
166
121
  declare const TemplateGroup: (props: TemplateGroupProps) => React__default.JSX.Element | null;
167
122
 
168
- /**
169
- * @alpha
170
- */
171
- type TemplateGroupFilter = {
172
- title?: React__default.ReactNode;
173
- filter: (entity: TemplateEntityV1beta3) => boolean;
174
- };
175
123
  /**
176
124
  * @alpha
177
125
  */
@@ -201,8 +149,11 @@ type WorkflowProps = {
201
149
  description?: string;
202
150
  namespace: string;
203
151
  templateName: string;
152
+ components?: {
153
+ ReviewStepComponent?: React__default.ComponentType<ReviewStepProps>;
154
+ };
204
155
  onError(error: Error | undefined): JSX.Element | null;
205
- } & Pick<StepperProps, 'extensions' | 'FormProps' | 'components' | 'onCreate' | 'initialState' | 'layouts'>;
156
+ } & Pick<StepperProps, 'extensions' | 'formProps' | 'components' | 'onCreate' | 'initialState' | 'layouts'>;
206
157
  /**
207
158
  * @alpha
208
159
  */
@@ -225,7 +176,7 @@ declare const DefaultTemplateOutputs: (props: {
225
176
  * The Form component
226
177
  * @alpha
227
178
  */
228
- declare const Form: (props: PropsWithChildren<FormProps$1>) => React__default.JSX.Element;
179
+ declare const Form: (props: PropsWithChildren<ScaffolderRJSFFormProps>) => React__default.JSX.Element;
229
180
 
230
181
  /**
231
182
  * Props for the TaskSteps component
@@ -326,4 +277,43 @@ declare const useTemplateParameterSchema: (templateRef: string) => {
326
277
  error: Error | undefined;
327
278
  };
328
279
 
329
- export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, FormProps, NextCustomFieldValidator, NextFieldExtensionComponentProps, NextFieldExtensionOptions, NextFieldExtensionUiSchema, ParsedTemplateSchema, ReviewState, ReviewStateProps, ScaffolderField, ScaffolderFieldProps, ScaffolderPageContextMenu, ScaffolderPageContextMenuProps, Stepper, StepperProps, TaskLogStream, TaskSteps, TaskStepsProps, TemplateCard, TemplateCardProps, TemplateCategoryPicker, TemplateGroup, TemplateGroupFilter, TemplateGroupProps, TemplateGroups, TemplateGroupsProps, Workflow, WorkflowProps, createFieldValidation, createNextScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
280
+ /**
281
+ * Field validation type for Custom Field Extensions.
282
+ *
283
+ * @alpha
284
+ */
285
+ type LegacyCustomFieldValidator<TFieldReturnValue> = (data: TFieldReturnValue, field: FieldValidation, context: {
286
+ apiHolder: ApiHolder;
287
+ }) => void | Promise<void>;
288
+ /**
289
+ * Type for the Custom Field Extension with the
290
+ * name and components and validation function.
291
+ *
292
+ * @alpha
293
+ */
294
+ type LegacyFieldExtensionOptions<TFieldReturnValue = unknown, TInputProps = unknown> = {
295
+ name: string;
296
+ component: (props: LegacyFieldExtensionComponentProps<TFieldReturnValue, TInputProps>) => JSX.Element | null;
297
+ validation?: LegacyCustomFieldValidator<TFieldReturnValue>;
298
+ schema?: CustomFieldExtensionSchema;
299
+ };
300
+ /**
301
+ * Type for field extensions and being able to type
302
+ * incoming props easier.
303
+ *
304
+ * @alpha
305
+ */
306
+ interface LegacyFieldExtensionComponentProps<TFieldReturnValue, TUiOptions = unknown> extends ScaffolderRJSFFieldProps<TFieldReturnValue> {
307
+ uiSchema: ScaffolderRJSFFieldProps['uiSchema'] & {
308
+ 'ui:options'?: TUiOptions;
309
+ };
310
+ }
311
+
312
+ /**
313
+ * Method for creating field extensions that can be used in the scaffolder
314
+ * frontend form.
315
+ * @alpha
316
+ */
317
+ declare function createLegacyScaffolderFieldExtension<TReturnValue = unknown, TInputProps = unknown>(options: LegacyFieldExtensionOptions<TReturnValue, TInputProps>): Extension<FieldExtensionComponent<TReturnValue, TInputProps>>;
318
+
319
+ export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, FormValidation, LegacyCustomFieldValidator, LegacyFieldExtensionComponentProps, LegacyFieldExtensionOptions, ParsedTemplateSchema, ReviewState, ReviewStateProps, ScaffolderField, ScaffolderFieldProps, ScaffolderPageContextMenu, ScaffolderPageContextMenuProps, Stepper, StepperProps, TaskLogStream, TaskSteps, TaskStepsProps, TemplateCard, TemplateCardProps, TemplateCategoryPicker, TemplateGroup, TemplateGroupProps, TemplateGroups, TemplateGroupsProps, Workflow, WorkflowProps, createAsyncValidators, createFieldValidation, createLegacyScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
package/dist/alpha.esm.js CHANGED
@@ -7,13 +7,13 @@ import validator from '@rjsf/validator-ajv8';
7
7
  import qs from 'qs';
8
8
  import useAsync from 'react-use/lib/useAsync';
9
9
  import { s as scaffolderApiRef, S as SecretsContextProvider, a as FIELD_EXTENSION_KEY } from './esm/ref-6fdfc121.esm.js';
10
- import { withTheme } from '@rjsf/core-v5';
10
+ import { withTheme } from '@rjsf/core';
11
11
  import { getUiOptions, getTemplate } from '@rjsf/utils';
12
+ import { Theme } from '@rjsf/material-ui';
12
13
  import { RELATION_OWNED_BY, stringifyEntityRef, parseEntityRef } from '@backstage/catalog-model';
13
14
  import { FavoriteEntity, getEntityRelations, EntityRefLinks, useEntityList, entityRouteRef, useEntityTypeFilter } from '@backstage/plugin-catalog-react';
14
15
  import LanguageIcon from '@material-ui/icons/Language';
15
16
  import { isTemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
16
- import { TemplateGroup as TemplateGroup$1 } from '@backstage/plugin-scaffolder-react/alpha';
17
17
  import WebIcon from '@material-ui/icons/Web';
18
18
  import RemoveCircleOutline from '@material-ui/icons/RemoveCircleOutline';
19
19
  import PanoramaFishEyeIcon from '@material-ui/icons/PanoramaFishEye';
@@ -491,14 +491,40 @@ const DescriptionFieldTemplate = (props) => {
491
491
  return null;
492
492
  };
493
493
 
494
- const WrappedForm = withTheme(require("@rjsf/material-ui-v5").Theme);
494
+ const WrappedForm = withTheme(Theme);
495
495
  const Form = (props) => {
496
- const templates = {
497
- FieldTemplate,
498
- DescriptionFieldTemplate,
499
- ...props.templates
500
- };
501
- return /* @__PURE__ */ React.createElement(WrappedForm, { ...props, templates });
496
+ const wrappedFields = React.useMemo(
497
+ () => {
498
+ var _a;
499
+ return Object.fromEntries(
500
+ Object.entries((_a = props.fields) != null ? _a : {}).map(([key, Component]) => [
501
+ key,
502
+ (wrapperProps) => {
503
+ var _a2, _b;
504
+ return /* @__PURE__ */ React.createElement(
505
+ Component,
506
+ {
507
+ ...wrapperProps,
508
+ uiSchema: (_a2 = wrapperProps.uiSchema) != null ? _a2 : {},
509
+ formData: wrapperProps.formData,
510
+ rawErrors: (_b = wrapperProps.rawErrors) != null ? _b : []
511
+ }
512
+ );
513
+ }
514
+ ])
515
+ );
516
+ },
517
+ [props.fields]
518
+ );
519
+ const templates = React.useMemo(
520
+ () => ({
521
+ FieldTemplate,
522
+ DescriptionFieldTemplate,
523
+ ...props.templates
524
+ }),
525
+ [props.templates]
526
+ );
527
+ return /* @__PURE__ */ React.createElement(WrappedForm, { ...props, templates, fields: wrappedFields });
502
528
  };
503
529
 
504
530
  const useStyles$8 = makeStyles((theme) => ({
@@ -520,6 +546,7 @@ const Stepper = (stepperProps) => {
520
546
  const { layouts = [], components = {}, ...props } = stepperProps;
521
547
  const {
522
548
  ReviewStateComponent = ReviewState,
549
+ ReviewStepComponent,
523
550
  createButtonText = "Create",
524
551
  reviewButtonText = "Review"
525
552
  } = components;
@@ -536,6 +563,10 @@ const Stepper = (stepperProps) => {
536
563
  props.extensions.map(({ name, component }) => [name, component])
537
564
  );
538
565
  }, [props.extensions]);
566
+ const fields = useMemo(
567
+ () => ({ ...FieldOverrides, ...extensions }),
568
+ [extensions]
569
+ );
539
570
  const validators = useMemo(() => {
540
571
  return Object.fromEntries(
541
572
  props.extensions.map(({ name, validation: validation2 }) => [name, validation2])
@@ -554,6 +585,12 @@ const Stepper = (stepperProps) => {
554
585
  (e) => setFormState((current) => ({ ...current, ...e.formData })),
555
586
  [setFormState]
556
587
  );
588
+ const handleCreate = useCallback(() => {
589
+ var _a2;
590
+ props.onCreate(formState);
591
+ const name = typeof formState.name === "string" ? formState.name : void 0;
592
+ analytics.captureEvent("create", (_a2 = name != null ? name : props.templateName) != null ? _a2 : "unknown");
593
+ }, [props, formState, analytics]);
557
594
  const currentStep = useTransformSchemaToProps(steps[activeStep], { layouts });
558
595
  const handleNext = async ({
559
596
  formData = {}
@@ -584,10 +621,10 @@ const Stepper = (stepperProps) => {
584
621
  schema: currentStep.schema,
585
622
  uiSchema: currentStep.uiSchema,
586
623
  onSubmit: handleNext,
587
- fields: { ...FieldOverrides, ...extensions },
624
+ fields,
588
625
  showErrorList: false,
589
626
  onChange: handleChange,
590
- ...(_a = props.FormProps) != null ? _a : {}
627
+ ...(_a = props.formProps) != null ? _a : {}
591
628
  },
592
629
  /* @__PURE__ */ React.createElement("div", { className: styles.footer }, /* @__PURE__ */ React.createElement(
593
630
  Button,
@@ -607,31 +644,37 @@ const Stepper = (stepperProps) => {
607
644
  },
608
645
  activeStep === steps.length - 1 ? reviewButtonText : "Next"
609
646
  ))
610
- ) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ReviewStateComponent, { formState, schemas: steps }), /* @__PURE__ */ React.createElement("div", { className: styles.footer }, /* @__PURE__ */ React.createElement(
611
- Button,
612
- {
613
- onClick: handleBack,
614
- className: styles.backButton,
615
- disabled: activeStep < 1
616
- },
617
- "Back"
618
- ), /* @__PURE__ */ React.createElement(
619
- Button,
620
- {
621
- variant: "contained",
622
- color: "primary",
623
- onClick: () => {
624
- var _a2;
625
- props.onCreate(formState);
626
- const name = typeof formState.name === "string" ? formState.name : void 0;
627
- analytics.captureEvent(
628
- "create",
629
- (_a2 = name != null ? name : props.templateName) != null ? _a2 : "unknown"
630
- );
647
+ ) : (
648
+ // TODO: potentially move away from this pattern, deprecate?
649
+ ReviewStepComponent ? /* @__PURE__ */ React.createElement(
650
+ ReviewStepComponent,
651
+ {
652
+ disableButtons: isValidating,
653
+ formData: formState,
654
+ handleBack,
655
+ handleReset: () => {
656
+ },
657
+ steps,
658
+ handleCreate
631
659
  }
632
- },
633
- createButtonText
634
- )))));
660
+ ) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ReviewStateComponent, { formState, schemas: steps }), /* @__PURE__ */ React.createElement("div", { className: styles.footer }, /* @__PURE__ */ React.createElement(
661
+ Button,
662
+ {
663
+ onClick: handleBack,
664
+ className: styles.backButton,
665
+ disabled: activeStep < 1
666
+ },
667
+ "Back"
668
+ ), /* @__PURE__ */ React.createElement(
669
+ Button,
670
+ {
671
+ variant: "contained",
672
+ color: "primary",
673
+ onClick: handleCreate
674
+ },
675
+ createButtonText
676
+ )))
677
+ )));
635
678
  };
636
679
 
637
680
  const useStyles$7 = makeStyles(() => ({
@@ -822,7 +865,7 @@ const TemplateGroups = (props) => {
822
865
  };
823
866
  });
824
867
  return /* @__PURE__ */ React.createElement(
825
- TemplateGroup$1,
868
+ TemplateGroup,
826
869
  {
827
870
  key: index,
828
871
  templates,
@@ -1210,7 +1253,7 @@ function ScaffolderPageContextMenu(props) {
1210
1253
  ));
1211
1254
  }
1212
1255
 
1213
- function createNextScaffolderFieldExtension(options) {
1256
+ function createLegacyScaffolderFieldExtension(options) {
1214
1257
  return {
1215
1258
  expose() {
1216
1259
  const FieldExtensionDataHolder = () => null;
@@ -1224,5 +1267,5 @@ function createNextScaffolderFieldExtension(options) {
1224
1267
  };
1225
1268
  }
1226
1269
 
1227
- export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, ReviewState, ScaffolderField, ScaffolderPageContextMenu, Stepper, TaskLogStream, TaskSteps, TemplateCard, TemplateCategoryPicker, TemplateGroup, TemplateGroups, Workflow, createFieldValidation, createNextScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
1270
+ export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, ReviewState, ScaffolderField, ScaffolderPageContextMenu, Stepper, TaskLogStream, TaskSteps, TemplateCard, TemplateCategoryPicker, TemplateGroup, TemplateGroups, Workflow, createAsyncValidators, createFieldValidation, createLegacyScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
1228
1271
  //# sourceMappingURL=alpha.esm.js.map