@backstage/plugin-scaffolder-react 1.2.0 → 1.3.0-next.1

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.3.0-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 1e4f5e91b8e: Bump `zod` and `zod-to-json-schema` dependencies.
8
+ - e0c6e8b9c3c: Update peer dependencies
9
+ - Updated dependencies
10
+ - @backstage/core-components@0.12.6-next.1
11
+ - @backstage/plugin-scaffolder-common@1.2.7-next.1
12
+ - @backstage/core-plugin-api@1.5.1-next.0
13
+ - @backstage/version-bridge@1.0.4-next.0
14
+ - @backstage/plugin-catalog-react@1.4.1-next.1
15
+ - @backstage/theme@0.2.19-next.0
16
+ - @backstage/catalog-client@1.4.0
17
+ - @backstage/catalog-model@1.2.1
18
+ - @backstage/errors@1.1.5
19
+ - @backstage/types@1.0.2
20
+
21
+ ## 1.3.0-next.0
22
+
23
+ ### Minor Changes
24
+
25
+ - 259d3407b9b: Move `CategoryPicker` from `scaffolder` into `scaffolder-react`
26
+ Move `ContextMenu` into `scaffolder-react` and rename it to `ScaffolderPageContextMenu`
27
+ - 2cfd03d7376: To offer better customization options, `ScaffolderPageContextMenu` takes callbacks as props instead of booleans
28
+ - 48da4c46e45: `scaffolder/next`: Export the `TemplateGroupFilter` and `TemplateGroups` and make an extensible component
29
+
30
+ ### Patch Changes
31
+
32
+ - e27ddc36dad: Added a possibility to cancel the running task (executing of a scaffolder template)
33
+ - 7a6b16cc506: `scaffolder/next`: Bump `@rjsf/*` deps to 5.3.1
34
+ - f84fc7fd040: Updated dependency `@rjsf/validator-ajv8` to `5.3.0`.
35
+ - 8e00acb28db: Small tweaks to remove warnings in the console during development (mainly focusing on techdocs)
36
+ - Updated dependencies
37
+ - @backstage/plugin-scaffolder-common@1.2.7-next.0
38
+ - @backstage/core-components@0.12.6-next.0
39
+ - @backstage/plugin-catalog-react@1.4.1-next.0
40
+ - @backstage/core-plugin-api@1.5.0
41
+ - @backstage/catalog-client@1.4.0
42
+ - @backstage/catalog-model@1.2.1
43
+ - @backstage/errors@1.1.5
44
+ - @backstage/theme@0.2.18
45
+ - @backstage/types@1.0.2
46
+ - @backstage/version-bridge@1.0.3
47
+
3
48
  ## 1.2.0
4
49
 
5
50
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-react",
3
- "version": "1.2.0",
3
+ "version": "1.3.0-next.1",
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,16 +1,18 @@
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, 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';
6
6
  import validator from '@rjsf/validator-ajv8';
7
7
  import qs from 'qs';
8
8
  import useAsync from 'react-use/lib/useAsync';
9
- import { getOrCreateGlobalSingleton, createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
9
+ import { s as scaffolderApiRef, S as SecretsContextProvider, a as FIELD_EXTENSION_KEY } from './esm/ref-6fdfc121.esm.js';
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,22 @@ 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';
42
+ import '@backstage/version-bridge';
25
43
 
26
44
  function isObject$1(value) {
27
45
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -281,13 +299,6 @@ const useFormDataFromQuery = (initialState) => {
281
299
  });
282
300
  };
283
301
 
