@backstage/plugin-scaffolder-react 1.2.0-next.2 → 1.3.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,61 @@
1
1
  # @backstage/plugin-scaffolder-react
2
2
 
3
+ ## 1.3.0-next.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 259d3407b9b: Move `CategoryPicker` from `scaffolder` into `scaffolder-react`
8
+ Move `ContextMenu` into `scaffolder-react` and rename it to `ScaffolderPageContextMenu`
9
+ - 2cfd03d7376: To offer better customization options, `ScaffolderPageContextMenu` takes callbacks as props instead of booleans
10
+ - 48da4c46e45: `scaffolder/next`: Export the `TemplateGroupFilter` and `TemplateGroups` and make an extensible component
11
+
12
+ ### Patch Changes
13
+
14
+ - e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template)
15
+ - 7a6b16cc506: `scaffolder/next`: Bump `@rjsf/*` deps to 5.3.1
16
+ - f84fc7fd040: Updated dependency `@rjsf/validator-ajv8` to `5.3.0`.
17
+ - 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs)
18
+ - Updated dependencies
19
+ - @backstage/plugin-scaffolder-common@1.2.7-next.0
20
+ - @backstage/core-components@0.12.6-next.0
21
+ - @backstage/plugin-catalog-react@1.4.1-next.0
22
+ - @backstage/core-plugin-api@1.5.0
23
+ - @backstage/catalog-client@1.4.0
24
+ - @backstage/catalog-model@1.2.1
25
+ - @backstage/errors@1.1.5
26
+ - @backstage/theme@0.2.18
27
+ - @backstage/types@1.0.2
28
+ - @backstage/version-bridge@1.0.3
29
+
30
+ ## 1.2.0
31
+
32
+ ### Minor Changes
33
+
34
+ - 8f4d13f21cf: Move `useTaskStream`, `TaskBorder`, `TaskLogStream` and `TaskSteps` into `scaffolder-react`.
35
+
36
+ ### Patch Changes
37
+
38
+ - 65454876fb2: Minor API report tweaks
39
+ - 3c96e77b513: Make scaffolder adhere to page themes by using page `fontColor` consistently. If your theme overwrites template list or card headers, review those styles.
40
+ - c8d78b9ae9d: fix bug with `hasErrors` returning false when dealing with empty objects
41
+ - 9b8c374ace5: Remove timer for skipped steps in Scaffolder Next's TaskSteps
42
+ - 44941fc97eb: scaffolder/next: Move the `uiSchema` to its own property in the validation `context` to align with component development and access of `ui:options`
43
+ - d9893263ba9: scaffolder/next: Fix for steps without properties
44
+ - 928a12a9b3e: Internal refactor of `/alpha` exports.
45
+ - cc418d652a7: scaffolder/next: Added the ability to get the fields definition in the schema in the validation function
46
+ - d4100d0ec42: Fix alignment bug for owners on `TemplateCard`
47
+ - Updated dependencies
48
+ - @backstage/catalog-client@1.4.0
49
+ - @backstage/core-components@0.12.5
50
+ - @backstage/plugin-catalog-react@1.4.0
51
+ - @backstage/errors@1.1.5
52
+ - @backstage/core-plugin-api@1.5.0
53
+ - @backstage/catalog-model@1.2.1
54
+ - @backstage/theme@0.2.18
55
+ - @backstage/types@1.0.2
56
+ - @backstage/version-bridge@1.0.3
57
+ - @backstage/plugin-scaffolder-common@1.2.6
58
+
3
59
  ## 1.2.0-next.2
4
60
 
5
61
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-react",
3
- "version": "1.2.0-next.2",
3
+ "version": "1.3.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,7 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import { JsonObject, JsonValue } from '@backstage/types';
3
- import * as react from 'react';
4
- import react__default, { PropsWithChildren, ReactNode } from 'react';
3
+ import * as React from 'react';
4
+ import React__default, { PropsWithChildren, ReactNode } from 'react';
5
5
  import { ApiHolder, Extension, IconComponent } from '@backstage/core-plugin-api';
6
6
  import * as _rjsf_utils from '@rjsf/utils';
7
7
  import { FieldProps, UiSchema, UIOptionsType, FieldValidation } from '@rjsf/utils';
