@backstage/plugin-scaffolder-react 1.8.4-next.1 → 1.8.5-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.
Files changed (94) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/alpha/package.json +1 -1
  3. package/dist/alpha.esm.js +19 -1451
  4. package/dist/alpha.esm.js.map +1 -1
  5. package/dist/api/ref.esm.js +12 -0
  6. package/dist/api/ref.esm.js.map +1 -0
  7. package/dist/extensions/index.esm.js +25 -0
  8. package/dist/extensions/index.esm.js.map +1 -0
  9. package/dist/extensions/keys.esm.js +5 -0
  10. package/dist/extensions/keys.esm.js.map +1 -0
  11. package/dist/hooks/useCustomFieldExtensions.esm.js +16 -0
  12. package/dist/hooks/useCustomFieldExtensions.esm.js.map +1 -0
  13. package/dist/hooks/useCustomLayouts.esm.js +16 -0
  14. package/dist/hooks/useCustomLayouts.esm.js.map +1 -0
  15. package/dist/hooks/useEventStream.esm.js +167 -0
  16. package/dist/hooks/useEventStream.esm.js.map +1 -0
  17. package/dist/index.esm.js +7 -228
  18. package/dist/index.esm.js.map +1 -1
  19. package/dist/layouts/createScaffolderLayout.esm.js +17 -0
  20. package/dist/layouts/createScaffolderLayout.esm.js.map +1 -0
  21. package/dist/layouts/keys.esm.js +5 -0
  22. package/dist/layouts/keys.esm.js.map +1 -0
  23. package/dist/next/components/Form/DescriptionFieldTemplate.esm.js +37 -0
  24. package/dist/next/components/Form/DescriptionFieldTemplate.esm.js.map +1 -0
  25. package/dist/next/components/Form/FieldTemplate.esm.js +65 -0
  26. package/dist/next/components/Form/FieldTemplate.esm.js.map +1 -0
  27. package/dist/next/components/Form/Form.esm.js +44 -0
  28. package/dist/next/components/Form/Form.esm.js.map +1 -0
  29. package/dist/next/components/ReviewState/ReviewState.esm.js +43 -0
  30. package/dist/next/components/ReviewState/ReviewState.esm.js.map +1 -0
  31. package/dist/next/components/ScaffolderField/ScaffolderField.esm.js +52 -0
  32. package/dist/next/components/ScaffolderField/ScaffolderField.esm.js.map +1 -0
  33. package/dist/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.esm.js +63 -0
  34. package/dist/next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.esm.js.map +1 -0
  35. package/dist/next/components/Stepper/ErrorListTemplate/errorListTemplate.esm.js +32 -0
  36. package/dist/next/components/Stepper/ErrorListTemplate/errorListTemplate.esm.js.map +1 -0
  37. package/dist/next/components/Stepper/FieldOverrides/DescriptionField.esm.js +7 -0
  38. package/dist/next/components/Stepper/FieldOverrides/DescriptionField.esm.js.map +1 -0
  39. package/dist/next/components/Stepper/FieldOverrides/index.esm.js +2 -0
  40. package/dist/next/components/Stepper/FieldOverrides/index.esm.js.map +1 -0
  41. package/dist/next/components/Stepper/Stepper.esm.js +203 -0
  42. package/dist/next/components/Stepper/Stepper.esm.js.map +1 -0
  43. package/dist/next/components/Stepper/createAsyncValidators.esm.js +80 -0
  44. package/dist/next/components/Stepper/createAsyncValidators.esm.js.map +1 -0
  45. package/dist/next/components/Stepper/utils.esm.js +27 -0
  46. package/dist/next/components/Stepper/utils.esm.js.map +1 -0
  47. package/dist/next/components/TaskLogStream/TaskLogStream.esm.js +23 -0
  48. package/dist/next/components/TaskLogStream/TaskLogStream.esm.js.map +1 -0
  49. package/dist/next/components/TaskSteps/StepIcon.esm.js +52 -0
  50. package/dist/next/components/TaskSteps/StepIcon.esm.js.map +1 -0
  51. package/dist/next/components/TaskSteps/StepTime.esm.js +36 -0
  52. package/dist/next/components/TaskSteps/StepTime.esm.js.map +1 -0
  53. package/dist/next/components/TaskSteps/TaskBorder.esm.js +29 -0
  54. package/dist/next/components/TaskSteps/TaskBorder.esm.js.map +1 -0
  55. package/dist/next/components/TaskSteps/TaskSteps.esm.js +54 -0
  56. package/dist/next/components/TaskSteps/TaskSteps.esm.js.map +1 -0
  57. package/dist/next/components/TemplateCard/CardHeader.esm.js +41 -0
  58. package/dist/next/components/TemplateCard/CardHeader.esm.js.map +1 -0
  59. package/dist/next/components/TemplateCard/CardLink.esm.js +17 -0
  60. package/dist/next/components/TemplateCard/CardLink.esm.js.map +1 -0
  61. package/dist/next/components/TemplateCard/TemplateCard.esm.js +114 -0
  62. package/dist/next/components/TemplateCard/TemplateCard.esm.js.map +1 -0
  63. package/dist/next/components/TemplateCategoryPicker/TemplateCategoryPicker.esm.js +80 -0
  64. package/dist/next/components/TemplateCategoryPicker/TemplateCategoryPicker.esm.js.map +1 -0
  65. package/dist/next/components/TemplateGroup/TemplateGroup.esm.js +30 -0
  66. package/dist/next/components/TemplateGroup/TemplateGroup.esm.js.map +1 -0
  67. package/dist/next/components/TemplateGroups/TemplateGroups.esm.js +52 -0
  68. package/dist/next/components/TemplateGroups/TemplateGroups.esm.js.map +1 -0
  69. package/dist/next/components/TemplateOutputs/DefaultTemplateOutputs.esm.js +51 -0
  70. package/dist/next/components/TemplateOutputs/DefaultTemplateOutputs.esm.js.map +1 -0
  71. package/dist/next/components/TemplateOutputs/LinkOutputs.esm.js +40 -0
  72. package/dist/next/components/TemplateOutputs/LinkOutputs.esm.js.map +1 -0
  73. package/dist/next/components/TemplateOutputs/TextOutputs.esm.js +39 -0
  74. package/dist/next/components/TemplateOutputs/TextOutputs.esm.js.map +1 -0
  75. package/dist/next/components/Workflow/Workflow.esm.js +83 -0
  76. package/dist/next/components/Workflow/Workflow.esm.js.map +1 -0
  77. package/dist/next/hooks/useFilteredSchemaProperties.esm.js +44 -0
  78. package/dist/next/hooks/useFilteredSchemaProperties.esm.js.map +1 -0
  79. package/dist/next/hooks/useFormDataFromQuery.esm.js +21 -0
  80. package/dist/next/hooks/useFormDataFromQuery.esm.js.map +1 -0
  81. package/dist/next/hooks/useTemplateParameterSchema.esm.js +19 -0
  82. package/dist/next/hooks/useTemplateParameterSchema.esm.js.map +1 -0
  83. package/dist/next/hooks/useTemplateSchema.esm.js +46 -0
  84. package/dist/next/hooks/useTemplateSchema.esm.js.map +1 -0
  85. package/dist/next/hooks/useTemplateTimeSaved.esm.js +25 -0
  86. package/dist/next/hooks/useTemplateTimeSaved.esm.js.map +1 -0
  87. package/dist/next/hooks/useTransformSchemaToProps.esm.js +24 -0
  88. package/dist/next/hooks/useTransformSchemaToProps.esm.js.map +1 -0
  89. package/dist/next/lib/schema.esm.js +108 -0
  90. package/dist/next/lib/schema.esm.js.map +1 -0
  91. package/dist/{esm/ref-NRtFlQHB.esm.js → secrets/SecretsContext.esm.js} +3 -11
  92. package/dist/secrets/SecretsContext.esm.js.map +1 -0
  93. package/package.json +20 -20
  94. package/dist/esm/ref-NRtFlQHB.esm.js.map +0 -1