284
- const scaffolderApiRef = getOrCreateGlobalSingleton(
285
- "scaffolder:scaffolder-api-ref",
286
- () => createApiRef({
287
- id: "plugin.scaffolder.service"
288
- })
289
- );
290
-
291
302
  const useTemplateParameterSchema = (templateRef) => {
292
303
  const scaffolderApi = useApi(scaffolderApiRef);
293
304
  const { value, loading, error } = useAsync(
@@ -328,7 +339,7 @@ var FieldOverrides = /*#__PURE__*/Object.freeze({
328
339
 
329
340
  const Form = withTheme(require("@rjsf/material-ui-v5").Theme);
330
341
 
331
- const useStyles$7 = makeStyles((theme) => ({
342
+ const useStyles$8 = makeStyles((theme) => ({
332
343
  backButton: {
333
344
  marginRight: theme.spacing(1)
334
345
  },
@@ -355,7 +366,7 @@ const Stepper = (stepperProps) => {
355
366
  const [activeStep, setActiveStep] = useState(0);
356
367
  const [formState, setFormState] = useFormDataFromQuery(props.initialState);
357
368
  const [errors, setErrors] = useState();
358
- const styles = useStyles$7();
369
+ const styles = useStyles$8();
359
370
  const extensions = useMemo(() => {
360
371
  return Object.fromEntries(
361
372
  props.extensions.map(({ name, component }) => [name, component])
@@ -447,7 +458,7 @@ const Stepper = (stepperProps) => {
447
458
  )))));
448
459
  };
449
460
 
450
- const useStyles$6 = makeStyles(() => ({
461
+ const useStyles$7 = makeStyles(() => ({
451
462
  header: {
452
463
  backgroundImage: ({ cardBackgroundImage }) => cardBackgroundImage,
453
464
  color: ({ cardFontColor }) => cardFontColor
@@ -466,7 +477,7 @@ const CardHeader = (props) => {
466
477
  } = props;
467
478
  const { getPageTheme } = useTheme();
468
479
  const themeForType = getPageTheme({ themeId: type });
469
- const styles = useStyles$6({
480
+ const styles = useStyles$7({
470
481
  cardFontColor: themeForType.fontColor,
471
482
  cardBackgroundImage: themeForType.backgroundImage
472
483
  });
@@ -481,18 +492,18 @@ const CardHeader = (props) => {
481
492
  );
482
493
  };
483
494
 
484
- const useStyles$5 = makeStyles(() => ({
495
+ const useStyles$6 = makeStyles(() => ({
485
496
  linkText: {
486
497
  display: "inline-flex",
487
498
  alignItems: "center"
488
499
  }
489
500
  }));
490
501
  const CardLink = ({ icon: Icon, text, url }) => {
491
- const styles = useStyles$5();
502
+ const styles = useStyles$6();
492
503
  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
504
  };
494
505
 
495
- const useStyles$4 = makeStyles((theme) => ({
506
+ const useStyles$5 = makeStyles((theme) => ({
496
507
  box: {
497
508
  overflow: "hidden",
498
509
  textOverflow: "ellipsis",
@@ -530,7 +541,7 @@ const useStyles$4 = makeStyles((theme) => ({
530
541
  const TemplateCard = (props) => {
531
542
  var _a, _b, _c, _d, _e, _f, _g;
532
543
  const { template } = props;
533
- const styles = useStyles$4();
544
+ const styles = useStyles$5();
534
545
  const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);
535
546
  const app = useApp();
536
547
  const iconResolver = (key) => {
@@ -551,14 +562,16 @@ const TemplateCard = (props) => {
551
562
  label: tag,
552
563
  key: tag
553
564
  }
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(
565
+ )))))), (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(
566
+ ({ url, icon, title }, index) => /* @__PURE__ */ React.createElement(Grid, { className: styles.linkText, item: true, xs: 6, key: index }, /* @__PURE__ */ React.createElement(
567
+ CardLink,
568
+ {
569
+ icon: iconResolver(icon),
570
+ text: title || url,
571
+ url
572
+ }
573
+ ))
574
+ )))))), /* @__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
575
  EntityRefLinks,
563
576
  {
564
577
  style: { marginLeft: "8px" },
@@ -603,19 +616,49 @@ const TemplateGroup = (props) => {
603
616
  ))));
604
617
  };
605
618
 
606
- const SecretsContext = createVersionedContext("secrets-context");
607
- const SecretsContextProvider = (props) => {
608
- const [secrets, setSecrets] = useState({});
609
- return /* @__PURE__ */ React.createElement(
610
- SecretsContext.Provider,
611
- {
612
- value: createVersionedValueMap({ 1: { secrets, setSecrets } })
619
+ const TemplateGroups = (props) => {
620
+ const { loading, error, entities } = useEntityList();
621
+ const { groups, templateFilter, TemplateCardComponent, onTemplateSelected } = props;
622
+ const errorApi = useApi(errorApiRef);
623
+ const onSelected = useCallback(
624
+ (template) => {
625
+ onTemplateSelected == null ? void 0 : onTemplateSelected(template);
613
626
  },
614
- props.children
627
+ [onTemplateSelected]
615
628
  );
629
+ if (loading) {
630
+ return /* @__PURE__ */ React.createElement(Progress, null);
631
+ }
632
+ if (error) {
633
+ errorApi.post(error);
634
+ return null;
635
+ }
636
+ if (!entities || !entities.length) {
637
+ 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"), ".");
638
+ }
639
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, groups.map(({ title, filter }, index) => {
640
+ const templates = entities.filter(isTemplateEntityV1beta3).filter((e) => templateFilter ? !templateFilter(e) : true).filter(filter).map((template) => {
641
+ var _a, _b;
642
+ const additionalLinks = (_b = (_a = props.additionalLinksForEntity) == null ? void 0 : _a.call(props, template)) != null ? _b : [];
643
+ return {
644
+ template,
645
+ additionalLinks
646
+ };
647
+ });
648
+ return /* @__PURE__ */ React.createElement(
649
+ TemplateGroup$1,
650
+ {
651
+ key: index,
652
+ templates,
653
+ title,
654
+ components: { CardComponent: TemplateCardComponent },
655
+ onSelected
656
+ }
657
+ );
658
+ }));
616
659
  };
617
660
 
618
- const useStyles$3 = makeStyles(() => ({
661
+ const useStyles$4 = makeStyles(() => ({
619
662
  markdown: {
620
663
  /** to make the styles for React Markdown not leak into the description */
621
664
  "& :first-child": {
@@ -629,7 +672,7 @@ const useStyles$3 = makeStyles(() => ({
629
672
  const Workflow = (workflowProps) => {
630
673
  var _a;
631
674
  const { title, description, namespace, templateName, ...props } = workflowProps;
632
- const styles = useStyles$3();
675
+ const styles = useStyles$4();
633
676
  const templateRef = stringifyEntityRef({
634
677
  kind: "Template",
635
678
  namespace,
@@ -664,7 +707,7 @@ const Workflow = (workflowProps) => {
664
707
  };
665
708
  const EmbeddableWorkflow = (props) => /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(Workflow, { ...props }));
666
709
 
667
- const useStyles$2 = makeStyles({
710
+ const useStyles$3 = makeStyles({
668
711
  root: {
669
712
  "&:hover": {
670
713
  textDecoration: "none"
@@ -673,7 +716,7 @@ const useStyles$2 = makeStyles({
673
716
  });
674
717
  const LinkOutputs = (props) => {
675
718
  const { links = [] } = props.output;
676
- const classes = useStyles$2();
719
+ const classes = useStyles$3();
677
720
  const app = useApp();
678
721
  const entityRoute = useRouteRef(entityRouteRef);
679
722
  const iconResolver = (key) => {
@@ -760,7 +803,7 @@ const StepTime = (props) => {
760
803
  return /* @__PURE__ */ React.createElement(Typography, { variant: "caption" }, time);
761
804
  };
762
805
 
763
- const useStyles$1 = makeStyles((theme) => ({
806
+ const useStyles$2 = makeStyles((theme) => ({
764
807
  failed: {
765
808
  backgroundColor: theme.palette.error.main
766
809
  },
@@ -769,7 +812,7 @@ const useStyles$1 = makeStyles((theme) => ({
769
812
  }
770
813
  }));
771
814
  const TaskBorder = (props) => {
772
- const styles = useStyles$1();
815
+ const styles = useStyles$2();
773
816
  if (!props.isComplete) {
774
817
  return /* @__PURE__ */ React.createElement(LinearProgress, { variant: "indeterminate" });
775
818
  }
@@ -823,7 +866,7 @@ const TaskSteps = (props) => {
823
866
  )));
824
867
  };
825
868
 
826
- const useStyles = makeStyles$1({
869
+ const useStyles$1 = makeStyles$1({
827
870
  root: {
828
871
  width: "100%",
829
872
  height: "100%",
@@ -831,7 +874,7 @@ const useStyles = makeStyles$1({
831
874
  }
832
875
  });
833
876
  const TaskLogStream = (props) => {
834
- const styles = useStyles();
877
+ const styles = useStyles$1();
835
878
  return /* @__PURE__ */ React.createElement("div", { className: styles.root }, /* @__PURE__ */ React.createElement(
836
879
  LogViewer,
837
880
  {
@@ -840,7 +883,93 @@ const TaskLogStream = (props) => {
840
883
  ));
841
884
  };
842
885
 
843
- const FIELD_EXTENSION_KEY = "scaffolder.extensions.field.v1";
886
+ const icon = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
887
+ const checkedIcon = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
888
+ const TemplateCategoryPicker = () => {
889
+ const alertApi = useApi(alertApiRef);
890
+ const { error, loading, availableTypes, selectedTypes, setSelectedTypes } = useEntityTypeFilter();
891
+ if (loading)
892
+ return /* @__PURE__ */ React.createElement(Progress, null);
893
+ if (error) {
894
+ alertApi.post({
895
+ message: `Failed to load entity types with error: ${error}`,
896
+ severity: "error"
897
+ });
898
+ return null;
899
+ }
900
+ if (!availableTypes)
901
+ return null;
902
+ return /* @__PURE__ */ React.createElement(Box, { pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(Typography, { variant: "button" }, "Categories"), /* @__PURE__ */ React.createElement(
903
+ Autocomplete,
904
+ {
905
+ multiple: true,
906
+ "aria-label": "Categories",
907
+ options: availableTypes,
908
+ value: selectedTypes,
909
+ onChange: (_, value) => setSelectedTypes(value),
910
+ renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(
911
+ FormControlLabel,
912
+ {
913
+ control: /* @__PURE__ */ React.createElement(
914
+ Checkbox,
915
+ {
916
+ icon,
917
+ checkedIcon,
918
+ checked: selected
919
+ }
920
+ ),
921
+ label: capitalize(option)
922
+ }
923
+ ),
924
+ size: "small",
925
+ popupIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
926
+ renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, { ...params, variant: "outlined" })
927
+ }
928
+ ));
929
+ };
930
+
931
+ const useStyles = makeStyles$1((theme) => ({
932
+ button: {
933
+ color: theme.page.fontColor
934
+ }
935
+ }));
936
+ function ScaffolderPageContextMenu(props) {
937
+ const { onEditorClicked, onActionsClicked, onTasksClicked } = props;
938
+ const classes = useStyles();
939
+ const [anchorEl, setAnchorEl] = useState();
940
+ if (!onEditorClicked && !onActionsClicked) {
941
+ return null;
942
+ }
943
+ const onOpen = (event) => {
944
+ setAnchorEl(event.currentTarget);
945
+ };
946
+ const onClose = () => {
947
+ setAnchorEl(void 0);
948
+ };
949
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
950
+ IconButton,
951
+ {
952
+ "aria-label": "more",
953
+ "aria-controls": "long-menu",
954
+ "aria-haspopup": "true",
955
+ onClick: onOpen,
956
+ "data-testid": "menu-button",
957
+ color: "inherit",
958
+ className: classes.button
959
+ },
960
+ /* @__PURE__ */ React.createElement(MoreVert, null)
961
+ ), /* @__PURE__ */ React.createElement(
962
+ Popover,
963
+ {
964
+ open: Boolean(anchorEl),
965
+ onClose,
966
+ anchorEl,
967
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
968
+ transformOrigin: { vertical: "top", horizontal: "right" }
969
+ },
970
+ /* @__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" })))
971
+ ));
972
+ }
844
973
 
845
974
  function createNextScaffolderFieldExtension(options) {
846
975
  return {
@@ -856,5 +985,5 @@ function createNextScaffolderFieldExtension(options) {
856
985
  };
857
986
  }
858
987
 
859
- export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, ReviewState, Stepper, TaskLogStream, TaskSteps, TemplateCard, TemplateGroup, Workflow, createFieldValidation, createNextScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
988
+ export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, ReviewState, ScaffolderPageContextMenu, Stepper, TaskLogStream, TaskSteps, TemplateCard, TemplateCategoryPicker, TemplateGroup, TemplateGroups, Workflow, createFieldValidation, createNextScaffolderFieldExtension, extractSchemaFromStep, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
860
989
  //# sourceMappingURL=alpha.esm.js.map