@backstage/plugin-scaffolder 0.12.1-next.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/esm/{Router-82282e23.esm.js → Router-d4d39aa6.esm.js} +8 -6
- package/dist/esm/Router-d4d39aa6.esm.js.map +1 -0
- package/dist/esm/{index-9d131a26.esm.js → index-9f303a62.esm.js} +66 -20
- package/dist/esm/index-9f303a62.esm.js.map +1 -0
- package/dist/index.d.ts +24 -7
- package/dist/index.esm.js +2 -1
- package/dist/index.esm.js.map +1 -1
- package/package.json +11 -11
- package/dist/esm/Router-82282e23.esm.js.map +0 -1
- package/dist/esm/index-9d131a26.esm.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder
|
|
2
2
|
|
|
3
|
+
## 0.12.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- ba59832aed: Permission the Register Existing Component button
|
|
8
|
+
- cee44ad289: Added the ability to collect users `oauth` token from the `RepoUrlPicker` for use in the template manifest
|
|
9
|
+
- a681cb9c2f: Make linkTarget configurable for MarkdownContent component
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
- @backstage/core-components@0.8.7
|
|
12
|
+
- @backstage/plugin-catalog-react@0.6.13
|
|
13
|
+
- @backstage/plugin-catalog-common@0.1.2
|
|
14
|
+
- @backstage/integration-react@0.1.20
|
|
15
|
+
|
|
3
16
|
## 0.12.1-next.1
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React, { useState, useCallback, useEffect, memo, useMemo } from 'react';
|
|
1
|
+
import React, { useState, useContext, useCallback, useEffect, memo, useMemo } from 'react';
|
|
2
2
|
import { useNavigate, Navigate, generatePath, useParams as useParams$1, useOutlet, Routes, Route } from 'react-router';
|
|
3
3
|
import { Page, Header, Lifecycle, Content, ContentHeader, CreateButton, SupportButton, MarkdownContent, StructuredMetadataTable, InfoCard, Link, ErrorPage, LogViewer, Progress } from '@backstage/core-components';
|
|
4
4
|
import { useRouteRef, useApi, errorApiRef, useApiHolder, useApp, useElementFilter } from '@backstage/core-plugin-api';
|
|
5
5
|
import { EntityListProvider, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, entityRouteRef } from '@backstage/plugin-catalog-react';
|
|
6
6
|
import { makeStyles, Stepper, Step, StepLabel, Typography, StepContent, Button, Paper, Box, LinearProgress, Grid, StepButton, CircularProgress, 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 scaffolderApiRef, g as rootRouteRef, F as FIELD_EXTENSION_WRAPPER_KEY, h as FIELD_EXTENSION_KEY } 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 } from './index-9f303a62.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';
|
|
@@ -37,6 +37,7 @@ import '@backstage/integration-react';
|
|
|
37
37
|
import '@material-ui/core/FormHelperText';
|
|
38
38
|
import '@material-ui/core/Input';
|
|
39
39
|
import '@material-ui/core/InputLabel';
|
|
40
|
+
import 'react-use/lib/useDebounce';
|
|
40
41
|
import '@material-ui/icons/Star';
|
|
41
42
|
import '@material-ui/icons/StarBorder';
|
|
42
43
|
import '@material-ui/icons/Warning';
|
|
@@ -402,6 +403,7 @@ const TemplatePage = ({
|
|
|
402
403
|
customFieldExtensions = []
|
|
403
404
|
}) => {
|
|
404
405
|
const apiHolder = useApiHolder();
|
|
406
|
+
const secretsContext = useContext(SecretsContext);
|
|
405
407
|
const errorApi = useApi(errorApiRef);
|
|
406
408
|
const scaffolderApi = useApi(scaffolderApiRef);
|
|
407
409
|
const { templateName } = useParams();
|
|
@@ -419,7 +421,7 @@ const TemplatePage = ({
|
|
|
419
421
|
const handleChange = useCallback((e) => setFormState(e.formData), [setFormState]);
|
|
420
422
|
const handleCreate = async () => {
|
|
421
423
|
var _a;
|
|
422
|
-
const id = await scaffolderApi.scaffold(templateName, formState);
|
|
424
|
+
const id = await scaffolderApi.scaffold(templateName, formState, secretsContext == null ? void 0 : secretsContext.secrets);
|
|
423
425
|
const formParams = qs.stringify({ formData: formState }, { addQueryPrefix: true });
|
|
424
426
|
const newUrl = `${window.location.pathname}${formParams}`;
|
|
425
427
|
(_a = window.history) == null ? void 0 : _a.replaceState(null, document.title, newUrl);
|
|
@@ -995,9 +997,9 @@ const Router = ({ TemplateCardComponent, groups }) => {
|
|
|
995
997
|
})
|
|
996
998
|
}), /* @__PURE__ */ React.createElement(Route, {
|
|
997
999
|
path: "/templates/:templateName",
|
|
998
|
-
element: /* @__PURE__ */ React.createElement(TemplatePage, {
|
|
1000
|
+
element: /* @__PURE__ */ React.createElement(SecretsContextProvider, null, /* @__PURE__ */ React.createElement(TemplatePage, {
|
|
999
1001
|
customFieldExtensions: fieldExtensions
|
|
1000
|
-
})
|
|
1002
|
+
}))
|
|
1001
1003
|
}), /* @__PURE__ */ React.createElement(Route, {
|
|
1002
1004
|
path: "/tasks/:taskId",
|
|
1003
1005
|
element: /* @__PURE__ */ React.createElement(TaskPage, null)
|
|
@@ -1008,4 +1010,4 @@ const Router = ({ TemplateCardComponent, groups }) => {
|
|
|
1008
1010
|
};
|
|
1009
1011
|
|
|
1010
1012
|
export { Router };
|
|
1011
|
-
//# sourceMappingURL=Router-
|
|
1013
|
+
//# sourceMappingURL=Router-d4d39aa6.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Router-d4d39aa6.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/hooks/useEventStream.ts","../../src/components/TaskPage/IconLink.tsx","../../src/components/TaskPage/TaskPageLinks.tsx","../../src/components/TaskPage/TaskPage.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[] = [\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 { TemplateEntityV1beta2, Entity } from '@backstage/catalog-model';\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 { errorApiRef, useApi } 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 * 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 = ({\n steps,\n formData,\n onChange,\n onReset,\n onFinish,\n fields,\n widgets,\n}: Props) => {\n const [activeStep, setActiveStep] = useState(0);\n const [disableButtons, setDisableButtons] = useState(false);\n const errorApi = useApi(errorApiRef);\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';\n\nconst useTemplateParameterSchema = (templateName: string) => {\n const scaffolderApi = useApi(scaffolderApiRef);\n const { value, loading, error } = useAsync(\n () =>\n scaffolderApi.getTemplateParameterSchema({\n name: templateName,\n kind: 'template',\n namespace: 'default',\n }),\n [scaffolderApi, templateName],\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 return query.formData ?? {};\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 id = await scaffolderApi.scaffold(\n templateName,\n formState,\n 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: id }));\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 { useImmerReducer } from 'use-immer';\nimport { useEffect } from 'react';\nimport { scaffolderApiRef, LogEvent } from '../../api';\nimport { ScaffolderTask, Status, TaskOutput } from '../../types';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Subscription } from '@backstage/types';\n\ntype Step = {\n id: string;\n status: Status;\n endedAt?: string;\n startedAt?: string;\n};\n\nexport type TaskStream = {\n loading: boolean;\n error?: Error;\n stepLogs: { [stepId in string]: string[] };\n completed: boolean;\n task?: ScaffolderTask;\n steps: { [stepId in string]: Step };\n output?: TaskOutput;\n};\n\ntype ReducerLogEntry = {\n createdAt: string;\n body: {\n stepId?: string;\n status?: Status;\n message: string;\n output?: TaskOutput;\n };\n};\n\ntype ReducerAction =\n | { type: 'INIT'; data: ScaffolderTask }\n | { type: 'LOGS'; data: ReducerLogEntry[] }\n | { type: 'COMPLETED'; data: ReducerLogEntry }\n | { type: 'ERROR'; data: Error };\n\nfunction reducer(draft: TaskStream, action: ReducerAction) {\n switch (action.type) {\n case 'INIT': {\n draft.steps = action.data.spec.steps.reduce((current, next) => {\n current[next.id] = { status: 'open', id: next.id };\n return current;\n }, {} as { [stepId in string]: Step });\n draft.stepLogs = action.data.spec.steps.reduce((current, next) => {\n current[next.id] = [];\n return current;\n }, {} as { [stepId in string]: string[] });\n draft.loading = false;\n draft.error = undefined;\n draft.completed = false;\n draft.task = action.data;\n return;\n }\n\n case 'LOGS': {\n const entries = action.data;\n const logLines = [];\n\n for (const entry of entries) {\n const logLine = `${entry.createdAt} ${entry.body.message}`;\n logLines.push(logLine);\n\n if (!entry.body.stepId || !draft.steps?.[entry.body.stepId]) {\n continue;\n }\n\n const currentStepLog = draft.stepLogs?.[entry.body.stepId];\n const currentStep = draft.steps?.[entry.body.stepId];\n\n if (entry.body.status && entry.body.status !== currentStep.status) {\n currentStep.status = entry.body.status;\n\n if (currentStep.status === 'processing') {\n currentStep.startedAt = entry.createdAt;\n }\n\n if (\n ['cancelled', 'failed', 'completed'].includes(currentStep.status)\n ) {\n currentStep.endedAt = entry.createdAt;\n }\n }\n\n currentStepLog?.push(logLine);\n }\n\n return;\n }\n\n case 'COMPLETED': {\n draft.completed = true;\n draft.output = action.data.body.output;\n return;\n }\n\n case 'ERROR': {\n draft.error = action.data;\n draft.loading = false;\n draft.completed = true;\n return;\n }\n\n default:\n return;\n }\n}\n\nexport const useTaskEventStream = (taskId: string): TaskStream => {\n const scaffolderApi = useApi(scaffolderApiRef);\n const [state, dispatch] = useImmerReducer(reducer, {\n loading: true,\n completed: false,\n stepLogs: {} as { [stepId in string]: string[] },\n steps: {} as { [stepId in string]: Step },\n });\n\n useEffect(() => {\n let didCancel = false;\n let subscription: Subscription | undefined;\n let logPusher: NodeJS.Timeout | undefined;\n\n scaffolderApi.getTask(taskId).then(\n task => {\n if (didCancel) {\n return;\n }\n dispatch({ type: 'INIT', data: task });\n\n // TODO(blam): Use a normal fetch to fetch the current log for the event stream\n // and use that for an INIT_EVENTs dispatch event, and then\n // use the last event ID to subscribe using after option to\n // stream logs. Without this, if you have a lot of logs, it can look like the\n // task is being rebuilt on load as it progresses through the steps at a slower\n // rate whilst it builds the status from the event logs\n const observable = scaffolderApi.streamLogs({ taskId });\n\n const collectedLogEvents = new Array<LogEvent>();\n\n function emitLogs() {\n if (collectedLogEvents.length) {\n const logs = collectedLogEvents.splice(\n 0,\n collectedLogEvents.length,\n );\n dispatch({ type: 'LOGS', data: logs });\n }\n }\n\n logPusher = setInterval(emitLogs, 500);\n\n subscription = observable.subscribe({\n next: event => {\n switch (event.type) {\n case 'log':\n return collectedLogEvents.push(event);\n case 'completion':\n emitLogs();\n dispatch({ type: 'COMPLETED', data: event });\n return undefined;\n default:\n throw new Error(\n `Unhandled event type ${event.type} in observer`,\n );\n }\n },\n error: error => {\n emitLogs();\n dispatch({ type: 'ERROR', data: error });\n },\n });\n },\n error => {\n if (!didCancel) {\n dispatch({ type: 'ERROR', data: error });\n }\n },\n );\n\n return () => {\n didCancel = true;\n if (subscription) {\n subscription.unsubscribe();\n }\n if (logPusher) {\n clearInterval(logPusher);\n }\n };\n }, [scaffolderApi, dispatch, taskId]);\n\n return state;\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 React from 'react';\nimport { Grid, LinkProps, makeStyles, Typography } from '@material-ui/core';\nimport LanguageIcon from '@material-ui/icons/Language';\n\nimport { IconComponent } from '@backstage/core-plugin-api';\nimport { Link } from '@backstage/core-components';\n\nconst useStyles = makeStyles({\n svgIcon: {\n display: 'inline-block',\n '& svg': {\n display: 'inline-block',\n fontSize: 'inherit',\n verticalAlign: 'baseline',\n },\n },\n});\n\nexport const IconLink = (\n props: {\n href: string;\n text?: string;\n Icon?: IconComponent;\n } & LinkProps,\n) => {\n const { href, text, Icon, ...linkProps } = props;\n\n const classes = useStyles();\n\n return (\n <Grid container direction=\"row\" spacing={1}>\n <Grid item>\n <Typography component=\"div\" className={classes.svgIcon}>\n {Icon ? <Icon /> : <LanguageIcon />}\n </Typography>\n </Grid>\n <Grid item>\n <Link to={href} {...linkProps}>\n {text || href}\n </Link>\n </Grid>\n </Grid>\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 { parseEntityName } from '@backstage/catalog-model';\nimport { entityRouteRef } from '@backstage/plugin-catalog-react';\nimport { Box } from '@material-ui/core';\nimport LanguageIcon from '@material-ui/icons/Language';\nimport React from 'react';\nimport { TaskOutput } from '../../types';\nimport { IconLink } from './IconLink';\nimport { IconComponent, useApp, useRouteRef } from '@backstage/core-plugin-api';\n\ntype TaskPageLinksProps = {\n output: TaskOutput;\n};\n\nexport const TaskPageLinks = ({ output }: TaskPageLinksProps) => {\n const { entityRef: entityRefOutput, remoteUrl } = output;\n let { links = [] } = output;\n const app = useApp();\n const entityRoute = useRouteRef(entityRouteRef);\n\n const iconResolver = (key?: string): IconComponent =>\n key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon;\n\n if (remoteUrl) {\n links = [{ url: remoteUrl, title: 'Repo' }, ...links];\n }\n\n if (entityRefOutput) {\n links = [\n {\n entityRef: entityRefOutput,\n title: 'Open in catalog',\n icon: 'catalog',\n },\n ...links,\n ];\n }\n\n return (\n <Box px={3} pb={3}>\n {links\n .filter(({ url, entityRef }) => url || entityRef)\n .map(({ url, entityRef, title, icon }) => {\n if (entityRef) {\n const entityName = parseEntityName(entityRef);\n const target = entityRoute(entityName);\n return { title, icon, url: target };\n }\n return { title, icon, url: url! };\n })\n .map(({ url, title, icon }, i) => (\n <IconLink\n key={`output-link-${i}`}\n href={url}\n text={title ?? url}\n Icon={iconResolver(icon)}\n target=\"_blank\"\n />\n ))}\n </Box>\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 {\n Content,\n ErrorPage,\n Header,\n Lifecycle,\n Page,\n LogViewer,\n} from '@backstage/core-components';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport { BackstageTheme } from '@backstage/theme';\nimport {\n Button,\n CircularProgress,\n Paper,\n StepButton,\n StepIconProps,\n} from '@material-ui/core';\nimport Grid from '@material-ui/core/Grid';\nimport Step from '@material-ui/core/Step';\nimport StepLabel from '@material-ui/core/StepLabel';\nimport Stepper from '@material-ui/core/Stepper';\nimport { createStyles, makeStyles, Theme } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport Cancel from '@material-ui/icons/Cancel';\nimport Check from '@material-ui/icons/Check';\nimport FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';\nimport classNames from 'classnames';\nimport { DateTime, Interval } from 'luxon';\nimport qs from 'qs';\nimport React, { memo, useEffect, useMemo, useState } from 'react';\nimport { generatePath, useNavigate, useParams } from 'react-router';\nimport useInterval from 'react-use/lib/useInterval';\nimport { rootRouteRef } from '../../routes';\nimport { Status, TaskOutput } from '../../types';\nimport { useTaskEventStream } from '../hooks/useEventStream';\nimport { TaskPageLinks } from './TaskPageLinks';\n\n// typings are wrong for this library, so fallback to not parsing types.\nconst humanizeDuration = require('humanize-duration');\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n width: '100%',\n },\n button: {\n marginBottom: theme.spacing(2),\n marginLeft: theme.spacing(2),\n },\n actionsContainer: {\n marginBottom: theme.spacing(2),\n },\n resetContainer: {\n padding: theme.spacing(3),\n },\n labelWrapper: {\n display: 'flex',\n flex: 1,\n flexDirection: 'row',\n justifyContent: 'space-between',\n },\n stepWrapper: {\n width: '100%',\n },\n }),\n);\n\ntype TaskStep = {\n id: string;\n name: string;\n status: Status;\n startedAt?: string;\n endedAt?: string;\n};\n\nconst StepTimeTicker = ({ step }: { step: TaskStep }) => {\n const [time, setTime] = useState('');\n\n useInterval(() => {\n if (!step.startedAt) {\n setTime('');\n return;\n }\n\n const end = step.endedAt\n ? DateTime.fromISO(step.endedAt)\n : DateTime.local();\n\n const startedAt = DateTime.fromISO(step.startedAt);\n const formatted = Interval.fromDateTimes(startedAt, end)\n .toDuration()\n .valueOf();\n\n setTime(humanizeDuration(formatted, { round: true }));\n }, 1000);\n\n return <Typography variant=\"caption\">{time}</Typography>;\n};\n\nconst useStepIconStyles = makeStyles((theme: BackstageTheme) =>\n createStyles({\n root: {\n color: theme.palette.text.disabled,\n display: 'flex',\n height: 22,\n alignItems: 'center',\n },\n completed: {\n color: theme.palette.status.ok,\n },\n error: {\n color: theme.palette.status.error,\n },\n }),\n);\n\nfunction TaskStepIconComponent(props: StepIconProps) {\n const classes = useStepIconStyles();\n const { active, completed, error } = props;\n\n const getMiddle = () => {\n if (active) {\n return <CircularProgress size=\"24px\" />;\n }\n if (completed) {\n return <Check />;\n }\n if (error) {\n return <Cancel />;\n }\n return <FiberManualRecordIcon />;\n };\n\n return (\n <div\n className={classNames(classes.root, {\n [classes.completed]: completed,\n [classes.error]: error,\n })}\n >\n {getMiddle()}\n </div>\n );\n}\n\nexport const TaskStatusStepper = memo(\n ({\n steps,\n currentStepId,\n onUserStepChange,\n }: {\n steps: TaskStep[];\n currentStepId: string | undefined;\n onUserStepChange: (id: string) => void;\n }) => {\n const classes = useStyles();\n\n return (\n <div className={classes.root}>\n <Stepper\n activeStep={steps.findIndex(s => s.id === currentStepId)}\n orientation=\"vertical\"\n nonLinear\n >\n {steps.map((step, index) => {\n const isCompleted = step.status === 'completed';\n const isFailed = step.status === 'failed';\n const isActive = step.status === 'processing';\n const isSkipped = step.status === 'skipped';\n\n return (\n <Step key={String(index)} expanded>\n <StepButton onClick={() => onUserStepChange(step.id)}>\n <StepLabel\n StepIconProps={{\n completed: isCompleted,\n error: isFailed,\n active: isActive,\n }}\n StepIconComponent={TaskStepIconComponent}\n className={classes.stepWrapper}\n >\n <div className={classes.labelWrapper}>\n <Typography variant=\"subtitle2\">{step.name}</Typography>\n {isSkipped ? (\n <Typography variant=\"caption\">Skipped</Typography>\n ) : (\n <StepTimeTicker step={step} />\n )}\n </div>\n </StepLabel>\n </StepButton>\n </Step>\n );\n })}\n </Stepper>\n </div>\n );\n },\n);\n\nconst hasLinks = ({ entityRef, remoteUrl, links = [] }: TaskOutput): boolean =>\n !!(entityRef || remoteUrl || links.length > 0);\n\nexport const TaskPage = () => {\n const classes = useStyles();\n const navigate = useNavigate();\n const rootLink = useRouteRef(rootRouteRef);\n const [userSelectedStepId, setUserSelectedStepId] = useState<\n string | undefined\n >(undefined);\n const [lastActiveStepId, setLastActiveStepId] = useState<string | undefined>(\n undefined,\n );\n const { taskId } = useParams();\n const taskStream = useTaskEventStream(taskId);\n const completed = taskStream.completed;\n const steps = useMemo(\n () =>\n taskStream.task?.spec.steps.map(step => ({\n ...step,\n ...taskStream?.steps?.[step.id],\n })) ?? [],\n [taskStream],\n );\n\n useEffect(() => {\n const mostRecentFailedOrActiveStep = steps.find(step =>\n ['failed', 'processing'].includes(step.status),\n );\n if (completed && !mostRecentFailedOrActiveStep) {\n setLastActiveStepId(steps[steps.length - 1]?.id);\n return;\n }\n\n setLastActiveStepId(mostRecentFailedOrActiveStep?.id);\n }, [steps, completed]);\n\n const currentStepId = userSelectedStepId ?? lastActiveStepId;\n\n const logAsString = useMemo(() => {\n if (!currentStepId) {\n return 'Loading...';\n }\n const log = taskStream.stepLogs[currentStepId];\n\n if (!log?.length) {\n return 'Waiting for logs...';\n }\n return log.join('\\n');\n }, [taskStream.stepLogs, currentStepId]);\n\n const taskNotFound =\n taskStream.completed === true &&\n taskStream.loading === false &&\n !taskStream.task;\n\n const { output } = taskStream;\n\n const handleStartOver = () => {\n if (!taskStream.task || !taskStream.task?.spec.metadata?.name) {\n navigate(generatePath(rootLink()));\n }\n\n const formData =\n taskStream.task!.spec.apiVersion === 'backstage.io/v1beta2'\n ? taskStream.task!.spec.values\n : taskStream.task!.spec.parameters;\n\n navigate(\n generatePath(\n `${rootLink()}/templates/:templateName?${qs.stringify({ formData })}`,\n {\n templateName: taskStream.task!.spec.metadata!.name,\n },\n ),\n );\n };\n\n return (\n <Page themeId=\"home\">\n <Header\n pageTitleOverride={`Task ${taskId}`}\n title={\n <>\n Task Activity <Lifecycle alpha shorthand />\n </>\n }\n subtitle={`Activity for task: ${taskId}`}\n />\n <Content>\n {taskNotFound ? (\n <ErrorPage\n status=\"404\"\n statusMessage=\"Task not found\"\n additionalInfo=\"No task found with this ID\"\n />\n ) : (\n <div>\n <Grid container>\n <Grid item xs={3}>\n <Paper>\n <TaskStatusStepper\n steps={steps}\n currentStepId={currentStepId}\n onUserStepChange={setUserSelectedStepId}\n />\n {output && hasLinks(output) && (\n <TaskPageLinks output={output} />\n )}\n <Button\n className={classes.button}\n onClick={handleStartOver}\n disabled={!completed}\n variant=\"contained\"\n color=\"primary\"\n >\n Start Over\n </Button>\n </Paper>\n </Grid>\n <Grid item xs={9}>\n <div style={{ height: '80vh' }}>\n <LogViewer text={logAsString} />\n </div>\n </Grid>\n </Grid>\n </div>\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 { JSONSchema } from '@backstage/catalog-model';\nimport { 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: JSONSchema) => {\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 JSONSchema;\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: JSONSchema) => {\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 JSONSchema)}</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 { TemplateEntityV1beta2, Entity } from '@backstage/catalog-model';\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 groups?: Array<{\n title?: string;\n titleComponent?: React.ReactNode;\n filter: (entity: Entity) => boolean;\n }>;\n};\n\nexport const Router = ({ TemplateCardComponent, groups }: RouterProps) => {\n const outlet = useOutlet();\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={<TaskPage />} />\n <Route path=\"/actions\" element={<ActionsPage />} />\n </Routes>\n );\n};\n"],"names":["useStyles","isObject","MuiTheme","StepUI","makeStyles","Typography","Stepper","Step","StepLabel","useParams","Grid"],"mappings":"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"}
|
|
@@ -6,16 +6,17 @@ import { catalogApiRef, formatEntityRefTitle, useOwnedEntities, useStarredEntity
|
|
|
6
6
|
import { TextField, FormControl as FormControl$1, withStyles, makeStyles, IconButton, Tooltip, useTheme, Card, CardMedia, CardContent, Box, Typography, Chip, CardActions, Link, FormControlLabel, Checkbox } from '@material-ui/core';
|
|
7
7
|
import FormControl from '@material-ui/core/FormControl';
|
|
8
8
|
import Autocomplete from '@material-ui/lab/Autocomplete';
|
|
9
|
-
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
|
9
|
+
import React, { useCallback, useEffect, useState, createContext, useContext, useMemo } from 'react';
|
|
10
10
|
import useAsync from 'react-use/lib/useAsync';
|
|
11
11
|
import { KubernetesValidatorFunctions, makeValidator, RELATION_OWNED_BY, stringifyEntityRef } 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
|
-
import { scmIntegrationsApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
|
|
14
|
+
import { scmIntegrationsApiRef, scmAuthApiRef, ScmIntegrationIcon } from '@backstage/integration-react';
|
|
15
15
|
import FormHelperText from '@material-ui/core/FormHelperText';
|
|
16
16
|
import Input from '@material-ui/core/Input';
|
|
17
17
|
import InputLabel from '@material-ui/core/InputLabel';
|
|
18
18
|
import { Select, Progress, ItemCardHeader, Button, ContentHeader, WarningPanel, Link as Link$1, Content, ItemCardGrid } from '@backstage/core-components';
|
|
19
|
+
import useDebounce from 'react-use/lib/useDebounce';
|
|
19
20
|
import Star from '@material-ui/icons/Star';
|
|
20
21
|
import StarBorder from '@material-ui/icons/StarBorder';
|
|
21
22
|
import WarningIcon from '@material-ui/icons/Warning';
|
|
@@ -493,11 +494,15 @@ const RepoUrlPickerHost = (props) => {
|
|
|
493
494
|
});
|
|
494
495
|
});
|
|
495
496
|
useEffect(() => {
|
|
496
|
-
if (
|
|
497
|
-
|
|
497
|
+
if (!host) {
|
|
498
|
+
if (hosts == null ? void 0 : hosts.length) {
|
|
499
|
+
onChange(hosts[0]);
|
|
500
|
+
} else if (integrations == null ? void 0 : integrations.length) {
|
|
501
|
+
onChange(integrations[0].host);
|
|
502
|
+
}
|
|
498
503
|
}
|
|
499
|
-
}, [hosts, host, onChange]);
|
|
500
|
-
const hostsOptions = integrations ? integrations.filter((i) => hosts == null ? void 0 : hosts.includes(i.host)).map((i) => ({ label: i.title, value: i.host })) : [{ label: "Loading...", value: "loading" }];
|
|
504
|
+
}, [hosts, host, onChange, integrations]);
|
|
505
|
+
const hostsOptions = integrations ? integrations.filter((i) => (hosts == null ? void 0 : hosts.length) ? hosts == null ? void 0 : hosts.includes(i.host) : true).map((i) => ({ label: i.title, value: i.host })) : [{ label: "Loading...", value: "loading" }];
|
|
501
506
|
if (loading) {
|
|
502
507
|
return /* @__PURE__ */ React.createElement(Progress, null);
|
|
503
508
|
}
|
|
@@ -539,32 +544,53 @@ function serializeRepoPickerUrl(data) {
|
|
|
539
544
|
return `${data.host}?${params.toString()}`;
|
|
540
545
|
}
|
|
541
546
|
function parseRepoPickerUrl(url) {
|
|
542
|
-
let host =
|
|
543
|
-
let owner =
|
|
544
|
-
let repoName =
|
|
545
|
-
let organization =
|
|
546
|
-
let workspace =
|
|
547
|
-
let project =
|
|
547
|
+
let host = "";
|
|
548
|
+
let owner = "";
|
|
549
|
+
let repoName = "";
|
|
550
|
+
let organization = "";
|
|
551
|
+
let workspace = "";
|
|
552
|
+
let project = "";
|
|
548
553
|
try {
|
|
549
554
|
if (url) {
|
|
550
555
|
const parsed = new URL(`https://${url}`);
|
|
551
556
|
host = parsed.host;
|
|
552
|
-
owner = parsed.searchParams.get("owner") ||
|
|
553
|
-
repoName = parsed.searchParams.get("repo") ||
|
|
554
|
-
organization = parsed.searchParams.get("organization") ||
|
|
555
|
-
workspace = parsed.searchParams.get("workspace") ||
|
|
556
|
-
project = parsed.searchParams.get("project") ||
|
|
557
|
+
owner = parsed.searchParams.get("owner") || "";
|
|
558
|
+
repoName = parsed.searchParams.get("repo") || "";
|
|
559
|
+
organization = parsed.searchParams.get("organization") || "";
|
|
560
|
+
workspace = parsed.searchParams.get("workspace") || "";
|
|
561
|
+
project = parsed.searchParams.get("project") || "";
|
|
557
562
|
}
|
|
558
563
|
} catch {
|
|
559
564
|
}
|
|
560
565
|
return { host, owner, repoName, organization, workspace, project };
|
|
561
566
|
}
|
|
562
567
|
|
|
568
|
+
const SecretsContext = createContext(void 0);
|
|
569
|
+
const SecretsContextProvider = ({ children }) => {
|
|
570
|
+
const [secrets, setSecrets] = useState({});
|
|
571
|
+
return /* @__PURE__ */ React.createElement(SecretsContext.Provider, {
|
|
572
|
+
value: { secrets, setSecrets }
|
|
573
|
+
}, children);
|
|
574
|
+
};
|
|
575
|
+
const useTemplateSecrets = () => {
|
|
576
|
+
const value = useContext(SecretsContext);
|
|
577
|
+
if (!value) {
|
|
578
|
+
throw new Error("useTemplateSecrets must be used within a SecretsContextProvider");
|
|
579
|
+
}
|
|
580
|
+
const { setSecrets } = value;
|
|
581
|
+
const setSecret = useCallback((input) => {
|
|
582
|
+
setSecrets((currentSecrets) => ({ ...currentSecrets, ...input }));
|
|
583
|
+
}, [setSecrets]);
|
|
584
|
+
return { setSecret };
|
|
585
|
+
};
|
|
586
|
+
|
|
563
587
|
const RepoUrlPicker = (props) => {
|
|
564
588
|
var _a, _b;
|
|
565
589
|
const { uiSchema, onChange, rawErrors, formData } = props;
|
|
566
590
|
const [state, setState] = useState(parseRepoPickerUrl(formData));
|
|
567
591
|
const integrationApi = useApi(scmIntegrationsApiRef);
|
|
592
|
+
const scmAuthApi = useApi(scmAuthApiRef);
|
|
593
|
+
const { setSecret } = useTemplateSecrets();
|
|
568
594
|
const allowedHosts = useMemo(() => {
|
|
569
595
|
var _a2, _b2;
|
|
570
596
|
return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedHosts) != null ? _b2 : [];
|
|
@@ -584,6 +610,26 @@ const RepoUrlPicker = (props) => {
|
|
|
584
610
|
const updateLocalState = useCallback((newState) => {
|
|
585
611
|
setState((prevState) => ({ ...prevState, ...newState }));
|
|
586
612
|
}, [setState]);
|
|
613
|
+
useDebounce(async () => {
|
|
614
|
+
var _a2;
|
|
615
|
+
const { requestUserCredentials } = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) != null ? _a2 : {};
|
|
616
|
+
if (!requestUserCredentials || !(state.host && state.owner && state.repoName)) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
const [host, owner, repoName] = [
|
|
620
|
+
state.host,
|
|
621
|
+
state.owner,
|
|
622
|
+
state.repoName
|
|
623
|
+
].map(encodeURIComponent);
|
|
624
|
+
const { token } = await scmAuthApi.getCredentials({
|
|
625
|
+
url: `https://${host}/${owner}/${repoName}`,
|
|
626
|
+
additionalScope: {
|
|
627
|
+
repoWrite: true,
|
|
628
|
+
customScopes: requestUserCredentials.additionalScopes
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
setSecret({ [requestUserCredentials.secretsKey]: token });
|
|
632
|
+
}, 500, [state, uiSchema]);
|
|
587
633
|
const hostType = (_b = state.host && ((_a = integrationApi.byHost(state.host)) == null ? void 0 : _a.type)) != null ? _b : null;
|
|
588
634
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(RepoUrlPickerHost, {
|
|
589
635
|
host: state.host,
|
|
@@ -747,7 +793,7 @@ const OwnerPickerFieldExtension = scaffolderPlugin.provide(createScaffolderField
|
|
|
747
793
|
}));
|
|
748
794
|
const ScaffolderPage = scaffolderPlugin.provide(createRoutableExtension({
|
|
749
795
|
name: "ScaffolderPage",
|
|
750
|
-
component: () => import('./Router-
|
|
796
|
+
component: () => import('./Router-d4d39aa6.esm.js').then((m) => m.Router),
|
|
751
797
|
mountPoint: rootRouteRef
|
|
752
798
|
}));
|
|
753
799
|
const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
|
|
@@ -989,5 +1035,5 @@ const TemplateTypePicker = () => {
|
|
|
989
1035
|
}));
|
|
990
1036
|
};
|
|
991
1037
|
|
|
992
|
-
export { EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, OwnerPicker as O, RepoUrlPicker as R,
|
|
993
|
-
//# sourceMappingURL=index-
|
|
1038
|
+
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, ScaffolderClient as j, createScaffolderFieldExtension as k, ScaffolderFieldExtensions as l, EntityPickerFieldExtension as m, EntityNamePickerFieldExtension as n, EntityTagsPickerFieldExtension as o, OwnerPickerFieldExtension as p, OwnedEntityPickerFieldExtension as q, repoPickerValidation as r, scaffolderApiRef as s, RepoUrlPickerFieldExtension as t, ScaffolderPage as u, scaffolderPlugin as v, TextValuePicker as w, FavouriteTemplate as x, useTemplateSecrets as y };
|
|
1039
|
+
//# sourceMappingURL=index-9f303a62.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-9f303a62.esm.js","sources":["../../src/api.ts","../../src/components/fields/EntityPicker/EntityPicker.tsx","../../src/components/fields/TextValuePicker/TextValuePicker.tsx","../../src/components/fields/EntityNamePicker/EntityNamePicker.tsx","../../src/components/fields/EntityNamePicker/validation.ts","../../src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx","../../src/components/fields/OwnerPicker/OwnerPicker.tsx","../../src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx","../../src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx","../../src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx","../../src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx","../../src/components/fields/RepoUrlPicker/RepoUrlPickerHost.tsx","../../src/components/fields/RepoUrlPicker/utils.ts","../../src/components/secrets/SecretsContext.tsx","../../src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx","../../src/components/fields/RepoUrlPicker/validation.ts","../../src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx","../../src/extensions/index.tsx","../../src/routes.ts","../../src/plugin.ts","../../src/components/FavouriteTemplate/FavouriteTemplate.tsx","../../src/components/TemplateCard/TemplateCard.tsx","../../src/components/TemplateList/TemplateList.tsx","../../src/components/TemplateTypePicker/TemplateTypePicker.tsx"],"sourcesContent":["/*\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 { EntityName } from '@backstage/catalog-model';\nimport {\n createApiRef,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport { Field, FieldValidation } from '@rjsf/core';\nimport qs from 'qs';\nimport ObservableImpl from 'zen-observable';\nimport { ListActionsResponse, ScaffolderTask, Status } from './types';\n\n/**\n * Utility API reference for the {@link ScaffolderApi}.\n *\n * @public\n */\nexport const scaffolderApiRef = createApiRef<ScaffolderApi>({\n id: 'plugin.scaffolder.service',\n});\n\ntype TemplateParameterSchema = {\n title: string;\n steps: Array<{\n title: string;\n schema: JsonObject;\n }>;\n};\n\nexport type LogEvent = {\n type: 'log' | 'completion';\n body: {\n message: string;\n stepId?: string;\n status?: Status;\n };\n createdAt: string;\n id: string;\n taskId: string;\n};\n\nexport type CustomField = {\n name: string;\n component: Field;\n validation: (data: JsonValue, field: FieldValidation) => void;\n};\n\n/**\n * An API to interact with the scaffolder backend.\n *\n * @public\n */\nexport interface ScaffolderApi {\n getTemplateParameterSchema(\n templateName: EntityName,\n ): Promise<TemplateParameterSchema>;\n\n /**\n * Executes the scaffolding of a component, given a template and its\n * parameter values.\n *\n * @param templateName - Name of the Template entity for the scaffolder to use. New project is going to be created out of this template.\n * @param values - Parameters for the template, e.g. name, description\n * @param secrets - Optional secrets to pass to as the secrets parameter to the template.\n */\n scaffold(\n templateName: string,\n values: Record<string, any>,\n secrets?: Record<string, string>,\n ): Promise<string>;\n\n getTask(taskId: string): Promise<ScaffolderTask>;\n\n getIntegrationsList(options: {\n allowedHosts: string[];\n }): Promise<{ type: string; title: string; host: string }[]>;\n\n /**\n * Returns a list of all installed actions.\n */\n listActions(): Promise<ListActionsResponse>;\n\n streamLogs(options: { taskId: string; after?: number }): Observable<LogEvent>;\n}\n\n/**\n * An API to interact with the scaffolder backend.\n *\n * @public\n */\nexport class ScaffolderClient implements ScaffolderApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly scmIntegrationsApi: ScmIntegrationRegistry;\n private readonly fetchApi: FetchApi;\n private readonly useLongPollingLogs: boolean;\n\n constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n scmIntegrationsApi: ScmIntegrationRegistry;\n useLongPollingLogs?: boolean;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi ?? { fetch };\n this.scmIntegrationsApi = options.scmIntegrationsApi;\n this.useLongPollingLogs = options.useLongPollingLogs ?? false;\n }\n\n async getIntegrationsList(options: { allowedHosts: string[] }) {\n return [\n ...this.scmIntegrationsApi.azure.list(),\n ...this.scmIntegrationsApi.bitbucket.list(),\n ...this.scmIntegrationsApi.github.list(),\n ...this.scmIntegrationsApi.gitlab.list(),\n ]\n .map(c => ({ type: c.type, title: c.title, host: c.config.host }))\n .filter(c => options.allowedHosts.includes(c.host));\n }\n\n async getTemplateParameterSchema(\n templateName: EntityName,\n ): Promise<TemplateParameterSchema> {\n const { namespace, kind, name } = templateName;\n\n const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder');\n const templatePath = [namespace, kind, name]\n .map(s => encodeURIComponent(s))\n .join('/');\n const url = `${baseUrl}/v2/templates/${templatePath}/parameter-schema`;\n\n const response = await this.fetchApi.fetch(url);\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const schema: TemplateParameterSchema = await response.json();\n return schema;\n }\n\n /**\n * Executes the scaffolding of a component, given a template and its\n * parameter values.\n *\n * @param templateName - Template name for the scaffolder to use. New project is going to be created out of this template.\n * @param values - Parameters for the template, e.g. name, description\n * @param secrets - Optional secrets to pass to as the secrets parameter to the template.\n */\n async scaffold(\n templateName: string,\n values: Record<string, any>,\n secrets: Record<string, string> = {},\n ): Promise<string> {\n const url = `${await this.discoveryApi.getBaseUrl('scaffolder')}/v2/tasks`;\n const response = await this.fetchApi.fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n templateName,\n values: { ...values },\n secrets,\n }),\n });\n\n if (response.status !== 201) {\n const status = `${response.status} ${response.statusText}`;\n const body = await response.text();\n throw new Error(`Backend request failed, ${status} ${body.trim()}`);\n }\n\n const { id } = (await response.json()) as { id: string };\n return id;\n }\n\n async getTask(taskId: string) {\n const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder');\n const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`;\n\n const response = await this.fetchApi.fetch(url);\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n streamLogs(options: {\n taskId: string;\n after?: number;\n }): Observable<LogEvent> {\n if (this.useLongPollingLogs) {\n return this.streamLogsPolling(options);\n }\n\n return this.streamLogsEventStream(options);\n }\n\n private streamLogsEventStream({\n taskId,\n after,\n }: {\n taskId: string;\n after?: number;\n }): Observable<LogEvent> {\n return new ObservableImpl(subscriber => {\n const params = new URLSearchParams();\n if (after !== undefined) {\n params.set('after', String(Number(after)));\n }\n\n this.discoveryApi.getBaseUrl('scaffolder').then(\n baseUrl => {\n const url = `${baseUrl}/v2/tasks/${encodeURIComponent(\n taskId,\n )}/eventstream`;\n const eventSource = new EventSource(url, { withCredentials: true });\n eventSource.addEventListener('log', (event: any) => {\n if (event.data) {\n try {\n subscriber.next(JSON.parse(event.data));\n } catch (ex) {\n subscriber.error(ex);\n }\n }\n });\n eventSource.addEventListener('completion', (event: any) => {\n if (event.data) {\n try {\n subscriber.next(JSON.parse(event.data));\n } catch (ex) {\n subscriber.error(ex);\n }\n }\n eventSource.close();\n subscriber.complete();\n });\n eventSource.addEventListener('error', event => {\n subscriber.error(event);\n });\n },\n error => {\n subscriber.error(error);\n },\n );\n });\n }\n\n private streamLogsPolling({\n taskId,\n after: inputAfter,\n }: {\n taskId: string;\n after?: number;\n }): Observable<LogEvent> {\n let after = inputAfter;\n\n return new ObservableImpl(subscriber => {\n this.discoveryApi.getBaseUrl('scaffolder').then(async baseUrl => {\n while (!subscriber.closed) {\n const url = `${baseUrl}/v2/tasks/${encodeURIComponent(\n taskId,\n )}/events?${qs.stringify({ after })}`;\n const response = await this.fetchApi.fetch(url);\n\n if (!response.ok) {\n // wait for one second to not run into an\n await new Promise(resolve => setTimeout(resolve, 1000));\n continue;\n }\n\n const logs = (await response.json()) as LogEvent[];\n\n for (const event of logs) {\n after = Number(event.id);\n\n subscriber.next(event);\n\n if (event.type === 'completion') {\n subscriber.complete();\n return;\n }\n }\n }\n });\n });\n }\n\n async listActions(): Promise<ListActionsResponse> {\n const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder');\n const response = await this.fetchApi.fetch(`${baseUrl}/v2/actions`);\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\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 { useApi } from '@backstage/core-plugin-api';\nimport {\n catalogApiRef,\n formatEntityRefTitle,\n} from '@backstage/plugin-catalog-react';\nimport { TextField } from '@material-ui/core';\nimport FormControl from '@material-ui/core/FormControl';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport { FieldProps, UiSchema } from '@rjsf/core';\nimport React, { useCallback, useEffect } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\n\nexport const allowArbitraryValues = (uiSchema: UiSchema): boolean =>\n (uiSchema['ui:options']?.allowArbitraryValues as boolean) ?? true;\n\nexport const EntityPicker = ({\n onChange,\n schema: { title = 'Entity', description = 'An entity from the catalog' },\n required,\n uiSchema,\n rawErrors,\n formData,\n idSchema,\n}: FieldProps<string>) => {\n const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[];\n const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined;\n const catalogApi = useApi(catalogApiRef);\n\n const { value: entities, loading } = useAsync(() =>\n catalogApi.getEntities(\n allowedKinds ? { filter: { kind: allowedKinds } } : undefined,\n ),\n );\n\n const entityRefs = entities?.items.map(e =>\n formatEntityRefTitle(e, { defaultKind }),\n );\n\n const onSelect = useCallback(\n (_: any, value: string | null) => {\n onChange(value || '');\n },\n [onChange],\n );\n\n useEffect(() => {\n if (entityRefs?.length === 1) {\n onChange(entityRefs[0]);\n }\n }, [entityRefs, onChange]);\n\n return (\n <FormControl\n margin=\"normal\"\n required={required}\n error={rawErrors?.length > 0 && !formData}\n >\n <Autocomplete\n disabled={entityRefs?.length === 1}\n id={idSchema?.$id}\n value={(formData as string) || ''}\n loading={loading}\n onChange={onSelect}\n options={entityRefs || []}\n autoSelect\n freeSolo={allowArbitraryValues(uiSchema)}\n renderInput={params => (\n <TextField\n {...params}\n label={title}\n margin=\"normal\"\n helperText={description}\n variant=\"outlined\"\n required={required}\n InputProps={params.InputProps}\n />\n )}\n />\n </FormControl>\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 { TextField } from '@material-ui/core';\nimport { FieldProps } from '@rjsf/core';\nimport React from 'react';\n\nexport const TextValuePicker = ({\n onChange,\n required,\n schema: { title, description },\n rawErrors,\n formData,\n uiSchema: { 'ui:autofocus': autoFocus },\n idSchema,\n placeholder,\n}: FieldProps<string>) => (\n <TextField\n id={idSchema?.$id}\n label={title}\n placeholder={placeholder}\n helperText={description}\n required={required}\n value={formData ?? ''}\n onChange={({ target: { value } }) => onChange(value)}\n margin=\"normal\"\n error={rawErrors?.length > 0 && !formData}\n inputProps={{ autoFocus }}\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 { FieldProps } from '@rjsf/core';\nimport { TextValuePicker } from '../TextValuePicker';\n\nexport const EntityNamePicker = ({\n schema: { title = 'Name', description = 'Unique name of the component' },\n ...props\n}: FieldProps<string>) => (\n <TextValuePicker schema={{ title, description }} {...props} />\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 { FieldValidation } from '@rjsf/core';\nimport { KubernetesValidatorFunctions } from '@backstage/catalog-model';\n\nexport const entityNamePickerValidation = (\n value: string,\n validation: FieldValidation,\n) => {\n if (!KubernetesValidatorFunctions.isValidObjectName(value)) {\n validation.addError(\n 'must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.',\n );\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, { useState } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport useEffectOnce from 'react-use/lib/useEffectOnce';\nimport { CatalogEntitiesRequest } from '@backstage/catalog-client';\nimport { Entity, makeValidator } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { FormControl, TextField } from '@material-ui/core';\nimport { Autocomplete } from '@material-ui/lab';\nimport { FieldProps } from '@rjsf/core';\n\n/**\n * EntityTagsPicker\n * @public\n */\nexport const EntityTagsPicker = ({\n formData,\n onChange,\n uiSchema,\n}: FieldProps<string[]>) => {\n const catalogApi = useApi(catalogApiRef);\n const [inputValue, setInputValue] = useState('');\n const [inputError, setInputError] = useState(false);\n const tagValidator = makeValidator().isValidTag;\n const kinds = uiSchema['ui:options']?.kinds as string[];\n\n const { loading, value: existingTags } = useAsync(async () => {\n const tagsRequest: CatalogEntitiesRequest = { fields: ['metadata.tags'] };\n if (kinds) {\n tagsRequest.filter = { kind: kinds };\n }\n\n const entities = await catalogApi.getEntities(tagsRequest);\n\n return [\n ...new Set(\n entities.items\n .flatMap((e: Entity) => e.metadata?.tags)\n .filter(Boolean) as string[],\n ),\n ].sort();\n });\n\n const setTags = (_: React.ChangeEvent<{}>, values: string[] | null) => {\n // Reset error state in case all tags were removed\n let hasError = false;\n let addDuplicate = false;\n const currentTags = formData || [];\n\n // If adding a new tag\n if (values?.length && currentTags.length < values.length) {\n const newTag = (values[values.length - 1] = values[values.length - 1]\n .toLocaleLowerCase('en-US')\n .trim());\n hasError = !tagValidator(newTag);\n addDuplicate = currentTags.indexOf(newTag) !== -1;\n }\n\n setInputError(hasError);\n setInputValue(!hasError ? '' : inputValue);\n if (!hasError && !addDuplicate) {\n onChange(values || []);\n }\n };\n\n // Initialize field to always return an array\n useEffectOnce(() => onChange(formData || []));\n\n return (\n <FormControl margin=\"normal\">\n <Autocomplete\n multiple\n freeSolo\n filterSelectedOptions\n onChange={setTags}\n value={formData || []}\n inputValue={inputValue}\n loading={loading}\n options={existingTags || []}\n ChipProps={{ size: 'small' }}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Tags\"\n onChange={e => setInputValue(e.target.value)}\n error={inputError}\n helperText=\"Add any relevant tags, hit 'Enter' to add new tags. Valid format: [a-z0-9+#] separated by [-], at most 63 characters\"\n />\n )}\n />\n </FormControl>\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 { FieldProps } from '@rjsf/core';\nimport React from 'react';\nimport { EntityPicker } from '../EntityPicker';\n\nexport const OwnerPicker = ({\n schema: { title = 'Owner', description = 'The owner of the component' },\n uiSchema,\n ...props\n}: FieldProps<string>) => {\n const ownerUiSchema = {\n ...uiSchema,\n 'ui:options': {\n allowedKinds: (uiSchema['ui:options']?.allowedKinds || [\n 'Group',\n 'User',\n ]) as string[],\n defaultKind: 'Group',\n },\n };\n\n return (\n <EntityPicker\n {...props}\n schema={{ title, description }}\n uiSchema={ownerUiSchema}\n />\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 FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport { Select, SelectItem } from '@backstage/core-components';\nimport { RepoUrlPickerState } from './types';\n\nexport const GithubRepoPicker = (props: {\n allowedOwners?: string[];\n rawErrors: string[];\n state: RepoUrlPickerState;\n onChange: (state: RepoUrlPickerState) => void;\n}) => {\n const { allowedOwners = [], rawErrors, state, onChange } = props;\n const ownerItems: SelectItem[] = allowedOwners\n ? allowedOwners.map(i => ({ label: i, value: i }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n const { owner, repoName } = state;\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !owner}\n >\n {allowedOwners?.length ? (\n <Select\n native\n label=\"Owner Available\"\n onChange={s =>\n onChange({ owner: String(Array.isArray(s) ? s[0] : s) })\n }\n disabled={allowedOwners.length === 1}\n selected={owner}\n items={ownerItems}\n />\n ) : (\n <>\n <InputLabel htmlFor=\"ownerInput\">Owner</InputLabel>\n <Input\n id=\"ownerInput\"\n onChange={e => onChange({ owner: e.target.value })}\n value={owner}\n />\n </>\n )}\n <FormHelperText>\n The organization, user or project that this repo will belong to\n </FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange({ repoName: e.target.value })}\n value={repoName}\n />\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\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 FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport { Select, SelectItem } from '@backstage/core-components';\nimport { RepoUrlPickerState } from './types';\n\nexport const GitlabRepoPicker = (props: {\n allowedOwners?: string[];\n state: RepoUrlPickerState;\n onChange: (state: RepoUrlPickerState) => void;\n rawErrors: string[];\n}) => {\n const { allowedOwners = [], rawErrors, state, onChange } = props;\n const ownerItems: SelectItem[] = allowedOwners\n ? allowedOwners.map(i => ({ label: i, value: i }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n const { owner, repoName } = state;\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !owner}\n >\n {allowedOwners?.length ? (\n <Select\n native\n label=\"Owner Available\"\n onChange={selected =>\n onChange({\n owner: String(Array.isArray(selected) ? selected[0] : selected),\n })\n }\n disabled={allowedOwners.length === 1}\n selected={owner}\n items={ownerItems}\n />\n ) : (\n <>\n <InputLabel htmlFor=\"ownerInput\">Owner</InputLabel>\n <Input\n id=\"ownerInput\"\n onChange={e => onChange({ owner: e.target.value })}\n value={owner}\n />\n </>\n )}\n <FormHelperText>\n The organization, user or project that this repo will belong to\n </FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange({ repoName: e.target.value })}\n value={repoName}\n />\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\n );\n};\n","/*\n * Copyright 2022 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 FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport { RepoUrlPickerState } from './types';\n\nexport const AzureRepoPicker = (props: {\n state: RepoUrlPickerState;\n onChange: (state: RepoUrlPickerState) => void;\n rawErrors: string[];\n}) => {\n const { rawErrors, state, onChange } = props;\n const { organization, repoName, owner } = state;\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !organization}\n >\n <InputLabel htmlFor=\"orgInput\">Organization</InputLabel>\n <Input\n id=\"orgInput\"\n onChange={e => onChange({ organization: e.target.value })}\n value={organization}\n />\n <FormHelperText>\n The organization that this repo will belong to\n </FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !owner}\n >\n <InputLabel htmlFor=\"ownerInput\">Owner</InputLabel>\n <Input\n id=\"ownerInput\"\n onChange={e => onChange({ owner: e.target.value })}\n value={owner}\n />\n <FormHelperText>The Owner that this repo will belong to</FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange({ repoName: e.target.value })}\n value={repoName}\n />\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\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 FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport { RepoUrlPickerState } from './types';\n\nexport const BitbucketRepoPicker = (props: {\n onChange: (state: RepoUrlPickerState) => void;\n state: RepoUrlPickerState;\n rawErrors: string[];\n}) => {\n const { onChange, rawErrors, state } = props;\n const { host, workspace, project, repoName } = state;\n return (\n <>\n {host === 'bitbucket.org' && (\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !workspace}\n >\n <InputLabel htmlFor=\"workspaceInput\">Workspace</InputLabel>\n <Input\n id=\"workspaceInput\"\n onChange={e => onChange({ workspace: e.target.value })}\n value={workspace}\n />\n <FormHelperText>\n The Organization that this repo will belong to\n </FormHelperText>\n </FormControl>\n )}\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !project}\n >\n <InputLabel htmlFor=\"projectInput\">Project</InputLabel>\n <Input\n id=\"projectInput\"\n onChange={e => onChange({ project: e.target.value })}\n value={project}\n />\n <FormHelperText>\n The Project that this repo will belong to\n </FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange({ repoName: e.target.value })}\n value={repoName}\n />\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\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, { useEffect } from 'react';\nimport { Progress, Select, SelectItem } from '@backstage/core-components';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { scaffolderApiRef } from '../../../api';\nimport useAsync from 'react-use/lib/useAsync';\n\nexport const RepoUrlPickerHost = (props: {\n host?: string;\n hosts?: string[];\n onChange: (host: string) => void;\n rawErrors: string[];\n}) => {\n const { host, hosts, onChange, rawErrors } = props;\n const scaffolderApi = useApi(scaffolderApiRef);\n\n const { value: integrations, loading } = useAsync(async () => {\n return await scaffolderApi.getIntegrationsList({\n allowedHosts: hosts ?? [],\n });\n });\n\n useEffect(() => {\n // If there is no host chosen currently\n if (!host) {\n // Set the first of the allowedHosts option if that available\n if (hosts?.length) {\n onChange(hosts[0]);\n // if there's no hosts provided, fallback to using the first integration\n } else if (integrations?.length) {\n onChange(integrations[0].host);\n }\n }\n }, [hosts, host, onChange, integrations]);\n\n // If there are no allowedHosts provided, then show all integrations. Otherwise, only show integrations\n // that are provided in the dropdown for the user to choose from.\n const hostsOptions: SelectItem[] = integrations\n ? integrations\n .filter(i => (hosts?.length ? hosts?.includes(i.host) : true))\n .map(i => ({ label: i.title, value: i.host }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n if (loading) {\n return <Progress />;\n }\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !host}\n >\n <Select\n native\n disabled={hosts?.length === 1 ?? false}\n label=\"Host\"\n onChange={s => onChange(String(Array.isArray(s) ? s[0] : s))}\n selected={host}\n items={hostsOptions}\n data-testid=\"host-select\"\n />\n\n <FormHelperText>\n The host where the repository will be created\n </FormHelperText>\n </FormControl>\n </>\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 { RepoUrlPickerState } from './types';\n\nexport function serializeRepoPickerUrl(data: RepoUrlPickerState) {\n if (!data.host) {\n return undefined;\n }\n\n const params = new URLSearchParams();\n if (data.owner) {\n params.set('owner', data.owner);\n }\n if (data.repoName) {\n params.set('repo', data.repoName);\n }\n if (data.organization) {\n params.set('organization', data.organization);\n }\n if (data.workspace) {\n params.set('workspace', data.workspace);\n }\n if (data.project) {\n params.set('project', data.project);\n }\n\n return `${data.host}?${params.toString()}`;\n}\n\nexport function parseRepoPickerUrl(\n url: string | undefined,\n): RepoUrlPickerState {\n let host = '';\n let owner = '';\n let repoName = '';\n let organization = '';\n let workspace = '';\n let project = '';\n\n try {\n if (url) {\n const parsed = new URL(`https://${url}`);\n host = parsed.host;\n owner = parsed.searchParams.get('owner') || '';\n repoName = parsed.searchParams.get('repo') || '';\n organization = parsed.searchParams.get('organization') || '';\n workspace = parsed.searchParams.get('workspace') || '';\n project = parsed.searchParams.get('project') || '';\n }\n } catch {\n /* ok */\n }\n\n return { host, owner, repoName, organization, workspace, project };\n}\n","/*\n * Copyright 2022 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, {\n useState,\n useCallback,\n useContext,\n createContext,\n PropsWithChildren,\n} from 'react';\n\ntype SecretsContextContents = {\n secrets: Record<string, string>;\n setSecrets: React.Dispatch<React.SetStateAction<Record<string, string>>>;\n};\n\n/**\n * The actual context object.\n */\nexport const SecretsContext = createContext<SecretsContextContents | undefined>(\n undefined,\n);\n\n/**\n * The Context Provider that holds the state for the secrets.\n *\n * @public\n */\nexport const SecretsContextProvider = ({ children }: PropsWithChildren<{}>) => {\n const [secrets, setSecrets] = useState<Record<string, string>>({});\n\n return (\n <SecretsContext.Provider value={{ secrets, setSecrets }}>\n {children}\n </SecretsContext.Provider>\n );\n};\n\n/**\n * Hook to access the secrets context.\n * @public\n */\nexport const useTemplateSecrets = () => {\n const value = useContext(SecretsContext);\n if (!value) {\n throw new Error(\n 'useTemplateSecrets must be used within a SecretsContextProvider',\n );\n }\n\n const { setSecrets } = value;\n\n const setSecret = useCallback(\n (input: Record<string, string>) => {\n setSecrets(currentSecrets => ({ ...currentSecrets, ...input }));\n },\n [setSecrets],\n );\n\n return { setSecret };\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 { useApi } from '@backstage/core-plugin-api';\nimport {\n scmIntegrationsApiRef,\n scmAuthApiRef,\n} from '@backstage/integration-react';\nimport React, { useEffect, useState, useMemo, useCallback } from 'react';\nimport { GithubRepoPicker } from './GithubRepoPicker';\nimport { GitlabRepoPicker } from './GitlabRepoPicker';\nimport { AzureRepoPicker } from './AzureRepoPicker';\nimport { BitbucketRepoPicker } from './BitbucketRepoPicker';\nimport { FieldExtensionComponentProps } from '../../../extensions';\nimport { RepoUrlPickerHost } from './RepoUrlPickerHost';\nimport { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils';\nimport { RepoUrlPickerState } from './types';\nimport useDebounce from 'react-use/lib/useDebounce';\nimport { useTemplateSecrets } from '../../secrets';\n\nexport interface RepoUrlPickerUiOptions {\n allowedHosts?: string[];\n allowedOwners?: string[];\n requestUserCredentials?: {\n secretsKey: string;\n additionalScopes?: {\n github?: string[];\n gitlab?: string[];\n bitbucket?: string[];\n azure?: string[];\n };\n };\n}\n\nexport const RepoUrlPicker = (\n props: FieldExtensionComponentProps<string, RepoUrlPickerUiOptions>,\n) => {\n const { uiSchema, onChange, rawErrors, formData } = props;\n const [state, setState] = useState<RepoUrlPickerState>(\n parseRepoPickerUrl(formData),\n );\n const integrationApi = useApi(scmIntegrationsApiRef);\n const scmAuthApi = useApi(scmAuthApiRef);\n const { setSecret } = useTemplateSecrets();\n const allowedHosts = useMemo(\n () => uiSchema?.['ui:options']?.allowedHosts ?? [],\n [uiSchema],\n );\n const allowedOwners = useMemo(\n () => uiSchema?.['ui:options']?.allowedOwners ?? [],\n [uiSchema],\n );\n\n useEffect(() => {\n onChange(serializeRepoPickerUrl(state));\n }, [state, onChange]);\n\n /* we deal with calling the repo setting here instead of in each components for ease */\n useEffect(() => {\n if (allowedOwners.length === 1) {\n setState(prevState => ({ ...prevState, owner: allowedOwners[0] }));\n }\n }, [setState, allowedOwners]);\n\n const updateLocalState = useCallback(\n (newState: RepoUrlPickerState) => {\n setState(prevState => ({ ...prevState, ...newState }));\n },\n [setState],\n );\n\n useDebounce(\n async () => {\n const { requestUserCredentials } = uiSchema?.['ui:options'] ?? {};\n\n if (\n !requestUserCredentials ||\n !(state.host && state.owner && state.repoName)\n ) {\n return;\n }\n\n const [host, owner, repoName] = [\n state.host,\n state.owner,\n state.repoName,\n ].map(encodeURIComponent);\n\n // user has requested that we use the users credentials\n // so lets grab them using the scmAuthApi and pass through\n // any additional scopes from the ui:options\n const { token } = await scmAuthApi.getCredentials({\n url: `https://${host}/${owner}/${repoName}`,\n additionalScope: {\n repoWrite: true,\n customScopes: requestUserCredentials.additionalScopes,\n },\n });\n\n // set the secret using the key provided in the the ui:options for use\n // in the templating the manifest with ${{ secrets[secretsKey] }}\n setSecret({ [requestUserCredentials.secretsKey]: token });\n },\n 500,\n [state, uiSchema],\n );\n\n const hostType =\n (state.host && integrationApi.byHost(state.host)?.type) ?? null;\n\n return (\n <>\n <RepoUrlPickerHost\n host={state.host}\n hosts={allowedHosts}\n onChange={host => setState(prevState => ({ ...prevState, host }))}\n rawErrors={rawErrors}\n />\n {hostType === 'github' && (\n <GithubRepoPicker\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gitlab' && (\n <GitlabRepoPicker\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'bitbucket' && (\n <BitbucketRepoPicker\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'azure' && (\n <AzureRepoPicker\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n </>\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 { FieldValidation } from '@rjsf/core';\nimport { ApiHolder } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\nexport const repoPickerValidation = (\n value: string,\n validation: FieldValidation,\n context: { apiHolder: ApiHolder },\n) => {\n try {\n const { host, searchParams } = new URL(`https://${value}`);\n\n const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);\n\n if (!host) {\n validation.addError(\n 'Incomplete repository location provided, host not provided',\n );\n } else {\n if (integrationApi?.byHost(host)?.type === 'bitbucket') {\n // workspace is only applicable for bitbucket cloud\n if (host === 'bitbucket.org' && !searchParams.get('workspace')) {\n validation.addError(\n 'Incomplete repository location provided, workspace not provided',\n );\n }\n\n if (!searchParams.get('project')) {\n validation.addError(\n 'Incomplete repository location provided, project not provided',\n );\n }\n }\n // For anything other than bitbucket\n else {\n if (!searchParams.get('owner')) {\n validation.addError(\n 'Incomplete repository location provided, owner not provided',\n );\n }\n }\n\n // Do this for all hosts\n if (!searchParams.get('repo')) {\n validation.addError(\n 'Incomplete repository location provided, repo not provided',\n );\n }\n }\n } catch {\n validation.addError('Unable to parse the Repository URL');\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 {\n formatEntityRefTitle,\n useOwnedEntities,\n} from '@backstage/plugin-catalog-react';\nimport { TextField } from '@material-ui/core';\nimport FormControl from '@material-ui/core/FormControl';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport { FieldProps } from '@rjsf/core';\nimport React from 'react';\n\nexport const OwnedEntityPicker = ({\n onChange,\n schema: { title = 'Entity', description = 'An entity from the catalog' },\n required,\n uiSchema,\n rawErrors,\n formData,\n idSchema,\n}: FieldProps<string>) => {\n const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[];\n const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined;\n const { ownedEntities, loading } = useOwnedEntities(allowedKinds);\n\n const entityRefs = ownedEntities?.items\n .map(e => formatEntityRefTitle(e, { defaultKind }))\n .filter(n => n);\n\n const onSelect = (_: any, value: string | null) => {\n onChange(value || '');\n };\n\n return (\n <FormControl\n margin=\"normal\"\n required={required}\n error={rawErrors?.length > 0 && !formData}\n >\n <Autocomplete\n id={idSchema?.$id}\n value={(formData as string) || ''}\n loading={loading}\n onChange={onSelect}\n options={entityRefs || []}\n autoSelect\n freeSolo\n renderInput={params => (\n <TextField\n {...params}\n label={title}\n margin=\"normal\"\n helperText={description}\n variant=\"outlined\"\n required={required}\n InputProps={params.InputProps}\n />\n )}\n />\n </FormControl>\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 from 'react';\nimport {\n CustomFieldValidator,\n FieldExtensionOptions,\n FieldExtensionComponentProps,\n} from './types';\nimport { Extension, attachComponentData } from '@backstage/core-plugin-api';\n\nexport const FIELD_EXTENSION_WRAPPER_KEY = 'scaffolder.extensions.wrapper.v1';\nexport const FIELD_EXTENSION_KEY = 'scaffolder.extensions.field.v1';\n\nexport function createScaffolderFieldExtension<T = any>(\n options: FieldExtensionOptions<T>,\n): Extension<() => null> {\n return {\n expose() {\n const FieldExtensionDataHolder: any = () => null;\n\n attachComponentData(\n FieldExtensionDataHolder,\n FIELD_EXTENSION_KEY,\n options,\n );\n\n return FieldExtensionDataHolder;\n },\n };\n}\n\nexport const ScaffolderFieldExtensions: React.ComponentType = () => null;\nattachComponentData(\n ScaffolderFieldExtensions,\n FIELD_EXTENSION_WRAPPER_KEY,\n true,\n);\n\nexport type {\n CustomFieldValidator,\n FieldExtensionOptions,\n FieldExtensionComponentProps,\n};\n\nexport { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default';\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 {\n createExternalRouteRef,\n createRouteRef,\n} from '@backstage/core-plugin-api';\n\nexport const registerComponentRouteRef = createExternalRouteRef({\n id: 'register-component',\n optional: true,\n});\n\nexport const rootRouteRef = createRouteRef({\n id: 'scaffolder',\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 { scmIntegrationsApiRef } from '@backstage/integration-react';\nimport { scaffolderApiRef, ScaffolderClient } from './api';\nimport { EntityPicker } from './components/fields/EntityPicker';\nimport {\n entityNamePickerValidation,\n EntityNamePicker,\n} from './components/fields/EntityNamePicker';\nimport { OwnerPicker } from './components/fields/OwnerPicker';\nimport {\n repoPickerValidation,\n RepoUrlPicker,\n} from './components/fields/RepoUrlPicker';\nimport { createScaffolderFieldExtension } from './extensions';\nimport { registerComponentRouteRef, rootRouteRef } from './routes';\nimport {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/core-plugin-api';\nimport { OwnedEntityPicker } from './components/fields/OwnedEntityPicker';\nimport { EntityTagsPicker } from './components/fields/EntityTagsPicker';\n\nexport const scaffolderPlugin = createPlugin({\n id: 'scaffolder',\n apis: [\n createApiFactory({\n api: scaffolderApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n scmIntegrationsApi: scmIntegrationsApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, scmIntegrationsApi, fetchApi }) =>\n new ScaffolderClient({\n discoveryApi,\n scmIntegrationsApi,\n fetchApi,\n }),\n }),\n ],\n routes: {\n root: rootRouteRef,\n },\n externalRoutes: {\n registerComponent: registerComponentRouteRef,\n },\n});\n\nexport const EntityPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: EntityPicker,\n name: 'EntityPicker',\n }),\n);\n\nexport const EntityNamePickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: EntityNamePicker,\n name: 'EntityNamePicker',\n validation: entityNamePickerValidation,\n }),\n);\n\nexport const RepoUrlPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: RepoUrlPicker,\n name: 'RepoUrlPicker',\n validation: repoPickerValidation,\n }),\n);\n\nexport const OwnerPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: OwnerPicker,\n name: 'OwnerPicker',\n }),\n);\n\nexport const ScaffolderPage = scaffolderPlugin.provide(\n createRoutableExtension({\n name: 'ScaffolderPage',\n component: () => import('./components/Router').then(m => m.Router),\n mountPoint: rootRouteRef,\n }),\n);\n\nexport const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: OwnedEntityPicker,\n name: 'OwnedEntityPicker',\n }),\n);\n\n/**\n * EntityTagsPickerFieldExtension\n * @public\n */\nexport const EntityTagsPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: EntityTagsPicker,\n name: 'EntityTagsPicker',\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 { Entity } from '@backstage/catalog-model';\nimport { useStarredEntity } from '@backstage/plugin-catalog-react';\nimport { IconButton, makeStyles, Tooltip, withStyles } from '@material-ui/core';\nimport Star from '@material-ui/icons/Star';\nimport StarBorder from '@material-ui/icons/StarBorder';\nimport React, { ComponentProps } from 'react';\n\ntype Props = ComponentProps<typeof IconButton> & { entity: Entity };\n\nconst YellowStar = withStyles({\n root: {\n color: '#f3ba37',\n },\n})(Star);\n\nconst WhiteBorderStar = withStyles({\n root: {\n color: '#ffffff',\n },\n})(StarBorder);\n\nconst useStyles = makeStyles(theme => ({\n starButton: {\n position: 'absolute',\n top: theme.spacing(0.5),\n right: theme.spacing(0.5),\n padding: '0.25rem',\n },\n}));\n\nexport const favouriteTemplateTooltip = (isStarred: boolean) =>\n isStarred ? 'Remove from favorites' : 'Add to favorites';\n\nexport const favouriteTemplateIcon = (isStarred: boolean) =>\n isStarred ? <YellowStar /> : <WhiteBorderStar />;\n\n/**\n * IconButton for showing if a current entity is starred and adding/removing it from the favourite entities\n * @param props - MaterialUI IconButton props extended by required `entity` prop\n */\nexport const FavouriteTemplate = (props: Props) => {\n const classes = useStyles();\n const { toggleStarredEntity, isStarredEntity } = useStarredEntity(\n props.entity,\n );\n return (\n <IconButton\n color=\"inherit\"\n className={classes.starButton}\n {...props}\n onClick={() => toggleStarredEntity()}\n >\n <Tooltip title={favouriteTemplateTooltip(isStarredEntity)}>\n {favouriteTemplateIcon(isStarredEntity)}\n </Tooltip>\n </IconButton>\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 {\n Entity,\n RELATION_OWNED_BY,\n TemplateEntityV1beta2,\n} from '@backstage/catalog-model';\nimport {\n ScmIntegrationIcon,\n scmIntegrationsApiRef,\n} from '@backstage/integration-react';\nimport {\n EntityRefLinks,\n getEntityRelations,\n getEntitySourceLocation,\n} from '@backstage/plugin-catalog-react';\nimport { BackstageTheme } from '@backstage/theme';\nimport {\n Box,\n Card,\n CardActions,\n CardContent,\n CardMedia,\n Chip,\n IconButton,\n Link,\n makeStyles,\n Tooltip,\n Typography,\n useTheme,\n} from '@material-ui/core';\nimport WarningIcon from '@material-ui/icons/Warning';\nimport React from 'react';\nimport { generatePath } from 'react-router';\nimport { rootRouteRef } from '../../routes';\nimport { FavouriteTemplate } from '../FavouriteTemplate/FavouriteTemplate';\n\nimport { Button, ItemCardHeader } from '@backstage/core-components';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\n\nconst useStyles = makeStyles(theme => ({\n cardHeader: {\n position: 'relative',\n },\n title: {\n backgroundImage: ({ backgroundImage }: any) => backgroundImage,\n },\n box: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n display: '-webkit-box',\n '-webkit-line-clamp': 10,\n '-webkit-box-orient': 'vertical',\n paddingBottom: '0.8em',\n },\n label: {\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n fontSize: '0.65rem',\n fontWeight: 'bold',\n letterSpacing: 0.5,\n lineHeight: 1,\n paddingBottom: '0.2rem',\n },\n leftButton: {\n marginRight: 'auto',\n },\n}));\n\nconst useDeprecationStyles = makeStyles(theme => ({\n deprecationIcon: {\n position: 'absolute',\n top: theme.spacing(0.5),\n right: theme.spacing(3.5),\n padding: '0.25rem',\n },\n link: {\n color: theme.palette.warning.light,\n },\n}));\n\nexport type TemplateCardProps = {\n template: TemplateEntityV1beta2;\n deprecated?: boolean;\n};\n\ntype TemplateProps = {\n description: string;\n tags: string[];\n title: string;\n type: string;\n name: string;\n};\n\nconst getTemplateCardProps = (\n template: TemplateEntityV1beta2,\n): TemplateProps & { key: string } => {\n return {\n key: template.metadata.uid!,\n name: template.metadata.name,\n title: `${(template.metadata.title || template.metadata.name) ?? ''}`,\n type: template.spec.type ?? '',\n description: template.metadata.description ?? '-',\n tags: (template.metadata?.tags as string[]) ?? [],\n };\n};\n\nconst DeprecationWarning = () => {\n const styles = useDeprecationStyles();\n\n const Title = (\n <Typography style={{ padding: 10, maxWidth: 300 }}>\n This template syntax is deprecated. Click for more info.\n </Typography>\n );\n\n return (\n <div className={styles.deprecationIcon}>\n <Tooltip title={Title}>\n <Link\n href=\"https://backstage.io/docs/features/software-templates/migrating-from-v1alpha1-to-v1beta2\"\n className={styles.link}\n >\n <WarningIcon />\n </Link>\n </Tooltip>\n </div>\n );\n};\n\nexport const TemplateCard = ({ template, deprecated }: TemplateCardProps) => {\n const backstageTheme = useTheme<BackstageTheme>();\n const rootLink = useRouteRef(rootRouteRef);\n const templateProps = getTemplateCardProps(template);\n const ownedByRelations = getEntityRelations(\n template as Entity,\n RELATION_OWNED_BY,\n );\n const themeId = backstageTheme.getPageTheme({ themeId: templateProps.type })\n ? templateProps.type\n : 'other';\n const theme = backstageTheme.getPageTheme({ themeId });\n const classes = useStyles({ backgroundImage: theme.backgroundImage });\n const href = generatePath(`${rootLink()}/templates/:templateName`, {\n templateName: templateProps.name,\n });\n\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const sourceLocation = getEntitySourceLocation(template, scmIntegrationsApi);\n\n return (\n <Card>\n <CardMedia className={classes.cardHeader}>\n <FavouriteTemplate entity={template} />\n {deprecated && <DeprecationWarning />}\n <ItemCardHeader\n title={templateProps.title}\n subtitle={templateProps.type}\n classes={{ root: classes.title }}\n />\n </CardMedia>\n <CardContent style={{ display: 'grid' }}>\n <Box className={classes.box}>\n <Typography variant=\"body2\" className={classes.label}>\n Description\n </Typography>\n {templateProps.description}\n </Box>\n <Box className={classes.box}>\n <Typography variant=\"body2\" className={classes.label}>\n Owner\n </Typography>\n <EntityRefLinks entityRefs={ownedByRelations} defaultKind=\"Group\" />\n </Box>\n <Box>\n <Typography variant=\"body2\" className={classes.label}>\n Tags\n </Typography>\n {templateProps.tags?.map(tag => (\n <Chip size=\"small\" label={tag} key={tag} />\n ))}\n </Box>\n </CardContent>\n <CardActions>\n {sourceLocation && (\n <IconButton\n className={classes.leftButton}\n href={sourceLocation.locationTargetUrl}\n >\n <ScmIntegrationIcon type={sourceLocation.integrationType} />\n </IconButton>\n )}\n <Button\n color=\"primary\"\n to={href}\n aria-label={`Choose ${templateProps.title}`}\n >\n Choose\n </Button>\n </CardActions>\n </Card>\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 {\n Entity,\n stringifyEntityRef,\n TemplateEntityV1beta2,\n} from '@backstage/catalog-model';\nimport {\n Content,\n ContentHeader,\n ItemCardGrid,\n Link,\n Progress,\n WarningPanel,\n} from '@backstage/core-components';\nimport { useEntityListProvider } from '@backstage/plugin-catalog-react';\nimport { Typography } from '@material-ui/core';\nimport { TemplateCard } from '../TemplateCard';\n\nexport type TemplateListProps = {\n TemplateCardComponent?:\n | ComponentType<{ template: TemplateEntityV1beta2 }>\n | undefined;\n group?: {\n title?: string;\n titleComponent?: React.ReactNode;\n filter: (entity: Entity) => boolean;\n };\n};\n\nexport const TemplateList = ({\n TemplateCardComponent,\n group,\n}: TemplateListProps) => {\n const { loading, error, entities } = useEntityListProvider();\n const Card = TemplateCardComponent || TemplateCard;\n const maybeFilteredEntities = group\n ? entities.filter(e => group.filter(e))\n : entities;\n const title = group ? (\n group.titleComponent || <ContentHeader title={group.title} />\n ) : (\n <ContentHeader title=\"Other Templates\" />\n );\n\n if (group && maybeFilteredEntities.length === 0) {\n return null;\n }\n return (\n <>\n {loading && <Progress />}\n\n {error && (\n <WarningPanel title=\"Oops! Something went wrong loading the templates\">\n {error.message}\n </WarningPanel>\n )}\n\n {!error && !loading && !entities.length && (\n <Typography variant=\"body2\">\n No templates found that match your filter. Learn more about{' '}\n <Link to=\"https://backstage.io/docs/features/software-templates/adding-templates\">\n adding templates\n </Link>\n .\n </Typography>\n )}\n\n <Content>\n {title}\n <ItemCardGrid>\n {maybeFilteredEntities &&\n maybeFilteredEntities?.length > 0 &&\n maybeFilteredEntities.map((template: Entity) => (\n <Card\n key={stringifyEntityRef(template)}\n template={template as TemplateEntityV1beta2}\n />\n ))}\n </ItemCardGrid>\n </Content>\n </>\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 from 'react';\nimport capitalize from 'lodash/capitalize';\nimport { Progress } from '@backstage/core-components';\nimport {\n Box,\n Checkbox,\n FormControlLabel,\n TextField,\n Typography,\n} from '@material-ui/core';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport { Autocomplete } from '@material-ui/lab';\nimport { useEntityTypeFilter } from '@backstage/plugin-catalog-react';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\n\nconst icon = <CheckBoxOutlineBlankIcon fontSize=\"small\" />;\nconst checkedIcon = <CheckBoxIcon fontSize=\"small\" />;\n\nexport const TemplateTypePicker = () => {\n const alertApi = useApi(alertApiRef);\n const { error, loading, availableTypes, selectedTypes, setSelectedTypes } =\n useEntityTypeFilter();\n\n if (loading) return <Progress />;\n\n if (!availableTypes) return null;\n\n if (error) {\n alertApi.post({\n message: `Failed to load entity types`,\n severity: 'error',\n });\n return null;\n }\n\n return (\n <Box pb={1} pt={1}>\n <Typography variant=\"button\">Categories</Typography>\n <Autocomplete\n multiple\n aria-label=\"Categories\"\n options={availableTypes}\n value={selectedTypes}\n onChange={(_: object, value: string[]) => setSelectedTypes(value)}\n renderOption={(option, { selected }) => (\n <FormControlLabel\n control={\n <Checkbox\n icon={icon}\n checkedIcon={checkedIcon}\n checked={selected}\n />\n }\n label={capitalize(option)}\n />\n )}\n size=\"small\"\n popupIcon={<ExpandMoreIcon data-testid=\"categories-picker-expand\" />}\n renderInput={params => <TextField {...params} variant=\"outlined\" />}\n />\n </Box>\n );\n};\n"],"names":["FormControl","Autocomplete","useStyles","Link"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ import { JSONSchema, EntityName, Entity, TemplateEntityV1beta2 } from '@backstag
|
|
|
6
6
|
import { ScmIntegrationRegistry } from '@backstage/integration';
|
|
7
7
|
import { Observable, JsonObject } from '@backstage/types';
|
|
8
8
|
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
|
9
|
-
import * as
|
|
10
|
-
import
|
|
9
|
+
import * as React from 'react';
|
|
10
|
+
import React__default, { ComponentProps, ComponentType } from 'react';
|
|
11
11
|
import { FieldValidation, FieldProps } from '@rjsf/core';
|
|
12
12
|
import { IconButton } from '@material-ui/core';
|
|
13
13
|
|
|
@@ -160,7 +160,7 @@ interface FieldExtensionComponentProps<ReturnValue, UiOptions extends {} = {}> e
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
declare function createScaffolderFieldExtension<T = any>(options: FieldExtensionOptions<T>): Extension<() => null>;
|
|
163
|
-
declare const ScaffolderFieldExtensions:
|
|
163
|
+
declare const ScaffolderFieldExtensions: React__default.ComponentType;
|
|
164
164
|
|
|
165
165
|
declare const scaffolderPlugin: _backstage_core_plugin_api.BackstagePlugin<{
|
|
166
166
|
root: _backstage_core_plugin_api.RouteRef<undefined>;
|
|
@@ -172,12 +172,12 @@ declare const EntityNamePickerFieldExtension: () => null;
|
|
|
172
172
|
declare const RepoUrlPickerFieldExtension: () => null;
|
|
173
173
|
declare const OwnerPickerFieldExtension: () => null;
|
|
174
174
|
declare const ScaffolderPage: ({ TemplateCardComponent, groups }: {
|
|
175
|
-
TemplateCardComponent?:
|
|
175
|
+
TemplateCardComponent?: React.ComponentType<{
|
|
176
176
|
template: _backstage_catalog_model.TemplateEntityV1beta2;
|
|
177
177
|
}> | undefined;
|
|
178
178
|
groups?: {
|
|
179
179
|
title?: string | undefined;
|
|
180
|
-
titleComponent?:
|
|
180
|
+
titleComponent?: React.ReactNode;
|
|
181
181
|
filter: (entity: _backstage_catalog_model.Entity) => boolean;
|
|
182
182
|
}[] | undefined;
|
|
183
183
|
}) => JSX.Element;
|
|
@@ -197,6 +197,15 @@ declare const OwnerPicker: ({ schema: { title, description }, uiSchema, ...props
|
|
|
197
197
|
interface RepoUrlPickerUiOptions {
|
|
198
198
|
allowedHosts?: string[];
|
|
199
199
|
allowedOwners?: string[];
|
|
200
|
+
requestUserCredentials?: {
|
|
201
|
+
secretsKey: string;
|
|
202
|
+
additionalScopes?: {
|
|
203
|
+
github?: string[];
|
|
204
|
+
gitlab?: string[];
|
|
205
|
+
bitbucket?: string[];
|
|
206
|
+
azure?: string[];
|
|
207
|
+
};
|
|
208
|
+
};
|
|
200
209
|
}
|
|
201
210
|
declare const RepoUrlPicker: (props: FieldExtensionComponentProps<string, RepoUrlPickerUiOptions>) => JSX.Element;
|
|
202
211
|
|
|
@@ -225,7 +234,7 @@ declare type TemplateListProps = {
|
|
|
225
234
|
}> | undefined;
|
|
226
235
|
group?: {
|
|
227
236
|
title?: string;
|
|
228
|
-
titleComponent?:
|
|
237
|
+
titleComponent?: React__default.ReactNode;
|
|
229
238
|
filter: (entity: Entity) => boolean;
|
|
230
239
|
};
|
|
231
240
|
};
|
|
@@ -233,4 +242,12 @@ declare const TemplateList: ({ TemplateCardComponent, group, }: TemplateListProp
|
|
|
233
242
|
|
|
234
243
|
declare const TemplateTypePicker: () => JSX.Element | null;
|
|
235
244
|
|
|
236
|
-
|
|
245
|
+
/**
|
|
246
|
+
* Hook to access the secrets context.
|
|
247
|
+
* @public
|
|
248
|
+
*/
|
|
249
|
+
declare const useTemplateSecrets: () => {
|
|
250
|
+
setSecret: (input: Record<string, string>) => void;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
export { CustomFieldValidator, EntityNamePicker, EntityNamePickerFieldExtension, EntityPicker, EntityPickerFieldExtension, EntityTagsPicker, EntityTagsPickerFieldExtension, FavouriteTemplate, FieldExtensionComponentProps, FieldExtensionOptions, OwnedEntityPicker, OwnedEntityPickerFieldExtension, OwnerPicker, OwnerPickerFieldExtension, RepoUrlPicker, RepoUrlPickerFieldExtension, RepoUrlPickerUiOptions, ScaffolderApi, ScaffolderClient, ScaffolderFieldExtensions, ScaffolderPage, TemplateList, TemplateListProps, TemplateTypePicker, TextValuePicker, createScaffolderFieldExtension, scaffolderPlugin as plugin, scaffolderApiRef, scaffolderPlugin, useTemplateSecrets };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as EntityNamePicker,
|
|
1
|
+
export { a as EntityNamePicker, n as EntityNamePickerFieldExtension, E as EntityPicker, m as EntityPickerFieldExtension, b as EntityTagsPicker, o as EntityTagsPickerFieldExtension, x as FavouriteTemplate, c as OwnedEntityPicker, q as OwnedEntityPickerFieldExtension, O as OwnerPicker, p as OwnerPickerFieldExtension, R as RepoUrlPicker, t as RepoUrlPickerFieldExtension, j as ScaffolderClient, l as ScaffolderFieldExtensions, u as ScaffolderPage, f as TemplateList, T as TemplateTypePicker, w as TextValuePicker, k as createScaffolderFieldExtension, v as plugin, s as scaffolderApiRef, v as scaffolderPlugin, y as useTemplateSecrets } from './esm/index-9f303a62.esm.js';
|
|
2
2
|
import '@backstage/catalog-model';
|
|
3
3
|
import '@backstage/integration-react';
|
|
4
4
|
import '@backstage/core-plugin-api';
|
|
@@ -17,6 +17,7 @@ import '@material-ui/core/FormHelperText';
|
|
|
17
17
|
import '@material-ui/core/Input';
|
|
18
18
|
import '@material-ui/core/InputLabel';
|
|
19
19
|
import '@backstage/core-components';
|
|
20
|
+
import 'react-use/lib/useDebounce';
|
|
20
21
|
import '@material-ui/icons/Star';
|
|
21
22
|
import '@material-ui/icons/StarBorder';
|
|
22
23
|
import '@material-ui/icons/Warning';
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-scaffolder",
|
|
3
3
|
"description": "The Backstage plugin that helps you create new things",
|
|
4
|
-
"version": "0.12.1
|
|
4
|
+
"version": "0.12.1",
|
|
5
5
|
"main": "dist/index.esm.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
"@backstage/catalog-client": "^0.5.5",
|
|
35
35
|
"@backstage/catalog-model": "^0.9.10",
|
|
36
36
|
"@backstage/config": "^0.1.13",
|
|
37
|
-
"@backstage/core-components": "^0.8.7
|
|
37
|
+
"@backstage/core-components": "^0.8.7",
|
|
38
38
|
"@backstage/core-plugin-api": "^0.6.0",
|
|
39
39
|
"@backstage/errors": "^0.2.0",
|
|
40
40
|
"@backstage/integration": "^0.7.2",
|
|
41
|
-
"@backstage/integration-react": "^0.1.20
|
|
42
|
-
"@backstage/plugin-catalog-common": "^0.1.2
|
|
43
|
-
"@backstage/plugin-catalog-react": "^0.6.13
|
|
41
|
+
"@backstage/integration-react": "^0.1.20",
|
|
42
|
+
"@backstage/plugin-catalog-common": "^0.1.2",
|
|
43
|
+
"@backstage/plugin-catalog-react": "^0.6.13",
|
|
44
44
|
"@backstage/plugin-permission-react": "^0.3.0",
|
|
45
45
|
"@backstage/plugin-scaffolder-common": "^0.1.3",
|
|
46
46
|
"@backstage/theme": "^0.2.14",
|
|
@@ -69,11 +69,11 @@
|
|
|
69
69
|
"react": "^16.13.1 || ^17.0.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@backstage/cli": "^0.13.1
|
|
73
|
-
"@backstage/core-app-api": "^0.5.2
|
|
74
|
-
"@backstage/dev-utils": "^0.2.20
|
|
75
|
-
"@backstage/plugin-catalog": "^0.7.11
|
|
76
|
-
"@backstage/test-utils": "^0.2.4
|
|
72
|
+
"@backstage/cli": "^0.13.1",
|
|
73
|
+
"@backstage/core-app-api": "^0.5.2",
|
|
74
|
+
"@backstage/dev-utils": "^0.2.20",
|
|
75
|
+
"@backstage/plugin-catalog": "^0.7.11",
|
|
76
|
+
"@backstage/test-utils": "^0.2.4",
|
|
77
77
|
"@testing-library/jest-dom": "^5.10.1",
|
|
78
78
|
"@testing-library/react": "^11.2.5",
|
|
79
79
|
"@testing-library/react-hooks": "^7.0.2",
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"files": [
|
|
89
89
|
"dist"
|
|
90
90
|
],
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "f944a625c4a8ec7f6a6237502691da9209ce6b14"
|
|
92
92
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Router-82282e23.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/hooks/useEventStream.ts","../../src/components/TaskPage/IconLink.tsx","../../src/components/TaskPage/TaskPageLinks.tsx","../../src/components/TaskPage/TaskPage.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[] = [\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 { TemplateEntityV1beta2, Entity } from '@backstage/catalog-model';\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 { errorApiRef, useApi } 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 * 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 = ({\n steps,\n formData,\n onChange,\n onReset,\n onFinish,\n fields,\n widgets,\n}: Props) => {\n const [activeStep, setActiveStep] = useState(0);\n const [disableButtons, setDisableButtons] = useState(false);\n const errorApi = useApi(errorApiRef);\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, 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 { 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';\n\nconst useTemplateParameterSchema = (templateName: string) => {\n const scaffolderApi = useApi(scaffolderApiRef);\n const { value, loading, error } = useAsync(\n () =>\n scaffolderApi.getTemplateParameterSchema({\n name: templateName,\n kind: 'template',\n namespace: 'default',\n }),\n [scaffolderApi, templateName],\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 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 return query.formData ?? {};\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 id = await scaffolderApi.scaffold(templateName, formState);\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: id }));\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 { useImmerReducer } from 'use-immer';\nimport { useEffect } from 'react';\nimport { scaffolderApiRef, LogEvent } from '../../api';\nimport { ScaffolderTask, Status, TaskOutput } from '../../types';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Subscription } from '@backstage/types';\n\ntype Step = {\n id: string;\n status: Status;\n endedAt?: string;\n startedAt?: string;\n};\n\nexport type TaskStream = {\n loading: boolean;\n error?: Error;\n stepLogs: { [stepId in string]: string[] };\n completed: boolean;\n task?: ScaffolderTask;\n steps: { [stepId in string]: Step };\n output?: TaskOutput;\n};\n\ntype ReducerLogEntry = {\n createdAt: string;\n body: {\n stepId?: string;\n status?: Status;\n message: string;\n output?: TaskOutput;\n };\n};\n\ntype ReducerAction =\n | { type: 'INIT'; data: ScaffolderTask }\n | { type: 'LOGS'; data: ReducerLogEntry[] }\n | { type: 'COMPLETED'; data: ReducerLogEntry }\n | { type: 'ERROR'; data: Error };\n\nfunction reducer(draft: TaskStream, action: ReducerAction) {\n switch (action.type) {\n case 'INIT': {\n draft.steps = action.data.spec.steps.reduce((current, next) => {\n current[next.id] = { status: 'open', id: next.id };\n return current;\n }, {} as { [stepId in string]: Step });\n draft.stepLogs = action.data.spec.steps.reduce((current, next) => {\n current[next.id] = [];\n return current;\n }, {} as { [stepId in string]: string[] });\n draft.loading = false;\n draft.error = undefined;\n draft.completed = false;\n draft.task = action.data;\n return;\n }\n\n case 'LOGS': {\n const entries = action.data;\n const logLines = [];\n\n for (const entry of entries) {\n const logLine = `${entry.createdAt} ${entry.body.message}`;\n logLines.push(logLine);\n\n if (!entry.body.stepId || !draft.steps?.[entry.body.stepId]) {\n continue;\n }\n\n const currentStepLog = draft.stepLogs?.[entry.body.stepId];\n const currentStep = draft.steps?.[entry.body.stepId];\n\n if (entry.body.status && entry.body.status !== currentStep.status) {\n currentStep.status = entry.body.status;\n\n if (currentStep.status === 'processing') {\n currentStep.startedAt = entry.createdAt;\n }\n\n if (\n ['cancelled', 'failed', 'completed'].includes(currentStep.status)\n ) {\n currentStep.endedAt = entry.createdAt;\n }\n }\n\n currentStepLog?.push(logLine);\n }\n\n return;\n }\n\n case 'COMPLETED': {\n draft.completed = true;\n draft.output = action.data.body.output;\n return;\n }\n\n case 'ERROR': {\n draft.error = action.data;\n draft.loading = false;\n draft.completed = true;\n return;\n }\n\n default:\n return;\n }\n}\n\nexport const useTaskEventStream = (taskId: string): TaskStream => {\n const scaffolderApi = useApi(scaffolderApiRef);\n const [state, dispatch] = useImmerReducer(reducer, {\n loading: true,\n completed: false,\n stepLogs: {} as { [stepId in string]: string[] },\n steps: {} as { [stepId in string]: Step },\n });\n\n useEffect(() => {\n let didCancel = false;\n let subscription: Subscription | undefined;\n let logPusher: NodeJS.Timeout | undefined;\n\n scaffolderApi.getTask(taskId).then(\n task => {\n if (didCancel) {\n return;\n }\n dispatch({ type: 'INIT', data: task });\n\n // TODO(blam): Use a normal fetch to fetch the current log for the event stream\n // and use that for an INIT_EVENTs dispatch event, and then\n // use the last event ID to subscribe using after option to\n // stream logs. Without this, if you have a lot of logs, it can look like the\n // task is being rebuilt on load as it progresses through the steps at a slower\n // rate whilst it builds the status from the event logs\n const observable = scaffolderApi.streamLogs({ taskId });\n\n const collectedLogEvents = new Array<LogEvent>();\n\n function emitLogs() {\n if (collectedLogEvents.length) {\n const logs = collectedLogEvents.splice(\n 0,\n collectedLogEvents.length,\n );\n dispatch({ type: 'LOGS', data: logs });\n }\n }\n\n logPusher = setInterval(emitLogs, 500);\n\n subscription = observable.subscribe({\n next: event => {\n switch (event.type) {\n case 'log':\n return collectedLogEvents.push(event);\n case 'completion':\n emitLogs();\n dispatch({ type: 'COMPLETED', data: event });\n return undefined;\n default:\n throw new Error(\n `Unhandled event type ${event.type} in observer`,\n );\n }\n },\n error: error => {\n emitLogs();\n dispatch({ type: 'ERROR', data: error });\n },\n });\n },\n error => {\n if (!didCancel) {\n dispatch({ type: 'ERROR', data: error });\n }\n },\n );\n\n return () => {\n didCancel = true;\n if (subscription) {\n subscription.unsubscribe();\n }\n if (logPusher) {\n clearInterval(logPusher);\n }\n };\n }, [scaffolderApi, dispatch, taskId]);\n\n return state;\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 React from 'react';\nimport { Grid, LinkProps, makeStyles, Typography } from '@material-ui/core';\nimport LanguageIcon from '@material-ui/icons/Language';\n\nimport { IconComponent } from '@backstage/core-plugin-api';\nimport { Link } from '@backstage/core-components';\n\nconst useStyles = makeStyles({\n svgIcon: {\n display: 'inline-block',\n '& svg': {\n display: 'inline-block',\n fontSize: 'inherit',\n verticalAlign: 'baseline',\n },\n },\n});\n\nexport const IconLink = (\n props: {\n href: string;\n text?: string;\n Icon?: IconComponent;\n } & LinkProps,\n) => {\n const { href, text, Icon, ...linkProps } = props;\n\n const classes = useStyles();\n\n return (\n <Grid container direction=\"row\" spacing={1}>\n <Grid item>\n <Typography component=\"div\" className={classes.svgIcon}>\n {Icon ? <Icon /> : <LanguageIcon />}\n </Typography>\n </Grid>\n <Grid item>\n <Link to={href} {...linkProps}>\n {text || href}\n </Link>\n </Grid>\n </Grid>\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 { parseEntityName } from '@backstage/catalog-model';\nimport { entityRouteRef } from '@backstage/plugin-catalog-react';\nimport { Box } from '@material-ui/core';\nimport LanguageIcon from '@material-ui/icons/Language';\nimport React from 'react';\nimport { TaskOutput } from '../../types';\nimport { IconLink } from './IconLink';\nimport { IconComponent, useApp, useRouteRef } from '@backstage/core-plugin-api';\n\ntype TaskPageLinksProps = {\n output: TaskOutput;\n};\n\nexport const TaskPageLinks = ({ output }: TaskPageLinksProps) => {\n const { entityRef: entityRefOutput, remoteUrl } = output;\n let { links = [] } = output;\n const app = useApp();\n const entityRoute = useRouteRef(entityRouteRef);\n\n const iconResolver = (key?: string): IconComponent =>\n key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon;\n\n if (remoteUrl) {\n links = [{ url: remoteUrl, title: 'Repo' }, ...links];\n }\n\n if (entityRefOutput) {\n links = [\n {\n entityRef: entityRefOutput,\n title: 'Open in catalog',\n icon: 'catalog',\n },\n ...links,\n ];\n }\n\n return (\n <Box px={3} pb={3}>\n {links\n .filter(({ url, entityRef }) => url || entityRef)\n .map(({ url, entityRef, title, icon }) => {\n if (entityRef) {\n const entityName = parseEntityName(entityRef);\n const target = entityRoute(entityName);\n return { title, icon, url: target };\n }\n return { title, icon, url: url! };\n })\n .map(({ url, title, icon }, i) => (\n <IconLink\n key={`output-link-${i}`}\n href={url}\n text={title ?? url}\n Icon={iconResolver(icon)}\n target=\"_blank\"\n />\n ))}\n </Box>\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 {\n Content,\n ErrorPage,\n Header,\n Lifecycle,\n Page,\n LogViewer,\n} from '@backstage/core-components';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport { BackstageTheme } from '@backstage/theme';\nimport {\n Button,\n CircularProgress,\n Paper,\n StepButton,\n StepIconProps,\n} from '@material-ui/core';\nimport Grid from '@material-ui/core/Grid';\nimport Step from '@material-ui/core/Step';\nimport StepLabel from '@material-ui/core/StepLabel';\nimport Stepper from '@material-ui/core/Stepper';\nimport { createStyles, makeStyles, Theme } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport Cancel from '@material-ui/icons/Cancel';\nimport Check from '@material-ui/icons/Check';\nimport FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';\nimport classNames from 'classnames';\nimport { DateTime, Interval } from 'luxon';\nimport qs from 'qs';\nimport React, { memo, useEffect, useMemo, useState } from 'react';\nimport { generatePath, useNavigate, useParams } from 'react-router';\nimport useInterval from 'react-use/lib/useInterval';\nimport { rootRouteRef } from '../../routes';\nimport { Status, TaskOutput } from '../../types';\nimport { useTaskEventStream } from '../hooks/useEventStream';\nimport { TaskPageLinks } from './TaskPageLinks';\n\n// typings are wrong for this library, so fallback to not parsing types.\nconst humanizeDuration = require('humanize-duration');\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n width: '100%',\n },\n button: {\n marginBottom: theme.spacing(2),\n marginLeft: theme.spacing(2),\n },\n actionsContainer: {\n marginBottom: theme.spacing(2),\n },\n resetContainer: {\n padding: theme.spacing(3),\n },\n labelWrapper: {\n display: 'flex',\n flex: 1,\n flexDirection: 'row',\n justifyContent: 'space-between',\n },\n stepWrapper: {\n width: '100%',\n },\n }),\n);\n\ntype TaskStep = {\n id: string;\n name: string;\n status: Status;\n startedAt?: string;\n endedAt?: string;\n};\n\nconst StepTimeTicker = ({ step }: { step: TaskStep }) => {\n const [time, setTime] = useState('');\n\n useInterval(() => {\n if (!step.startedAt) {\n setTime('');\n return;\n }\n\n const end = step.endedAt\n ? DateTime.fromISO(step.endedAt)\n : DateTime.local();\n\n const startedAt = DateTime.fromISO(step.startedAt);\n const formatted = Interval.fromDateTimes(startedAt, end)\n .toDuration()\n .valueOf();\n\n setTime(humanizeDuration(formatted, { round: true }));\n }, 1000);\n\n return <Typography variant=\"caption\">{time}</Typography>;\n};\n\nconst useStepIconStyles = makeStyles((theme: BackstageTheme) =>\n createStyles({\n root: {\n color: theme.palette.text.disabled,\n display: 'flex',\n height: 22,\n alignItems: 'center',\n },\n completed: {\n color: theme.palette.status.ok,\n },\n error: {\n color: theme.palette.status.error,\n },\n }),\n);\n\nfunction TaskStepIconComponent(props: StepIconProps) {\n const classes = useStepIconStyles();\n const { active, completed, error } = props;\n\n const getMiddle = () => {\n if (active) {\n return <CircularProgress size=\"24px\" />;\n }\n if (completed) {\n return <Check />;\n }\n if (error) {\n return <Cancel />;\n }\n return <FiberManualRecordIcon />;\n };\n\n return (\n <div\n className={classNames(classes.root, {\n [classes.completed]: completed,\n [classes.error]: error,\n })}\n >\n {getMiddle()}\n </div>\n );\n}\n\nexport const TaskStatusStepper = memo(\n ({\n steps,\n currentStepId,\n onUserStepChange,\n }: {\n steps: TaskStep[];\n currentStepId: string | undefined;\n onUserStepChange: (id: string) => void;\n }) => {\n const classes = useStyles();\n\n return (\n <div className={classes.root}>\n <Stepper\n activeStep={steps.findIndex(s => s.id === currentStepId)}\n orientation=\"vertical\"\n nonLinear\n >\n {steps.map((step, index) => {\n const isCompleted = step.status === 'completed';\n const isFailed = step.status === 'failed';\n const isActive = step.status === 'processing';\n const isSkipped = step.status === 'skipped';\n\n return (\n <Step key={String(index)} expanded>\n <StepButton onClick={() => onUserStepChange(step.id)}>\n <StepLabel\n StepIconProps={{\n completed: isCompleted,\n error: isFailed,\n active: isActive,\n }}\n StepIconComponent={TaskStepIconComponent}\n className={classes.stepWrapper}\n >\n <div className={classes.labelWrapper}>\n <Typography variant=\"subtitle2\">{step.name}</Typography>\n {isSkipped ? (\n <Typography variant=\"caption\">Skipped</Typography>\n ) : (\n <StepTimeTicker step={step} />\n )}\n </div>\n </StepLabel>\n </StepButton>\n </Step>\n );\n })}\n </Stepper>\n </div>\n );\n },\n);\n\nconst hasLinks = ({ entityRef, remoteUrl, links = [] }: TaskOutput): boolean =>\n !!(entityRef || remoteUrl || links.length > 0);\n\nexport const TaskPage = () => {\n const classes = useStyles();\n const navigate = useNavigate();\n const rootLink = useRouteRef(rootRouteRef);\n const [userSelectedStepId, setUserSelectedStepId] = useState<\n string | undefined\n >(undefined);\n const [lastActiveStepId, setLastActiveStepId] = useState<string | undefined>(\n undefined,\n );\n const { taskId } = useParams();\n const taskStream = useTaskEventStream(taskId);\n const completed = taskStream.completed;\n const steps = useMemo(\n () =>\n taskStream.task?.spec.steps.map(step => ({\n ...step,\n ...taskStream?.steps?.[step.id],\n })) ?? [],\n [taskStream],\n );\n\n useEffect(() => {\n const mostRecentFailedOrActiveStep = steps.find(step =>\n ['failed', 'processing'].includes(step.status),\n );\n if (completed && !mostRecentFailedOrActiveStep) {\n setLastActiveStepId(steps[steps.length - 1]?.id);\n return;\n }\n\n setLastActiveStepId(mostRecentFailedOrActiveStep?.id);\n }, [steps, completed]);\n\n const currentStepId = userSelectedStepId ?? lastActiveStepId;\n\n const logAsString = useMemo(() => {\n if (!currentStepId) {\n return 'Loading...';\n }\n const log = taskStream.stepLogs[currentStepId];\n\n if (!log?.length) {\n return 'Waiting for logs...';\n }\n return log.join('\\n');\n }, [taskStream.stepLogs, currentStepId]);\n\n const taskNotFound =\n taskStream.completed === true &&\n taskStream.loading === false &&\n !taskStream.task;\n\n const { output } = taskStream;\n\n const handleStartOver = () => {\n if (!taskStream.task || !taskStream.task?.spec.metadata?.name) {\n navigate(generatePath(rootLink()));\n }\n\n const formData =\n taskStream.task!.spec.apiVersion === 'backstage.io/v1beta2'\n ? taskStream.task!.spec.values\n : taskStream.task!.spec.parameters;\n\n navigate(\n generatePath(\n `${rootLink()}/templates/:templateName?${qs.stringify({ formData })}`,\n {\n templateName: taskStream.task!.spec.metadata!.name,\n },\n ),\n );\n };\n\n return (\n <Page themeId=\"home\">\n <Header\n pageTitleOverride={`Task ${taskId}`}\n title={\n <>\n Task Activity <Lifecycle alpha shorthand />\n </>\n }\n subtitle={`Activity for task: ${taskId}`}\n />\n <Content>\n {taskNotFound ? (\n <ErrorPage\n status=\"404\"\n statusMessage=\"Task not found\"\n additionalInfo=\"No task found with this ID\"\n />\n ) : (\n <div>\n <Grid container>\n <Grid item xs={3}>\n <Paper>\n <TaskStatusStepper\n steps={steps}\n currentStepId={currentStepId}\n onUserStepChange={setUserSelectedStepId}\n />\n {output && hasLinks(output) && (\n <TaskPageLinks output={output} />\n )}\n <Button\n className={classes.button}\n onClick={handleStartOver}\n disabled={!completed}\n variant=\"contained\"\n color=\"primary\"\n >\n Start Over\n </Button>\n </Paper>\n </Grid>\n <Grid item xs={9}>\n <div style={{ height: '80vh' }}>\n <LogViewer text={logAsString} />\n </div>\n </Grid>\n </Grid>\n </div>\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 { JSONSchema } from '@backstage/catalog-model';\nimport { 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: JSONSchema) => {\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 JSONSchema;\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: JSONSchema) => {\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 JSONSchema)}</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 { TemplateEntityV1beta2, Entity } from '@backstage/catalog-model';\nimport { ScaffolderPage } from './ScaffolderPage';\nimport { TemplatePage } from './TemplatePage';\nimport { TaskPage } from './TaskPage';\nimport { ActionsPage } from './ActionsPage';\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 groups?: Array<{\n title?: string;\n titleComponent?: React.ReactNode;\n filter: (entity: Entity) => boolean;\n }>;\n};\n\nexport const Router = ({ TemplateCardComponent, groups }: RouterProps) => {\n const outlet = useOutlet();\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={<TemplatePage customFieldExtensions={fieldExtensions} />}\n />\n <Route path=\"/tasks/:taskId\" element={<TaskPage />} />\n <Route path=\"/actions\" element={<ActionsPage />} />\n </Routes>\n );\n};\n"],"names":["useStyles","isObject","MuiTheme","StepUI","makeStyles","Typography","Stepper","Step","StepLabel","useParams","Grid"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-9d131a26.esm.js","sources":["../../src/api.ts","../../src/components/fields/EntityPicker/EntityPicker.tsx","../../src/components/fields/TextValuePicker/TextValuePicker.tsx","../../src/components/fields/EntityNamePicker/EntityNamePicker.tsx","../../src/components/fields/EntityNamePicker/validation.ts","../../src/components/fields/EntityTagsPicker/EntityTagsPicker.tsx","../../src/components/fields/OwnerPicker/OwnerPicker.tsx","../../src/components/fields/RepoUrlPicker/GithubRepoPicker.tsx","../../src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx","../../src/components/fields/RepoUrlPicker/AzureRepoPicker.tsx","../../src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx","../../src/components/fields/RepoUrlPicker/RepoUrlPickerHost.tsx","../../src/components/fields/RepoUrlPicker/utils.ts","../../src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx","../../src/components/fields/RepoUrlPicker/validation.ts","../../src/components/fields/OwnedEntityPicker/OwnedEntityPicker.tsx","../../src/extensions/index.tsx","../../src/routes.ts","../../src/plugin.ts","../../src/components/FavouriteTemplate/FavouriteTemplate.tsx","../../src/components/TemplateCard/TemplateCard.tsx","../../src/components/TemplateList/TemplateList.tsx","../../src/components/TemplateTypePicker/TemplateTypePicker.tsx"],"sourcesContent":["/*\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 { EntityName } from '@backstage/catalog-model';\nimport {\n createApiRef,\n DiscoveryApi,\n FetchApi,\n} from '@backstage/core-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport { Field, FieldValidation } from '@rjsf/core';\nimport qs from 'qs';\nimport ObservableImpl from 'zen-observable';\nimport { ListActionsResponse, ScaffolderTask, Status } from './types';\n\n/**\n * Utility API reference for the {@link ScaffolderApi}.\n *\n * @public\n */\nexport const scaffolderApiRef = createApiRef<ScaffolderApi>({\n id: 'plugin.scaffolder.service',\n});\n\ntype TemplateParameterSchema = {\n title: string;\n steps: Array<{\n title: string;\n schema: JsonObject;\n }>;\n};\n\nexport type LogEvent = {\n type: 'log' | 'completion';\n body: {\n message: string;\n stepId?: string;\n status?: Status;\n };\n createdAt: string;\n id: string;\n taskId: string;\n};\n\nexport type CustomField = {\n name: string;\n component: Field;\n validation: (data: JsonValue, field: FieldValidation) => void;\n};\n\n/**\n * An API to interact with the scaffolder backend.\n *\n * @public\n */\nexport interface ScaffolderApi {\n getTemplateParameterSchema(\n templateName: EntityName,\n ): Promise<TemplateParameterSchema>;\n\n /**\n * Executes the scaffolding of a component, given a template and its\n * parameter values.\n *\n * @param templateName - Name of the Template entity for the scaffolder to use. New project is going to be created out of this template.\n * @param values - Parameters for the template, e.g. name, description\n * @param secrets - Optional secrets to pass to as the secrets parameter to the template.\n */\n scaffold(\n templateName: string,\n values: Record<string, any>,\n secrets?: Record<string, string>,\n ): Promise<string>;\n\n getTask(taskId: string): Promise<ScaffolderTask>;\n\n getIntegrationsList(options: {\n allowedHosts: string[];\n }): Promise<{ type: string; title: string; host: string }[]>;\n\n /**\n * Returns a list of all installed actions.\n */\n listActions(): Promise<ListActionsResponse>;\n\n streamLogs(options: { taskId: string; after?: number }): Observable<LogEvent>;\n}\n\n/**\n * An API to interact with the scaffolder backend.\n *\n * @public\n */\nexport class ScaffolderClient implements ScaffolderApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly scmIntegrationsApi: ScmIntegrationRegistry;\n private readonly fetchApi: FetchApi;\n private readonly useLongPollingLogs: boolean;\n\n constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n scmIntegrationsApi: ScmIntegrationRegistry;\n useLongPollingLogs?: boolean;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi ?? { fetch };\n this.scmIntegrationsApi = options.scmIntegrationsApi;\n this.useLongPollingLogs = options.useLongPollingLogs ?? false;\n }\n\n async getIntegrationsList(options: { allowedHosts: string[] }) {\n return [\n ...this.scmIntegrationsApi.azure.list(),\n ...this.scmIntegrationsApi.bitbucket.list(),\n ...this.scmIntegrationsApi.github.list(),\n ...this.scmIntegrationsApi.gitlab.list(),\n ]\n .map(c => ({ type: c.type, title: c.title, host: c.config.host }))\n .filter(c => options.allowedHosts.includes(c.host));\n }\n\n async getTemplateParameterSchema(\n templateName: EntityName,\n ): Promise<TemplateParameterSchema> {\n const { namespace, kind, name } = templateName;\n\n const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder');\n const templatePath = [namespace, kind, name]\n .map(s => encodeURIComponent(s))\n .join('/');\n const url = `${baseUrl}/v2/templates/${templatePath}/parameter-schema`;\n\n const response = await this.fetchApi.fetch(url);\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n const schema: TemplateParameterSchema = await response.json();\n return schema;\n }\n\n /**\n * Executes the scaffolding of a component, given a template and its\n * parameter values.\n *\n * @param templateName - Template name for the scaffolder to use. New project is going to be created out of this template.\n * @param values - Parameters for the template, e.g. name, description\n * @param secrets - Optional secrets to pass to as the secrets parameter to the template.\n */\n async scaffold(\n templateName: string,\n values: Record<string, any>,\n secrets: Record<string, string> = {},\n ): Promise<string> {\n const url = `${await this.discoveryApi.getBaseUrl('scaffolder')}/v2/tasks`;\n const response = await this.fetchApi.fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n templateName,\n values: { ...values },\n secrets,\n }),\n });\n\n if (response.status !== 201) {\n const status = `${response.status} ${response.statusText}`;\n const body = await response.text();\n throw new Error(`Backend request failed, ${status} ${body.trim()}`);\n }\n\n const { id } = (await response.json()) as { id: string };\n return id;\n }\n\n async getTask(taskId: string) {\n const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder');\n const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}`;\n\n const response = await this.fetchApi.fetch(url);\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n streamLogs(options: {\n taskId: string;\n after?: number;\n }): Observable<LogEvent> {\n if (this.useLongPollingLogs) {\n return this.streamLogsPolling(options);\n }\n\n return this.streamLogsEventStream(options);\n }\n\n private streamLogsEventStream({\n taskId,\n after,\n }: {\n taskId: string;\n after?: number;\n }): Observable<LogEvent> {\n return new ObservableImpl(subscriber => {\n const params = new URLSearchParams();\n if (after !== undefined) {\n params.set('after', String(Number(after)));\n }\n\n this.discoveryApi.getBaseUrl('scaffolder').then(\n baseUrl => {\n const url = `${baseUrl}/v2/tasks/${encodeURIComponent(\n taskId,\n )}/eventstream`;\n const eventSource = new EventSource(url, { withCredentials: true });\n eventSource.addEventListener('log', (event: any) => {\n if (event.data) {\n try {\n subscriber.next(JSON.parse(event.data));\n } catch (ex) {\n subscriber.error(ex);\n }\n }\n });\n eventSource.addEventListener('completion', (event: any) => {\n if (event.data) {\n try {\n subscriber.next(JSON.parse(event.data));\n } catch (ex) {\n subscriber.error(ex);\n }\n }\n eventSource.close();\n subscriber.complete();\n });\n eventSource.addEventListener('error', event => {\n subscriber.error(event);\n });\n },\n error => {\n subscriber.error(error);\n },\n );\n });\n }\n\n private streamLogsPolling({\n taskId,\n after: inputAfter,\n }: {\n taskId: string;\n after?: number;\n }): Observable<LogEvent> {\n let after = inputAfter;\n\n return new ObservableImpl(subscriber => {\n this.discoveryApi.getBaseUrl('scaffolder').then(async baseUrl => {\n while (!subscriber.closed) {\n const url = `${baseUrl}/v2/tasks/${encodeURIComponent(\n taskId,\n )}/events?${qs.stringify({ after })}`;\n const response = await this.fetchApi.fetch(url);\n\n if (!response.ok) {\n // wait for one second to not run into an\n await new Promise(resolve => setTimeout(resolve, 1000));\n continue;\n }\n\n const logs = (await response.json()) as LogEvent[];\n\n for (const event of logs) {\n after = Number(event.id);\n\n subscriber.next(event);\n\n if (event.type === 'completion') {\n subscriber.complete();\n return;\n }\n }\n }\n });\n });\n }\n\n async listActions(): Promise<ListActionsResponse> {\n const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder');\n const response = await this.fetchApi.fetch(`${baseUrl}/v2/actions`);\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\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 { useApi } from '@backstage/core-plugin-api';\nimport {\n catalogApiRef,\n formatEntityRefTitle,\n} from '@backstage/plugin-catalog-react';\nimport { TextField } from '@material-ui/core';\nimport FormControl from '@material-ui/core/FormControl';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport { FieldProps, UiSchema } from '@rjsf/core';\nimport React, { useCallback, useEffect } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\n\nexport const allowArbitraryValues = (uiSchema: UiSchema): boolean =>\n (uiSchema['ui:options']?.allowArbitraryValues as boolean) ?? true;\n\nexport const EntityPicker = ({\n onChange,\n schema: { title = 'Entity', description = 'An entity from the catalog' },\n required,\n uiSchema,\n rawErrors,\n formData,\n idSchema,\n}: FieldProps<string>) => {\n const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[];\n const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined;\n const catalogApi = useApi(catalogApiRef);\n\n const { value: entities, loading } = useAsync(() =>\n catalogApi.getEntities(\n allowedKinds ? { filter: { kind: allowedKinds } } : undefined,\n ),\n );\n\n const entityRefs = entities?.items.map(e =>\n formatEntityRefTitle(e, { defaultKind }),\n );\n\n const onSelect = useCallback(\n (_: any, value: string | null) => {\n onChange(value || '');\n },\n [onChange],\n );\n\n useEffect(() => {\n if (entityRefs?.length === 1) {\n onChange(entityRefs[0]);\n }\n }, [entityRefs, onChange]);\n\n return (\n <FormControl\n margin=\"normal\"\n required={required}\n error={rawErrors?.length > 0 && !formData}\n >\n <Autocomplete\n disabled={entityRefs?.length === 1}\n id={idSchema?.$id}\n value={(formData as string) || ''}\n loading={loading}\n onChange={onSelect}\n options={entityRefs || []}\n autoSelect\n freeSolo={allowArbitraryValues(uiSchema)}\n renderInput={params => (\n <TextField\n {...params}\n label={title}\n margin=\"normal\"\n helperText={description}\n variant=\"outlined\"\n required={required}\n InputProps={params.InputProps}\n />\n )}\n />\n </FormControl>\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 { TextField } from '@material-ui/core';\nimport { FieldProps } from '@rjsf/core';\nimport React from 'react';\n\nexport const TextValuePicker = ({\n onChange,\n required,\n schema: { title, description },\n rawErrors,\n formData,\n uiSchema: { 'ui:autofocus': autoFocus },\n idSchema,\n placeholder,\n}: FieldProps<string>) => (\n <TextField\n id={idSchema?.$id}\n label={title}\n placeholder={placeholder}\n helperText={description}\n required={required}\n value={formData ?? ''}\n onChange={({ target: { value } }) => onChange(value)}\n margin=\"normal\"\n error={rawErrors?.length > 0 && !formData}\n inputProps={{ autoFocus }}\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 { FieldProps } from '@rjsf/core';\nimport { TextValuePicker } from '../TextValuePicker';\n\nexport const EntityNamePicker = ({\n schema: { title = 'Name', description = 'Unique name of the component' },\n ...props\n}: FieldProps<string>) => (\n <TextValuePicker schema={{ title, description }} {...props} />\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 { FieldValidation } from '@rjsf/core';\nimport { KubernetesValidatorFunctions } from '@backstage/catalog-model';\n\nexport const entityNamePickerValidation = (\n value: string,\n validation: FieldValidation,\n) => {\n if (!KubernetesValidatorFunctions.isValidObjectName(value)) {\n validation.addError(\n 'must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.',\n );\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, { useState } from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport useEffectOnce from 'react-use/lib/useEffectOnce';\nimport { CatalogEntitiesRequest } from '@backstage/catalog-client';\nimport { Entity, makeValidator } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { FormControl, TextField } from '@material-ui/core';\nimport { Autocomplete } from '@material-ui/lab';\nimport { FieldProps } from '@rjsf/core';\n\n/**\n * EntityTagsPicker\n * @public\n */\nexport const EntityTagsPicker = ({\n formData,\n onChange,\n uiSchema,\n}: FieldProps<string[]>) => {\n const catalogApi = useApi(catalogApiRef);\n const [inputValue, setInputValue] = useState('');\n const [inputError, setInputError] = useState(false);\n const tagValidator = makeValidator().isValidTag;\n const kinds = uiSchema['ui:options']?.kinds as string[];\n\n const { loading, value: existingTags } = useAsync(async () => {\n const tagsRequest: CatalogEntitiesRequest = { fields: ['metadata.tags'] };\n if (kinds) {\n tagsRequest.filter = { kind: kinds };\n }\n\n const entities = await catalogApi.getEntities(tagsRequest);\n\n return [\n ...new Set(\n entities.items\n .flatMap((e: Entity) => e.metadata?.tags)\n .filter(Boolean) as string[],\n ),\n ].sort();\n });\n\n const setTags = (_: React.ChangeEvent<{}>, values: string[] | null) => {\n // Reset error state in case all tags were removed\n let hasError = false;\n let addDuplicate = false;\n const currentTags = formData || [];\n\n // If adding a new tag\n if (values?.length && currentTags.length < values.length) {\n const newTag = (values[values.length - 1] = values[values.length - 1]\n .toLocaleLowerCase('en-US')\n .trim());\n hasError = !tagValidator(newTag);\n addDuplicate = currentTags.indexOf(newTag) !== -1;\n }\n\n setInputError(hasError);\n setInputValue(!hasError ? '' : inputValue);\n if (!hasError && !addDuplicate) {\n onChange(values || []);\n }\n };\n\n // Initialize field to always return an array\n useEffectOnce(() => onChange(formData || []));\n\n return (\n <FormControl margin=\"normal\">\n <Autocomplete\n multiple\n freeSolo\n filterSelectedOptions\n onChange={setTags}\n value={formData || []}\n inputValue={inputValue}\n loading={loading}\n options={existingTags || []}\n ChipProps={{ size: 'small' }}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Tags\"\n onChange={e => setInputValue(e.target.value)}\n error={inputError}\n helperText=\"Add any relevant tags, hit 'Enter' to add new tags. Valid format: [a-z0-9+#] separated by [-], at most 63 characters\"\n />\n )}\n />\n </FormControl>\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 { FieldProps } from '@rjsf/core';\nimport React from 'react';\nimport { EntityPicker } from '../EntityPicker';\n\nexport const OwnerPicker = ({\n schema: { title = 'Owner', description = 'The owner of the component' },\n uiSchema,\n ...props\n}: FieldProps<string>) => {\n const ownerUiSchema = {\n ...uiSchema,\n 'ui:options': {\n allowedKinds: (uiSchema['ui:options']?.allowedKinds || [\n 'Group',\n 'User',\n ]) as string[],\n defaultKind: 'Group',\n },\n };\n\n return (\n <EntityPicker\n {...props}\n schema={{ title, description }}\n uiSchema={ownerUiSchema}\n />\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 FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport { Select, SelectItem } from '@backstage/core-components';\nimport { RepoUrlPickerState } from './types';\n\nexport const GithubRepoPicker = (props: {\n allowedOwners?: string[];\n rawErrors: string[];\n state: RepoUrlPickerState;\n onChange: (state: RepoUrlPickerState) => void;\n}) => {\n const { allowedOwners = [], rawErrors, state, onChange } = props;\n const ownerItems: SelectItem[] = allowedOwners\n ? allowedOwners.map(i => ({ label: i, value: i }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n const { owner, repoName } = state;\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !owner}\n >\n {allowedOwners?.length ? (\n <Select\n native\n label=\"Owner Available\"\n onChange={s =>\n onChange({ owner: String(Array.isArray(s) ? s[0] : s) })\n }\n disabled={allowedOwners.length === 1}\n selected={owner}\n items={ownerItems}\n />\n ) : (\n <>\n <InputLabel htmlFor=\"ownerInput\">Owner</InputLabel>\n <Input\n id=\"ownerInput\"\n onChange={e => onChange({ owner: e.target.value })}\n value={owner}\n />\n </>\n )}\n <FormHelperText>\n The organization, user or project that this repo will belong to\n </FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange({ repoName: e.target.value })}\n value={repoName}\n />\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\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 FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport { Select, SelectItem } from '@backstage/core-components';\nimport { RepoUrlPickerState } from './types';\n\nexport const GitlabRepoPicker = (props: {\n allowedOwners?: string[];\n state: RepoUrlPickerState;\n onChange: (state: RepoUrlPickerState) => void;\n rawErrors: string[];\n}) => {\n const { allowedOwners = [], rawErrors, state, onChange } = props;\n const ownerItems: SelectItem[] = allowedOwners\n ? allowedOwners.map(i => ({ label: i, value: i }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n const { owner, repoName } = state;\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !owner}\n >\n {allowedOwners?.length ? (\n <Select\n native\n label=\"Owner Available\"\n onChange={selected =>\n onChange({\n owner: String(Array.isArray(selected) ? selected[0] : selected),\n })\n }\n disabled={allowedOwners.length === 1}\n selected={owner}\n items={ownerItems}\n />\n ) : (\n <>\n <InputLabel htmlFor=\"ownerInput\">Owner</InputLabel>\n <Input\n id=\"ownerInput\"\n onChange={e => onChange({ owner: e.target.value })}\n value={owner}\n />\n </>\n )}\n <FormHelperText>\n The organization, user or project that this repo will belong to\n </FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange({ repoName: e.target.value })}\n value={repoName}\n />\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\n );\n};\n","/*\n * Copyright 2022 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 FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport { RepoUrlPickerState } from './types';\n\nexport const AzureRepoPicker = (props: {\n state: RepoUrlPickerState;\n onChange: (state: RepoUrlPickerState) => void;\n rawErrors: string[];\n}) => {\n const { rawErrors, state, onChange } = props;\n const { organization, repoName, owner } = state;\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !organization}\n >\n <InputLabel htmlFor=\"orgInput\">Organization</InputLabel>\n <Input\n id=\"orgInput\"\n onChange={e => onChange({ organization: e.target.value })}\n value={organization}\n />\n <FormHelperText>\n The organization that this repo will belong to\n </FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !owner}\n >\n <InputLabel htmlFor=\"ownerInput\">Owner</InputLabel>\n <Input\n id=\"ownerInput\"\n onChange={e => onChange({ owner: e.target.value })}\n value={owner}\n />\n <FormHelperText>The Owner that this repo will belong to</FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange({ repoName: e.target.value })}\n value={repoName}\n />\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\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 FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport Input from '@material-ui/core/Input';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport { RepoUrlPickerState } from './types';\n\nexport const BitbucketRepoPicker = (props: {\n onChange: (state: RepoUrlPickerState) => void;\n state: RepoUrlPickerState;\n rawErrors: string[];\n}) => {\n const { onChange, rawErrors, state } = props;\n const { host, workspace, project, repoName } = state;\n return (\n <>\n {host === 'bitbucket.org' && (\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !workspace}\n >\n <InputLabel htmlFor=\"workspaceInput\">Workspace</InputLabel>\n <Input\n id=\"workspaceInput\"\n onChange={e => onChange({ workspace: e.target.value })}\n value={workspace}\n />\n <FormHelperText>\n The Organization that this repo will belong to\n </FormHelperText>\n </FormControl>\n )}\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !project}\n >\n <InputLabel htmlFor=\"projectInput\">Project</InputLabel>\n <Input\n id=\"projectInput\"\n onChange={e => onChange({ project: e.target.value })}\n value={project}\n />\n <FormHelperText>\n The Project that this repo will belong to\n </FormHelperText>\n </FormControl>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !repoName}\n >\n <InputLabel htmlFor=\"repoNameInput\">Repository</InputLabel>\n <Input\n id=\"repoNameInput\"\n onChange={e => onChange({ repoName: e.target.value })}\n value={repoName}\n />\n <FormHelperText>The name of the repository</FormHelperText>\n </FormControl>\n </>\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, { useEffect } from 'react';\nimport { Progress, Select, SelectItem } from '@backstage/core-components';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormHelperText from '@material-ui/core/FormHelperText';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { scaffolderApiRef } from '../../../api';\nimport useAsync from 'react-use/lib/useAsync';\n\nexport const RepoUrlPickerHost = (props: {\n host?: string;\n hosts?: string[];\n onChange: (host: string) => void;\n rawErrors: string[];\n}) => {\n const { host, hosts, onChange, rawErrors } = props;\n const scaffolderApi = useApi(scaffolderApiRef);\n\n const { value: integrations, loading } = useAsync(async () => {\n return await scaffolderApi.getIntegrationsList({\n allowedHosts: hosts ?? [],\n });\n });\n\n useEffect(() => {\n if (hosts && !host) {\n // This is only hear to set the default as the first one in the hosts array\n // if the host is not set yet and there is a list of hosts.\n onChange(hosts[0]);\n }\n }, [hosts, host, onChange]);\n\n const hostsOptions: SelectItem[] = integrations\n ? integrations\n .filter(i => hosts?.includes(i.host))\n .map(i => ({ label: i.title, value: i.host }))\n : [{ label: 'Loading...', value: 'loading' }];\n\n if (loading) {\n return <Progress />;\n }\n\n return (\n <>\n <FormControl\n margin=\"normal\"\n required\n error={rawErrors?.length > 0 && !host}\n >\n <Select\n native\n disabled={hosts?.length === 1 ?? false}\n label=\"Host\"\n onChange={s => onChange(String(Array.isArray(s) ? s[0] : s))}\n selected={host}\n items={hostsOptions}\n data-testid=\"host-select\"\n />\n\n <FormHelperText>\n The host where the repository will be created\n </FormHelperText>\n </FormControl>\n </>\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 { RepoUrlPickerState } from './types';\n\nexport function serializeRepoPickerUrl(data: RepoUrlPickerState) {\n if (!data.host) {\n return undefined;\n }\n\n const params = new URLSearchParams();\n if (data.owner) {\n params.set('owner', data.owner);\n }\n if (data.repoName) {\n params.set('repo', data.repoName);\n }\n if (data.organization) {\n params.set('organization', data.organization);\n }\n if (data.workspace) {\n params.set('workspace', data.workspace);\n }\n if (data.project) {\n params.set('project', data.project);\n }\n\n return `${data.host}?${params.toString()}`;\n}\n\nexport function parseRepoPickerUrl(\n url: string | undefined,\n): RepoUrlPickerState {\n let host = undefined;\n let owner = undefined;\n let repoName = undefined;\n let organization = undefined;\n let workspace = undefined;\n let project = undefined;\n\n try {\n if (url) {\n const parsed = new URL(`https://${url}`);\n host = parsed.host;\n owner = parsed.searchParams.get('owner') || undefined;\n repoName = parsed.searchParams.get('repo') || undefined;\n organization = parsed.searchParams.get('organization') || undefined;\n workspace = parsed.searchParams.get('workspace') || undefined;\n project = parsed.searchParams.get('project') || undefined;\n }\n } catch {\n /* ok */\n }\n\n return { host, owner, repoName, organization, workspace, project };\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 { useApi } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\nimport React, { useEffect, useState, useMemo, useCallback } from 'react';\nimport { GithubRepoPicker } from './GithubRepoPicker';\nimport { GitlabRepoPicker } from './GitlabRepoPicker';\nimport { AzureRepoPicker } from './AzureRepoPicker';\nimport { BitbucketRepoPicker } from './BitbucketRepoPicker';\nimport { FieldExtensionComponentProps } from '../../../extensions';\nimport { RepoUrlPickerHost } from './RepoUrlPickerHost';\nimport { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils';\nimport { RepoUrlPickerState } from './types';\n\nexport interface RepoUrlPickerUiOptions {\n allowedHosts?: string[];\n allowedOwners?: string[];\n}\n\nexport const RepoUrlPicker = (\n props: FieldExtensionComponentProps<string, RepoUrlPickerUiOptions>,\n) => {\n const { uiSchema, onChange, rawErrors, formData } = props;\n const [state, setState] = useState<RepoUrlPickerState>(\n parseRepoPickerUrl(formData),\n );\n const integrationApi = useApi(scmIntegrationsApiRef);\n\n const allowedHosts = useMemo(\n () => uiSchema?.['ui:options']?.allowedHosts ?? [],\n [uiSchema],\n );\n const allowedOwners = useMemo(\n () => uiSchema?.['ui:options']?.allowedOwners ?? [],\n [uiSchema],\n );\n\n useEffect(() => {\n onChange(serializeRepoPickerUrl(state));\n }, [state, onChange]);\n\n /* we deal with calling the repo setting here instead of in each components for ease */\n useEffect(() => {\n if (allowedOwners.length === 1) {\n setState(prevState => ({ ...prevState, owner: allowedOwners[0] }));\n }\n }, [setState, allowedOwners]);\n\n const updateLocalState = useCallback(\n (newState: RepoUrlPickerState) => {\n setState(prevState => ({ ...prevState, ...newState }));\n },\n [setState],\n );\n\n const hostType =\n (state.host && integrationApi.byHost(state.host)?.type) ?? null;\n\n return (\n <>\n <RepoUrlPickerHost\n host={state.host}\n hosts={allowedHosts}\n onChange={host => setState(prevState => ({ ...prevState, host }))}\n rawErrors={rawErrors}\n />\n {hostType === 'github' && (\n <GithubRepoPicker\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'gitlab' && (\n <GitlabRepoPicker\n allowedOwners={allowedOwners}\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'bitbucket' && (\n <BitbucketRepoPicker\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n {hostType === 'azure' && (\n <AzureRepoPicker\n rawErrors={rawErrors}\n state={state}\n onChange={updateLocalState}\n />\n )}\n </>\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 { FieldValidation } from '@rjsf/core';\nimport { ApiHolder } from '@backstage/core-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\n\nexport const repoPickerValidation = (\n value: string,\n validation: FieldValidation,\n context: { apiHolder: ApiHolder },\n) => {\n try {\n const { host, searchParams } = new URL(`https://${value}`);\n\n const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);\n\n if (!host) {\n validation.addError(\n 'Incomplete repository location provided, host not provided',\n );\n } else {\n if (integrationApi?.byHost(host)?.type === 'bitbucket') {\n // workspace is only applicable for bitbucket cloud\n if (host === 'bitbucket.org' && !searchParams.get('workspace')) {\n validation.addError(\n 'Incomplete repository location provided, workspace not provided',\n );\n }\n\n if (!searchParams.get('project')) {\n validation.addError(\n 'Incomplete repository location provided, project not provided',\n );\n }\n }\n // For anything other than bitbucket\n else {\n if (!searchParams.get('owner')) {\n validation.addError(\n 'Incomplete repository location provided, owner not provided',\n );\n }\n }\n\n // Do this for all hosts\n if (!searchParams.get('repo')) {\n validation.addError(\n 'Incomplete repository location provided, repo not provided',\n );\n }\n }\n } catch {\n validation.addError('Unable to parse the Repository URL');\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 {\n formatEntityRefTitle,\n useOwnedEntities,\n} from '@backstage/plugin-catalog-react';\nimport { TextField } from '@material-ui/core';\nimport FormControl from '@material-ui/core/FormControl';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport { FieldProps } from '@rjsf/core';\nimport React from 'react';\n\nexport const OwnedEntityPicker = ({\n onChange,\n schema: { title = 'Entity', description = 'An entity from the catalog' },\n required,\n uiSchema,\n rawErrors,\n formData,\n idSchema,\n}: FieldProps<string>) => {\n const allowedKinds = uiSchema['ui:options']?.allowedKinds as string[];\n const defaultKind = uiSchema['ui:options']?.defaultKind as string | undefined;\n const { ownedEntities, loading } = useOwnedEntities(allowedKinds);\n\n const entityRefs = ownedEntities?.items\n .map(e => formatEntityRefTitle(e, { defaultKind }))\n .filter(n => n);\n\n const onSelect = (_: any, value: string | null) => {\n onChange(value || '');\n };\n\n return (\n <FormControl\n margin=\"normal\"\n required={required}\n error={rawErrors?.length > 0 && !formData}\n >\n <Autocomplete\n id={idSchema?.$id}\n value={(formData as string) || ''}\n loading={loading}\n onChange={onSelect}\n options={entityRefs || []}\n autoSelect\n freeSolo\n renderInput={params => (\n <TextField\n {...params}\n label={title}\n margin=\"normal\"\n helperText={description}\n variant=\"outlined\"\n required={required}\n InputProps={params.InputProps}\n />\n )}\n />\n </FormControl>\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 from 'react';\nimport {\n CustomFieldValidator,\n FieldExtensionOptions,\n FieldExtensionComponentProps,\n} from './types';\nimport { Extension, attachComponentData } from '@backstage/core-plugin-api';\n\nexport const FIELD_EXTENSION_WRAPPER_KEY = 'scaffolder.extensions.wrapper.v1';\nexport const FIELD_EXTENSION_KEY = 'scaffolder.extensions.field.v1';\n\nexport function createScaffolderFieldExtension<T = any>(\n options: FieldExtensionOptions<T>,\n): Extension<() => null> {\n return {\n expose() {\n const FieldExtensionDataHolder: any = () => null;\n\n attachComponentData(\n FieldExtensionDataHolder,\n FIELD_EXTENSION_KEY,\n options,\n );\n\n return FieldExtensionDataHolder;\n },\n };\n}\n\nexport const ScaffolderFieldExtensions: React.ComponentType = () => null;\nattachComponentData(\n ScaffolderFieldExtensions,\n FIELD_EXTENSION_WRAPPER_KEY,\n true,\n);\n\nexport type {\n CustomFieldValidator,\n FieldExtensionOptions,\n FieldExtensionComponentProps,\n};\n\nexport { DEFAULT_SCAFFOLDER_FIELD_EXTENSIONS } from './default';\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 {\n createExternalRouteRef,\n createRouteRef,\n} from '@backstage/core-plugin-api';\n\nexport const registerComponentRouteRef = createExternalRouteRef({\n id: 'register-component',\n optional: true,\n});\n\nexport const rootRouteRef = createRouteRef({\n id: 'scaffolder',\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 { scmIntegrationsApiRef } from '@backstage/integration-react';\nimport { scaffolderApiRef, ScaffolderClient } from './api';\nimport { EntityPicker } from './components/fields/EntityPicker';\nimport {\n entityNamePickerValidation,\n EntityNamePicker,\n} from './components/fields/EntityNamePicker';\nimport { OwnerPicker } from './components/fields/OwnerPicker';\nimport {\n repoPickerValidation,\n RepoUrlPicker,\n} from './components/fields/RepoUrlPicker';\nimport { createScaffolderFieldExtension } from './extensions';\nimport { registerComponentRouteRef, rootRouteRef } from './routes';\nimport {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/core-plugin-api';\nimport { OwnedEntityPicker } from './components/fields/OwnedEntityPicker';\nimport { EntityTagsPicker } from './components/fields/EntityTagsPicker';\n\nexport const scaffolderPlugin = createPlugin({\n id: 'scaffolder',\n apis: [\n createApiFactory({\n api: scaffolderApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n scmIntegrationsApi: scmIntegrationsApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, scmIntegrationsApi, fetchApi }) =>\n new ScaffolderClient({\n discoveryApi,\n scmIntegrationsApi,\n fetchApi,\n }),\n }),\n ],\n routes: {\n root: rootRouteRef,\n },\n externalRoutes: {\n registerComponent: registerComponentRouteRef,\n },\n});\n\nexport const EntityPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: EntityPicker,\n name: 'EntityPicker',\n }),\n);\n\nexport const EntityNamePickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: EntityNamePicker,\n name: 'EntityNamePicker',\n validation: entityNamePickerValidation,\n }),\n);\n\nexport const RepoUrlPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: RepoUrlPicker,\n name: 'RepoUrlPicker',\n validation: repoPickerValidation,\n }),\n);\n\nexport const OwnerPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: OwnerPicker,\n name: 'OwnerPicker',\n }),\n);\n\nexport const ScaffolderPage = scaffolderPlugin.provide(\n createRoutableExtension({\n name: 'ScaffolderPage',\n component: () => import('./components/Router').then(m => m.Router),\n mountPoint: rootRouteRef,\n }),\n);\n\nexport const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: OwnedEntityPicker,\n name: 'OwnedEntityPicker',\n }),\n);\n\n/**\n * EntityTagsPickerFieldExtension\n * @public\n */\nexport const EntityTagsPickerFieldExtension = scaffolderPlugin.provide(\n createScaffolderFieldExtension({\n component: EntityTagsPicker,\n name: 'EntityTagsPicker',\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 { Entity } from '@backstage/catalog-model';\nimport { useStarredEntity } from '@backstage/plugin-catalog-react';\nimport { IconButton, makeStyles, Tooltip, withStyles } from '@material-ui/core';\nimport Star from '@material-ui/icons/Star';\nimport StarBorder from '@material-ui/icons/StarBorder';\nimport React, { ComponentProps } from 'react';\n\ntype Props = ComponentProps<typeof IconButton> & { entity: Entity };\n\nconst YellowStar = withStyles({\n root: {\n color: '#f3ba37',\n },\n})(Star);\n\nconst WhiteBorderStar = withStyles({\n root: {\n color: '#ffffff',\n },\n})(StarBorder);\n\nconst useStyles = makeStyles(theme => ({\n starButton: {\n position: 'absolute',\n top: theme.spacing(0.5),\n right: theme.spacing(0.5),\n padding: '0.25rem',\n },\n}));\n\nexport const favouriteTemplateTooltip = (isStarred: boolean) =>\n isStarred ? 'Remove from favorites' : 'Add to favorites';\n\nexport const favouriteTemplateIcon = (isStarred: boolean) =>\n isStarred ? <YellowStar /> : <WhiteBorderStar />;\n\n/**\n * IconButton for showing if a current entity is starred and adding/removing it from the favourite entities\n * @param props - MaterialUI IconButton props extended by required `entity` prop\n */\nexport const FavouriteTemplate = (props: Props) => {\n const classes = useStyles();\n const { toggleStarredEntity, isStarredEntity } = useStarredEntity(\n props.entity,\n );\n return (\n <IconButton\n color=\"inherit\"\n className={classes.starButton}\n {...props}\n onClick={() => toggleStarredEntity()}\n >\n <Tooltip title={favouriteTemplateTooltip(isStarredEntity)}>\n {favouriteTemplateIcon(isStarredEntity)}\n </Tooltip>\n </IconButton>\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 {\n Entity,\n RELATION_OWNED_BY,\n TemplateEntityV1beta2,\n} from '@backstage/catalog-model';\nimport {\n ScmIntegrationIcon,\n scmIntegrationsApiRef,\n} from '@backstage/integration-react';\nimport {\n EntityRefLinks,\n getEntityRelations,\n getEntitySourceLocation,\n} from '@backstage/plugin-catalog-react';\nimport { BackstageTheme } from '@backstage/theme';\nimport {\n Box,\n Card,\n CardActions,\n CardContent,\n CardMedia,\n Chip,\n IconButton,\n Link,\n makeStyles,\n Tooltip,\n Typography,\n useTheme,\n} from '@material-ui/core';\nimport WarningIcon from '@material-ui/icons/Warning';\nimport React from 'react';\nimport { generatePath } from 'react-router';\nimport { rootRouteRef } from '../../routes';\nimport { FavouriteTemplate } from '../FavouriteTemplate/FavouriteTemplate';\n\nimport { Button, ItemCardHeader } from '@backstage/core-components';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\n\nconst useStyles = makeStyles(theme => ({\n cardHeader: {\n position: 'relative',\n },\n title: {\n backgroundImage: ({ backgroundImage }: any) => backgroundImage,\n },\n box: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n display: '-webkit-box',\n '-webkit-line-clamp': 10,\n '-webkit-box-orient': 'vertical',\n paddingBottom: '0.8em',\n },\n label: {\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n fontSize: '0.65rem',\n fontWeight: 'bold',\n letterSpacing: 0.5,\n lineHeight: 1,\n paddingBottom: '0.2rem',\n },\n leftButton: {\n marginRight: 'auto',\n },\n}));\n\nconst useDeprecationStyles = makeStyles(theme => ({\n deprecationIcon: {\n position: 'absolute',\n top: theme.spacing(0.5),\n right: theme.spacing(3.5),\n padding: '0.25rem',\n },\n link: {\n color: theme.palette.warning.light,\n },\n}));\n\nexport type TemplateCardProps = {\n template: TemplateEntityV1beta2;\n deprecated?: boolean;\n};\n\ntype TemplateProps = {\n description: string;\n tags: string[];\n title: string;\n type: string;\n name: string;\n};\n\nconst getTemplateCardProps = (\n template: TemplateEntityV1beta2,\n): TemplateProps & { key: string } => {\n return {\n key: template.metadata.uid!,\n name: template.metadata.name,\n title: `${(template.metadata.title || template.metadata.name) ?? ''}`,\n type: template.spec.type ?? '',\n description: template.metadata.description ?? '-',\n tags: (template.metadata?.tags as string[]) ?? [],\n };\n};\n\nconst DeprecationWarning = () => {\n const styles = useDeprecationStyles();\n\n const Title = (\n <Typography style={{ padding: 10, maxWidth: 300 }}>\n This template syntax is deprecated. Click for more info.\n </Typography>\n );\n\n return (\n <div className={styles.deprecationIcon}>\n <Tooltip title={Title}>\n <Link\n href=\"https://backstage.io/docs/features/software-templates/migrating-from-v1alpha1-to-v1beta2\"\n className={styles.link}\n >\n <WarningIcon />\n </Link>\n </Tooltip>\n </div>\n );\n};\n\nexport const TemplateCard = ({ template, deprecated }: TemplateCardProps) => {\n const backstageTheme = useTheme<BackstageTheme>();\n const rootLink = useRouteRef(rootRouteRef);\n const templateProps = getTemplateCardProps(template);\n const ownedByRelations = getEntityRelations(\n template as Entity,\n RELATION_OWNED_BY,\n );\n const themeId = backstageTheme.getPageTheme({ themeId: templateProps.type })\n ? templateProps.type\n : 'other';\n const theme = backstageTheme.getPageTheme({ themeId });\n const classes = useStyles({ backgroundImage: theme.backgroundImage });\n const href = generatePath(`${rootLink()}/templates/:templateName`, {\n templateName: templateProps.name,\n });\n\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const sourceLocation = getEntitySourceLocation(template, scmIntegrationsApi);\n\n return (\n <Card>\n <CardMedia className={classes.cardHeader}>\n <FavouriteTemplate entity={template} />\n {deprecated && <DeprecationWarning />}\n <ItemCardHeader\n title={templateProps.title}\n subtitle={templateProps.type}\n classes={{ root: classes.title }}\n />\n </CardMedia>\n <CardContent style={{ display: 'grid' }}>\n <Box className={classes.box}>\n <Typography variant=\"body2\" className={classes.label}>\n Description\n </Typography>\n {templateProps.description}\n </Box>\n <Box className={classes.box}>\n <Typography variant=\"body2\" className={classes.label}>\n Owner\n </Typography>\n <EntityRefLinks entityRefs={ownedByRelations} defaultKind=\"Group\" />\n </Box>\n <Box>\n <Typography variant=\"body2\" className={classes.label}>\n Tags\n </Typography>\n {templateProps.tags?.map(tag => (\n <Chip size=\"small\" label={tag} key={tag} />\n ))}\n </Box>\n </CardContent>\n <CardActions>\n {sourceLocation && (\n <IconButton\n className={classes.leftButton}\n href={sourceLocation.locationTargetUrl}\n >\n <ScmIntegrationIcon type={sourceLocation.integrationType} />\n </IconButton>\n )}\n <Button\n color=\"primary\"\n to={href}\n aria-label={`Choose ${templateProps.title}`}\n >\n Choose\n </Button>\n </CardActions>\n </Card>\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 {\n Entity,\n stringifyEntityRef,\n TemplateEntityV1beta2,\n} from '@backstage/catalog-model';\nimport {\n Content,\n ContentHeader,\n ItemCardGrid,\n Link,\n Progress,\n WarningPanel,\n} from '@backstage/core-components';\nimport { useEntityListProvider } from '@backstage/plugin-catalog-react';\nimport { Typography } from '@material-ui/core';\nimport { TemplateCard } from '../TemplateCard';\n\nexport type TemplateListProps = {\n TemplateCardComponent?:\n | ComponentType<{ template: TemplateEntityV1beta2 }>\n | undefined;\n group?: {\n title?: string;\n titleComponent?: React.ReactNode;\n filter: (entity: Entity) => boolean;\n };\n};\n\nexport const TemplateList = ({\n TemplateCardComponent,\n group,\n}: TemplateListProps) => {\n const { loading, error, entities } = useEntityListProvider();\n const Card = TemplateCardComponent || TemplateCard;\n const maybeFilteredEntities = group\n ? entities.filter(e => group.filter(e))\n : entities;\n const title = group ? (\n group.titleComponent || <ContentHeader title={group.title} />\n ) : (\n <ContentHeader title=\"Other Templates\" />\n );\n\n if (group && maybeFilteredEntities.length === 0) {\n return null;\n }\n return (\n <>\n {loading && <Progress />}\n\n {error && (\n <WarningPanel title=\"Oops! Something went wrong loading the templates\">\n {error.message}\n </WarningPanel>\n )}\n\n {!error && !loading && !entities.length && (\n <Typography variant=\"body2\">\n No templates found that match your filter. Learn more about{' '}\n <Link to=\"https://backstage.io/docs/features/software-templates/adding-templates\">\n adding templates\n </Link>\n .\n </Typography>\n )}\n\n <Content>\n {title}\n <ItemCardGrid>\n {maybeFilteredEntities &&\n maybeFilteredEntities?.length > 0 &&\n maybeFilteredEntities.map((template: Entity) => (\n <Card\n key={stringifyEntityRef(template)}\n template={template as TemplateEntityV1beta2}\n />\n ))}\n </ItemCardGrid>\n </Content>\n </>\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 from 'react';\nimport capitalize from 'lodash/capitalize';\nimport { Progress } from '@backstage/core-components';\nimport {\n Box,\n Checkbox,\n FormControlLabel,\n TextField,\n Typography,\n} from '@material-ui/core';\nimport CheckBoxIcon from '@material-ui/icons/CheckBox';\nimport CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport { Autocomplete } from '@material-ui/lab';\nimport { useEntityTypeFilter } from '@backstage/plugin-catalog-react';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\n\nconst icon = <CheckBoxOutlineBlankIcon fontSize=\"small\" />;\nconst checkedIcon = <CheckBoxIcon fontSize=\"small\" />;\n\nexport const TemplateTypePicker = () => {\n const alertApi = useApi(alertApiRef);\n const { error, loading, availableTypes, selectedTypes, setSelectedTypes } =\n useEntityTypeFilter();\n\n if (loading) return <Progress />;\n\n if (!availableTypes) return null;\n\n if (error) {\n alertApi.post({\n message: `Failed to load entity types`,\n severity: 'error',\n });\n return null;\n }\n\n return (\n <Box pb={1} pt={1}>\n <Typography variant=\"button\">Categories</Typography>\n <Autocomplete\n multiple\n aria-label=\"Categories\"\n options={availableTypes}\n value={selectedTypes}\n onChange={(_: object, value: string[]) => setSelectedTypes(value)}\n renderOption={(option, { selected }) => (\n <FormControlLabel\n control={\n <Checkbox\n icon={icon}\n checkedIcon={checkedIcon}\n checked={selected}\n />\n }\n label={capitalize(option)}\n />\n )}\n size=\"small\"\n popupIcon={<ExpandMoreIcon data-testid=\"categories-picker-expand\" />}\n renderInput={params => <TextField {...params} variant=\"outlined\" />}\n />\n </Box>\n );\n};\n"],"names":["FormControl","Autocomplete","useStyles","Link"],"mappings":"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"}
|