@@ -156,9 +156,9 @@ interface TemplateGroupProps {
156
156
  }[];
157
157
  }[];
158
158
  onSelected: (template: TemplateEntityV1beta3) => void;
159
- title: react__default.ReactNode;
159
+ title: React__default.ReactNode;
160
160
  components?: {
161
- CardComponent?: react__default.ComponentType<TemplateCardProps>;
161
+ CardComponent?: React__default.ComponentType<TemplateCardProps>;
162
162
  };
163
163
  }
164
164
  /**
@@ -167,6 +167,34 @@ interface TemplateGroupProps {
167
167
  */
168
168
  declare const TemplateGroup: (props: TemplateGroupProps) => JSX.Element;
169
169
 
170
+ /**
171
+ * @alpha
172
+ */
173
+ declare type TemplateGroupFilter = {
174
+ title?: React__default.ReactNode;
175
+ filter: (entity: TemplateEntityV1beta3) => boolean;
176
+ };
177
+ /**
178
+ * @alpha
179
+ */
180
+ interface TemplateGroupsProps {
181
+ groups: TemplateGroupFilter[];
182
+ templateFilter?: (entity: TemplateEntityV1beta3) => boolean;
183
+ TemplateCardComponent?: React__default.ComponentType<{
184
+ template: TemplateEntityV1beta3;
185
+ }>;
186
+ onTemplateSelected?: (template: TemplateEntityV1beta3) => void;
187
+ additionalLinksForEntity?: (template: TemplateEntityV1beta3) => {
188
+ icon: IconComponent;
189
+ text: string;
190
+ url: string;
191
+ }[];
192
+ }
193
+ /**
194
+ * @alpha
195
+ */
196
+ declare const TemplateGroups: (props: TemplateGroupsProps) => JSX.Element | null;
197
+
170
198
  /**
171
199
  * @alpha
172
200
  */
@@ -196,7 +224,7 @@ declare const DefaultTemplateOutputs: (props: {
196
224
  }) => JSX.Element | null;
197
225
 
198
226
  /** @alpha */
199
- declare const Form: react.ComponentType<_rjsf_core_v5.FormProps<any, _rjsf_utils.RJSFSchema, any>>;
227
+ declare const Form: React.ComponentType<_rjsf_core_v5.FormProps<any, _rjsf_utils.RJSFSchema, any>>;
200
228
 
201
229
  /**
202
230
  * Props for the TaskSteps component
@@ -227,6 +255,26 @@ declare const TaskLogStream: (props: {
227
255
  };
228
256
  }) => JSX.Element;
229
257
 
258
+ /**
259
+ * The Category Picker that is rendered on the left side for picking
260
+ * categories and filtering the template list.
261
+ * @alpha
262
+ */
263
+ declare const TemplateCategoryPicker: () => JSX.Element | null;
264
+
265
+ /**
266
+ * @alpha
267
+ */
268
+ declare type ScaffolderPageContextMenuProps = {
269
+ onEditorClicked?: () => void;
270
+ onActionsClicked?: () => void;
271
+ onTasksClicked?: () => void;
272
+ };
273
+ /**
274
+ * @alpha
275
+ */
276
+ declare function ScaffolderPageContextMenu(props: ScaffolderPageContextMenuProps): JSX.Element | null;
277
+
230
278
  /**
231
279
  * Takes a step from a Backstage Template Manifest and converts it to a JSON Schema and UI Schema for rjsf
232
280
  * @alpha
@@ -245,7 +293,7 @@ declare const createFieldValidation: () => FieldValidation;
245
293
  * This hook is used to get the formData from the query string.
246
294
  * @alpha
247
295
  */
248
- declare const useFormDataFromQuery: (initialState?: Record<string, JsonValue>) => [Record<string, any>, react.Dispatch<react.SetStateAction<Record<string, any>>>];
296
+ declare const useFormDataFromQuery: (initialState?: Record<string, JsonValue>) => [Record<string, any>, React.Dispatch<React.SetStateAction<Record<string, any>>>];
249
297
 
