@backstage/plugin-scaffolder 0.12.3 → 0.13.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 +70 -0
- package/dist/esm/{Router-fe84df85.esm.js → Router-8ca04a51.esm.js} +44 -21
- package/dist/esm/Router-8ca04a51.esm.js.map +1 -0
- package/dist/esm/{index-87e5c74b.esm.js → index-7ce19edf.esm.js} +85 -82
- package/dist/esm/index-7ce19edf.esm.js.map +1 -0
- package/dist/index.d.ts +108 -65
- package/dist/index.esm.js +2 -2
- package/package.json +21 -20
- package/dist/esm/Router-fe84df85.esm.js.map +0 -1
- package/dist/esm/index-87e5c74b.esm.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,75 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder
|
|
2
2
|
|
|
3
|
+
## 0.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 50e0242ac2: - **BREAKING** - `scaffolderApi.scaffold()` now takes one `options` argument instead of 3, the existing arguments should just be wrapped up in one object instead.
|
|
8
|
+
- **BREAKING** - `scaffolderApi.scaffold()` now returns an object instead of a single string for the job ID. It's now `{ taskId: string }`
|
|
9
|
+
- **BREAKING** - `scaffolderApi.scaffold()` now takes a `templateRef` instead of `templateName` as an argument in the options. This should be a valid stringified `entityRef`.
|
|
10
|
+
- **BREAKING** - `scaffolderApi.getIntegrationsList` now returns an object `{ integrations: { type: string, title: string, host: string }[] }` instead of just an array.
|
|
11
|
+
- a2589000ee: - **BREAKING** - Removed the `plugin` export, use `scaffolderPlugin` instead.
|
|
12
|
+
- **BREAKING** - Removed the `TextValuePicker` component export, you can inline this component instead as it's a simple wrapper around a `TextField` from `@material-ui/core`.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 67a7c02d26: Remove usages of `EntityRef` and `parseEntityName` from `@backstage/catalog-model`
|
|
17
|
+
- 6e1cbc12a6: Updated according to the new `getEntityFacets` catalog API method
|
|
18
|
+
- b776ce5aab: Replaced use of deprecated `useEntityListProvider` hook with `useEntityList`.
|
|
19
|
+
- 0f37cdef19: Migrated over from the deprecated `spec.metadata` to `spec.templateInfo` for the `name` and the `baseUrl` of the template.
|
|
20
|
+
- 50e0242ac2: - Moved the `JSONSchema` type from `@backstage/catalog-model` to `JSONSchema7`.
|
|
21
|
+
- Renamed and prefixed some types ready for exporting.
|
|
22
|
+
- a2589000ee: - Reworking the `FieldExtensionComponentType` so we can export the `ui:schema:options` props in the `api-report.md`.
|
|
23
|
+
- Exporting all of the `UiOptions` types for the `FieldExtensions` so we can see them in the `api-report.md`.
|
|
24
|
+
- Removing the redundant type in the `CustomFieldValidator` union.
|
|
25
|
+
- 2f2543592c: You can now hide sections or fields in your templates based on a feature flag. For example, take this template:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
title: 'my-schema',
|
|
30
|
+
steps: [
|
|
31
|
+
{
|
|
32
|
+
title: 'Fill in some steps',
|
|
33
|
+
schema: {
|
|
34
|
+
title: 'Fill in some steps',
|
|
35
|
+
'backstage:featureFlag': 'experimental-feature',
|
|
36
|
+
properties: {
|
|
37
|
+
name: {
|
|
38
|
+
title: 'Name',
|
|
39
|
+
type: 'string',
|
|
40
|
+
'backstage:featureFlag': 'should-show-some-stuff-first-option',
|
|
41
|
+
},
|
|
42
|
+
description: {
|
|
43
|
+
title: 'Description',
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'A description for the component',
|
|
46
|
+
},
|
|
47
|
+
owner: {
|
|
48
|
+
title: 'Owner',
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'Owner of the component',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
type: 'object',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If you have a feature flag that is called `experimental-feature` then your first step would be shown if you that feature flag was not active then it wouldn't be shown. The same goes for the properties in the schema. Make sure to use the key `backstage:featureFlag` in your templates if you want to use this functionality.
|
|
61
|
+
|
|
62
|
+
- Updated dependencies
|
|
63
|
+
- @backstage/core-components@0.8.10
|
|
64
|
+
- @backstage/plugin-scaffolder-common@0.2.2
|
|
65
|
+
- @backstage/plugin-catalog-react@0.7.0
|
|
66
|
+
- @backstage/catalog-model@0.11.0
|
|
67
|
+
- @backstage/catalog-client@0.7.2
|
|
68
|
+
- @backstage/core-plugin-api@0.7.0
|
|
69
|
+
- @backstage/integration@0.7.5
|
|
70
|
+
- @backstage/integration-react@0.1.23
|
|
71
|
+
- @backstage/plugin-permission-react@0.3.2
|
|
72
|
+
|
|
3
73
|
## 0.12.3
|
|
4
74
|
|
|
5
75
|
### Patch Changes
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React, { useState, useContext, useCallback } from 'react';
|
|
2
2
|
import { useNavigate, Navigate, generatePath, useOutlet, Routes, Route } from 'react-router';
|
|
3
3
|
import { Page, Header, Lifecycle, Content, ContentHeader, CreateButton, SupportButton, MarkdownContent, StructuredMetadataTable, InfoCard, Progress, ErrorPage } from '@backstage/core-components';
|
|
4
|
-
import { useRouteRef, useApi, errorApiRef, useApiHolder, useElementFilter } from '@backstage/core-plugin-api';
|
|
4
|
+
import { useRouteRef, useApi, errorApiRef, featureFlagsApiRef, useApiHolder, useElementFilter } from '@backstage/core-plugin-api';
|
|
5
5
|
import { EntityListProvider, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker } from '@backstage/plugin-catalog-react';
|
|
6
6
|
import { makeStyles, Stepper, Step, StepLabel, Typography, StepContent, Button, Paper, Box, LinearProgress, TableContainer, Table, TableHead, TableRow, TableCell, TableBody } from '@material-ui/core';
|
|
7
|
-
import { E as EntityPicker, a as EntityNamePicker, e as entityNamePickerValidation, b as EntityTagsPicker, R as RepoUrlPicker, r as repoPickerValidation, O as OwnerPicker, c as OwnedEntityPicker, d as registerComponentRouteRef, T as TemplateTypePicker, f as TemplateList, S as SecretsContext, s as scaffolderApiRef, g as rootRouteRef, F as FIELD_EXTENSION_WRAPPER_KEY, h as FIELD_EXTENSION_KEY, i as SecretsContextProvider, j as TaskPage } from './index-
|
|
7
|
+
import { E as EntityPicker, a as EntityNamePicker, e as entityNamePickerValidation, b as EntityTagsPicker, R as RepoUrlPicker, r as repoPickerValidation, O as OwnerPicker, c as OwnedEntityPicker, d as registerComponentRouteRef, T as TemplateTypePicker, f as TemplateList, S as SecretsContext, s as scaffolderApiRef, g as rootRouteRef, F as FIELD_EXTENSION_WRAPPER_KEY, h as FIELD_EXTENSION_KEY, i as SecretsContextProvider, j as TaskPage } from './index-7ce19edf.esm.js';
|
|
8
8
|
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';
|
|
9
9
|
import { usePermission } from '@backstage/plugin-permission-react';
|
|
10
10
|
import qs from 'qs';
|
|
@@ -12,12 +12,13 @@ import { useParams } from 'react-router-dom';
|
|
|
12
12
|
import useAsync from 'react-use/lib/useAsync';
|
|
13
13
|
import { withTheme } from '@rjsf/core';
|
|
14
14
|
import { Theme } from '@rjsf/material-ui';
|
|
15
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
16
|
+
import { stringifyEntityRef } from '@backstage/catalog-model';
|
|
15
17
|
import classNames from 'classnames';
|
|
16
18
|
import '@backstage/errors';
|
|
17
19
|
import 'zen-observable';
|
|
18
20
|
import '@material-ui/core/FormControl';
|
|
19
21
|
import '@material-ui/lab/Autocomplete';
|
|
20
|
-
import '@backstage/catalog-model';
|
|
21
22
|
import 'react-use/lib/useEffectOnce';
|
|
22
23
|
import '@material-ui/lab';
|
|
23
24
|
import '@backstage/integration-react';
|
|
@@ -271,18 +272,36 @@ function getReviewData(formData, steps) {
|
|
|
271
272
|
}
|
|
272
273
|
return reviewData;
|
|
273
274
|
}
|
|
274
|
-
const MultistepJsonForm = ({
|
|
275
|
-
|
|
276
|
-
formData,
|
|
277
|
-
onChange,
|
|
278
|
-
onReset,
|
|
279
|
-
onFinish,
|
|
280
|
-
fields,
|
|
281
|
-
widgets
|
|
282
|
-
}) => {
|
|
275
|
+
const MultistepJsonForm = (props) => {
|
|
276
|
+
const { formData, onChange, onReset, onFinish, fields, widgets } = props;
|
|
283
277
|
const [activeStep, setActiveStep] = useState(0);
|
|
284
278
|
const [disableButtons, setDisableButtons] = useState(false);
|
|
285
279
|
const errorApi = useApi(errorApiRef);
|
|
280
|
+
const featureFlagApi = useApi(featureFlagsApiRef);
|
|
281
|
+
const featureFlagKey = "backstage:featureFlag";
|
|
282
|
+
const filterOutProperties = (step) => {
|
|
283
|
+
var _a;
|
|
284
|
+
const filteredStep = cloneDeep(step);
|
|
285
|
+
const removedPropertyKeys = [];
|
|
286
|
+
if (filteredStep.schema.properties) {
|
|
287
|
+
filteredStep.schema.properties = Object.fromEntries(Object.entries(filteredStep.schema.properties).filter(([key, value]) => {
|
|
288
|
+
if (value[featureFlagKey]) {
|
|
289
|
+
if (featureFlagApi.isActive(value[featureFlagKey])) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
removedPropertyKeys.push(key);
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
296
|
+
}));
|
|
297
|
+
filteredStep.schema.required = Array.isArray(filteredStep.schema.required) ? (_a = filteredStep.schema.required) == null ? void 0 : _a.filter((r) => !removedPropertyKeys.includes(r)) : filteredStep.schema.required;
|
|
298
|
+
}
|
|
299
|
+
return filteredStep;
|
|
300
|
+
};
|
|
301
|
+
const steps = props.steps.filter((step) => {
|
|
302
|
+
const featureFlag = step.schema[featureFlagKey];
|
|
303
|
+
return typeof featureFlag !== "string" || featureFlagApi.isActive(featureFlag);
|
|
304
|
+
}).map(filterOutProperties);
|
|
286
305
|
const handleReset = () => {
|
|
287
306
|
setActiveStep(0);
|
|
288
307
|
onReset();
|
|
@@ -360,13 +379,9 @@ const MultistepJsonForm = ({
|
|
|
360
379
|
}, "Create"))));
|
|
361
380
|
};
|
|
362
381
|
|
|
363
|
-
const useTemplateParameterSchema = (
|
|
382
|
+
const useTemplateParameterSchema = (templateRef) => {
|
|
364
383
|
const scaffolderApi = useApi(scaffolderApiRef);
|
|
365
|
-
const { value, loading, error } = useAsync(() => scaffolderApi.getTemplateParameterSchema(
|
|
366
|
-
name: templateName,
|
|
367
|
-
kind: "template",
|
|
368
|
-
namespace: "default"
|
|
369
|
-
}), [scaffolderApi, templateName]);
|
|
384
|
+
const { value, loading, error } = useAsync(() => scaffolderApi.getTemplateParameterSchema(templateRef), [scaffolderApi, templateRef]);
|
|
370
385
|
return { schema: value, loading, error };
|
|
371
386
|
};
|
|
372
387
|
function isObject(obj) {
|
|
@@ -425,11 +440,19 @@ const TemplatePage = ({
|
|
|
425
440
|
const handleChange = useCallback((e) => setFormState(e.formData), [setFormState]);
|
|
426
441
|
const handleCreate = async () => {
|
|
427
442
|
var _a;
|
|
428
|
-
const
|
|
443
|
+
const { taskId } = await scaffolderApi.scaffold({
|
|
444
|
+
templateRef: stringifyEntityRef({
|
|
445
|
+
name: templateName,
|
|
446
|
+
kind: "template",
|
|
447
|
+
namespace: "default"
|
|
448
|
+
}),
|
|
449
|
+
values: formState,
|
|
450
|
+
secrets: secretsContext == null ? void 0 : secretsContext.secrets
|
|
451
|
+
});
|
|
429
452
|
const formParams = qs.stringify({ formData: formState }, { addQueryPrefix: true });
|
|
430
453
|
const newUrl = `${window.location.pathname}${formParams}`;
|
|
431
454
|
(_a = window.history) == null ? void 0 : _a.replaceState(null, document.title, newUrl);
|
|
432
|
-
navigate(generatePath(`${rootLink()}/tasks/:taskId`, { taskId
|
|
455
|
+
navigate(generatePath(`${rootLink()}/tasks/:taskId`, { taskId }));
|
|
433
456
|
};
|
|
434
457
|
if (error) {
|
|
435
458
|
errorApi.post(new Error(`Failed to load template, ${error}`));
|
|
@@ -619,4 +642,4 @@ const Router = ({
|
|
|
619
642
|
};
|
|
620
643
|
|
|
621
644
|
export { Router };
|
|
622
|
-
//# sourceMappingURL=Router-
|
|
645
|
+
//# sourceMappingURL=Router-8ca04a51.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Router-8ca04a51.esm.js","sources":["../../src/extensions/default.ts","../../src/components/ScaffolderPage/ScaffolderPage.tsx","../../src/components/MultistepJsonForm/schema.ts","../../src/components/MultistepJsonForm/FieldOverrides/DescriptionField.tsx","../../src/components/MultistepJsonForm/MultistepJsonForm.tsx","../../src/components/TemplatePage/TemplatePage.tsx","../../src/components/ActionsPage/ActionsPage.tsx","../../src/components/Router.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { EntityPicker } from '../components/fields/EntityPicker';\nimport {\n EntityNamePicker,\n entityNamePickerValidation,\n} from '../components/fields/EntityNamePicker';\nimport { EntityTagsPicker } from '../components/fields/EntityTagsPicker';\nimport { OwnerPicker } from '../components/fields/OwnerPicker';\nimport {\n repoPickerValidation,\n RepoUrlPicker,\n} from '../components/fields/RepoUrlPicker';\nimport { FieldExtensionOptions } from './types';\nimport { OwnedEntityPicker } from '../components/fields/OwnedEntityPicker';\n\nexport const DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS: FieldExtensionOptions<any>[] =\n [\n {\n component: EntityPicker,\n name: 'EntityPicker',\n },\n {\n component: EntityNamePicker,\n name: 'EntityNamePicker',\n validation: entityNamePickerValidation,\n },\n {\n component: EntityTagsPicker,\n name: 'EntityTagsPicker',\n },\n {\n component: RepoUrlPicker,\n name: 'RepoUrlPicker',\n validation: repoPickerValidation,\n },\n {\n component: OwnerPicker,\n name: 'OwnerPicker',\n },\n {\n component: OwnedEntityPicker,\n name: 'OwnedEntityPicker',\n },\n ];\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Content,\n ContentHeader,\n CreateButton,\n Header,\n Lifecycle,\n Page,\n SupportButton,\n} from '@backstage/core-components';\nimport { Entity } from '@backstage/catalog-model';\nimport { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport {\n EntityKindPicker,\n EntityListProvider,\n EntitySearchBar,\n EntityTagPicker,\n UserListPicker,\n} from '@backstage/plugin-catalog-react';\nimport { makeStyles } from '@material-ui/core';\nimport React, { ComponentType } from 'react';\nimport { registerComponentRouteRef } from '../../routes';\nimport { TemplateList } from '../TemplateList';\nimport { TemplateTypePicker } from '../TemplateTypePicker';\nimport { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common';\nimport { usePermission } from '@backstage/plugin-permission-react';\n\nconst useStyles = makeStyles(theme => ({\n contentWrapper: {\n display: 'grid',\n gridTemplateAreas: \"'filters' 'grid'\",\n gridTemplateColumns: '250px 1fr',\n gridColumnGap: theme.spacing(2),\n },\n}));\n\nexport type ScaffolderPageProps = {\n TemplateCardComponent?:\n | ComponentType<{ template: TemplateEntityV1beta2 }>\n | undefined;\n groups?: Array<{\n title?: string;\n titleComponent?: React.ReactNode;\n filter: (entity: Entity) => boolean;\n }>;\n};\n\nexport const ScaffolderPageContents = ({\n TemplateCardComponent,\n groups,\n}: ScaffolderPageProps) => {\n const styles = useStyles();\n const registerComponentLink = useRouteRef(registerComponentRouteRef);\n const otherTemplatesGroup = {\n title: groups ? 'Other Templates' : 'Templates',\n filter: (entity: Entity) => {\n const filtered = (groups ?? []).map(group => group.filter(entity));\n return !filtered.some(result => result === true);\n },\n };\n\n const { allowed } = usePermission(catalogEntityCreatePermission);\n\n return (\n <Page themeId=\"home\">\n <Header\n pageTitleOverride=\"Create a New Component\"\n title={\n <>\n Create a New Component <Lifecycle shorthand />\n </>\n }\n subtitle=\"Create new software components using standard templates\"\n />\n <Content>\n <ContentHeader title=\"Available Templates\">\n {allowed && (\n <CreateButton\n title=\"Register Existing Component\"\n to={registerComponentLink && registerComponentLink()}\n />\n )}\n <SupportButton>\n Create new software components using standard templates. Different\n templates create different kinds of components (services, websites,\n documentation, ...).\n </SupportButton>\n </ContentHeader>\n\n <div className={styles.contentWrapper}>\n <div>\n <EntitySearchBar />\n <EntityKindPicker initialFilter=\"template\" hidden />\n <UserListPicker\n initialFilter=\"all\"\n availableFilters={['all', 'starred']}\n />\n <TemplateTypePicker />\n <EntityTagPicker />\n </div>\n <div>\n {groups &&\n groups.map((group, index) => (\n <TemplateList\n key={index}\n TemplateCardComponent={TemplateCardComponent}\n group={group}\n />\n ))}\n <TemplateList\n key=\"other\"\n TemplateCardComponent={TemplateCardComponent}\n group={otherTemplatesGroup}\n />\n </div>\n </div>\n </Content>\n </Page>\n );\n};\n\nexport const ScaffolderPage = ({\n TemplateCardComponent,\n groups,\n}: ScaffolderPageProps) => (\n <EntityListProvider>\n <ScaffolderPageContents\n TemplateCardComponent={TemplateCardComponent}\n groups={groups}\n />\n </EntityListProvider>\n);\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { FormProps } from '@rjsf/core';\n\nfunction isObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction extractUiSchema(schema: JsonObject, uiSchema: JsonObject) {\n if (!isObject(schema)) {\n return;\n }\n\n const { properties, items, anyOf, oneOf, allOf, dependencies } = schema;\n\n for (const propName in schema) {\n if (!schema.hasOwnProperty(propName)) {\n continue;\n }\n\n if (propName.startsWith('ui:')) {\n uiSchema[propName] = schema[propName];\n delete schema[propName];\n }\n }\n\n if (isObject(properties)) {\n for (const propName in properties) {\n if (!properties.hasOwnProperty(propName)) {\n continue;\n }\n\n const schemaNode = properties[propName];\n if (!isObject(schemaNode)) {\n continue;\n }\n const innerUiSchema = {};\n uiSchema[propName] = innerUiSchema;\n extractUiSchema(schemaNode, innerUiSchema);\n }\n }\n\n if (isObject(items)) {\n const innerUiSchema = {};\n uiSchema.items = innerUiSchema;\n extractUiSchema(items, innerUiSchema);\n }\n\n if (Array.isArray(anyOf)) {\n for (const schemaNode of anyOf) {\n if (!isObject(schemaNode)) {\n continue;\n }\n extractUiSchema(schemaNode, uiSchema);\n }\n }\n\n if (Array.isArray(oneOf)) {\n for (const schemaNode of oneOf) {\n if (!isObject(schemaNode)) {\n continue;\n }\n extractUiSchema(schemaNode, uiSchema);\n }\n }\n\n if (Array.isArray(allOf)) {\n for (const schemaNode of allOf) {\n if (!isObject(schemaNode)) {\n continue;\n }\n extractUiSchema(schemaNode, uiSchema);\n }\n }\n\n if (isObject(dependencies)) {\n for (const depName of Object.keys(dependencies)) {\n const schemaNode = dependencies[depName];\n if (!isObject(schemaNode)) {\n continue;\n }\n extractUiSchema(schemaNode, uiSchema);\n }\n }\n}\n\nexport function transformSchemaToProps(inputSchema: JsonObject): {\n schema: FormProps<any>['schema'];\n uiSchema: FormProps<any>['uiSchema'];\n} {\n inputSchema.type = inputSchema.type || 'object';\n const schema = JSON.parse(JSON.stringify(inputSchema));\n delete schema.title; // Rendered separately\n const uiSchema = {};\n extractUiSchema(schema, uiSchema);\n return { schema, uiSchema };\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { MarkdownContent } from '@backstage/core-components';\nimport { FieldProps } from '@rjsf/core';\n\nexport const DescriptionField = ({ description }: FieldProps) =>\n description && <MarkdownContent content={description} linkTarget=\"_blank\" />;\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { JsonObject } from '@backstage/types';\nimport {\n Box,\n Button,\n Paper,\n Step as StepUI,\n StepContent,\n StepLabel,\n Stepper,\n Typography,\n} from '@material-ui/core';\nimport {\n errorApiRef,\n useApi,\n featureFlagsApiRef,\n} from '@backstage/core-plugin-api';\nimport { FormProps, IChangeEvent, UiSchema, withTheme } from '@rjsf/core';\nimport { Theme as MuiTheme } from '@rjsf/material-ui';\nimport React, { useState } from 'react';\nimport { transformSchemaToProps } from './schema';\nimport { Content, StructuredMetadataTable } from '@backstage/core-components';\nimport cloneDeep from 'lodash/cloneDeep';\nimport * as fieldOverrides from './FieldOverrides';\n\nconst Form = withTheme(MuiTheme);\ntype Step = {\n schema: JsonObject;\n title: string;\n} & Partial<Omit<FormProps<any>, 'schema'>>;\n\ntype Props = {\n /**\n * Steps for the form, each contains title and form schema\n */\n steps: Step[];\n formData: Record<string, any>;\n onChange: (e: IChangeEvent) => void;\n onReset: () => void;\n onFinish: () => Promise<void>;\n widgets?: FormProps<any>['widgets'];\n fields?: FormProps<any>['fields'];\n};\n\nexport function getUiSchemasFromSteps(steps: Step[]): UiSchema[] {\n const uiSchemas: Array<UiSchema> = [];\n steps.forEach(step => {\n const schemaProps = step.schema.properties as JsonObject;\n for (const key in schemaProps) {\n if (schemaProps.hasOwnProperty(key)) {\n const uiSchema = schemaProps[key] as UiSchema;\n uiSchema.name = key;\n uiSchemas.push(uiSchema);\n }\n }\n });\n return uiSchemas;\n}\n\nexport function getReviewData(formData: Record<string, any>, steps: Step[]) {\n const uiSchemas = getUiSchemasFromSteps(steps);\n const reviewData: Record<string, any> = {};\n for (const key in formData) {\n if (formData.hasOwnProperty(key)) {\n const uiSchema = uiSchemas.find(us => us.name === key);\n\n if (!uiSchema) {\n reviewData[key] = formData[key];\n continue;\n }\n\n if (uiSchema['ui:widget'] === 'password') {\n reviewData[key] = '******';\n continue;\n }\n\n if (!uiSchema['ui:backstage'] || !uiSchema['ui:backstage'].review) {\n reviewData[key] = formData[key];\n continue;\n }\n\n const review = uiSchema['ui:backstage'].review as JsonObject;\n if (!review.show) {\n continue;\n }\n\n if (review.mask) {\n reviewData[key] = review.mask;\n continue;\n }\n reviewData[key] = formData[key];\n }\n }\n\n return reviewData;\n}\n\nexport const MultistepJsonForm = (props: Props) => {\n const { formData, onChange, onReset, onFinish, fields, widgets } = props;\n const [activeStep, setActiveStep] = useState(0);\n const [disableButtons, setDisableButtons] = useState(false);\n const errorApi = useApi(errorApiRef);\n const featureFlagApi = useApi(featureFlagsApiRef);\n const featureFlagKey = 'backstage:featureFlag';\n const filterOutProperties = (step: Step): Step => {\n const filteredStep = cloneDeep(step);\n const removedPropertyKeys: Array<string> = [];\n if (filteredStep.schema.properties) {\n filteredStep.schema.properties = Object.fromEntries(\n Object.entries(filteredStep.schema.properties).filter(\n ([key, value]) => {\n if (value[featureFlagKey]) {\n if (featureFlagApi.isActive(value[featureFlagKey])) {\n return true;\n }\n removedPropertyKeys.push(key);\n return false;\n }\n return true;\n },\n ),\n );\n\n // remove the feature flag property key from required if they are not active\n filteredStep.schema.required = Array.isArray(filteredStep.schema.required)\n ? filteredStep.schema.required?.filter(\n r => !removedPropertyKeys.includes(r as string),\n )\n : filteredStep.schema.required;\n }\n return filteredStep;\n };\n\n const steps = props.steps\n .filter(step => {\n const featureFlag = step.schema[featureFlagKey];\n return (\n typeof featureFlag !== 'string' || featureFlagApi.isActive(featureFlag)\n );\n })\n .map(filterOutProperties);\n\n const handleReset = () => {\n setActiveStep(0);\n onReset();\n };\n const handleNext = () => {\n setActiveStep(Math.min(activeStep + 1, steps.length));\n };\n const handleBack = () => setActiveStep(Math.max(activeStep - 1, 0));\n const handleCreate = async () => {\n setDisableButtons(true);\n try {\n await onFinish();\n } catch (err) {\n setDisableButtons(false);\n errorApi.post(err);\n }\n };\n\n return (\n <>\n <Stepper activeStep={activeStep} orientation=\"vertical\">\n {steps.map(({ title, schema, ...formProps }, index) => {\n return (\n <StepUI key={title}>\n <StepLabel\n aria-label={`Step ${index + 1} ${title}`}\n aria-disabled=\"false\"\n tabIndex={0}\n >\n <Typography variant=\"h6\" component=\"h3\">\n {title}\n </Typography>\n </StepLabel>\n <StepContent key={title}>\n <Form\n showErrorList={false}\n fields={{ ...fieldOverrides, ...fields }}\n widgets={widgets}\n noHtml5Validate\n formData={formData}\n onChange={onChange}\n onSubmit={e => {\n if (e.errors.length === 0) handleNext();\n }}\n {...formProps}\n {...transformSchemaToProps(schema)}\n >\n <Button disabled={activeStep === 0} onClick={handleBack}>\n Back\n </Button>\n <Button variant=\"contained\" color=\"primary\" type=\"submit\">\n Next step\n </Button>\n </Form>\n </StepContent>\n </StepUI>\n );\n })}\n </Stepper>\n {activeStep === steps.length && (\n <Content>\n <Paper square elevation={0}>\n <Typography variant=\"h6\">Review and create</Typography>\n <StructuredMetadataTable\n dense\n metadata={getReviewData(formData, steps)}\n />\n <Box mb={4} />\n <Button onClick={handleBack} disabled={disableButtons}>\n Back\n </Button>\n <Button onClick={handleReset} disabled={disableButtons}>\n Reset\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={handleCreate}\n disabled={disableButtons}\n >\n Create\n </Button>\n </Paper>\n </Content>\n )}\n </>\n );\n};\n","/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { LinearProgress } from '@material-ui/core';\nimport { FormValidation, IChangeEvent } from '@rjsf/core';\nimport qs from 'qs';\nimport React, { useCallback, useContext, useState } from 'react';\nimport { generatePath, Navigate, useNavigate } from 'react-router';\nimport { useParams } from 'react-router-dom';\nimport useAsync from 'react-use/lib/useAsync';\nimport { scaffolderApiRef } from '../../api';\nimport { CustomFieldValidator, FieldExtensionOptions } from '../../extensions';\nimport { SecretsContext } from '../secrets/SecretsContext';\nimport { rootRouteRef } from '../../routes';\nimport { MultistepJsonForm } from '../MultistepJsonForm';\n\nimport {\n Content,\n Header,\n InfoCard,\n Lifecycle,\n Page,\n} from '@backstage/core-components';\nimport {\n ApiHolder,\n errorApiRef,\n useApi,\n useApiHolder,\n useRouteRef,\n} from '@backstage/core-plugin-api';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\n\nconst useTemplateParameterSchema = (templateRef: string) => {\n const scaffolderApi = useApi(scaffolderApiRef);\n const { value, loading, error } = useAsync(\n () => scaffolderApi.getTemplateParameterSchema(templateRef),\n [scaffolderApi, templateRef],\n );\n return { schema: value, loading, error };\n};\n\nfunction isObject(obj: unknown): obj is JsonObject {\n return typeof obj === 'object' && obj !== null && !Array.isArray(obj);\n}\n\nexport const createValidator = (\n rootSchema: JsonObject,\n validators: Record<string, undefined | CustomFieldValidator<unknown>>,\n context: {\n apiHolder: ApiHolder;\n },\n) => {\n function validate(\n schema: JsonObject,\n formData: JsonObject,\n errors: FormValidation,\n ) {\n const schemaProps = schema.properties;\n if (!isObject(schemaProps)) {\n return;\n }\n\n for (const [key, propData] of Object.entries(formData)) {\n const propValidation = errors[key];\n\n if (isObject(propData)) {\n const propSchemaProps = schemaProps[key];\n if (isObject(propSchemaProps)) {\n validate(\n propSchemaProps,\n propData as JsonObject,\n propValidation as FormValidation,\n );\n }\n } else {\n const propSchema = schemaProps[key];\n const fieldName =\n isObject(propSchema) && (propSchema['ui:field'] as string);\n if (fieldName && typeof validators[fieldName] === 'function') {\n validators[fieldName]!(\n propData as JsonValue,\n propValidation,\n context,\n );\n }\n }\n }\n }\n\n return (formData: JsonObject, errors: FormValidation) => {\n validate(rootSchema, formData, errors);\n return errors;\n };\n};\n\nexport const TemplatePage = ({\n customFieldExtensions = [],\n}: {\n customFieldExtensions?: FieldExtensionOptions[];\n}) => {\n const apiHolder = useApiHolder();\n const secretsContext = useContext(SecretsContext);\n const errorApi = useApi(errorApiRef);\n const scaffolderApi = useApi(scaffolderApiRef);\n const { templateName } = useParams();\n const navigate = useNavigate();\n const rootLink = useRouteRef(rootRouteRef);\n const { schema, loading, error } = useTemplateParameterSchema(templateName);\n const [formState, setFormState] = useState<Record<string, any>>(() => {\n const query = qs.parse(window.location.search, {\n ignoreQueryPrefix: true,\n });\n\n try {\n return JSON.parse(query.formData as string);\n } catch (e) {\n return query.formData ?? {};\n }\n });\n const handleFormReset = () => setFormState({});\n const handleChange = useCallback(\n (e: IChangeEvent) => setFormState(e.formData),\n [setFormState],\n );\n\n const handleCreate = async () => {\n const { taskId } = await scaffolderApi.scaffold({\n templateRef: stringifyEntityRef({\n name: templateName,\n kind: 'template',\n namespace: 'default',\n }),\n values: formState,\n secrets: secretsContext?.secrets,\n });\n\n const formParams = qs.stringify(\n { formData: formState },\n { addQueryPrefix: true },\n );\n const newUrl = `${window.location.pathname}${formParams}`;\n // We use direct history manipulation since useSearchParams and\n // useNavigate in react-router-dom cause unnecessary extra rerenders.\n // Also make sure to replace the state rather than pushing to avoid\n // extra back/forward slots.\n window.history?.replaceState(null, document.title, newUrl);\n\n navigate(generatePath(`${rootLink()}/tasks/:taskId`, { taskId }));\n };\n\n if (error) {\n errorApi.post(new Error(`Failed to load template, ${error}`));\n return <Navigate to={rootLink()} />;\n }\n if (!loading && !schema) {\n errorApi.post(new Error('Template was not found.'));\n return <Navigate to={rootLink()} />;\n }\n\n const customFieldComponents = Object.fromEntries(\n customFieldExtensions.map(({ name, component }) => [name, component]),\n );\n\n const customFieldValidators = Object.fromEntries(\n customFieldExtensions.map(({ name, validation }) => [name, validation]),\n );\n\n return (\n <Page themeId=\"home\">\n <Header\n pageTitleOverride=\"Create a New Component\"\n title={\n <>\n Create a New Component <Lifecycle shorthand />\n </>\n }\n subtitle=\"Create new software components using standard templates\"\n />\n <Content>\n {loading && <LinearProgress data-testid=\"loading-progress\" />}\n {schema && (\n <InfoCard\n title={schema.title}\n noPadding\n titleTypographyProps={{ component: 'h2' }}\n >\n <MultistepJsonForm\n formData={formState}\n fields={customFieldComponents}\n onChange={handleChange}\n onReset={handleFormReset}\n onFinish={handleCreate}\n steps={schema.steps.map(step => {\n return {\n ...step,\n validate: createValidator(\n step.schema,\n customFieldValidators,\n { apiHolder },\n ),\n };\n })}\n />\n </InfoCard>\n )}\n </Content>\n </Page>\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport { scaffolderApiRef } from '../../api';\nimport {\n Typography,\n Paper,\n Table,\n TableBody,\n Box,\n TableCell,\n TableContainer,\n TableHead,\n TableRow,\n makeStyles,\n} from '@material-ui/core';\nimport { JSONSchema7, JSONSchema7Definition } from 'json-schema';\nimport classNames from 'classnames';\n\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n Progress,\n Content,\n Header,\n Page,\n ErrorPage,\n} from '@backstage/core-components';\n\nconst useStyles = makeStyles(theme => ({\n code: {\n fontFamily: 'Menlo, monospace',\n padding: theme.spacing(1),\n backgroundColor:\n theme.palette.type === 'dark'\n ? theme.palette.grey[700]\n : theme.palette.grey[300],\n display: 'inline-block',\n borderRadius: 5,\n border: `1px solid ${theme.palette.grey[500]}`,\n position: 'relative',\n },\n\n codeRequired: {\n '&::after': {\n position: 'absolute',\n content: '\"*\"',\n top: 0,\n right: theme.spacing(0.5),\n fontWeight: 'bolder',\n color: theme.palette.error.light,\n },\n },\n}));\n\nexport const ActionsPage = () => {\n const api = useApi(scaffolderApiRef);\n const classes = useStyles();\n const { loading, value, error } = useAsync(async () => {\n return api.listActions();\n });\n\n if (loading) {\n return <Progress />;\n }\n\n if (error) {\n return (\n <ErrorPage\n statusMessage=\"Failed to load installed actions\"\n status=\"500\"\n />\n );\n }\n\n const formatRows = (input: JSONSchema7) => {\n const properties = input.properties;\n if (!properties) {\n return undefined;\n }\n\n return Object.entries(properties).map(entry => {\n const [key] = entry;\n const props = entry[1] as unknown as JSONSchema7;\n const codeClassname = classNames(classes.code, {\n [classes.codeRequired]: input.required?.includes(key),\n });\n\n return (\n <TableRow key={key}>\n <TableCell>\n <div className={codeClassname}>{key}</div>\n </TableCell>\n <TableCell>{props.title}</TableCell>\n <TableCell>{props.description}</TableCell>\n <TableCell>\n <span className={classes.code}>{props.type}</span>\n </TableCell>\n </TableRow>\n );\n });\n };\n\n const renderTable = (input: JSONSchema7) => {\n if (!input.properties) {\n return undefined;\n }\n return (\n <TableContainer component={Paper}>\n <Table size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>Name</TableCell>\n <TableCell>Title</TableCell>\n <TableCell>Description</TableCell>\n <TableCell>Type</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>{formatRows(input)}</TableBody>\n </Table>\n </TableContainer>\n );\n };\n\n const renderTables = (name: string, input?: JSONSchema7Definition[]) => {\n if (!input) {\n return undefined;\n }\n\n return (\n <>\n <Typography variant=\"h6\">{name}</Typography>\n {input.map((i, index) => (\n <div key={index}>{renderTable(i as unknown as JSONSchema7)}</div>\n ))}\n </>\n );\n };\n\n const items = value?.map(action => {\n if (action.id.startsWith('legacy:')) {\n return undefined;\n }\n\n const oneOf = renderTables('oneOf', action.schema?.input?.oneOf);\n return (\n <Box pb={4} key={action.id}>\n <Typography variant=\"h4\" className={classes.code}>\n {action.id}\n </Typography>\n <Typography>{action.description}</Typography>\n {action.schema?.input && (\n <Box pb={2}>\n <Typography variant=\"h5\">Input</Typography>\n {renderTable(action.schema.input)}\n {oneOf}\n </Box>\n )}\n {action.schema?.output && (\n <Box pb={2}>\n <Typography variant=\"h5\">Output</Typography>\n {renderTable(action.schema.output)}\n </Box>\n )}\n </Box>\n );\n });\n\n return (\n <Page themeId=\"home\">\n <Header\n pageTitleOverride=\"Create a New Component\"\n title=\"Installed actions\"\n subtitle=\"This is the collection of all installed actions\"\n />\n <Content>{items}</Content>\n </Page>\n );\n};\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { ComponentType } from 'react';\nimport { Routes, Route, useOutlet } from 'react-router';\nimport { Entity } from '@backstage/catalog-model';\nimport { TemplateEntityV1beta2 } from '@backstage/plugin-scaffolder-common';\nimport { ScaffolderPage } from './ScaffolderPage';\nimport { TemplatePage } from './TemplatePage';\nimport { TaskPage } from './TaskPage';\nimport { ActionsPage } from './ActionsPage';\nimport { SecretsContextProvider } from './secrets/SecretsContext';\n\nimport {\n FieldExtensionOptions,\n FIELD_EXTENSION_WRAPPER_KEY,\n FIELD_EXTENSION_KEY,\n DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS,\n} from '../extensions';\nimport { useElementFilter } from '@backstage/core-plugin-api';\n\ntype RouterProps = {\n TemplateCardComponent?:\n | ComponentType<{ template: TemplateEntityV1beta2 }>\n | undefined;\n TaskPageComponent?: ComponentType<{}>;\n groups?: Array<{\n title?: string;\n titleComponent?: React.ReactNode;\n filter: (entity: Entity) => boolean;\n }>;\n};\n\nexport const Router = ({\n TemplateCardComponent,\n TaskPageComponent,\n groups,\n}: RouterProps) => {\n const outlet = useOutlet();\n const TaskPageElement = TaskPageComponent || TaskPage;\n\n const customFieldExtensions = useElementFilter(outlet, elements =>\n elements\n .selectByComponentData({\n key: FIELD_EXTENSION_WRAPPER_KEY,\n })\n .findComponentData<FieldExtensionOptions>({\n key: FIELD_EXTENSION_KEY,\n }),\n );\n\n const fieldExtensions = [\n ...customFieldExtensions,\n ...DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS.filter(\n ({ name }) =>\n !customFieldExtensions.some(\n customFieldExtension => customFieldExtension.name === name,\n ),\n ),\n ];\n\n return (\n <Routes>\n <Route\n path=\"/\"\n element={\n <ScaffolderPage\n TemplateCardComponent={TemplateCardComponent}\n groups={groups}\n />\n }\n />\n <Route\n path=\"/templates/:templateName\"\n element={\n <SecretsContextProvider>\n <TemplatePage customFieldExtensions={fieldExtensions} />\n </SecretsContextProvider>\n }\n />\n <Route path=\"/tasks/:taskId\" element={<TaskPageElement />} />\n <Route path=\"/actions\" element={<ActionsPage />} />\n </Routes>\n );\n};\n"],"names":["useStyles","isObject","MuiTheme","StepUI"],"mappings":"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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { parseEntityRef, KubernetesValidatorFunctions, makeValidator, RELATION_OWNED_BY, stringifyEntityRef } from '@backstage/catalog-model';
|
|
1
2
|
import { createApiRef, useApi, attachComponentData, createExternalRouteRef, createRouteRef, createPlugin, createApiFactory, discoveryApiRef, fetchApiRef, createRoutableExtension, useRouteRef, alertApiRef, useApp } from '@backstage/core-plugin-api';
|
|
2
3
|
import { ResponseError } from '@backstage/errors';
|
|
3
4
|
import qs from 'qs';
|
|
4
5
|
import ObservableImpl from 'zen-observable';
|
|
5
|
-
import { catalogApiRef, formatEntityRefTitle, useOwnedEntities, useStarredEntity, getEntityRelations, getEntitySourceLocation, EntityRefLinks,
|
|
6
|
+
import { catalogApiRef, formatEntityRefTitle, useOwnedEntities, useStarredEntity, getEntityRelations, getEntitySourceLocation, EntityRefLinks, useEntityList, useEntityTypeFilter, entityRouteRef } from '@backstage/plugin-catalog-react';
|
|
6
7
|
import { TextField, FormControl as FormControl$1, withStyles, makeStyles, IconButton, Tooltip, useTheme, Card, CardMedia, CardContent, Box, Typography, Chip, CardActions, Link, FormControlLabel, Checkbox, Grid, StepButton, Paper, Button as Button$1, CircularProgress } from '@material-ui/core';
|
|
7
8
|
import FormControl from '@material-ui/core/FormControl';
|
|
8
9
|
import Autocomplete from '@material-ui/lab/Autocomplete';
|
|
9
10
|
import React, { useCallback, useEffect, useState, createContext, useContext, useMemo, memo } from 'react';
|
|
10
11
|
import useAsync from 'react-use/lib/useAsync';
|
|
11
|
-
import { KubernetesValidatorFunctions, makeValidator, RELATION_OWNED_BY, stringifyEntityRef, parseEntityName } from '@backstage/catalog-model';
|
|
12
12
|
import useEffectOnce from 'react-use/lib/useEffectOnce';
|
|
13
13
|
import { Autocomplete as Autocomplete$1 } from '@material-ui/lab';
|
|
14
14
|
import { scmIntegrationsApiRef, scmAuthApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
|
|
@@ -52,15 +52,20 @@ class ScaffolderClient {
|
|
|
52
52
|
this.useLongPollingLogs = (_b = options.useLongPollingLogs) != null ? _b : false;
|
|
53
53
|
}
|
|
54
54
|
async getIntegrationsList(options) {
|
|
55
|
-
|
|
55
|
+
const integrations = [
|
|
56
56
|
...this.scmIntegrationsApi.azure.list(),
|
|
57
57
|
...this.scmIntegrationsApi.bitbucket.list(),
|
|
58
58
|
...this.scmIntegrationsApi.github.list(),
|
|
59
59
|
...this.scmIntegrationsApi.gitlab.list()
|
|
60
60
|
].map((c) => ({ type: c.type, title: c.title, host: c.config.host })).filter((c) => options.allowedHosts.includes(c.host));
|
|
61
|
+
return {
|
|
62
|
+
integrations
|
|
63
|
+
};
|
|
61
64
|
}
|
|
62
|
-
async getTemplateParameterSchema(
|
|
63
|
-
const { namespace, kind, name } =
|
|
65
|
+
async getTemplateParameterSchema(templateRef) {
|
|
66
|
+
const { namespace, kind, name } = parseEntityRef(templateRef, {
|
|
67
|
+
defaultKind: "template"
|
|
68
|
+
});
|
|
64
69
|
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
65
70
|
const templatePath = [namespace, kind, name].map((s) => encodeURIComponent(s)).join("/");
|
|
66
71
|
const url = `${baseUrl}/v2/templates/${templatePath}/parameter-schema`;
|
|
@@ -71,7 +76,8 @@ class ScaffolderClient {
|
|
|
71
76
|
const schema = await response.json();
|
|
72
77
|
return schema;
|
|
73
78
|
}
|
|
74
|
-
async scaffold(
|
|
79
|
+
async scaffold(options) {
|
|
80
|
+
const { templateRef, values, secrets = {} } = options;
|
|
75
81
|
const url = `${await this.discoveryApi.getBaseUrl("scaffolder")}/v2/tasks`;
|
|
76
82
|
const response = await this.fetchApi.fetch(url, {
|
|
77
83
|
method: "POST",
|
|
@@ -79,7 +85,7 @@ class ScaffolderClient {
|
|
|
79
85
|
"Content-Type": "application/json"
|
|
80
86
|
},
|
|
81
87
|
body: JSON.stringify({
|
|
82
|
-
|
|
88
|
+
templateRef,
|
|
83
89
|
values: { ...values },
|
|
84
90
|
secrets
|
|
85
91
|
})
|
|
@@ -90,7 +96,7 @@ class ScaffolderClient {
|
|
|
90
96
|
throw new Error(`Backend request failed, ${status} ${body.trim()}`);
|
|
91
97
|
}
|
|
92
98
|
const { id } = await response.json();
|
|
93
|
-
return id;
|
|
99
|
+
return { taskId: id };
|
|
94
100
|
}
|
|
95
101
|
async getTask(taskId) {
|
|
96
102
|
const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
|
|
@@ -184,20 +190,17 @@ class ScaffolderClient {
|
|
|
184
190
|
}
|
|
185
191
|
}
|
|
186
192
|
|
|
187
|
-
const
|
|
188
|
-
var _a, _b;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
idSchema
|
|
199
|
-
}) => {
|
|
200
|
-
var _a, _b;
|
|
193
|
+
const EntityPicker = (props) => {
|
|
194
|
+
var _a, _b, _c, _d;
|
|
195
|
+
const {
|
|
196
|
+
onChange,
|
|
197
|
+
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
198
|
+
required,
|
|
199
|
+
uiSchema,
|
|
200
|
+
rawErrors,
|
|
201
|
+
formData,
|
|
202
|
+
idSchema
|
|
203
|
+
} = props;
|
|
201
204
|
const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
|
|
202
205
|
const defaultKind = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultKind;
|
|
203
206
|
const catalogApi = useApi(catalogApiRef);
|
|
@@ -223,7 +226,7 @@ const EntityPicker = ({
|
|
|
223
226
|
onChange: onSelect,
|
|
224
227
|
options: entityRefs || [],
|
|
225
228
|
autoSelect: true,
|
|
226
|
-
freeSolo:
|
|
229
|
+
freeSolo: (_d = (_c = uiSchema["ui:options"]) == null ? void 0 : _c.allowArbitraryValues) != null ? _d : true,
|
|
227
230
|
renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, {
|
|
228
231
|
...params,
|
|
229
232
|
label: title,
|
|
@@ -236,35 +239,30 @@ const EntityPicker = ({
|
|
|
236
239
|
}));
|
|
237
240
|
};
|
|
238
241
|
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
...props
|
|
264
|
-
}) => /* @__PURE__ */ React.createElement(TextValuePicker, {
|
|
265
|
-
schema: { title, description },
|
|
266
|
-
...props
|
|
267
|
-
});
|
|
242
|
+
const EntityNamePicker = (props) => {
|
|
243
|
+
const {
|
|
244
|
+
onChange,
|
|
245
|
+
required,
|
|
246
|
+
schema: { title = "Name", description = "Unique name of the component" },
|
|
247
|
+
rawErrors,
|
|
248
|
+
formData,
|
|
249
|
+
uiSchema: { "ui:autofocus": autoFocus },
|
|
250
|
+
idSchema,
|
|
251
|
+
placeholder
|
|
252
|
+
} = props;
|
|
253
|
+
return /* @__PURE__ */ React.createElement(TextField, {
|
|
254
|
+
id: idSchema == null ? void 0 : idSchema.$id,
|
|
255
|
+
label: title,
|
|
256
|
+
placeholder,
|
|
257
|
+
helperText: description,
|
|
258
|
+
required,
|
|
259
|
+
value: formData != null ? formData : "",
|
|
260
|
+
onChange: ({ target: { value } }) => onChange(value),
|
|
261
|
+
margin: "normal",
|
|
262
|
+
error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !formData,
|
|
263
|
+
inputProps: { autoFocus }
|
|
264
|
+
});
|
|
265
|
+
};
|
|
268
266
|
|
|
269
267
|
const entityNamePickerValidation = (value, validation) => {
|
|
270
268
|
if (!KubernetesValidatorFunctions.isValidObjectName(value)) {
|
|
@@ -272,12 +270,9 @@ const entityNamePickerValidation = (value, validation) => {
|
|
|
272
270
|
}
|
|
273
271
|
};
|
|
274
272
|
|
|
275
|
-
const EntityTagsPicker = ({
|
|
276
|
-
formData,
|
|
277
|
-
onChange,
|
|
278
|
-
uiSchema
|
|
279
|
-
}) => {
|
|
273
|
+
const EntityTagsPicker = (props) => {
|
|
280
274
|
var _a;
|
|
275
|
+
const { formData, onChange, uiSchema } = props;
|
|
281
276
|
const catalogApi = useApi(catalogApiRef);
|
|
282
277
|
const [inputValue, setInputValue] = useState("");
|
|
283
278
|
const [inputError, setInputError] = useState(false);
|
|
@@ -334,12 +329,13 @@ const EntityTagsPicker = ({
|
|
|
334
329
|
}));
|
|
335
330
|
};
|
|
336
331
|
|
|
337
|
-
const OwnerPicker = ({
|
|
338
|
-
schema: { title = "Owner", description = "The owner of the component" },
|
|
339
|
-
uiSchema,
|
|
340
|
-
...props
|
|
341
|
-
}) => {
|
|
332
|
+
const OwnerPicker = (props) => {
|
|
342
333
|
var _a;
|
|
334
|
+
const {
|
|
335
|
+
schema: { title = "Owner", description = "The owner of the component" },
|
|
336
|
+
uiSchema,
|
|
337
|
+
...restProps
|
|
338
|
+
} = props;
|
|
343
339
|
const ownerUiSchema = {
|
|
344
340
|
...uiSchema,
|
|
345
341
|
"ui:options": {
|
|
@@ -351,7 +347,7 @@ const OwnerPicker = ({
|
|
|
351
347
|
}
|
|
352
348
|
};
|
|
353
349
|
return /* @__PURE__ */ React.createElement(EntityPicker, {
|
|
354
|
-
...
|
|
350
|
+
...restProps,
|
|
355
351
|
schema: { title, description },
|
|
356
352
|
uiSchema: ownerUiSchema
|
|
357
353
|
});
|
|
@@ -502,7 +498,7 @@ const BitbucketRepoPicker = (props) => {
|
|
|
502
498
|
const RepoUrlPickerHost = (props) => {
|
|
503
499
|
const { host, hosts, onChange, rawErrors } = props;
|
|
504
500
|
const scaffolderApi = useApi(scaffolderApiRef);
|
|
505
|
-
const { value: integrations, loading } = useAsync(async () => {
|
|
501
|
+
const { value: { integrations } = { integrations: [] }, loading } = useAsync(async () => {
|
|
506
502
|
return await scaffolderApi.getIntegrationsList({
|
|
507
503
|
allowedHosts: hosts != null ? hosts : []
|
|
508
504
|
});
|
|
@@ -700,16 +696,17 @@ const repoPickerValidation = (value, validation, context) => {
|
|
|
700
696
|
}
|
|
701
697
|
};
|
|
702
698
|
|
|
703
|
-
const OwnedEntityPicker = ({
|
|
704
|
-
onChange,
|
|
705
|
-
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
706
|
-
required,
|
|
707
|
-
uiSchema,
|
|
708
|
-
rawErrors,
|
|
709
|
-
formData,
|
|
710
|
-
idSchema
|
|
711
|
-
}) => {
|
|
699
|
+
const OwnedEntityPicker = (props) => {
|
|
712
700
|
var _a, _b;
|
|
701
|
+
const {
|
|
702
|
+
onChange,
|
|
703
|
+
schema: { title = "Entity", description = "An entity from the catalog" },
|
|
704
|
+
required,
|
|
705
|
+
uiSchema,
|
|
706
|
+
rawErrors,
|
|
707
|
+
formData,
|
|
708
|
+
idSchema
|
|
709
|
+
} = props;
|
|
713
710
|
const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
|
|
714
711
|
const defaultKind = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultKind;
|
|
715
712
|
const { ownedEntities, loading } = useOwnedEntities(allowedKinds);
|
|
@@ -807,7 +804,7 @@ const OwnerPickerFieldExtension = scaffolderPlugin.provide(createScaffolderField
|
|
|
807
804
|
}));
|
|
808
805
|
const ScaffolderPage = scaffolderPlugin.provide(createRoutableExtension({
|
|
809
806
|
name: "ScaffolderPage",
|
|
810
|
-
component: () => import('./Router-
|
|
807
|
+
component: () => import('./Router-8ca04a51.esm.js').then((m) => m.Router),
|
|
811
808
|
mountPoint: rootRouteRef
|
|
812
809
|
}));
|
|
813
810
|
const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
|
|
@@ -976,7 +973,7 @@ const TemplateList = ({
|
|
|
976
973
|
TemplateCardComponent,
|
|
977
974
|
group
|
|
978
975
|
}) => {
|
|
979
|
-
const { loading, error, entities } =
|
|
976
|
+
const { loading, error, entities } = useEntityList();
|
|
980
977
|
const Card = TemplateCardComponent || TemplateCard;
|
|
981
978
|
const maybeFilteredEntities = group ? entities.filter((e) => group.filter(e)) : entities;
|
|
982
979
|
const title = group ? group.titleComponent || /* @__PURE__ */ React.createElement(ContentHeader, {
|
|
@@ -1224,7 +1221,7 @@ const TaskPageLinks = ({ output }) => {
|
|
|
1224
1221
|
pb: 3
|
|
1225
1222
|
}, links.filter(({ url, entityRef }) => url || entityRef).map(({ url, entityRef, title, icon }) => {
|
|
1226
1223
|
if (entityRef) {
|
|
1227
|
-
const entityName =
|
|
1224
|
+
const entityName = parseEntityRef(entityRef);
|
|
1228
1225
|
const target = entityRoute(entityName);
|
|
1229
1226
|
return { title, icon, url: target };
|
|
1230
1227
|
}
|
|
@@ -1358,7 +1355,11 @@ const TaskStatusStepper = memo(({
|
|
|
1358
1355
|
})))));
|
|
1359
1356
|
})));
|
|
1360
1357
|
});
|
|
1361
|
-
const hasLinks = ({
|
|
1358
|
+
const hasLinks = ({
|
|
1359
|
+
entityRef,
|
|
1360
|
+
remoteUrl,
|
|
1361
|
+
links = []
|
|
1362
|
+
}) => !!(entityRef || remoteUrl || links.length > 0);
|
|
1362
1363
|
const TaskPage = ({ loadingText }) => {
|
|
1363
1364
|
const classes = useStyles();
|
|
1364
1365
|
const navigate = useNavigate();
|
|
@@ -1401,15 +1402,17 @@ const TaskPage = ({ loadingText }) => {
|
|
|
1401
1402
|
const taskNotFound = taskStream.completed === true && taskStream.loading === false && !taskStream.task;
|
|
1402
1403
|
const { output } = taskStream;
|
|
1403
1404
|
const handleStartOver = () => {
|
|
1404
|
-
var _a, _b;
|
|
1405
|
-
if (!taskStream.task || !((_b = (_a = taskStream.task) == null ? void 0 : _a.spec.
|
|
1405
|
+
var _a, _b, _c;
|
|
1406
|
+
if (!taskStream.task || !((_b = (_a = taskStream.task) == null ? void 0 : _a.spec.templateInfo) == null ? void 0 : _b.entityRef)) {
|
|
1406
1407
|
navigate(generatePath(rootLink()));
|
|
1408
|
+
return;
|
|
1407
1409
|
}
|
|
1408
1410
|
const formData = taskStream.task.spec.apiVersion === "backstage.io/v1beta2" ? taskStream.task.spec.values : taskStream.task.spec.parameters;
|
|
1411
|
+
const { name } = parseEntityRef((_c = taskStream.task.spec.templateInfo) == null ? void 0 : _c.entityRef);
|
|
1409
1412
|
navigate(generatePath(`${rootLink()}/templates/:templateName?${qs.stringify({
|
|
1410
1413
|
formData: JSON.stringify(formData)
|
|
1411
1414
|
})}`, {
|
|
1412
|
-
templateName:
|
|
1415
|
+
templateName: name
|
|
1413
1416
|
}));
|
|
1414
1417
|
};
|
|
1415
1418
|
return /* @__PURE__ */ React.createElement(Page, {
|
|
@@ -1452,5 +1455,5 @@ const TaskPage = ({ loadingText }) => {
|
|
|
1452
1455
|
})))))));
|
|
1453
1456
|
};
|
|
1454
1457
|
|
|
1455
|
-
export { EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, OwnerPicker as O, RepoUrlPicker as R, SecretsContext as S, TemplateTypePicker as T, EntityNamePicker as a, EntityTagsPicker as b, OwnedEntityPicker as c, registerComponentRouteRef as d, entityNamePickerValidation as e, TemplateList as f, rootRouteRef as g, FIELD_EXTENSION_KEY as h, SecretsContextProvider as i, TaskPage as j, ScaffolderClient as k, createScaffolderFieldExtension as l, ScaffolderFieldExtensions as m, EntityPickerFieldExtension as n, EntityNamePickerFieldExtension as o, EntityTagsPickerFieldExtension as p, OwnerPickerFieldExtension as q, repoPickerValidation as r, scaffolderApiRef as s, OwnedEntityPickerFieldExtension as t, RepoUrlPickerFieldExtension as u, ScaffolderPage as v, scaffolderPlugin as w,
|
|
1456
|
-
//# sourceMappingURL=index-
|
|
1458
|
+
export { EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, OwnerPicker as O, RepoUrlPicker as R, SecretsContext as S, TemplateTypePicker as T, EntityNamePicker as a, EntityTagsPicker as b, OwnedEntityPicker as c, registerComponentRouteRef as d, entityNamePickerValidation as e, TemplateList as f, rootRouteRef as g, FIELD_EXTENSION_KEY as h, SecretsContextProvider as i, TaskPage as j, ScaffolderClient as k, createScaffolderFieldExtension as l, ScaffolderFieldExtensions as m, EntityPickerFieldExtension as n, EntityNamePickerFieldExtension as o, EntityTagsPickerFieldExtension as p, OwnerPickerFieldExtension as q, repoPickerValidation as r, scaffolderApiRef as s, OwnedEntityPickerFieldExtension as t, RepoUrlPickerFieldExtension as u, ScaffolderPage as v, scaffolderPlugin as w, FavouriteTemplate as x, useTemplateSecrets as y };
|
|
1459
|
+
//# sourceMappingURL=index-7ce19edf.esm.js.map
|