package/dist/alpha.esm.js CHANGED
@@ -1,1452 +1,20 @@
1
- import { useApi, featureFlagsApiRef, useAnalytics, useApiHolder, useApp, errorApiRef, useRouteRef, alertApiRef } from '@backstage/core-plugin-api';
2
- import { makeStyles, FormControl, Typography, createStyles, Paper, List, ListItem, ListItemIcon, ListItemText, LinearProgress, Stepper as Stepper$1, Step, StepLabel, Button, useTheme, Card, CardContent, Grid, Box, Divider, Chip, CardActions, CircularProgress, StepButton, FormControlLabel, Checkbox, TextField } from '@material-ui/core';
3
- import React, { useState, useMemo, useCallback, useEffect } from 'react';
4
- import { Draft07 } from 'json-schema-library';
5
- import { parse, stringify } from 'flatted';
6
- import { StructuredMetadataTable, MarkdownContent, ItemCardHeader, Link, UserIcon, Content, ItemCardGrid, ContentHeader, Progress, InfoCard, LogViewer } from '@backstage/core-components';
7
- import validator from '@rjsf/validator-ajv8';
8
- import qs from 'qs';
9
- import useAsync from 'react-use/esm/useAsync';
10
- import { s as scaffolderApiRef, S as SecretsContextProvider } from './esm/ref-NRtFlQHB.esm.js';
11
- import cloneDeep from 'lodash/cloneDeep';
12
- import { withTheme } from '@rjsf/core';
13
- import { getUiOptions, getTemplate } from '@rjsf/utils';
14
- import { Theme } from '@rjsf/material-ui';
15
- import ErrorIcon from '@material-ui/icons/Error';
16
- import { RELATION_OWNED_BY, stringifyEntityRef, parseEntityRef } from '@backstage/catalog-model';
17
- import { FavoriteEntity, getEntityRelations, EntityRefLinks, useEntityList, catalogApiRef, entityRouteRef, useEntityTypeFilter } from '@backstage/plugin-catalog-react';
18
- import LanguageIcon from '@material-ui/icons/Language';
19
- import { isTemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
20
- import { Duration, DateTime, Interval } from 'luxon';
21
- import useAsync$1 from 'react-use/lib/useAsync';
22
- import LinkIcon from '@material-ui/icons/Link';
23
- import DescriptionIcon from '@material-ui/icons/Description';
24
- import RemoveCircleOutline from '@material-ui/icons/RemoveCircleOutline';
25
- import PanoramaFishEyeIcon from '@material-ui/icons/PanoramaFishEye';
26
- import classNames from 'classnames';
27
- import CheckCircleOutline from '@material-ui/icons/CheckCircleOutline';
28
- import ErrorOutline from '@material-ui/icons/ErrorOutline';
29
- import useInterval from 'react-use/esm/useInterval';
30
- import humanizeDuration from 'humanize-duration';
31
- import { useMountEffect } from '@react-hookz/web';
32
- import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
33
- import capitalize from 'lodash/capitalize';
34
- import CheckBoxIcon from '@material-ui/icons/CheckBox';
35
- import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
36
- import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
37
- import { Autocomplete } from '@material-ui/lab';
38
- import IconButton from '@material-ui/core/IconButton';
39
- import ListItemIcon$1 from '@material-ui/core/ListItemIcon';
40
- import ListItemText$1 from '@material-ui/core/ListItemText';
41
- import MenuItem from '@material-ui/core/MenuItem';
42
- import MenuList from '@material-ui/core/MenuList';
43
- import Popover from '@material-ui/core/Popover';
44
- import CreateComponentIcon from '@material-ui/icons/AddCircleOutline';
45
- import Edit from '@material-ui/icons/Edit';
46
- import List$1 from '@material-ui/icons/List';
47
- import MoreVert from '@material-ui/icons/MoreVert';
48
- import '@backstage/version-bridge';
49
-
50
- function isObject$1(value) {
51
- return typeof value === "object" && value !== null && !Array.isArray(value);
52
- }
53
- function extractUiSchema(schema, uiSchema) {
54
- if (!isObject$1(schema)) {
55
- return;
56
- }
57
- const {
58
- properties,
59
- items,
60
- anyOf,
61
- oneOf,
62
- allOf,
63
- dependencies,
64
- then,
65
- else: _else
66
- } = schema;
67
- for (const propName in schema) {
68
- if (!schema.hasOwnProperty(propName)) {
69
- continue;
70
- }
71
- if (propName.startsWith("ui:")) {
72
- uiSchema[propName] = schema[propName];
73
- delete schema[propName];
74
- }
75
- }
76
- if (isObject$1(properties)) {
77
- for (const propName in properties) {
78
- if (!properties.hasOwnProperty(propName)) {
79
- continue;
80
- }
81
- const schemaNode = properties[propName];
82
- if (!isObject$1(schemaNode)) {
83
- continue;
84
- }
85
- if (!isObject$1(uiSchema[propName])) {
86
- const innerUiSchema = {};
87
- uiSchema[propName] = innerUiSchema;
88
- }
89
- extractUiSchema(schemaNode, uiSchema[propName]);
90
- }
91
- }
92
- if (isObject$1(items)) {
93
- const innerUiSchema = {};
94
- uiSchema.items = innerUiSchema;
95
- extractUiSchema(items, innerUiSchema);
96
- }
97
- if (Array.isArray(anyOf)) {
98
- for (const schemaNode of anyOf) {
99
- if (!isObject$1(schemaNode)) {
100
- continue;
101
- }
102
- extractUiSchema(schemaNode, uiSchema);
103
- }
104
- }
105
- if (Array.isArray(oneOf)) {
106
- for (const schemaNode of oneOf) {
107
- if (!isObject$1(schemaNode)) {
108
- continue;
109
- }
110
- extractUiSchema(schemaNode, uiSchema);
111
- }
112
- }
113
- if (Array.isArray(allOf)) {
114
- for (const schemaNode of allOf) {
115
- if (!isObject$1(schemaNode)) {
116
- continue;
117
- }
118
- extractUiSchema(schemaNode, uiSchema);
119
- }
120
- }
121
- if (isObject$1(dependencies)) {
122
- for (const depName of Object.keys(dependencies)) {
123
- const schemaNode = dependencies[depName];
124
- if (!isObject$1(schemaNode)) {
125
- continue;
126
- }
127
- extractUiSchema(schemaNode, uiSchema);
128
- }
129
- }
130
- if (isObject$1(then)) {
131
- extractUiSchema(then, uiSchema);
132
- }
133
- if (isObject$1(_else)) {
134
- extractUiSchema(_else, uiSchema);
135
- }
136
- }
137
- const extractSchemaFromStep = (inputStep) => {
138
- const uiSchema = {};
139
- const returnSchema = parse(stringify(inputStep));
140
- extractUiSchema(returnSchema, uiSchema);
141
- return { uiSchema, schema: returnSchema };
142
- };
143
- const createFieldValidation = () => {
144
- const fieldValidation = {
145
- __errors: [],
146
- addError: (message) => {
147
- var _a;
148
- (_a = fieldValidation.__errors) == null ? void 0 : _a.push(message);
149
- }
150
- };
151
- return fieldValidation;
152
- };
153
-
154
- function isFieldValidation(error) {
155
- return !!error && "__errors" in error;
156
- }
157
- function hasErrors(errors) {
158
- var _a;
159
- if (!errors) {
160
- return false;
161
- }
162
- for (const error of Object.values(errors)) {
163
- if (isFieldValidation(error)) {
164
- if (((_a = error.__errors) != null ? _a : []).length > 0) {
165
- return true;
166
- }
167
- continue;
168
- }
169
- if (hasErrors(error)) {
170
- return true;
171
- }
172
- }
173
- return false;
174
- }
175
- function isObject(value) {
176
- return typeof value === "object" && value !== null && !Array.isArray(value);
177
- }
178
-
179
- const isJsonError = (value) => "type" in value && value.type === "error";
180
- const createAsyncValidators = (rootSchema, validators, context) => {
181
- async function validate(formData, pathPrefix = "#", current = formData) {
182
- var _a, _b;
183
- const parsedSchema = new Draft07(rootSchema);
184
- const formValidation = {};
185
- const validateForm = async (validatorName, key, value, schema, uiSchema) => {
186
- const validator = validators[validatorName];
187
- if (validator) {
188
- const fieldValidation = createFieldValidation();
189
- try {
190
- await validator(value, fieldValidation, {
191
- ...context,
192
- formData,
193
- schema,
194
- uiSchema
195
- });
196
- } catch (ex) {
197
- fieldValidation.addError(ex.message);
198
- }
199
- formValidation[key] = fieldValidation;
200
- }
201
- };
202
- for (const [key, value] of Object.entries(current)) {
203
- const pointer = `${pathPrefix}/${key}`;
204
- const definitionInSchema = parsedSchema.getSchema({
205
- pointer,
206
- data: formData
207
- });
208
- if (!definitionInSchema) {
209
- continue;
210
- }
211
- if (isJsonError(definitionInSchema)) {
212
- throw new Error(definitionInSchema.message);
213
- }
214
- const { schema, uiSchema } = extractSchemaFromStep(
215
- definitionInSchema
216
- );
217
- const hasItems = definitionInSchema && definitionInSchema.items;
218
- const doValidateItem = async (propValue, itemSchema, itemUiSchema) => {
219
- await validateForm(
220
- propValue["ui:field"],
221
- key,
222
- value,
223
- itemSchema,
224
- itemUiSchema
225
- );
226
- };
227
- const doValidate = async (propValue) => {
228
- if ("ui:field" in propValue) {
229
- const { schema: itemsSchema, uiSchema: itemsUiSchema } = extractSchemaFromStep(definitionInSchema.items);
230
- await doValidateItem(propValue, itemsSchema, itemsUiSchema);
231
- }
232
- };
233
- if ("ui:field" in definitionInSchema) {
234
- await doValidateItem(definitionInSchema, schema, uiSchema);
235
- } else if (hasItems && "ui:field" in definitionInSchema.items) {
236
- await doValidate(definitionInSchema.items);
237
- } else if (hasItems && definitionInSchema.items.type === "object") {
238
- const properties = (_b = (_a = definitionInSchema.items) == null ? void 0 : _a.properties) != null ? _b : [];
239
- for (const [, propValue] of Object.entries(properties)) {
240
- await doValidate(propValue);
241
- }
242
- } else if (isObject(value)) {
243
- formValidation[key] = await validate(formData, pointer, value);
244
- }
245
- }
246
- return formValidation;
247
- }
248
- return async (formData) => {
249
- return await validate(formData);
250
- };
251
- };
252
-
253
- const ReviewState = (props) => {
254
- const reviewData = Object.fromEntries(
255
- Object.entries(props.formState).map(([key, value]) => {
256
- var _a;
257
- for (const step of props.schemas) {
258
- const parsedSchema = new Draft07(step.mergedSchema);
259
- const definitionInSchema = parsedSchema.getSchema({
260
- pointer: `#/${key}`,
261
- data: props.formState
262
- });
263
- if (definitionInSchema) {
264
- const backstageReviewOptions = (_a = definitionInSchema["ui:backstage"]) == null ? void 0 : _a.review;
265
- if (backstageReviewOptions) {
266
- if (backstageReviewOptions.mask) {
267
- return [key, backstageReviewOptions.mask];
268
- }
269
- if (backstageReviewOptions.show === false) {
270
- return [];
271
- }
272
- }
273
- if (definitionInSchema["ui:widget"] === "password") {
274
- return [key, "******"];
275
- }
276
- if (definitionInSchema.enum && definitionInSchema.enumNames) {
277
- return [
278
- key,
279
- definitionInSchema.enumNames[definitionInSchema.enum.indexOf(value)] || value
280
- ];
281
- }
282
- }
283
- }
284
- return [key, value];
285
- }).filter((prop) => prop.length > 0)
286
- );
287
- return /* @__PURE__ */ React.createElement(StructuredMetadataTable, { metadata: reviewData });
288
- };
289
-
290
- const useTemplateSchema = (manifest) => {
291
- const featureFlags = useApi(featureFlagsApiRef);
292
- const steps = manifest.steps.map(({ title, description, schema }) => ({
293
- title,
294
- description,
295
- mergedSchema: schema,
296
- ...extractSchemaFromStep(schema)
297
- }));
298
- const returningSteps = steps.filter((step) => {
299
- var _a;
300
- const stepFeatureFlag = (_a = step.uiSchema["ui:backstage"]) == null ? void 0 : _a.featureFlag;
301
- return stepFeatureFlag ? featureFlags.isActive(stepFeatureFlag) : true;
302
- }).map((step) => {
303
- var _a, _b, _c, _d;
304
- const strippedSchema = {
305
- ...step,
306
- schema: {
307
- ...step.schema,
308
- // Title is rendered at the top of the page, so let's ignore this from jsonschemaform
309
- title: void 0
310
- }
311
- };
312
- if (((_a = step.schema) == null ? void 0 : _a.properties) || !((_b = step.schema) == null ? void 0 : _b.dependencies)) {
313
- strippedSchema.schema.properties = Object.fromEntries(
314
- Object.entries((_d = (_c = step.schema) == null ? void 0 : _c.properties) != null ? _d : {}).filter(
315
- ([key]) => {
316
- var _a2, _b2;
317
- const stepFeatureFlag = (_b2 = (_a2 = step.uiSchema[key]) == null ? void 0 : _a2["ui:backstage"]) == null ? void 0 : _b2.featureFlag;
318
- return stepFeatureFlag ? featureFlags.isActive(stepFeatureFlag) : true;
319
- }
320
- )
321
- );
322
- }
323
- return strippedSchema;
324
- });
325
- return {
326
- presentation: manifest.presentation,
327
- steps: returningSteps
328
- };
329
- };
330
-
331
- const useFormDataFromQuery = (initialState) => {
332
- return useState(() => {
333
- if (initialState) {
334
- return initialState;
335
- }
336
- const query = qs.parse(window.location.search, {
337
- ignoreQueryPrefix: true
338
- });
339
- try {
340
- return JSON.parse(query.formData);
341
- } catch (e) {
342
- return {};
343
- }
344
- });
345
- };
346
-
347
- const useTemplateParameterSchema = (templateRef) => {
348
- const scaffolderApi = useApi(scaffolderApiRef);
349
- const { value, loading, error } = useAsync(
350
- () => scaffolderApi.getTemplateParameterSchema(templateRef),
351
- [scaffolderApi, templateRef]
352
- );
353
- return {
354
- manifest: value,
355
- loading,
356
- error
357
- };
358
- };
359
-
360
- const useFilteredSchemaProperties = (manifest) => {
361
- const featureFlagKey = "backstage:featureFlag";
362
- const featureFlagApi = useApi(featureFlagsApiRef);
363
- if (!manifest) {
364
- return void 0;
365
- }
366
- const filteredSteps = manifest == null ? void 0 : manifest.steps.filter((step) => {
367
- const featureFlag = step.schema[featureFlagKey];
368
- return typeof featureFlag !== "string" || featureFlagApi.isActive(featureFlag);
369
- }).map((step) => {
370
- var _a;
371
- const filteredStep = cloneDeep(step);
372
- const removedPropertyKeys = [];
373
- if (filteredStep.schema.properties) {
374
- filteredStep.schema.properties = Object.fromEntries(
375
- Object.entries(filteredStep.schema.properties).filter(
376
- ([key, value]) => {
377
- if (value[featureFlagKey]) {
378
- if (featureFlagApi.isActive(value[featureFlagKey])) {
379
- return true;
380
- }
381
- removedPropertyKeys.push(key);
382
- return false;
383
- }
384
- return true;
385
- }
386
- )
387
- );
388
- filteredStep.schema.required = Array.isArray(
389
- filteredStep.schema.required
390
- ) ? (_a = filteredStep.schema.required) == null ? void 0 : _a.filter(
391
- (r) => !removedPropertyKeys.includes(r)
392
- ) : filteredStep.schema.required;
393
- }
394
- return filteredStep;
395
- });
396
- return { ...manifest, steps: filteredSteps };
397
- };
398
-
399
- const useTransformSchemaToProps = (step, options = {}) => {
400
- var _a;
401
- const { layouts = [] } = options;
402
- const objectFieldTemplate = step == null ? void 0 : step.uiSchema["ui:ObjectFieldTemplate"];
403
- if (typeof objectFieldTemplate !== "string") {
404
- return step;
405
- }
406
- const Layout = (_a = layouts.find(
407
- (layout) => layout.name === objectFieldTemplate
408
- )) == null ? void 0 : _a.component;
409
- if (!Layout) {
410
- return step;
411
- }
412
- return {
413
- ...step,
414
- uiSchema: {
415
- ...step.uiSchema,
416
- ["ui:ObjectFieldTemplate"]: Layout
417
- }
418
- };
419
- };
420
-
421
- const DescriptionField = ({ description }) => description && /* @__PURE__ */ React.createElement(MarkdownContent, { content: description, linkTarget: "_blank" });
422
-
423
- var FieldOverrides = /*#__PURE__*/Object.freeze({
424
- __proto__: null,
425
- DescriptionField: DescriptionField
426
- });
427
-
428
- const useStyles$c = makeStyles((theme) => ({
429
- markdownDescription: {
430
- fontSize: theme.typography.caption.fontSize,
431
- margin: 0,
432
- color: theme.palette.text.secondary,
433
- "& :first-child": {
434
- margin: 0,
435
- marginTop: "3px"
436
- // to keep the standard browser padding
437
- }
438
- }
439
- }));
440
- const ScaffolderField = (props) => {
441
- const {
442
- children,
443
- displayLabel = true,
444
- rawErrors = [],
445
- errors,
446
- help,
447
- rawDescription,
448
- required,
449
- disabled
450
- } = props;
451
- const classes = useStyles$c();
452
- return /* @__PURE__ */ React.createElement(
453
- FormControl,
454
- {
455
- fullWidth: true,
456
- error: rawErrors.length ? true : false,
457
- required,
458
- disabled
459
- },
460
- children,
461
- displayLabel && rawDescription ? /* @__PURE__ */ React.createElement(
462
- MarkdownContent,
463
- {
464
- content: rawDescription,
465
- className: classes.markdownDescription
466
- }
467
- ) : null,
468
- errors,
469
- help
470
- );
471
- };
472
-
473
- const FieldTemplate = (props) => {
474
- const {
475
- id,
476
- children,
477
- classNames,
478
- style,
479
- disabled,
480
- displayLabel,
481
- hidden,
482
- label,
483
- onDropPropertyClick,
484
- onKeyChange,
485
- readonly,
486
- required,
487
- rawErrors = [],
488
- errors,
489
- help,
490
- rawDescription,
491
- schema,
492
- uiSchema,
493
- registry
494
- } = props;
495
- const uiOptions = getUiOptions(uiSchema);
496
- const WrapIfAdditionalTemplate = getTemplate("WrapIfAdditionalTemplate", registry, uiOptions);
497
- if (hidden) {
498
- return /* @__PURE__ */ React.createElement("div", { style: { display: "none" } }, children);
499
- }
500
- return /* @__PURE__ */ React.createElement(
501
- WrapIfAdditionalTemplate,
502
- {
503
- classNames,
504
- style,
505
- disabled,
506
- id,
507
- label,
508
- onDropPropertyClick,
509
- onKeyChange,
510
- readonly,
511
- required,
512
- schema,
513
- uiSchema,
514
- registry
515
- },
516
- /* @__PURE__ */ React.createElement(
517
- ScaffolderField,
518
- {
519
- displayLabel,
520
- rawErrors,
521
- help,
522
- disabled,
523
- rawDescription,
524
- errors,
525
- required
526
- },
527
- children
528
- )
529
- );
530
- };
531
-
532
- const useStyles$b = makeStyles((theme) => ({
533
- markdownDescription: {
534
- fontSize: theme.typography.caption.fontSize,
535
- margin: 0,
536
- color: theme.palette.text.secondary,
537
- "& :first-child": {
538
- margin: 0,
539
- marginTop: "3px"
540
- // to keep the standard browser padding
541
- }
542
- }
543
- }));
544
- const DescriptionFieldTemplate = (props) => {
545
- const { id, description } = props;
546
- const classes = useStyles$b();
547
- if (description) {
548
- if (typeof description === "string") {
549
- return /* @__PURE__ */ React.createElement(
550
- MarkdownContent,
551
- {
552
- content: description,
553
- className: classes.markdownDescription
554
- }
555
- );
556
- }
557
- return /* @__PURE__ */ React.createElement(Typography, { id, variant: "subtitle2", style: { marginTop: "5px" } }, description);
558
- }
559
- return null;
560
- };
561
-
562
- const WrappedForm = withTheme(Theme);
563
- const Form = (props) => {
564
- const wrappedFields = React.useMemo(
565
- () => {
566
- var _a;
567
- return Object.fromEntries(
568
- Object.entries((_a = props.fields) != null ? _a : {}).map(([key, Component]) => [
569
- key,
570
- (wrapperProps) => {
571
- var _a2, _b;
572
- return /* @__PURE__ */ React.createElement(
573
- Component,
574
- {
575
- ...wrapperProps,
576
- uiSchema: (_a2 = wrapperProps.uiSchema) != null ? _a2 : {},
577
- formData: wrapperProps.formData,
578
- rawErrors: (_b = wrapperProps.rawErrors) != null ? _b : []
579
- }
580
- );
581
- }
582
- ])
583
- );
584
- },
585
- [props.fields]
586
- );
587
- const templates = React.useMemo(
588
- () => ({
589
- FieldTemplate,
590
- DescriptionFieldTemplate,
591
- ...props.templates
592
- }),
593
- [props.templates]
594
- );
595
- return /* @__PURE__ */ React.createElement(WrappedForm, { ...props, templates, fields: wrappedFields });
596
- };
597
-
598
- const useStyles$a = makeStyles(
599
- (_theme) => createStyles({
600
- list: {
601
- width: "100%"
602
- },
603
- text: {
604
- textWrap: "wrap"
605
- }
606
- })
607
- );
608
- const ErrorListTemplate = ({ errors }) => {
609
- const classes = useStyles$a();
610
- return /* @__PURE__ */ React.createElement(Paper, null, /* @__PURE__ */ React.createElement(List, { dense: true, className: classes.list }, errors.map((error, index) => /* @__PURE__ */ React.createElement(ListItem, { key: index }, /* @__PURE__ */ React.createElement(ListItemIcon, null, /* @__PURE__ */ React.createElement(ErrorIcon, { color: "error" })), /* @__PURE__ */ React.createElement(
611
- ListItemText,
612
- {
613
- classes: { primary: classes.text },
614
- primary: error.stack
615
- }
616
- )))));
617
- };
618
-
619
- const useStyles$9 = makeStyles((theme) => ({
620
- backButton: {
621
- marginRight: theme.spacing(1)
622
- },
623
- footer: {
624
- display: "flex",
625
- flexDirection: "row",
626
- justifyContent: "right",
627
- marginTop: theme.spacing(2)
628
- },
629
- formWrapper: {
630
- padding: theme.spacing(2)
631
- }
632
- }));
633
- const Stepper = (stepperProps) => {
634
- var _a, _b, _c, _d, _e, _f, _g;
635
- const { layouts = [], components = {}, ...props } = stepperProps;
636
- const {
637
- ReviewStateComponent = ReviewState,
638
- ReviewStepComponent,
639
- backButtonText = "Back",
640
- createButtonText = "Create",
641
- reviewButtonText = "Review"
642
- } = components;
643
- const analytics = useAnalytics();
644
- const { presentation, steps } = useTemplateSchema(props.manifest);
645
- const apiHolder = useApiHolder();
646
- const [activeStep, setActiveStep] = useState(0);
647
- const [isValidating, setIsValidating] = useState(false);
648
- const [formState, setFormState] = useFormDataFromQuery(props.initialState);
649
- const [errors, setErrors] = useState();
650
- const styles = useStyles$9();
651
- const extensions = useMemo(() => {
652
- return Object.fromEntries(
653
- props.extensions.map(({ name, component }) => [name, component])
654
- );
655
- }, [props.extensions]);
656
- const fields = useMemo(
657
- () => ({ ...FieldOverrides, ...extensions }),
658
- [extensions]
659
- );
660
- const validators = useMemo(() => {
661
- return Object.fromEntries(
662
- props.extensions.map(({ name, validation: validation2 }) => [name, validation2])
663
- );
664
- }, [props.extensions]);
665
- const validation = useMemo(() => {
666
- var _a2;
667
- return createAsyncValidators((_a2 = steps[activeStep]) == null ? void 0 : _a2.mergedSchema, validators, {
668
- apiHolder
669
- });
670
- }, [steps, activeStep, validators, apiHolder]);
671
- const handleBack = () => {
672
- setActiveStep((prevActiveStep) => prevActiveStep - 1);
673
- };
674
- const handleChange = useCallback(
675
- (e) => setFormState((current) => ({ ...current, ...e.formData })),
676
- [setFormState]
677
- );
678
- const handleCreate = useCallback(() => {
679
- props.onCreate(formState);
680
- }, [props, formState]);
681
- const currentStep = useTransformSchemaToProps(steps[activeStep], { layouts });
682
- const handleNext = async ({
683
- formData = {}
684
- }) => {
685
- setErrors(void 0);
686
- setIsValidating(true);
687
- const returnedValidation = await validation(formData);
688
- setIsValidating(false);
689
- if (hasErrors(returnedValidation)) {
690
- setErrors(returnedValidation);
691
- } else {
692
- setErrors(void 0);
693
- setActiveStep((prevActiveStep) => {
694
- const stepNum = prevActiveStep + 1;
695
- analytics.captureEvent("click", `Next Step (${stepNum})`);
696
- return stepNum;
697
- });
698
- }
699
- setFormState((current) => ({ ...current, ...formData }));
700
- };
701
- const backLabel = (_b = (_a = presentation == null ? void 0 : presentation.buttonLabels) == null ? void 0 : _a.backButtonText) != null ? _b : backButtonText;
702
- const createLabel = (_d = (_c = presentation == null ? void 0 : presentation.buttonLabels) == null ? void 0 : _c.createButtonText) != null ? _d : createButtonText;
703
- const reviewLabel = (_f = (_e = presentation == null ? void 0 : presentation.buttonLabels) == null ? void 0 : _e.reviewButtonText) != null ? _f : reviewButtonText;
704
- return /* @__PURE__ */ React.createElement(React.Fragment, null, isValidating && /* @__PURE__ */ React.createElement(LinearProgress, { variant: "indeterminate" }), /* @__PURE__ */ React.createElement(
705
- Stepper$1,
706
- {
707
- activeStep,
708
- alternativeLabel: true,
709
- variant: "elevation",
710
- style: { overflowX: "auto" }
711
- },
712
- steps.map((step, index) => {
713
- const isAllowedLabelClick = activeStep > index;
714
- return /* @__PURE__ */ React.createElement(Step, { key: index }, /* @__PURE__ */ React.createElement(
715
- StepLabel,
716
- {
717
- "aria-label": `Step ${index + 1}`,
718
- style: { cursor: isAllowedLabelClick ? "pointer" : "default" },
719
- onClick: () => {
720
- if (isAllowedLabelClick)
721
- setActiveStep(index);
722
- }
723
- },
724
- step.title
725
- ));
726
- }),
727
- /* @__PURE__ */ React.createElement(Step, null, /* @__PURE__ */ React.createElement(StepLabel, null, "Review"))
728
- ), /* @__PURE__ */ React.createElement("div", { className: styles.formWrapper }, activeStep < steps.length ? /* @__PURE__ */ React.createElement(
729
- Form,
730
- {
731
- validator,
732
- extraErrors: errors,
733
- formData: formState,
734
- formContext: { formData: formState },
735
- schema: currentStep.schema,
736
- uiSchema: currentStep.uiSchema,
737
- onSubmit: handleNext,
738
- fields,
739
- showErrorList: "top",
740
- templates: { ErrorListTemplate },
741
- onChange: handleChange,
742
- experimental_defaultFormStateBehavior: {
743
- allOf: "populateDefaults"
744
- },
745
- ...(_g = props.formProps) != null ? _g : {}
746
- },
747
- /* @__PURE__ */ React.createElement("div", { className: styles.footer }, /* @__PURE__ */ React.createElement(
748
- Button,
749
- {
750
- onClick: handleBack,
751
- className: styles.backButton,
752
- disabled: activeStep < 1 || isValidating
753
- },
754
- backLabel
755
- ), /* @__PURE__ */ React.createElement(
756
- Button,
757
- {
758
- variant: "contained",
759
- color: "primary",
760
- type: "submit",
761
- disabled: isValidating
762
- },
763
- activeStep === steps.length - 1 ? reviewLabel : "Next"
764
- ))
765
- ) : (
766
- // TODO: potentially move away from this pattern, deprecate?
767
- ReviewStepComponent ? /* @__PURE__ */ React.createElement(
768
- ReviewStepComponent,
769
- {
770
- disableButtons: isValidating,
771
- formData: formState,
772
- handleBack,
773
- handleReset: () => {
774
- },
775
- steps,
776
- handleCreate
777
- }
778
- ) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ReviewStateComponent, { formState, schemas: steps }), /* @__PURE__ */ React.createElement("div", { className: styles.footer }, /* @__PURE__ */ React.createElement(
779
- Button,
780
- {
781
- onClick: handleBack,
782
- className: styles.backButton,
783
- disabled: activeStep < 1
784
- },
785
- "Back"
786
- ), /* @__PURE__ */ React.createElement(
787
- Button,
788
- {
789
- variant: "contained",
790
- color: "primary",
791
- onClick: handleCreate
792
- },
793
- createLabel
794
- )))
795
- )));
796
- };
797
-
798
- const useStyles$8 = makeStyles(() => ({
799
- header: {
800
- backgroundImage: ({ cardBackgroundImage }) => cardBackgroundImage,
801
- color: ({ cardFontColor }) => cardFontColor
802
- },
803
- subtitleWrapper: {
804
- display: "flex",
805
- justifyContent: "space-between"
806
- }
807
- }));
808
- const CardHeader = (props) => {
809
- const {
810
- template: {
811
- metadata: { title, name },
812
- spec: { type }
813
- }
814
- } = props;
815
- const { getPageTheme } = useTheme();
816
- const themeForType = getPageTheme({ themeId: type });
817
- const styles = useStyles$8({
818
- cardFontColor: themeForType.fontColor,
819
- cardBackgroundImage: themeForType.backgroundImage
820
- });
821
- const SubtitleComponent = /* @__PURE__ */ React.createElement("div", { className: styles.subtitleWrapper }, /* @__PURE__ */ React.createElement("div", null, type), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(FavoriteEntity, { entity: props.template, style: { padding: 0 } })));
822
- return /* @__PURE__ */ React.createElement(
823
- ItemCardHeader,
824
- {
825
- title: title != null ? title : name,
826
- subtitle: SubtitleComponent,
827
- classes: { root: styles.header }
828
- }
829
- );
830
- };
831
-
832
- const useStyles$7 = makeStyles(() => ({
833
- linkText: {
834
- display: "inline-flex",
835
- alignItems: "center"
836
- }
837
- }));
838
- const CardLink = ({ icon: Icon, text, url }) => {
839
- const styles = useStyles$7();
840
- 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));
841
- };
842
-
843
- const useStyles$6 = makeStyles((theme) => ({
844
- box: {
845
- overflow: "hidden",
846
- textOverflow: "ellipsis",
847
- display: "-webkit-box",
848
- "-webkit-line-clamp": 10,
849
- "-webkit-box-orient": "vertical"
850
- },
851
- markdown: {
852
- /** to make the styles for React Markdown not leak into the description */
853
- "& :first-child": {
854
- margin: 0
855
- }
856
- },
857
- label: {
858
- color: theme.palette.text.secondary,
859
- textTransform: "uppercase",
860
- fontWeight: "bold",
861
- letterSpacing: 0.5,
862
- lineHeight: 1,
863
- fontSize: "0.75rem"
864
- },
865
- footer: {
866
- display: "flex",
867
- justifyContent: "space-between",
868
- flex: 1,
869
- alignItems: "center"
870
- },
871
- ownedBy: {
872
- display: "flex",
873
- alignItems: "center",
874
- flex: 1,
875
- color: theme.palette.link
876
- }
877
- }));
878
- const TemplateCard = (props) => {
879
- var _a, _b, _c, _d, _e, _f, _g;
880
- const { template } = props;
881
- const styles = useStyles$6();
882
- const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);
883
- const app = useApp();
884
- const iconResolver = (key) => {
885
- var _a2;
886
- return key ? (_a2 = app.getSystemIcon(key)) != null ? _a2 : LanguageIcon : LanguageIcon;
887
- };
888
- const hasTags = !!((_a = template.metadata.tags) == null ? void 0 : _a.length);
889
- const hasLinks = !!((_b = props.additionalLinks) == null ? void 0 : _b.length) || !!((_c = template.metadata.links) == null ? void 0 : _c.length);
890
- const displayDefaultDivider = !hasTags && !hasLinks;
891
- return /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { template }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Box, { className: styles.box }, /* @__PURE__ */ React.createElement(
892
- MarkdownContent,
893
- {
894
- className: styles.markdown,
895
- content: (_d = template.metadata.description) != null ? _d : "No description"
896
- }
897
- ))), displayDefaultDivider && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator" })), hasTags && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator--tags" })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, (_e = template.metadata.tags) == null ? void 0 : _e.map((tag) => /* @__PURE__ */ React.createElement(Grid, { key: `grid-${tag}`, item: true }, /* @__PURE__ */ React.createElement(
898
- Chip,
899
- {
900
- style: { margin: 0 },
901
- size: "small",
902
- label: tag,
903
- key: tag
904
- }
905
- )))))), hasLinks && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator--links" })), /* @__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(
906
- ({ url, icon, title }, index) => /* @__PURE__ */ React.createElement(Grid, { className: styles.linkText, item: true, xs: 6, key: index }, /* @__PURE__ */ React.createElement(
907
- CardLink,
908
- {
909
- icon: iconResolver(icon),
910
- text: title || url,
911
- url
912
- }
913
- ))
914
- )))))), /* @__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(
915
- EntityRefLinks,
916
- {
917
- style: { marginLeft: "8px" },
918
- entityRefs: ownedByRelations,
919
- defaultKind: "Group",
920
- hideIcons: true
921
- }
922
- ))), /* @__PURE__ */ React.createElement(
923
- Button,
924
- {
925
- size: "small",
926
- variant: "outlined",
927
- color: "primary",
928
- onClick: () => {
929
- var _a2;
930
- return (_a2 = props.onSelected) == null ? void 0 : _a2.call(props, template);
931
- }
932
- },
933
- "Choose"
934
- ))));
935
- };
936
-
937
- const TemplateGroup = (props) => {
938
- const {
939
- templates,
940
- title,
941
- components: { CardComponent } = {},
942
- onSelected
943
- } = props;
944
- const titleComponent = typeof title === "string" ? /* @__PURE__ */ React.createElement(ContentHeader, { title }) : title;
945
- if (templates.length === 0) {
946
- return null;
947
- }
948
- const Card = CardComponent || TemplateCard;
949
- return /* @__PURE__ */ React.createElement(Content, null, titleComponent, /* @__PURE__ */ React.createElement(ItemCardGrid, null, templates.map(({ template, additionalLinks }) => /* @__PURE__ */ React.createElement(
950
- Card,
951
- {
952
- key: stringifyEntityRef(template),
953
- additionalLinks,
954
- template,
955
- onSelected
956
- }
957
- ))));
958
- };
959
-
960
- const TemplateGroups = (props) => {
961
- const { loading, error, entities } = useEntityList();
962
- const { groups, templateFilter, TemplateCardComponent, onTemplateSelected } = props;
963
- const errorApi = useApi(errorApiRef);
964
- const onSelected = useCallback(
965
- (template) => {
966
- onTemplateSelected == null ? void 0 : onTemplateSelected(template);
967
- },
968
- [onTemplateSelected]
969
- );
970
- if (loading) {
971
- return /* @__PURE__ */ React.createElement(Progress, null);
972
- }
973
- if (error) {
974
- errorApi.post(error);
975
- return null;
976
- }
977
- if (!entities || !entities.length) {
978
- 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"), ".");
979
- }
980
- return /* @__PURE__ */ React.createElement(React.Fragment, null, groups.map(({ title, filter }, index) => {
981
- const templates = entities.filter(isTemplateEntityV1beta3).filter((e) => templateFilter ? templateFilter(e) : true).filter(filter).map((template) => {
982
- var _a, _b;
983
- const additionalLinks = (_b = (_a = props.additionalLinksForEntity) == null ? void 0 : _a.call(props, template)) != null ? _b : [];
984
- return {
985
- template,
986
- additionalLinks
987
- };
988
- });
989
- return /* @__PURE__ */ React.createElement(
990
- TemplateGroup,
991
- {
992
- key: index,
993
- templates,
994
- title,
995
- components: { CardComponent: TemplateCardComponent },
996
- onSelected
997
- }
998
- );
999
- }));
1000
- };
1001
-
1002
- const useTemplateTimeSavedMinutes = (templateRef) => {
1003
- const catalogApi = useApi(catalogApiRef);
1004
- const { value: timeSavedMinutes } = useAsync$1(async () => {
1005
- var _a;
1006
- const entity = await catalogApi.getEntityByRef(templateRef);
1007
- const timeSaved = (_a = entity == null ? void 0 : entity.metadata.annotations) == null ? void 0 : _a["backstage.io/time-saved"];
1008
- if (!entity || !timeSaved) {
1009
- return void 0;
1010
- }
1011
- const durationMs = Duration.fromISO(timeSaved).as("minutes");
1012
- if (Number.isNaN(durationMs)) {
1013
- return void 0;
1014
- }
1015
- return durationMs;
1016
- }, [catalogApi, templateRef]);
1017
- return timeSavedMinutes;
1018
- };
1019
-
1020
- const useStyles$5 = makeStyles({
1021
- markdown: {
1022
- /** to make the styles for React Markdown not leak into the description */
1023
- "& :first-child": {
1024
- marginTop: 0
1025
- },
1026
- "& :last-child": {
1027
- marginBottom: 0
1028
- }
1029
- }
1030
- });
1031
- const Workflow = (workflowProps) => {
1032
- var _a;
1033
- const { title, description, namespace, templateName, onCreate, ...props } = workflowProps;
1034
- const analytics = useAnalytics();
1035
- const styles = useStyles$5();
1036
- const templateRef = stringifyEntityRef({
1037
- kind: "Template",
1038
- namespace,
1039
- name: templateName
1040
- });
1041
- const errorApi = useApi(errorApiRef);
1042
- const { loading, manifest, error } = useTemplateParameterSchema(templateRef);
1043
- const sortedManifest = useFilteredSchemaProperties(manifest);
1044
- const minutesSaved = useTemplateTimeSavedMinutes(templateRef);
1045
- const workflowOnCreate = useCallback(
1046
- async (formState) => {
1047
- var _a2;
1048
- onCreate(formState);
1049
- const name = typeof formState.name === "string" ? formState.name : void 0;
1050
- analytics.captureEvent("create", (_a2 = name != null ? name : templateName) != null ? _a2 : "unknown", {
1051
- value: minutesSaved
1052
- });
1053
- },
1054
- [onCreate, analytics, templateName, minutesSaved]
1055
- );
1056
- useEffect(() => {
1057
- if (error) {
1058
- errorApi.post(new Error(`Failed to load template, ${error}`));
1059
- }
1060
- }, [error, errorApi]);
1061
- if (error) {
1062
- return props.onError(error);
1063
- }
1064
- return /* @__PURE__ */ React.createElement(Content, null, loading && /* @__PURE__ */ React.createElement(Progress, null), sortedManifest && /* @__PURE__ */ React.createElement(
1065
- InfoCard,
1066
- {
1067
- title: title != null ? title : sortedManifest.title,
1068
- subheader: /* @__PURE__ */ React.createElement(
1069
- MarkdownContent,
1070
- {
1071
- className: styles.markdown,
1072
- content: (_a = description != null ? description : sortedManifest.description) != null ? _a : "No description"
1073
- }
1074
- ),
1075
- noPadding: true,
1076
- titleTypographyProps: { component: "h2" }
1077
- },
1078
- /* @__PURE__ */ React.createElement(
1079
- Stepper,
1080
- {
1081
- manifest: sortedManifest,
1082
- onCreate: workflowOnCreate,
1083
- ...props
1084
- }
1085
- )
1086
- ));
1087
- };
1088
- const EmbeddableWorkflow = (props) => /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(Workflow, { ...props }));
1089
-
1090
- const useStyles$4 = makeStyles({
1091
- root: {
1092
- "&:hover": {
1093
- textDecoration: "none"
1094
- }
1095
- }
1096
- });
1097
- const LinkOutputs = (props) => {
1098
- const { links = [] } = props.output;
1099
- const classes = useStyles$4();
1100
- const app = useApp();
1101
- const entityRoute = useRouteRef(entityRouteRef);
1102
- const iconResolver = (key) => {
1103
- var _a;
1104
- return (_a = app.getSystemIcon(key)) != null ? _a : LinkIcon;
1105
- };
1106
- return /* @__PURE__ */ React.createElement(React.Fragment, null, links.filter(({ url, entityRef }) => url || entityRef).map(({ url, entityRef, title, icon }) => {
1107
- if (entityRef) {
1108
- const entityName = parseEntityRef(entityRef);
1109
- const target = entityRoute(entityName);
1110
- return { title, icon, url: target };
1111
- }
1112
- return { title, icon, url };
1113
- }).map(({ url, title, icon }, i) => {
1114
- const Icon = iconResolver(icon);
1115
- return /* @__PURE__ */ React.createElement(Link, { to: url, key: i, classes: { root: classes.root } }, /* @__PURE__ */ React.createElement(Button, { startIcon: /* @__PURE__ */ React.createElement(Icon, null), component: "div", color: "primary" }, title));
1116
- }));
1117
- };
1118
-
1119
- const TextOutputs = (props) => {
1120
- const {
1121
- output: { text = [] },
1122
- index,
1123
- setIndex
1124
- } = props;
1125
- const app = useApp();
1126
- const iconResolver = (key) => {
1127
- var _a;
1128
- return (_a = app.getSystemIcon(key)) != null ? _a : DescriptionIcon;
1129
- };
1130
- return /* @__PURE__ */ React.createElement(React.Fragment, null, text.filter(({ content }) => content !== void 0).map(({ title, icon }, i) => {
1131
- const Icon = iconResolver(icon);
1132
- return /* @__PURE__ */ React.createElement(
1133
- Button,
1134
- {
1135
- key: i,
1136
- startIcon: /* @__PURE__ */ React.createElement(Icon, null),
1137
- component: "div",
1138
- color: "primary",
1139
- onClick: () => {
1140
- if (index !== i) {
1141
- setIndex == null ? void 0 : setIndex(i);
1142
- }
1143
- },
1144
- variant: index === i ? "outlined" : void 0
1145
- },
1146
- title
1147
- );
1148
- }));
1149
- };
1150
-
1151
- const DefaultTemplateOutputs = (props) => {
1152
- var _a, _b;
1153
- const { output } = props;
1154
- const [textOutputIndex, setTextOutputIndex] = useState(
1155
- void 0
1156
- );
1157
- useEffect(() => {
1158
- if (textOutputIndex === void 0 && (output == null ? void 0 : output.text)) {
1159
- const defaultIndex = output.text.findIndex(
1160
- (t) => t.default
1161
- );
1162
- setTextOutputIndex(defaultIndex >= 0 ? defaultIndex : 0);
1163
- }
1164
- }, [textOutputIndex, output]);
1165
- const textOutput = useMemo(
1166
- () => {
1167
- var _a2;
1168
- return textOutputIndex !== void 0 ? (_a2 = output == null ? void 0 : output.text) == null ? void 0 : _a2[textOutputIndex] : null;
1169
- },
1170
- [output, textOutputIndex]
1171
- );
1172
- if (!output) {
1173
- return null;
1174
- }
1175
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { paddingBottom: 2 }, /* @__PURE__ */ React.createElement(Paper, null, /* @__PURE__ */ React.createElement(Box, { padding: 2, justifyContent: "center", display: "flex", gridGap: 16 }, /* @__PURE__ */ React.createElement(
1176
- TextOutputs,
1177
- {
1178
- output,
1179
- index: textOutputIndex,
1180
- setIndex: setTextOutputIndex
1181
- }
1182
- ), /* @__PURE__ */ React.createElement(LinkOutputs, { output })))), textOutput ? /* @__PURE__ */ React.createElement(Box, { paddingBottom: 2 }, /* @__PURE__ */ React.createElement(
1183
- InfoCard,
1184
- {
1185
- title: (_a = textOutput.title) != null ? _a : "Text Output",
1186
- noPadding: true,
1187
- titleTypographyProps: { component: "h2" }
1188
- },
1189
- /* @__PURE__ */ React.createElement(Box, { padding: 2, height: "100%" }, /* @__PURE__ */ React.createElement(MarkdownContent, { content: (_b = textOutput.content) != null ? _b : "" }))
1190
- )) : null);
1191
- };
1192
-
1193
- const useStepIconStyles = makeStyles((theme) => ({
1194
- root: {
1195
- color: theme.palette.text.disabled
1196
- },
1197
- completed: {
1198
- color: theme.palette.status.ok
1199
- },
1200
- error: {
1201
- color: theme.palette.status.error
1202
- }
1203
- }));
1204
- const StepIcon = (props) => {
1205
- const classes = useStepIconStyles();
1206
- const { active, completed, error, skipped } = props;
1207
- const getMiddle = () => {
1208
- if (active) {
1209
- return /* @__PURE__ */ React.createElement(CircularProgress, { size: "20px" });
1210
- }
1211
- if (completed) {
1212
- return /* @__PURE__ */ React.createElement(CheckCircleOutline, null);
1213
- }
1214
- if (error) {
1215
- return /* @__PURE__ */ React.createElement(ErrorOutline, null);
1216
- }
1217
- if (skipped) {
1218
- return /* @__PURE__ */ React.createElement(RemoveCircleOutline, null);
1219
- }
1220
- return /* @__PURE__ */ React.createElement(PanoramaFishEyeIcon, null);
1221
- };
1222
- return /* @__PURE__ */ React.createElement(
1223
- "div",
1224
- {
1225
- className: classNames(classes.root, {
1226
- [classes.completed]: completed,
1227
- [classes.error]: error
1228
- })
1229
- },
1230
- getMiddle()
1231
- );
1232
- };
1233
-
1234
- const StepTime = (props) => {
1235
- const [time, setTime] = useState("");
1236
- const { step } = props;
1237
- const getDelay = () => {
1238
- if (step.startedAt && step.endedAt && time) {
1239
- return null;
1240
- }
1241
- if (step.startedAt && step.endedAt) {
1242
- return 1;
1243
- }
1244
- return 1e3;
1245
- };
1246
- const calculate = useCallback(() => {
1247
- if (!step.startedAt) {
1248
- setTime("");
1249
- return;
1250
- }
1251
- const end = step.endedAt ? DateTime.fromISO(step.endedAt) : DateTime.local();
1252
- const startedAt = DateTime.fromISO(step.startedAt);
1253
- const formatted = Interval.fromDateTimes(startedAt, end).toDuration().valueOf();
1254
- setTime(humanizeDuration(formatted, { round: true }));
1255
- }, [step.endedAt, step.startedAt]);
1256
- useMountEffect(calculate);
1257
- useInterval(calculate, getDelay());
1258
- return /* @__PURE__ */ React.createElement(Typography, { variant: "caption" }, time);
1259
- };
1260
-
1261
- const useStyles$3 = makeStyles((theme) => ({
1262
- failed: {
1263
- backgroundColor: theme.palette.error.main
1264
- },
1265
- success: {
1266
- backgroundColor: theme.palette.success.main
1267
- }
1268
- }));
1269
- const TaskBorder = (props) => {
1270
- const styles = useStyles$3();
1271
- if (!props.isComplete) {
1272
- return /* @__PURE__ */ React.createElement(LinearProgress, { variant: "indeterminate" });
1273
- }
1274
- return /* @__PURE__ */ React.createElement(
1275
- LinearProgress,
1276
- {
1277
- variant: "determinate",
1278
- classes: { bar: props.isError ? styles.failed : styles.success },
1279
- value: 100
1280
- }
1281
- );
1282
- };
1283
-
1284
- const TaskSteps = (props) => {
1285
- var _a, _b;
1286
- return /* @__PURE__ */ React.createElement(Paper, { style: { position: "relative", overflow: "hidden" } }, /* @__PURE__ */ React.createElement(
1287
- TaskBorder,
1288
- {
1289
- isComplete: (_a = props.isComplete) != null ? _a : false,
1290
- isError: (_b = props.isError) != null ? _b : false
1291
- }
1292
- ), /* @__PURE__ */ React.createElement(Box, { padding: 2 }, /* @__PURE__ */ React.createElement(
1293
- Stepper$1,
1294
- {
1295
- activeStep: props.activeStep,
1296
- alternativeLabel: true,
1297
- variant: "elevation",
1298
- style: { overflowX: "auto" }
1299
- },
1300
- props.steps.map((step) => {
1301
- const isCompleted = step.status === "completed";
1302
- const isFailed = step.status === "failed";
1303
- const isActive = step.status === "processing";
1304
- const isSkipped = step.status === "skipped";
1305
- const stepIconProps = {
1306
- completed: isCompleted,
1307
- error: isFailed,
1308
- active: isActive,
1309
- skipped: isSkipped
1310
- };
1311
- return /* @__PURE__ */ React.createElement(Step, { key: step.id }, /* @__PURE__ */ React.createElement(StepButton, null, /* @__PURE__ */ React.createElement(
1312
- StepLabel,
1313
- {
1314
- StepIconProps: stepIconProps,
1315
- StepIconComponent: StepIcon,
1316
- "data-testid": "step-label"
1317
- },
1318
- /* @__PURE__ */ React.createElement(Box, null, step.name),
1319
- !isSkipped && /* @__PURE__ */ React.createElement(StepTime, { step })
1320
- )));
1321
- })
1322
- )));
1323
- };
1324
-
1325
- const useStyles$2 = makeStyles$1({
1326
- root: {
1327
- width: "100%",
1328
- height: "100%",
1329
- position: "relative"
1330
- }
1331
- });
1332
- const TaskLogStream = (props) => {
1333
- const styles = useStyles$2();
1334
- return /* @__PURE__ */ React.createElement("div", { className: styles.root }, /* @__PURE__ */ React.createElement(
1335
- LogViewer,
1336
- {
1337
- text: Object.values(props.logs).map((l) => l.join("\n")).filter(Boolean).join("\n")
1338
- }
1339
- ));
1340
- };
1341
-
1342
- const icon = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
1343
- const checkedIcon = /* @__PURE__ */ React.createElement(CheckBoxIcon, { fontSize: "small" });
1344
- const useStyles$1 = makeStyles(
1345
- {
1346
- root: {},
1347
- label: {}
1348
- },
1349
- { name: "ScaffolderReactTemplateCategoryPicker" }
1350
- );
1351
- const TemplateCategoryPicker = () => {
1352
- const classes = useStyles$1();
1353
- const alertApi = useApi(alertApiRef);
1354
- const { error, loading, availableTypes, selectedTypes, setSelectedTypes } = useEntityTypeFilter();
1355
- if (loading)
1356
- return /* @__PURE__ */ React.createElement(Progress, null);
1357
- if (error) {
1358
- alertApi.post({
1359
- message: `Failed to load entity types with error: ${error}`,
1360
- severity: "error"
1361
- });
1362
- return null;
1363
- }
1364
- if (!availableTypes)
1365
- return null;
1366
- return /* @__PURE__ */ React.createElement(Box, { className: classes.root, pb: 1, pt: 1 }, /* @__PURE__ */ React.createElement(
1367
- Typography,
1368
- {
1369
- className: classes.label,
1370
- variant: "button",
1371
- component: "label",
1372
- htmlFor: "categories-picker"
1373
- },
1374
- "Categories"
1375
- ), /* @__PURE__ */ React.createElement(
1376
- Autocomplete,
1377
- {
1378
- multiple: true,
1379
- id: "categories-picker",
1380
- options: availableTypes,
1381
- value: selectedTypes,
1382
- onChange: (_, value) => setSelectedTypes(value),
1383
- renderOption: (option, { selected }) => /* @__PURE__ */ React.createElement(
1384
- FormControlLabel,
1385
- {
1386
- control: /* @__PURE__ */ React.createElement(
1387
- Checkbox,
1388
- {
1389
- icon,
1390
- checkedIcon,
1391
- checked: selected
1392
- }
1393
- ),
1394
- label: capitalize(option)
1395
- }
1396
- ),
1397
- size: "small",
1398
- popupIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
1399
- renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, { ...params, variant: "outlined" })
1400
- }
1401
- ));
1402
- };
1403
-
1404
- const useStyles = makeStyles$1((theme) => ({
1405
- button: {
1406
- color: theme.page.fontColor
1407
- }
1408
- }));
1409
- function ScaffolderPageContextMenu(props) {
1410
- const { onEditorClicked, onActionsClicked, onTasksClicked, onCreateClicked } = props;
1411
- const classes = useStyles();
1412
- const [anchorEl, setAnchorEl] = useState();
1413
- if (!onEditorClicked && !onActionsClicked) {
1414
- return null;
1415
- }
1416
- const onOpen = (event) => {
1417
- setAnchorEl(event.currentTarget);
1418
- };
1419
- const onClose = () => {
1420
- setAnchorEl(void 0);
1421
- };
1422
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
1423
- IconButton,
1424
- {
1425
- id: "long-menu",
1426
- "aria-label": "more",
1427
- "aria-controls": "long-menu",
1428
- "aria-expanded": !!anchorEl,
1429
- "aria-haspopup": "true",
1430
- role: "button",
1431
- onClick: onOpen,
1432
- "data-testid": "menu-button",
1433
- color: "inherit",
1434
- className: classes.button
1435
- },
1436
- /* @__PURE__ */ React.createElement(MoreVert, null)
1437
- ), /* @__PURE__ */ React.createElement(
1438
- Popover,
1439
- {
1440
- "aria-labelledby": "long-menu",
1441
- open: Boolean(anchorEl),
1442
- onClose,
1443
- anchorEl,
1444
- anchorOrigin: { vertical: "bottom", horizontal: "right" },
1445
- transformOrigin: { vertical: "top", horizontal: "right" }
1446
- },
1447
- /* @__PURE__ */ React.createElement(MenuList, null, onCreateClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onCreateClicked }, /* @__PURE__ */ React.createElement(ListItemIcon$1, null, /* @__PURE__ */ React.createElement(CreateComponentIcon, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText$1, { primary: "Create" })), onEditorClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onEditorClicked }, /* @__PURE__ */ React.createElement(ListItemIcon$1, null, /* @__PURE__ */ React.createElement(Edit, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText$1, { primary: "Template Editor" })), onActionsClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onActionsClicked }, /* @__PURE__ */ React.createElement(ListItemIcon$1, null, /* @__PURE__ */ React.createElement(DescriptionIcon, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText$1, { primary: "Installed Actions" })), onTasksClicked && /* @__PURE__ */ React.createElement(MenuItem, { onClick: onTasksClicked }, /* @__PURE__ */ React.createElement(ListItemIcon$1, null, /* @__PURE__ */ React.createElement(List$1, { fontSize: "small" })), /* @__PURE__ */ React.createElement(ListItemText$1, { primary: "Task List" })))
1448
- ));
1449
- }
1450
-
1451
- export { DefaultTemplateOutputs, EmbeddableWorkflow, Form, ReviewState, ScaffolderField, ScaffolderPageContextMenu, Stepper, TaskLogStream, TaskSteps, TemplateCard, TemplateCategoryPicker, TemplateGroup, TemplateGroups, Workflow, createAsyncValidators, createFieldValidation, extractSchemaFromStep, useFilteredSchemaProperties, useFormDataFromQuery, useTemplateParameterSchema, useTemplateSchema };
1
+ export { Stepper } from './next/components/Stepper/Stepper.esm.js';
2
+ export { createAsyncValidators } from './next/components/Stepper/createAsyncValidators.esm.js';
3
+ export { TemplateCard } from './next/components/TemplateCard/TemplateCard.esm.js';
4
+ export { ReviewState } from './next/components/ReviewState/ReviewState.esm.js';
5
+ export { TemplateGroup } from './next/components/TemplateGroup/TemplateGroup.esm.js';
6
+ export { TemplateGroups } from './next/components/TemplateGroups/TemplateGroups.esm.js';
7
+ export { EmbeddableWorkflow, Workflow } from './next/components/Workflow/Workflow.esm.js';
8
+ export { DefaultTemplateOutputs } from './next/components/TemplateOutputs/DefaultTemplateOutputs.esm.js';
9
+ export { Form } from './next/components/Form/Form.esm.js';
10
+ export { TaskSteps } from './next/components/TaskSteps/TaskSteps.esm.js';
11
+ export { TaskLogStream } from './next/components/TaskLogStream/TaskLogStream.esm.js';
12
+ export { TemplateCategoryPicker } from './next/components/TemplateCategoryPicker/TemplateCategoryPicker.esm.js';
13
+ export { ScaffolderPageContextMenu } from './next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.esm.js';
14
+ export { ScaffolderField } from './next/components/ScaffolderField/ScaffolderField.esm.js';
15
+ export { createFieldValidation, extractSchemaFromStep } from './next/lib/schema.esm.js';
16
+ export { useFormDataFromQuery } from './next/hooks/useFormDataFromQuery.esm.js';
17
+ export { useTemplateSchema } from './next/hooks/useTemplateSchema.esm.js';
18
+ export { useTemplateParameterSchema } from './next/hooks/useTemplateParameterSchema.esm.js';
19
+ export { useFilteredSchemaProperties } from './next/hooks/useFilteredSchemaProperties.esm.js';
1452
20
  //# sourceMappingURL=alpha.esm.js.map