250
298
  /**
251
299
  * @alpha
@@ -256,4 +304,4 @@ declare const useTemplateParameterSchema: (templateRef: string) => {
256
304
  error: Error | undefined;
257
305
  };
258
306
 
259
- export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, FormProps, NextCustomFieldValidator, NextFieldExtensionComponentProps, NextFieldExtensionOptions, NextFieldExtensionUiSchema, ParsedTemplateSchema, ReviewState, ReviewStateProps, Stepper, StepperProps, TaskLogStream, TaskSteps, TaskStepsProps, TemplateCard, TemplateCardProps, TemplateGroup, TemplateGroupProps, Workflow, WorkflowProps, createFieldValidation, createNextScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
307
+ export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, FormProps, NextCustomFieldValidator, NextFieldExtensionComponentProps, NextFieldExtensionOptions, NextFieldExtensionUiSchema, ParsedTemplateSchema, ReviewState, ReviewStateProps, ScaffolderPageContextMenu, ScaffolderPageContextMenuProps, Stepper, StepperProps, TaskLogStream, TaskSteps, TaskStepsProps, TemplateCard, TemplateCardProps, TemplateCategoryPicker, TemplateGroup, TemplateGroupFilter, TemplateGroupProps, TemplateGroups, TemplateGroupsProps, Workflow, WorkflowProps, createFieldValidation, createNextScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
package/dist/alpha.esm.js CHANGED
@@ -1,5 +1,5 @@
1
- import { useApi, featureFlagsApiRef, createApiRef, useAnalytics, useApiHolder, useApp, errorApiRef, useRouteRef, attachComponentData } from '@backstage/core-plugin-api';
2
- import { makeStyles, Stepper as Stepper$1, Step, StepLabel, Button, useTheme, Card, CardContent, Grid, Box, Divider, Chip, CardActions, Typography, Paper, CircularProgress, LinearProgress, StepButton } from '@material-ui/core';
1
+ import { useApi, featureFlagsApiRef, createApiRef, useAnalytics, useApiHolder, useApp, errorApiRef, useRouteRef, alertApiRef, attachComponentData } from '@backstage/core-plugin-api';
2
+ import { makeStyles, Stepper as Stepper$1, Step, StepLabel, Button, useTheme, Card, CardContent, Grid, Box, Divider, Chip, CardActions, Typography, Paper, CircularProgress, LinearProgress, StepButton, FormControlLabel, Checkbox, TextField } from '@material-ui/core';
3
3
  import React, { useState, useMemo, useCallback, useEffect } from 'react';
4
4
  import { Draft07 } from 'json-schema-library';
5
5
  import { StructuredMetadataTable, MarkdownContent, ItemCardHeader, Link, UserIcon, Content, ItemCardGrid, ContentHeader, Progress, InfoCard, LogViewer } from '@backstage/core-components';
@@ -9,8 +9,10 @@ import useAsync from 'react-use/lib/useAsync';
9
9
  import { getOrCreateGlobalSingleton, createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
10
10
  import { withTheme } from '@rjsf/core-v5';
11
11
  import { RELATION_OWNED_BY, stringifyEntityRef, parseEntityRef } from '@backstage/catalog-model';
12
- import { FavoriteEntity, getEntityRelations, EntityRefLinks, entityRouteRef } from '@backstage/plugin-catalog-react';
12
+ import { FavoriteEntity, getEntityRelations, EntityRefLinks, useEntityList, entityRouteRef, useEntityTypeFilter } from '@backstage/plugin-catalog-react';
13
13
  import LanguageIcon from '@material-ui/icons/Language';
14
+ import { isTemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
15
+ import { TemplateGroup as TemplateGroup$1 } from '@backstage/plugin-scaffolder-react/alpha';
14
16
  import WebIcon from '@material-ui/icons/Web';
15
17
  import RemoveCircleOutline from '@material-ui/icons/RemoveCircleOutline';
16
18
  import PanoramaFishEyeIcon from '@material-ui/icons/PanoramaFishEye';
@@ -22,6 +24,21 @@ import { DateTime, Interval } from 'luxon';
22
24
  import humanizeDuration from 'humanize-duration';
23
25
  import { useMountEffect } from '@react-hookz/web';
24
26
  import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
27
+ import capitalize from 'lodash/capitalize';
28
+ import CheckBoxIcon from '@material-ui/icons/CheckBox';
29
+ import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
30
+ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
31
+ import { Autocomplete } from '@material-ui/lab';
32
+ import IconButton from '@material-ui/core/IconButton';
33
+ import ListItemIcon from '@material-ui/core/ListItemIcon';
34
+ import ListItemText from '@material-ui/core/ListItemText';
35
+ import MenuItem from '@material-ui/core/MenuItem';
36
+ import MenuList from '@material-ui/core/MenuList';
37
+ import Popover from '@material-ui/core/Popover';
38
+ import Description from '@material-ui/icons/Description';
39
+ import Edit from '@material-ui/icons/Edit';
40
+ import List from '@material-ui/icons/List';
41
+ import MoreVert from '@material-ui/icons/MoreVert';
25
42
 
26
43
  function isObject$1(value) {
27
44
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -328,7 +345,7 @@ var FieldOverrides = /*#__PURE__*/Object.freeze({
328
345
 
329
346
  const Form = withTheme(require("@rjsf/material-ui-v5").Theme);
330
347
 
331
- const useStyles$7 = makeStyles((theme) => ({
348
+ const useStyles$8 = makeStyles((theme) => ({
332
349
  backButton: {
333
350
  marginRight: theme.spacing(1)
334
351
  },
@@ -355,7 +372,7 @@ const Stepper = (stepperProps) => {
355
372
  const [activeStep, setActiveStep] = useState(0);
356
373
  const [formState, setFormState] = useFormDataFromQuery(props.initialState);
357
374
  const [errors, setErrors] = useState();
358
- const styles = useStyles$7();
375
+ const styles = useStyles$8();
359
376
  const extensions = useMemo(() => {
360
377
  return Object.fromEntries(
361
378
  props.extensions.map(({ name, component }) => [name, component])
@@ -447,7 +464,7 @@ const Stepper = (stepperProps) => {
447
464
  )))));
448
465
  };
449
466
 
450
- const useStyles$6 = makeStyles(() => ({
467
+ const useStyles$7 = makeStyles(() => ({
451
468
  header: {
452
469
  backgroundImage: ({ cardBackgroundImage }) => cardBackgroundImage,
453
470
  color: ({ cardFontColor }) => cardFontColor
@@ -466,7 +483,7 @@ const CardHeader = (props) => {
466
483
  } = props;
467
484
  const { getPageTheme } = useTheme();
468
485
  const themeForType = getPageTheme({ themeId: type });
469
- const styles = useStyles$6({
486
+ const styles = useStyles$7({
470
487
  cardFontColor: themeForType.fontColor,
471
488
  cardBackgroundImage: themeForType.backgroundImage
472
489
  });
@@ -481,18 +498,18 @@ const CardHeader = (props) => {
481
498
  );
482
499
  };
483
500
 
484
- const useStyles$5 = makeStyles(() => ({
501
+ const useStyles$6 = makeStyles(() => ({
485
502
  linkText: {
486
503
  display: "inline-flex",
487
504
  alignItems: "center"
488
505
  }
489
506
  }));
490
507
  const CardLink = ({ icon: Icon, text, url }) => {
491
- const styles = useStyles$5();
508
+ const styles = useStyles$6();
492
509
  return /* @__PURE__ */ React.createElement("div", { className: styles.linkText }, /* @__PURE__ */ React.createElement(Icon, { fontSize: "small" }), /* @__PURE__ */ React.createElement(Link, { style: { marginLeft: "8px" }, to: url }, text || url));
493
510
  };
494
511
 
495
- const useStyles$4 = makeStyles((theme) => ({
512
+ const useStyles$5 = makeStyles((theme) => ({
496
513
  box: {
497
514
  overflow: "hidden",
498
515
  textOverflow: "ellipsis",
@@ -530,7 +547,7 @@ const useStyles$4 = makeStyles((theme) => ({
530
547
  const TemplateCard = (props) => {
531
548
  var _a, _b, _c, _d, _e, _f, _g;
532
549
  const { template } = props;
533
- const styles = useStyles$4();
550
+ const styles = useStyles$5();
534
551
  const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);
535
552
  const app = useApp();
536
553
  const iconResolver = (key) => {
@@ -551,14 +568,16 @@ const TemplateCard = (props) => {
551
568
  label: tag,
552
569
  key: tag
553
570
  }
554
- )))))), (props.additionalLinks || ((_e = template.metadata.links) == null ? void 0 : _e.length)) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, null)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, (_f = props.additionalLinks) == null ? void 0 : _f.map(({ icon, text, url }) => /* @__PURE__ */ React.createElement(Grid, { className: styles.linkText, item: true, xs: 6 }, /* @__PURE__ */ React.createElement(CardLink, { icon, text, url }))), (_g = template.metadata.links) == null ? void 0 : _g.map(({ url, icon, title }) => /* @__PURE__ */ React.createElement(Grid, { className: styles.linkText, item: true, xs: 6 }, /* @__PURE__ */ React.createElement(
555
- CardLink,
556
- {
557
- icon: iconResolver(icon),
558
- text: title || url,
559
- url
560
- }
561
- )))))))), /* @__PURE__ */ React.createElement(CardActions, { style: { padding: "16px", flex: 1, alignItems: "flex-end" } }, /* @__PURE__ */ React.createElement("div", { className: styles.footer }, /* @__PURE__ */ React.createElement("div", { className: styles.ownedBy }, ownedByRelations.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(UserIcon, { fontSize: "small" }), /* @__PURE__ */ React.createElement(
571
+ )))))), (props.additionalLinks || ((_e = template.metadata.links) == null ? void 0 : _e.length)) && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, null)), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, (_f = props.additionalLinks) == null ? void 0 : _f.map(({ icon, text, url }, index) => /* @__PURE__ */ React.createElement(Grid, { className: styles.linkText, item: true, xs: 6, key: index }, /* @__PURE__ */ React.createElement(CardLink, { icon, text, url }))), (_g = template.metadata.links) == null ? void 0 : _g.map(
572
+ ({ url, icon, title }, index) => /* @__PURE__ */ React.createElement(Grid, { className: styles.linkText, item: true, xs: 6, key: index }, /* @__PURE__ */ React.createElement(
573
+ CardLink,
574
+ {
575
+ icon: iconResolver(icon),
576
+ text: title || url,
577
+ url
578
+ }
579
+ ))
580
+ )))))), /* @__PURE__ */ React.createElement(CardActions, { style: { padding: "16px", flex: 1, alignItems: "flex-end" } }, /* @__PURE__ */ React.createElement("div", { className: styles.footer }, /* @__PURE__ */ React.createElement("div", { className: styles.ownedBy }, ownedByRelations.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(UserIcon, { fontSize: "small" }), /* @__PURE__ */ React.createElement(
562
581
  EntityRefLinks,
563
582
  {
564
583
  style: { marginLeft: "8px" },
@@ -603,6 +622,48 @@ const TemplateGroup = (props) => {
603
622
  ))));
604
623
  };
605
624
 
625
+ const TemplateGroups = (props) => {
626
+ const { loading, error, entities } = useEntityList();
627
+ const { groups, templateFilter, TemplateCardComponent, onTemplateSelected } = props;
628
+ const errorApi = useApi(errorApiRef);
629
+ const onSelected = useCallback(
630
+ (template) => {
631
+ onTemplateSelected == null ? void 0 : onTemplateSelected(template);
632
+ },
633
+ [onTemplateSelected]
634
+ );
635
+ if (loading) {
636
+ return /* @__PURE__ */ React.createElement(Progress, null);
637
+ }
638
+ if (error) {
639
+ errorApi.post(error);
640
+ return null;
641
+ }
642
+ if (!entities || !entities.length) {
643
+ return /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, "No templates found that match your filter. Learn more about", " ", /* @__PURE__ */ React.createElement(Link, { to: "https://backstage.io/docs/features/software-templates/adding-templates" }, "adding templates"), ".");
644
+ }
645
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, groups.map(({ title, filter }, index) => {
646
+ const templates = entities.filter(isTemplateEntityV1beta3).filter((e) => templateFilter ? !templateFilter(e) : true).filter(filter).map((template) => {
647
+ var _a, _b;
648
+ const additionalLinks = (_b = (_a = props.additionalLinksForEntity) == null ? void 0 : _a.call(props, template)) != null ? _b : [];
649
+ return {
650
+ template,
651
+ additionalLinks
652
+ };
653
+ });
654
+ return /* @__PURE__ */ React.createElement(
655
+ TemplateGroup$1,
656
+ {
657
+ key: index,
658
+ templates,
659
+ title,
660
+ components: { CardComponent: TemplateCardComponent },
661
+ onSelected
662
+ }
663
+ );
664
+ }));
665
+ };
666
+
606
667
  const SecretsContext = createVersionedContext("secrets-context");
607
668
  const SecretsContextProvider = (props) => {
608
669
  const [secrets, setSecrets] = useState({});
@@ -615,7 +676,7 @@ const SecretsContextProvider = (props) => {
615
676
  );
616
677
  };
617
678
 
618
- const useStyles$3 = makeStyles(() => ({
679
+ const useStyles$4 = makeStyles(() => ({
619
680
  markdown: {
620
681
  /** to make the styles for React Markdown not leak into the description */
621
682
  "& :first-child": {
@@ -629,7 +690,7 @@ const useStyles$3 = makeStyles(() => ({
629
690
  const Workflow = (workflowProps) => {
630
691
  var _a;
631
692
  const { title, description, namespace, templateName, ...props } = workflowProps;
632
- const styles = useStyles$3();
693
+ const styles = useStyles$4();
633
694
  const templateRef = stringifyEntityRef({
634
695
  kind: "Template",
635
696
  namespace,
@@ -664,7 +725,7 @@ const Workflow = (workflowProps) => {
664
725
  };
665
726
  const EmbeddableWorkflow = (props) => /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(Workflow, { ...props }));
666
727
 
667
- const useStyles$2 = makeStyles({
728
+ const useStyles$3 = makeStyles({
668
729
  root: {
669
730
  "&:hover": {
670
731
  textDecoration: "none"
@@ -673,7 +734,7 @@ const useStyles$2 = makeStyles({
673
734
  });
674
735
  const LinkOutputs = (props) => {
675
736
  const { links = [] } = props.output;
676
- const classes = useStyles$2();
737
+ const classes = useStyles$3();
677
738
  const app = useApp();
678
739
  const entityRoute = useRouteRef(entityRouteRef);
679
740
  const iconResolver = (key) => {
@@ -760,7 +821,7 @@ const StepTime = (props) => {
760
821
  return /* @__PURE__ */ React.createElement(Typography, { variant: "caption" }, time);
761
822
  };
762
823
 
763
- const useStyles$1 = makeStyles((theme) => ({
824
+ const useStyles$2 = makeStyles((theme) => ({
764
825
  failed: {
765
826
  backgroundColor: theme.palette.error.main
766
827
  },
@@ -769,7 +830,7 @@ const useStyles$1 = makeStyles((theme) => ({
769
830
  }
770
831
  }));
771
832
  const TaskBorder = (props) => {
772
- const styles = useStyles$1();
833
+ const styles = useStyles$2();
773
834
  if (!props.isComplete) {
774
835
  return /* @__PURE__ */ React.createElement(LinearProgress, { variant: "indeterminate" });
775
836
  }
@@ -813,16 +874,17 @@ const TaskSteps = (props) => {
813
874
  StepLabel,
814
875
  {
815
876
  StepIconProps: stepIconProps,
816
- StepIconComponent: StepIcon
877
+ StepIconComponent: StepIcon,
878
+ "data-testid": "step-label"
817
879
  },
818
880
  /* @__PURE__ */ React.createElement(Box, null, step.name),
819
- /* @__PURE__ */ React.createElement(StepTime, { step })
881
+ !isSkipped && /* @__PURE__ */ React.createElement(StepTime, { step })
820
882
  )));
821
883
  })
822
884
  )));
823
885
  };
824
886
 
825
- const useStyles = makeStyles$1({
887
+ const useStyles$1 = makeStyles$1({
826
888
  root: {
827
889
  width: "100%",
828
890
  height: "100%",
@@ -830,7 +892,7 @@ const useStyles = makeStyles$1({
830
892
  }
831
893
  });
832
894
  const TaskLogStream = (props) => {
833
- const styles = useStyles();
895
+ const styles = useStyles$1();
834
896
  return /* @__PURE__ */ React.createElement("div", { className: styles.root }, /* @__PURE__ */ React.createElement(
835
897
  LogViewer,
836
898
  {
@@ -839,6 +901,94 @@ const TaskLogStream = (props) => {
839
901
  ));
840
902
  };
841
903
 
904
+ const icon = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
905
+ const checkedIcon = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
906
+ const TemplateCategoryPicker = () => {
907
+ const alertApi = useApi(alertApiRef);
908
+ const { error, loading, availableTypes, selectedTypes, setSelectedTypes } = useEntityTypeFilter();
909
+ if (loading)
910
+ return /* @__PURE__ */ React.createElement(Progress, null);
911
+ if (error) {
912
+ alertApi.post({
913
+ message: `Failed to load entity types with error: ${error}`,
914
+ severity: "error"
915
+ });
916
+ return null;
917
+ }
918
+ if (!availableTypes)
919
+ return null;
920
+ return /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(Typography, { variant: "button" }, "Categories"), /* @__PURE__ */ React.createElement(
921
+ Autocomplete,
922
+ {
923
+ multiple: true,
924
+ "aria-label": "Categories",
925
+ options: availableTypes,
926
+ value: selectedTypes,
927
+ onChange: (_, value) => setSelectedTypes(value),
928
+ renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(
929
+ FormControlLabel,
930
+ {
931
+ control: /* @__PURE__ */ React.createElement(
932
+ Checkbox,
933
+ {
934
+ icon,
935
+ checkedIcon,
936
+ checked: selected
937
+ }
938
+ ),
939
+ label: capitalize(option)
940
+ }
941
+ ),
942
+ size: "small",
943
+ popupIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
944
+ renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, { ...params, variant: "outlined" })
945
+ }
946
+ ));
947
+ };
948
+
949
+ const useStyles = makeStyles$1((theme) => ({
950
+ button: {
951
+ color: theme.page.fontColor
952
+ }
953
+ }));
954
+ function ScaffolderPageContextMenu(props) {
955
+ const { onEditorClicked, onActionsClicked, onTasksClicked } = props;
956
+ const classes = useStyles();
957
+ const [anchorEl, setAnchorEl] = useState();
958
+ if (!onEditorClicked && !onActionsClicked) {
959
+ return null;
960
+ }
961
+ const onOpen = (event) => {
962
+ setAnchorEl(event.currentTarget);
963
+ };
964
+ const onClose = () => {
965
+ setAnchorEl(void 0);
966
+ };
967
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
968
+ IconButton,
969
+ {
970
+ "aria-label": "more",
971
+ "aria-controls": "long-menu",
972
+ "aria-haspopup": "true",
973
+ onClick: onOpen,
974
+ "data-testid": "menu-button",
975
+ color: "inherit",
976
+ className: classes.button
977
+ },
978
+ /* @__PURE__ */ React.createElement(MoreVert, null)
979
+ ), /* @__PURE__ */ React.createElement(
980
+ Popover,
981
+ {
982
+ open: Boolean(anchorEl),
983
+ onClose,
984
+ anchorEl,
985
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
986
+ transformOrigin: { vertical: "top", horizontal: "right" }
987
+ },
988
+ /* @__PURE__ */ React.createElement(MenuList, null, onEditorClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onEditorClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Edit, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Template Editor" })), onActionsClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onActionsClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(Description, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Installed Actions" })), onTasksClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onTasksClicked }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(List, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText, { primary: "Task List" })))
989
+ ));
990
+ }
991
+
842
992
  const FIELD_EXTENSION_KEY = "scaffolder.extensions.field.v1";
843
993
 
844
994
  function createNextScaffolderFieldExtension(options) {
@@ -855,5 +1005,5 @@ function createNextScaffolderFieldExtension(options) {
855
1005
  };
856
1006
  }
857
1007
 
858
- export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, ReviewState, Stepper, TaskLogStream, TaskSteps, TemplateCard, TemplateGroup, Workflow, createFieldValidation, createNextScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
1008
+ export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, ReviewState, ScaffolderPageContextMenu, Stepper, TaskLogStream, TaskSteps, TemplateCard, TemplateCategoryPicker, TemplateGroup, TemplateGroups, Workflow, createFieldValidation, createNextScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
859
1009
  //# sourceMappingURL=alpha.esm.js.map