@backstage/plugin-scaffolder-react 1.14.2-next.2 → 1.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @backstage/plugin-scaffolder-react
2
2
 
3
+ ## 1.14.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks
8
+ - c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker
9
+ - 28e286f: Added test coverage selectors to TemplateCard and its sub-components
10
+ - c846d76: Updated dependency `flatted` to `3.3.2`.
11
+ - 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`.
12
+ Updated dependency `@rjsf/core` to `5.23.1`.
13
+ Updated dependency `@rjsf/material-ui` to `5.23.1`.
14
+ Updated dependency `@rjsf/validator-ajv8` to `5.23.1`.
15
+ - 97a13ad: Improve performance of typing into scaffolder secret widget
16
+ - 184161f: Scaffolder field extensions registered with `FormFieldBlueprint` are now collected in the `useCustomFieldExtensions` hook, enabling them for use in the scaffolder.
17
+ - b21a5ae: Open links in the scaffolder entity and step descriptions in a new tab, to ensure consistency and improve user experience
18
+ - Updated dependencies
19
+ - @backstage/plugin-catalog-react@1.15.0
20
+ - @backstage/plugin-scaffolder-common@1.5.8
21
+ - @backstage/catalog-client@1.9.0
22
+ - @backstage/frontend-plugin-api@0.9.3
23
+ - @backstage/theme@0.6.3
24
+ - @backstage/core-components@0.16.2
25
+ - @backstage/catalog-model@1.7.2
26
+ - @backstage/core-plugin-api@1.10.2
27
+ - @backstage/types@1.2.0
28
+ - @backstage/version-bridge@1.0.10
29
+ - @backstage/plugin-permission-react@0.4.29
30
+
3
31
  ## 1.14.2-next.2
4
32
 
5
33
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  import { useAsync, useMountEffect } from '@react-hookz/web';
2
- import { useApiHolder, useElementFilter } from '@backstage/core-plugin-api';
2
+ import { useApi, useElementFilter } from '@backstage/core-plugin-api';
3
3
  import '../next/api/FormFieldsApi.esm.js';
4
4
  import { formFieldsApiRef } from '../next/api/ref.esm.js';
5
5
  import '../next/components/Stepper/Stepper.esm.js';
@@ -35,6 +35,7 @@ import '../next/components/ScaffolderPageContextMenu/ScaffolderPageContextMenu.e
35
35
  import '../next/components/ScaffolderField/ScaffolderField.esm.js';
36
36
  import '@backstage/plugin-scaffolder-react';
37
37
  import '@material-ui/core/TextField';
38
+ import 'lodash/debounce';
38
39
  import 'qs';
39
40
  import 'react-use/esm/useAsync';
40
41
  import '../api/ref.esm.js';
@@ -43,10 +44,9 @@ import '../next/blueprints/FormFieldBlueprint.esm.js';
43
44
  import { FIELD_EXTENSION_WRAPPER_KEY, FIELD_EXTENSION_KEY } from '../extensions/keys.esm.js';
44
45
 
45
46
  const useCustomFieldExtensions = (outlet) => {
46
- const apiHolder = useApiHolder();
47
- const formFieldsApi = apiHolder.get(formFieldsApiRef);
47
+ const formFieldsApi = useApi(formFieldsApiRef);
48
48
  const [{ result: blueprintFields }, methods] = useAsync(
49
- formFieldsApi?.getFormFields ?? (async () => []),
49
+ formFieldsApi.getFormFields,
50
50
  []
51
51
  );
52
52
  useMountEffect(methods.execute);
@@ -1 +1 @@
1
- {"version":3,"file":"useCustomFieldExtensions.esm.js","sources":["../../src/hooks/useCustomFieldExtensions.ts"],"sourcesContent":["/*\n * Copyright 2023 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 { useAsync, useMountEffect } from '@react-hookz/web';\nimport { useApiHolder, useElementFilter } from '@backstage/core-plugin-api';\nimport { formFieldsApiRef } from '../next';\nimport { FieldExtensionOptions } from '../extensions';\nimport {\n FIELD_EXTENSION_KEY,\n FIELD_EXTENSION_WRAPPER_KEY,\n} from '../extensions/keys';\n\n/**\n * Hook that returns all custom field extensions from the current outlet.\n * @public\n */\nexport const useCustomFieldExtensions = <\n // todo(blam): this shouldn't be here, should remove this, but this is a breaking change to remove the generic.\n TComponentDataType = FieldExtensionOptions,\n>(\n outlet: React.ReactNode,\n) => {\n // Get custom fields created with FormFieldBlueprint\n const apiHolder = useApiHolder();\n const formFieldsApi = apiHolder.get(formFieldsApiRef);\n const [{ result: blueprintFields }, methods] = useAsync(\n formFieldsApi?.getFormFields ?? (async () => []),\n [],\n );\n useMountEffect(methods.execute);\n\n // Get custom fields created with ScaffolderFieldExtensions\n const outletFields = useElementFilter(outlet, elements =>\n elements\n .selectByComponentData({\n key: FIELD_EXTENSION_WRAPPER_KEY,\n })\n .findComponentData<TComponentDataType>({\n key: FIELD_EXTENSION_KEY,\n }),\n );\n\n // This should really be a different type moving foward, but we do this to keep type compatibility.\n // should probably also move the defaults into the API eventually too, but that will come with the move\n // to the new frontend system.\n const blueprintsToLegacy: FieldExtensionOptions[] = blueprintFields?.map(\n field => ({\n component: field.component,\n name: field.name,\n validation: field.validation,\n schema: field.schema?.schema,\n }),\n );\n\n return [...blueprintsToLegacy, ...outletFields] as TComponentDataType[];\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4Ba,MAAA,wBAAA,GAA2B,CAItC,MACG,KAAA;AAEH,EAAA,MAAM,YAAY,YAAa,EAAA;AAC/B,EAAM,MAAA,aAAA,GAAgB,SAAU,CAAA,GAAA,CAAI,gBAAgB,CAAA;AACpD,EAAA,MAAM,CAAC,EAAE,MAAA,EAAQ,eAAgB,EAAA,EAAG,OAAO,CAAI,GAAA,QAAA;AAAA,IAC7C,aAAA,EAAe,aAAkB,KAAA,YAAY,EAAC,CAAA;AAAA,IAC9C;AAAC,GACH;AACA,EAAA,cAAA,CAAe,QAAQ,OAAO,CAAA;AAG9B,EAAA,MAAM,YAAe,GAAA,gBAAA;AAAA,IAAiB,MAAA;AAAA,IAAQ,CAAA,QAAA,KAC5C,SACG,qBAAsB,CAAA;AAAA,MACrB,GAAK,EAAA;AAAA,KACN,EACA,iBAAsC,CAAA;AAAA,MACrC,GAAK,EAAA;AAAA,KACN;AAAA,GACL;AAKA,EAAA,MAAM,qBAA8C,eAAiB,EAAA,GAAA;AAAA,IACnE,CAAU,KAAA,MAAA;AAAA,MACR,WAAW,KAAM,CAAA,SAAA;AAAA,MACjB,MAAM,KAAM,CAAA,IAAA;AAAA,MACZ,YAAY,KAAM,CAAA,UAAA;AAAA,MAClB,MAAA,EAAQ,MAAM,MAAQ,EAAA;AAAA,KACxB;AAAA,GACF;AAEA,EAAA,OAAO,CAAC,GAAG,kBAAoB,EAAA,GAAG,YAAY,CAAA;AAChD;;;;"}
1
+ {"version":3,"file":"useCustomFieldExtensions.esm.js","sources":["../../src/hooks/useCustomFieldExtensions.ts"],"sourcesContent":["/*\n * Copyright 2023 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 { useAsync, useMountEffect } from '@react-hookz/web';\nimport { useApi, useElementFilter } from '@backstage/core-plugin-api';\nimport { formFieldsApiRef } from '../next';\nimport { FieldExtensionOptions } from '../extensions';\nimport {\n FIELD_EXTENSION_KEY,\n FIELD_EXTENSION_WRAPPER_KEY,\n} from '../extensions/keys';\n\n/**\n * Hook that returns all custom field extensions from the current outlet.\n * @public\n */\nexport const useCustomFieldExtensions = <\n // todo(blam): this shouldn't be here, should remove this, but this is a breaking change to remove the generic.\n TComponentDataType = FieldExtensionOptions,\n>(\n outlet: React.ReactNode,\n) => {\n // Get custom fields created with FormFieldBlueprint\n const formFieldsApi = useApi(formFieldsApiRef);\n const [{ result: blueprintFields }, methods] = useAsync(\n formFieldsApi.getFormFields,\n [],\n );\n useMountEffect(methods.execute);\n\n // Get custom fields created with ScaffolderFieldExtensions\n const outletFields = useElementFilter(outlet, elements =>\n elements\n .selectByComponentData({\n key: FIELD_EXTENSION_WRAPPER_KEY,\n })\n .findComponentData<TComponentDataType>({\n key: FIELD_EXTENSION_KEY,\n }),\n );\n\n // This should really be a different type moving foward, but we do this to keep type compatibility.\n // should probably also move the defaults into the API eventually too, but that will come with the move\n // to the new frontend system.\n const blueprintsToLegacy: FieldExtensionOptions[] = blueprintFields?.map(\n field => ({\n component: field.component,\n name: field.name,\n validation: field.validation,\n schema: field.schema?.schema,\n }),\n );\n\n return [...blueprintsToLegacy, ...outletFields] as TComponentDataType[];\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4Ba,MAAA,wBAAA,GAA2B,CAItC,MACG,KAAA;AAEH,EAAM,MAAA,aAAA,GAAgB,OAAO,gBAAgB,CAAA;AAC7C,EAAA,MAAM,CAAC,EAAE,MAAA,EAAQ,eAAgB,EAAA,EAAG,OAAO,CAAI,GAAA,QAAA;AAAA,IAC7C,aAAc,CAAA,aAAA;AAAA,IACd;AAAC,GACH;AACA,EAAA,cAAA,CAAe,QAAQ,OAAO,CAAA;AAG9B,EAAA,MAAM,YAAe,GAAA,gBAAA;AAAA,IAAiB,MAAA;AAAA,IAAQ,CAAA,QAAA,KAC5C,SACG,qBAAsB,CAAA;AAAA,MACrB,GAAK,EAAA;AAAA,KACN,EACA,iBAAsC,CAAA;AAAA,MACrC,GAAK,EAAA;AAAA,KACN;AAAA,GACL;AAKA,EAAA,MAAM,qBAA8C,eAAiB,EAAA,GAAA;AAAA,IACnE,CAAU,KAAA,MAAA;AAAA,MACR,WAAW,KAAM,CAAA,SAAA;AAAA,MACjB,MAAM,KAAM,CAAA,IAAA;AAAA,MACZ,YAAY,KAAM,CAAA,UAAA;AAAA,MAClB,MAAA,EAAQ,MAAM,MAAQ,EAAA;AAAA,KACxB;AAAA,GACF;AAEA,EAAA,OAAO,CAAC,GAAG,kBAAoB,EAAA,GAAG,YAAY,CAAA;AAChD;;;;"}
@@ -1,6 +1,7 @@
1
1
  import { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';
2
2
  import TextField from '@material-ui/core/TextField';
3
- import React from 'react';
3
+ import React, { useState, useMemo } from 'react';
4
+ import debounce from 'lodash/debounce';
4
5
 
5
6
  const SecretWidget = (props) => {
6
7
  const { setSecrets, secrets } = useTemplateSecrets();
@@ -11,17 +12,27 @@ const SecretWidget = (props) => {
11
12
  required,
12
13
  disabled
13
14
  } = props;
15
+ const [localValue, setLocalValue] = useState(secrets[name] ?? "");
16
+ const debouncedSetSecrets = useMemo(
17
+ () => debounce((value) => {
18
+ setSecrets({ [name]: value });
19
+ }, 300),
20
+ [setSecrets, name]
21
+ );
22
+ const handleChange = (e) => {
23
+ const newValue = e.target.value;
24
+ setLocalValue(newValue);
25
+ onChange(Array(newValue.length).fill("*").join(""));
26
+ debouncedSetSecrets(newValue);
27
+ };
14
28
  return /* @__PURE__ */ React.createElement(
15
29
  TextField,
16
30
  {
17
31
  id: title,
18
32
  label: title,
19
33
  "aria-describedby": title,
20
- onChange: (e) => {
21
- onChange(Array(e.target.value.length).fill("*").join(""));
22
- setSecrets({ [name]: e.target.value });
23
- },
24
- value: secrets[name] ?? "",
34
+ onChange: handleChange,
35
+ value: localValue,
25
36
  type: "password",
26
37
  autoComplete: "off",
27
38
  required,
@@ -1 +1 @@
1
- {"version":3,"file":"SecretWidget.esm.js","sources":["../../../../src/next/components/SecretWidget/SecretWidget.tsx"],"sourcesContent":["/*\n * Copyright 2024 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 { WidgetProps } from '@rjsf/utils';\nimport { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';\nimport TextField from '@material-ui/core/TextField';\nimport React from 'react';\n\n/**\n * Secret Widget for overriding the default password input widget\n * @alpha\n */\nexport const SecretWidget = (\n props: Pick<\n WidgetProps,\n 'name' | 'onChange' | 'schema' | 'required' | 'disabled'\n >,\n) => {\n const { setSecrets, secrets } = useTemplateSecrets();\n const {\n name,\n onChange,\n schema: { title, minLength, maxLength },\n required,\n disabled,\n } = props;\n\n return (\n <TextField\n id={title}\n label={title}\n aria-describedby={title}\n onChange={e => {\n onChange(Array(e.target.value.length).fill('*').join(''));\n setSecrets({ [name]: e.target.value });\n }}\n value={secrets[name] ?? ''}\n type=\"password\"\n autoComplete=\"off\"\n required={required}\n disabled={disabled}\n inputProps={{\n minLength,\n maxLength,\n }}\n />\n );\n};\n"],"names":[],"mappings":";;;;AAyBa,MAAA,YAAA,GAAe,CAC1B,KAIG,KAAA;AACH,EAAA,MAAM,EAAE,UAAA,EAAY,OAAQ,EAAA,GAAI,kBAAmB,EAAA;AACnD,EAAM,MAAA;AAAA,IACJ,IAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAQ,EAAA,EAAE,KAAO,EAAA,SAAA,EAAW,SAAU,EAAA;AAAA,IACtC,QAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AAEJ,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,EAAI,EAAA,KAAA;AAAA,MACJ,KAAO,EAAA,KAAA;AAAA,MACP,kBAAkB,EAAA,KAAA;AAAA,MAClB,UAAU,CAAK,CAAA,KAAA;AACb,QAAS,QAAA,CAAA,KAAA,CAAM,CAAE,CAAA,MAAA,CAAO,KAAM,CAAA,MAAM,CAAE,CAAA,IAAA,CAAK,GAAG,CAAA,CAAE,IAAK,CAAA,EAAE,CAAC,CAAA;AACxD,QAAA,UAAA,CAAW,EAAE,CAAC,IAAI,GAAG,CAAE,CAAA,MAAA,CAAO,OAAO,CAAA;AAAA,OACvC;AAAA,MACA,KAAA,EAAO,OAAQ,CAAA,IAAI,CAAK,IAAA,EAAA;AAAA,MACxB,IAAK,EAAA,UAAA;AAAA,MACL,YAAa,EAAA,KAAA;AAAA,MACb,QAAA;AAAA,MACA,QAAA;AAAA,MACA,UAAY,EAAA;AAAA,QACV,SAAA;AAAA,QACA;AAAA;AACF;AAAA,GACF;AAEJ;;;;"}
1
+ {"version":3,"file":"SecretWidget.esm.js","sources":["../../../../src/next/components/SecretWidget/SecretWidget.tsx"],"sourcesContent":["/*\n * Copyright 2024 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 { WidgetProps } from '@rjsf/utils';\nimport { useTemplateSecrets } from '@backstage/plugin-scaffolder-react';\nimport TextField from '@material-ui/core/TextField';\nimport React, { useMemo, useState } from 'react';\nimport debounce from 'lodash/debounce';\n\n/**\n * Secret Widget for overriding the default password input widget\n * @alpha\n */\nexport const SecretWidget = (\n props: Pick<\n WidgetProps,\n 'name' | 'onChange' | 'schema' | 'required' | 'disabled'\n >,\n) => {\n const { setSecrets, secrets } = useTemplateSecrets();\n const {\n name,\n onChange,\n schema: { title, minLength, maxLength },\n required,\n disabled,\n } = props;\n\n const [localValue, setLocalValue] = useState(secrets[name] ?? '');\n\n // Memoize the debounced function so it persists across re-renders\n const debouncedSetSecrets = useMemo(\n () =>\n debounce((value: string) => {\n setSecrets({ [name]: value });\n }, 300),\n [setSecrets, name],\n );\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setLocalValue(newValue);\n onChange(Array(newValue.length).fill('*').join(''));\n debouncedSetSecrets(newValue);\n };\n\n return (\n <TextField\n id={title}\n label={title}\n aria-describedby={title}\n onChange={handleChange}\n value={localValue}\n type=\"password\"\n autoComplete=\"off\"\n required={required}\n disabled={disabled}\n inputProps={{\n minLength,\n maxLength,\n }}\n />\n );\n};\n"],"names":[],"mappings":";;;;;AA0Ba,MAAA,YAAA,GAAe,CAC1B,KAIG,KAAA;AACH,EAAA,MAAM,EAAE,UAAA,EAAY,OAAQ,EAAA,GAAI,kBAAmB,EAAA;AACnD,EAAM,MAAA;AAAA,IACJ,IAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAQ,EAAA,EAAE,KAAO,EAAA,SAAA,EAAW,SAAU,EAAA;AAAA,IACtC,QAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AAEJ,EAAM,MAAA,CAAC,YAAY,aAAa,CAAA,GAAI,SAAS,OAAQ,CAAA,IAAI,KAAK,EAAE,CAAA;AAGhE,EAAA,MAAM,mBAAsB,GAAA,OAAA;AAAA,IAC1B,MACE,QAAS,CAAA,CAAC,KAAkB,KAAA;AAC1B,MAAA,UAAA,CAAW,EAAE,CAAC,IAAI,GAAG,OAAO,CAAA;AAAA,OAC3B,GAAG,CAAA;AAAA,IACR,CAAC,YAAY,IAAI;AAAA,GACnB;AAEA,EAAM,MAAA,YAAA,GAAe,CAAC,CAA2C,KAAA;AAC/D,IAAM,MAAA,QAAA,GAAW,EAAE,MAAO,CAAA,KAAA;AAC1B,IAAA,aAAA,CAAc,QAAQ,CAAA;AACtB,IAAS,QAAA,CAAA,KAAA,CAAM,SAAS,MAAM,CAAA,CAAE,KAAK,GAAG,CAAA,CAAE,IAAK,CAAA,EAAE,CAAC,CAAA;AAClD,IAAA,mBAAA,CAAoB,QAAQ,CAAA;AAAA,GAC9B;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,EAAI,EAAA,KAAA;AAAA,MACJ,KAAO,EAAA,KAAA;AAAA,MACP,kBAAkB,EAAA,KAAA;AAAA,MAClB,QAAU,EAAA,YAAA;AAAA,MACV,KAAO,EAAA,UAAA;AAAA,MACP,IAAK,EAAA,UAAA;AAAA,MACL,YAAa,EAAA,KAAA;AAAA,MACb,QAAA;AAAA,MACA,QAAA;AAAA,MACA,UAAY,EAAA;AAAA,QACV,SAAA;AAAA,QACA;AAAA;AACF;AAAA,GACF;AAEJ;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"CardLink.esm.js","sources":["../../../../src/next/components/TemplateCard/CardLink.tsx"],"sourcesContent":["/*\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 { IconComponent } from '@backstage/core-plugin-api';\nimport { Link } from '@backstage/core-components';\nimport { makeStyles } from '@material-ui/core/styles';\nimport React from 'react';\n\ninterface CardLinkProps {\n icon: IconComponent;\n text: string;\n url: string;\n}\n\nconst useStyles = makeStyles(() => ({\n linkText: {\n display: 'inline-flex',\n alignItems: 'center',\n },\n}));\n\nexport const CardLink = ({ icon: Icon, text, url }: CardLinkProps) => {\n const styles = useStyles();\n\n return (\n <div className={styles.linkText}>\n <Icon fontSize=\"small\" />\n <Link style={{ marginLeft: '8px' }} to={url}>\n {text || url}\n </Link>\n </div>\n );\n};\n"],"names":[],"mappings":";;;;AA2BA,MAAM,SAAA,GAAY,WAAW,OAAO;AAAA,EAClC,QAAU,EAAA;AAAA,IACR,OAAS,EAAA,aAAA;AAAA,IACT,UAAY,EAAA;AAAA;AAEhB,CAAE,CAAA,CAAA;AAEK,MAAM,WAAW,CAAC,EAAE,MAAM,IAAM,EAAA,IAAA,EAAM,KAAyB,KAAA;AACpE,EAAA,MAAM,SAAS,SAAU,EAAA;AAEzB,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,SAAI,SAAW,EAAA,MAAA,CAAO,4BACpB,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,UAAS,OAAQ,EAAA,CAAA,sCACtB,IAAK,EAAA,EAAA,KAAA,EAAO,EAAE,UAAY,EAAA,KAAA,IAAS,EAAI,EAAA,GAAA,EAAA,EACrC,IAAQ,IAAA,GACX,CACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"CardLink.esm.js","sources":["../../../../src/next/components/TemplateCard/CardLink.tsx"],"sourcesContent":["/*\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 { IconComponent } from '@backstage/core-plugin-api';\nimport { Link } from '@backstage/core-components';\nimport { makeStyles } from '@material-ui/core/styles';\nimport React from 'react';\n\nexport interface CardLinkProps {\n icon: IconComponent;\n text: string;\n url: string;\n}\n\nconst useStyles = makeStyles(() => ({\n linkText: {\n display: 'inline-flex',\n alignItems: 'center',\n },\n}));\n\nexport const CardLink = ({ icon: Icon, text, url }: CardLinkProps) => {\n const styles = useStyles();\n\n return (\n <div className={styles.linkText}>\n <Icon fontSize=\"small\" />\n <Link style={{ marginLeft: '8px' }} to={url}>\n {text || url}\n </Link>\n </div>\n );\n};\n"],"names":[],"mappings":";;;;AA2BA,MAAM,SAAA,GAAY,WAAW,OAAO;AAAA,EAClC,QAAU,EAAA;AAAA,IACR,OAAS,EAAA,aAAA;AAAA,IACT,UAAY,EAAA;AAAA;AAEhB,CAAE,CAAA,CAAA;AAEK,MAAM,WAAW,CAAC,EAAE,MAAM,IAAM,EAAA,IAAA,EAAM,KAAyB,KAAA;AACpE,EAAA,MAAM,SAAS,SAAU,EAAA;AAEzB,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,SAAI,SAAW,EAAA,MAAA,CAAO,4BACpB,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,UAAS,OAAQ,EAAA,CAAA,sCACtB,IAAK,EAAA,EAAA,KAAA,EAAO,EAAE,UAAY,EAAA,KAAA,IAAS,EAAI,EAAA,GAAA,EAAA,EACrC,IAAQ,IAAA,GACX,CACF,CAAA;AAEJ;;;;"}
@@ -1,67 +1,31 @@
1
1
  import { RELATION_OWNED_BY } from '@backstage/catalog-model';
2
- import { MarkdownContent, UserIcon } from '@backstage/core-components';
3
- import { useAnalytics, useApp } from '@backstage/core-plugin-api';
4
- import { getEntityRelations, EntityRefLinks } from '@backstage/plugin-catalog-react';
5
- import Box from '@material-ui/core/Box';
2
+ import { useAnalytics } from '@backstage/core-plugin-api';
3
+ import { getEntityRelations } from '@backstage/plugin-catalog-react';
6
4
  import Card from '@material-ui/core/Card';
7
5
  import CardActions from '@material-ui/core/CardActions';
8
6
  import CardContent from '@material-ui/core/CardContent';
9
- import Chip from '@material-ui/core/Chip';
10
7
  import Divider from '@material-ui/core/Divider';
11
- import Button from '@material-ui/core/Button';
12
8
  import Grid from '@material-ui/core/Grid';
13
9
  import { makeStyles } from '@material-ui/core/styles';
14
- import LanguageIcon from '@material-ui/icons/Language';
15
10
  import React, { useCallback } from 'react';
16
11
  import { CardHeader } from './CardHeader.esm.js';
17
- import { CardLink } from './CardLink.esm.js';
18
12
  import { usePermission } from '@backstage/plugin-permission-react';
19
13
  import { taskCreatePermission } from '@backstage/plugin-scaffolder-common/alpha';
14
+ import { TemplateCardContent } from './TemplateCardContent.esm.js';
15
+ import { TemplateCardTags } from './TemplateCardTags.esm.js';
16
+ import { TemplateCardLinks } from './TemplateCardLinks.esm.js';
17
+ import { TemplateCardActions } from './TemplateCardActions.esm.js';
20
18
 
21
- const useStyles = makeStyles((theme) => ({
22
- box: {
23
- overflow: "hidden",
24
- textOverflow: "ellipsis",
25
- display: "-webkit-box",
26
- "-webkit-line-clamp": 10,
27
- "-webkit-box-orient": "vertical"
28
- },
29
- markdown: {
30
- /** to make the styles for React Markdown not leak into the description */
31
- "& :first-child": {
32
- margin: 0
33
- }
34
- },
35
- label: {
36
- color: theme.palette.text.secondary,
37
- textTransform: "uppercase",
38
- fontWeight: "bold",
39
- letterSpacing: 0.5,
40
- lineHeight: 1,
41
- fontSize: "0.75rem"
42
- },
43
- footer: {
44
- display: "flex",
45
- justifyContent: "space-between",
46
- flex: 1,
47
- alignItems: "center"
48
- },
49
- ownedBy: {
50
- display: "flex",
51
- alignItems: "center",
52
- flex: 1,
53
- color: theme.palette.link
54
- }
19
+ const useStyles = makeStyles(() => ({
20
+ actionContainer: { padding: "16px", flex: 1, alignItems: "flex-end" }
55
21
  }));
56
22
  const TemplateCard = (props) => {
57
- const { onSelected, template } = props;
23
+ const { additionalLinks, onSelected, template } = props;
58
24
  const styles = useStyles();
59
25
  const analytics = useAnalytics();
60
26
  const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);
61
- const app = useApp();
62
- const iconResolver = (key) => key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon;
63
27
  const hasTags = !!template.metadata.tags?.length;
64
- const hasLinks = !!props.additionalLinks?.length || !!template.metadata.links?.length;
28
+ const hasLinks = !!additionalLinks?.length || !!template.metadata.links?.length;
65
29
  const displayDefaultDivider = !hasTags && !hasLinks;
66
30
  const { allowed: canCreateTask } = usePermission({
67
31
  permission: taskCreatePermission
@@ -70,47 +34,27 @@ const TemplateCard = (props) => {
70
34
  analytics.captureEvent("click", `Template has been opened`);
71
35
  onSelected?.(template);
72
36
  }, [analytics, onSelected, template]);
73
- return /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { template }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Box, { className: styles.box }, /* @__PURE__ */ React.createElement(
74
- MarkdownContent,
37
+ return /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, { template, "data-testid": "template-card-header" }), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2, "data-testid": "template-card-content" }, /* @__PURE__ */ React.createElement(TemplateCardContent, { template }), displayDefaultDivider && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator" })), hasTags && /* @__PURE__ */ React.createElement(TemplateCardTags, { template }), hasLinks && /* @__PURE__ */ React.createElement(
38
+ TemplateCardLinks,
75
39
  {
76
- className: styles.markdown,
77
- content: template.metadata.description ?? "No description"
40
+ template,
41
+ additionalLinks
78
42
  }
79
- ))), displayDefaultDivider && /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator" })), hasTags && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator--tags" })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, template.metadata.tags?.map((tag) => /* @__PURE__ */ React.createElement(Grid, { key: `grid-${tag}`, item: true }, /* @__PURE__ */ React.createElement(
80
- Chip,
43
+ ))), /* @__PURE__ */ React.createElement(
44
+ CardActions,
81
45
  {
82
- style: { margin: 0 },
83
- size: "small",
84
- label: tag,
85
- key: tag
86
- }
87
- )))))), hasLinks && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator--links" })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2 }, props.additionalLinks?.map(({ icon, text, url }, index) => /* @__PURE__ */ React.createElement(Grid, { className: styles.linkText, item: true, xs: 6, key: index }, /* @__PURE__ */ React.createElement(CardLink, { icon, text, url }))), template.metadata.links?.map(
88
- ({ url, icon, title }, index) => /* @__PURE__ */ React.createElement(Grid, { className: styles.linkText, item: true, xs: 6, key: index }, /* @__PURE__ */ React.createElement(
89
- CardLink,
46
+ className: styles.actionContainer,
47
+ "data-testid": "template-card-actions"
48
+ },
49
+ /* @__PURE__ */ React.createElement(
50
+ TemplateCardActions,
90
51
  {
91
- icon: iconResolver(icon),
92
- text: title || url,
93
- url
52
+ canCreateTask,
53
+ handleChoose,
54
+ ownedByRelations
94
55
  }
95
- ))
96
- )))))), /* @__PURE__ */ React.createElement(CardActions, { style: { padding: "16px", flex: 1, alignItems: "flex-end" } }, /* @__PURE__ */ React.createElement("div", { className: styles.footer }, /* @__PURE__ */ React.createElement("div", { className: styles.ownedBy }, ownedByRelations.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(UserIcon, { fontSize: "small" }), /* @__PURE__ */ React.createElement(
97
- EntityRefLinks,
98
- {
99
- style: { marginLeft: "8px" },
100
- entityRefs: ownedByRelations,
101
- defaultKind: "Group",
102
- hideIcons: true
103
- }
104
- ))), canCreateTask ? /* @__PURE__ */ React.createElement(
105
- Button,
106
- {
107
- size: "small",
108
- variant: "outlined",
109
- color: "primary",
110
- onClick: handleChoose
111
- },
112
- "Choose"
113
- ) : null)));
56
+ )
57
+ ));
114
58
  };
115
59
 
116
60
  export { TemplateCard };
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateCard.esm.js","sources":["../../../../src/next/components/TemplateCard/TemplateCard.tsx"],"sourcesContent":["/*\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 { RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport { MarkdownContent, UserIcon } from '@backstage/core-components';\nimport {\n IconComponent,\n useAnalytics,\n useApp,\n} from '@backstage/core-plugin-api';\nimport {\n EntityRefLinks,\n getEntityRelations,\n} from '@backstage/plugin-catalog-react';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport Box from '@material-ui/core/Box';\nimport Card from '@material-ui/core/Card';\nimport CardActions from '@material-ui/core/CardActions';\nimport CardContent from '@material-ui/core/CardContent';\nimport Chip from '@material-ui/core/Chip';\nimport Divider from '@material-ui/core/Divider';\nimport Button from '@material-ui/core/Button';\nimport Grid from '@material-ui/core/Grid';\nimport { makeStyles, Theme } from '@material-ui/core/styles';\nimport LanguageIcon from '@material-ui/icons/Language';\nimport React, { useCallback } from 'react';\nimport { CardHeader } from './CardHeader';\nimport { CardLink } from './CardLink';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { taskCreatePermission } from '@backstage/plugin-scaffolder-common/alpha';\n\nconst useStyles = makeStyles<Theme>(theme => ({\n box: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n display: '-webkit-box',\n '-webkit-line-clamp': 10,\n '-webkit-box-orient': 'vertical',\n },\n markdown: {\n /** to make the styles for React Markdown not leak into the description */\n '& :first-child': {\n margin: 0,\n },\n },\n label: {\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n fontWeight: 'bold',\n letterSpacing: 0.5,\n lineHeight: 1,\n fontSize: '0.75rem',\n },\n footer: {\n display: 'flex',\n justifyContent: 'space-between',\n flex: 1,\n alignItems: 'center',\n },\n ownedBy: {\n display: 'flex',\n alignItems: 'center',\n flex: 1,\n color: theme.palette.link,\n },\n}));\n\n/**\n * The Props for the {@link TemplateCard} component\n * @alpha\n */\nexport interface TemplateCardProps {\n template: TemplateEntityV1beta3;\n additionalLinks?: {\n icon: IconComponent;\n text: string;\n url: string;\n }[];\n\n onSelected?: (template: TemplateEntityV1beta3) => void;\n}\n\n/**\n * The `TemplateCard` component that is rendered in a list for each template\n * @alpha\n */\nexport const TemplateCard = (props: TemplateCardProps) => {\n const { onSelected, template } = props;\n const styles = useStyles();\n const analytics = useAnalytics();\n const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);\n const app = useApp();\n const iconResolver = (key?: string): IconComponent =>\n key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon;\n const hasTags = !!template.metadata.tags?.length;\n const hasLinks =\n !!props.additionalLinks?.length || !!template.metadata.links?.length;\n const displayDefaultDivider = !hasTags && !hasLinks;\n\n const { allowed: canCreateTask } = usePermission({\n permission: taskCreatePermission,\n });\n const handleChoose = useCallback(() => {\n analytics.captureEvent('click', `Template has been opened`);\n onSelected?.(template);\n }, [analytics, onSelected, template]);\n\n return (\n <Card>\n <CardHeader template={template} />\n <CardContent>\n <Grid container spacing={2}>\n <Grid item xs={12}>\n <Box className={styles.box}>\n <MarkdownContent\n className={styles.markdown}\n content={template.metadata.description ?? 'No description'}\n />\n </Box>\n </Grid>\n {displayDefaultDivider && (\n <Grid item xs={12}>\n <Divider data-testid=\"template-card-separator\" />\n </Grid>\n )}\n {hasTags && (\n <>\n <Grid item xs={12}>\n <Divider data-testid=\"template-card-separator--tags\" />\n </Grid>\n <Grid item xs={12}>\n <Grid container spacing={2}>\n {template.metadata.tags?.map(tag => (\n <Grid key={`grid-${tag}`} item>\n <Chip\n style={{ margin: 0 }}\n size=\"small\"\n label={tag}\n key={tag}\n />\n </Grid>\n ))}\n </Grid>\n </Grid>\n </>\n )}\n {hasLinks && (\n <>\n <Grid item xs={12}>\n <Divider data-testid=\"template-card-separator--links\" />\n </Grid>\n <Grid item xs={12}>\n <Grid container spacing={2}>\n {props.additionalLinks?.map(({ icon, text, url }, index) => (\n <Grid className={styles.linkText} item xs={6} key={index}>\n <CardLink icon={icon} text={text} url={url} />\n </Grid>\n ))}\n {template.metadata.links?.map(\n ({ url, icon, title }, index) => (\n <Grid className={styles.linkText} item xs={6} key={index}>\n <CardLink\n icon={iconResolver(icon)}\n text={title || url}\n url={url}\n />\n </Grid>\n ),\n )}\n </Grid>\n </Grid>\n </>\n )}\n </Grid>\n </CardContent>\n <CardActions style={{ padding: '16px', flex: 1, alignItems: 'flex-end' }}>\n <div className={styles.footer}>\n <div className={styles.ownedBy}>\n {ownedByRelations.length > 0 && (\n <>\n <UserIcon fontSize=\"small\" />\n <EntityRefLinks\n style={{ marginLeft: '8px' }}\n entityRefs={ownedByRelations}\n defaultKind=\"Group\"\n hideIcons\n />\n </>\n )}\n </div>\n {canCreateTask ? (\n <Button\n size=\"small\"\n variant=\"outlined\"\n color=\"primary\"\n onClick={handleChoose}\n >\n Choose\n </Button>\n ) : null}\n </div>\n </CardActions>\n </Card>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TemplateCard.esm.js","sources":["../../../../src/next/components/TemplateCard/TemplateCard.tsx"],"sourcesContent":["/*\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 { RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport { IconComponent, useAnalytics } from '@backstage/core-plugin-api';\nimport { getEntityRelations } from '@backstage/plugin-catalog-react';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport Card from '@material-ui/core/Card';\nimport CardActions from '@material-ui/core/CardActions';\nimport CardContent from '@material-ui/core/CardContent';\nimport Divider from '@material-ui/core/Divider';\nimport Grid from '@material-ui/core/Grid';\nimport { makeStyles, Theme } from '@material-ui/core/styles';\nimport React, { useCallback } from 'react';\nimport { CardHeader } from './CardHeader';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { taskCreatePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport { TemplateCardContent } from './TemplateCardContent';\nimport { TemplateCardTags } from './TemplateCardTags';\nimport { TemplateCardLinks } from './TemplateCardLinks';\nimport { TemplateCardActions } from './TemplateCardActions';\n\nconst useStyles = makeStyles<Theme>(() => ({\n actionContainer: { padding: '16px', flex: 1, alignItems: 'flex-end' },\n}));\n\n/**\n * The Props for the {@link TemplateCard} component\n * @alpha\n */\nexport interface TemplateCardProps {\n template: TemplateEntityV1beta3;\n additionalLinks?: {\n icon: IconComponent;\n text: string;\n url: string;\n }[];\n onSelected?: (template: TemplateEntityV1beta3) => void;\n}\n\n/**\n * The `TemplateCard` component that is rendered in a list for each template\n * @alpha\n */\nexport const TemplateCard = (props: TemplateCardProps) => {\n const { additionalLinks, onSelected, template } = props;\n const styles = useStyles();\n const analytics = useAnalytics();\n const ownedByRelations = getEntityRelations(template, RELATION_OWNED_BY);\n const hasTags = !!template.metadata.tags?.length;\n const hasLinks =\n !!additionalLinks?.length || !!template.metadata.links?.length;\n const displayDefaultDivider = !hasTags && !hasLinks;\n\n const { allowed: canCreateTask } = usePermission({\n permission: taskCreatePermission,\n });\n const handleChoose = useCallback(() => {\n analytics.captureEvent('click', `Template has been opened`);\n onSelected?.(template);\n }, [analytics, onSelected, template]);\n\n return (\n <Card>\n <CardHeader template={template} data-testid=\"template-card-header\" />\n <CardContent>\n <Grid container spacing={2} data-testid=\"template-card-content\">\n <TemplateCardContent template={template} />\n {displayDefaultDivider && (\n <Grid item xs={12}>\n <Divider data-testid=\"template-card-separator\" />\n </Grid>\n )}\n {hasTags && <TemplateCardTags template={template} />}\n {hasLinks && (\n <TemplateCardLinks\n template={template}\n additionalLinks={additionalLinks}\n />\n )}\n </Grid>\n </CardContent>\n <CardActions\n className={styles.actionContainer}\n data-testid=\"template-card-actions\"\n >\n <TemplateCardActions\n canCreateTask={canCreateTask}\n handleChoose={handleChoose}\n ownedByRelations={ownedByRelations}\n />\n </CardActions>\n </Card>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAmCA,MAAM,SAAA,GAAY,WAAkB,OAAO;AAAA,EACzC,iBAAiB,EAAE,OAAA,EAAS,QAAQ,IAAM,EAAA,CAAA,EAAG,YAAY,UAAW;AACtE,CAAE,CAAA,CAAA;AAoBW,MAAA,YAAA,GAAe,CAAC,KAA6B,KAAA;AACxD,EAAA,MAAM,EAAE,eAAA,EAAiB,UAAY,EAAA,QAAA,EAAa,GAAA,KAAA;AAClD,EAAA,MAAM,SAAS,SAAU,EAAA;AACzB,EAAA,MAAM,YAAY,YAAa,EAAA;AAC/B,EAAM,MAAA,gBAAA,GAAmB,kBAAmB,CAAA,QAAA,EAAU,iBAAiB,CAAA;AACvE,EAAA,MAAM,OAAU,GAAA,CAAC,CAAC,QAAA,CAAS,SAAS,IAAM,EAAA,MAAA;AAC1C,EAAM,MAAA,QAAA,GACJ,CAAC,CAAC,eAAA,EAAiB,UAAU,CAAC,CAAC,QAAS,CAAA,QAAA,CAAS,KAAO,EAAA,MAAA;AAC1D,EAAM,MAAA,qBAAA,GAAwB,CAAC,OAAA,IAAW,CAAC,QAAA;AAE3C,EAAA,MAAM,EAAE,OAAA,EAAS,aAAc,EAAA,GAAI,aAAc,CAAA;AAAA,IAC/C,UAAY,EAAA;AAAA,GACb,CAAA;AACD,EAAM,MAAA,YAAA,GAAe,YAAY,MAAM;AACrC,IAAU,SAAA,CAAA,YAAA,CAAa,SAAS,CAA0B,wBAAA,CAAA,CAAA;AAC1D,IAAA,UAAA,GAAa,QAAQ,CAAA;AAAA,GACpB,EAAA,CAAC,SAAW,EAAA,UAAA,EAAY,QAAQ,CAAC,CAAA;AAEpC,EAAA,2CACG,IACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,QAAoB,EAAA,aAAA,EAAY,wBAAuB,CACnE,kBAAA,KAAA,CAAA,aAAA,CAAC,WACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,SAAS,EAAA,IAAA,EAAC,SAAS,CAAG,EAAA,aAAA,EAAY,2CACrC,KAAA,CAAA,aAAA,CAAA,mBAAA,EAAA,EAAoB,QAAoB,EAAA,CAAA,EACxC,yCACE,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,MAAI,IAAC,EAAA,EAAA,EAAI,sBACZ,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAQ,aAAY,EAAA,yBAAA,EAA0B,CACjD,CAED,EAAA,OAAA,wCAAY,gBAAiB,EAAA,EAAA,QAAA,EAAoB,GACjD,QACC,oBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,iBAAA;AAAA,IAAA;AAAA,MACC,QAAA;AAAA,MACA;AAAA;AAAA,GAGN,CACF,CACA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,WAAW,MAAO,CAAA,eAAA;AAAA,MAClB,aAAY,EAAA;AAAA,KAAA;AAAA,oBAEZ,KAAA,CAAA,aAAA;AAAA,MAAC,mBAAA;AAAA,MAAA;AAAA,QACC,aAAA;AAAA,QACA,YAAA;AAAA,QACA;AAAA;AAAA;AACF,GAEJ,CAAA;AAEJ;;;;"}
@@ -0,0 +1,57 @@
1
+ import { UserIcon } from '@backstage/core-components';
2
+ import { EntityRefLinks } from '@backstage/plugin-catalog-react';
3
+ import Button from '@material-ui/core/Button';
4
+ import { makeStyles } from '@material-ui/core/styles';
5
+ import React from 'react';
6
+
7
+ const useStyles = makeStyles((theme) => ({
8
+ footer: {
9
+ display: "flex",
10
+ justifyContent: "space-between",
11
+ flex: 1,
12
+ alignItems: "center"
13
+ },
14
+ ownedBy: {
15
+ display: "flex",
16
+ alignItems: "center",
17
+ flex: 1,
18
+ color: theme.palette.link
19
+ },
20
+ actionContainer: { padding: "16px", flex: 1, alignItems: "flex-end" }
21
+ }));
22
+ const TemplateCardActions = ({
23
+ canCreateTask,
24
+ handleChoose,
25
+ ownedByRelations
26
+ }) => {
27
+ const styles = useStyles();
28
+ return /* @__PURE__ */ React.createElement("div", { className: styles.footer, "data-testid": "template-card-actions--footer" }, /* @__PURE__ */ React.createElement(
29
+ "div",
30
+ {
31
+ className: styles.ownedBy,
32
+ "data-testid": "template-card-actions--ownedby"
33
+ },
34
+ ownedByRelations.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(UserIcon, { fontSize: "small" }), /* @__PURE__ */ React.createElement(
35
+ EntityRefLinks,
36
+ {
37
+ style: { marginLeft: "8px" },
38
+ entityRefs: ownedByRelations,
39
+ defaultKind: "Group",
40
+ hideIcons: true
41
+ }
42
+ ))
43
+ ), canCreateTask ? /* @__PURE__ */ React.createElement(
44
+ Button,
45
+ {
46
+ size: "small",
47
+ variant: "outlined",
48
+ color: "primary",
49
+ "data-testid": "template-card-actions--create",
50
+ onClick: handleChoose
51
+ },
52
+ "Choose"
53
+ ) : null);
54
+ };
55
+
56
+ export { TemplateCardActions };
57
+ //# sourceMappingURL=TemplateCardActions.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateCardActions.esm.js","sources":["../../../../src/next/components/TemplateCard/TemplateCardActions.tsx"],"sourcesContent":["/*\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 { UserIcon } from '@backstage/core-components';\nimport { EntityRefLinks } from '@backstage/plugin-catalog-react';\nimport Button from '@material-ui/core/Button';\nimport { makeStyles, Theme } from '@material-ui/core/styles';\nimport React from 'react';\n\nconst useStyles = makeStyles<Theme>(theme => ({\n footer: {\n display: 'flex',\n justifyContent: 'space-between',\n flex: 1,\n alignItems: 'center',\n },\n ownedBy: {\n display: 'flex',\n alignItems: 'center',\n flex: 1,\n color: theme.palette.link,\n },\n actionContainer: { padding: '16px', flex: 1, alignItems: 'flex-end' },\n}));\n\n/**\n * The Props for the {@link TemplateCardActions} component\n * @alpha\n */\nexport interface TemplateCardActionsProps {\n ownedByRelations: any;\n canCreateTask: boolean;\n handleChoose: () => void;\n}\nexport const TemplateCardActions = ({\n canCreateTask,\n handleChoose,\n ownedByRelations,\n}: TemplateCardActionsProps) => {\n const styles = useStyles();\n\n return (\n <div className={styles.footer} data-testid=\"template-card-actions--footer\">\n <div\n className={styles.ownedBy}\n data-testid=\"template-card-actions--ownedby\"\n >\n {ownedByRelations.length > 0 && (\n <>\n <UserIcon fontSize=\"small\" />\n <EntityRefLinks\n style={{ marginLeft: '8px' }}\n entityRefs={ownedByRelations}\n defaultKind=\"Group\"\n hideIcons\n />\n </>\n )}\n </div>\n {canCreateTask ? (\n <Button\n size=\"small\"\n variant=\"outlined\"\n color=\"primary\"\n data-testid=\"template-card-actions--create\"\n onClick={handleChoose}\n >\n Choose\n </Button>\n ) : null}\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;AAsBA,MAAM,SAAA,GAAY,WAAkB,CAAU,KAAA,MAAA;AAAA,EAC5C,MAAQ,EAAA;AAAA,IACN,OAAS,EAAA,MAAA;AAAA,IACT,cAAgB,EAAA,eAAA;AAAA,IAChB,IAAM,EAAA,CAAA;AAAA,IACN,UAAY,EAAA;AAAA,GACd;AAAA,EACA,OAAS,EAAA;AAAA,IACP,OAAS,EAAA,MAAA;AAAA,IACT,UAAY,EAAA,QAAA;AAAA,IACZ,IAAM,EAAA,CAAA;AAAA,IACN,KAAA,EAAO,MAAM,OAAQ,CAAA;AAAA,GACvB;AAAA,EACA,iBAAiB,EAAE,OAAA,EAAS,QAAQ,IAAM,EAAA,CAAA,EAAG,YAAY,UAAW;AACtE,CAAE,CAAA,CAAA;AAWK,MAAM,sBAAsB,CAAC;AAAA,EAClC,aAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAgC,KAAA;AAC9B,EAAA,MAAM,SAAS,SAAU,EAAA;AAEzB,EAAA,2CACG,KAAI,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,MAAA,EAAQ,eAAY,+BACzC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,WAAW,MAAO,CAAA,OAAA;AAAA,MAClB,aAAY,EAAA;AAAA,KAAA;AAAA,IAEX,gBAAA,CAAiB,SAAS,CACzB,oBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,sCACG,QAAS,EAAA,EAAA,QAAA,EAAS,SAAQ,CAC3B,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO,EAAE,UAAA,EAAY,KAAM,EAAA;AAAA,QAC3B,UAAY,EAAA,gBAAA;AAAA,QACZ,WAAY,EAAA,OAAA;AAAA,QACZ,SAAS,EAAA;AAAA;AAAA,KAEb;AAAA,KAGH,aACC,mBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,IAAK,EAAA,OAAA;AAAA,MACL,OAAQ,EAAA,UAAA;AAAA,MACR,KAAM,EAAA,SAAA;AAAA,MACN,aAAY,EAAA,+BAAA;AAAA,MACZ,OAAS,EAAA;AAAA,KAAA;AAAA,IACV;AAAA,MAGC,IACN,CAAA;AAEJ;;;;"}
@@ -0,0 +1,34 @@
1
+ import { MarkdownContent } from '@backstage/core-components';
2
+ import { makeStyles } from '@material-ui/core/styles';
3
+ import Box from '@material-ui/core/Box';
4
+ import Grid from '@material-ui/core/Grid';
5
+ import React from 'react';
6
+
7
+ const useStyles = makeStyles(() => ({
8
+ box: {
9
+ overflow: "hidden",
10
+ textOverflow: "ellipsis",
11
+ display: "-webkit-box",
12
+ "-webkit-line-clamp": 10,
13
+ "-webkit-box-orient": "vertical"
14
+ },
15
+ markdown: {
16
+ /** to make the styles for React Markdown not leak into the description */
17
+ "& :first-child": {
18
+ margin: 0
19
+ }
20
+ }
21
+ }));
22
+ const TemplateCardContent = ({ template }) => {
23
+ const styles = useStyles();
24
+ return /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12, "data-testid": "template-card-content-grid" }, /* @__PURE__ */ React.createElement(Box, { className: styles.box, "data-testid": "template-card-content-container" }, /* @__PURE__ */ React.createElement(
25
+ MarkdownContent,
26
+ {
27
+ className: styles.markdown,
28
+ content: template.metadata.description ?? "No description"
29
+ }
30
+ )));
31
+ };
32
+
33
+ export { TemplateCardContent };
34
+ //# sourceMappingURL=TemplateCardContent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateCardContent.esm.js","sources":["../../../../src/next/components/TemplateCard/TemplateCardContent.tsx"],"sourcesContent":["/*\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 { MarkdownContent } from '@backstage/core-components';\nimport type { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport React from 'react';\n\nconst useStyles = makeStyles(() => ({\n box: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n display: '-webkit-box',\n '-webkit-line-clamp': 10,\n '-webkit-box-orient': 'vertical',\n },\n markdown: {\n /** to make the styles for React Markdown not leak into the description */\n '& :first-child': {\n margin: 0,\n },\n },\n}));\n\n/**\n * The Props for the {@link TemplateCardContent} component\n * @alpha\n */\nexport interface TemplateCardContentProps {\n template: TemplateEntityV1beta3;\n}\nexport const TemplateCardContent = ({ template }: TemplateCardContentProps) => {\n const styles = useStyles();\n return (\n <Grid item xs={12} data-testid=\"template-card-content-grid\">\n <Box className={styles.box} data-testid=\"template-card-content-container\">\n <MarkdownContent\n className={styles.markdown}\n content={template.metadata.description ?? 'No description'}\n />\n </Box>\n </Grid>\n );\n};\n"],"names":[],"mappings":";;;;;;AAuBA,MAAM,SAAA,GAAY,WAAW,OAAO;AAAA,EAClC,GAAK,EAAA;AAAA,IACH,QAAU,EAAA,QAAA;AAAA,IACV,YAAc,EAAA,UAAA;AAAA,IACd,OAAS,EAAA,aAAA;AAAA,IACT,oBAAsB,EAAA,EAAA;AAAA,IACtB,oBAAsB,EAAA;AAAA,GACxB;AAAA,EACA,QAAU,EAAA;AAAA;AAAA,IAER,gBAAkB,EAAA;AAAA,MAChB,MAAQ,EAAA;AAAA;AACV;AAEJ,CAAE,CAAA,CAAA;AASK,MAAM,mBAAsB,GAAA,CAAC,EAAE,QAAA,EAAyC,KAAA;AAC7E,EAAA,MAAM,SAAS,SAAU,EAAA;AACzB,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,IAAI,EAAI,EAAA,aAAA,EAAY,4BAC7B,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,SAAA,EAAW,MAAO,CAAA,GAAA,EAAK,eAAY,iCACtC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,eAAA;AAAA,IAAA;AAAA,MACC,WAAW,MAAO,CAAA,QAAA;AAAA,MAClB,OAAA,EAAS,QAAS,CAAA,QAAA,CAAS,WAAe,IAAA;AAAA;AAAA,GAE9C,CACF,CAAA;AAEJ;;;;"}
@@ -0,0 +1,48 @@
1
+ import { useApp } from '@backstage/core-plugin-api';
2
+ import Divider from '@material-ui/core/Divider';
3
+ import Grid from '@material-ui/core/Grid';
4
+ import { makeStyles } from '@material-ui/core/styles';
5
+ import LanguageIcon from '@material-ui/icons/Language';
6
+ import React from 'react';
7
+ import { CardLink } from './CardLink.esm.js';
8
+
9
+ const useStyles = makeStyles({});
10
+ const TemplateCardLinks = ({
11
+ template,
12
+ additionalLinks
13
+ }) => {
14
+ const styles = useStyles();
15
+ const app = useApp();
16
+ const iconResolver = (key) => key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon;
17
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator--links" })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2, "data-testid": "template-card-links" }, additionalLinks?.map(({ icon, text, url }, index) => /* @__PURE__ */ React.createElement(
18
+ Grid,
19
+ {
20
+ className: styles.linkText,
21
+ item: true,
22
+ xs: 6,
23
+ key: index,
24
+ "data-testid": "template-card-links--item"
25
+ },
26
+ /* @__PURE__ */ React.createElement(CardLink, { icon, text, url })
27
+ )), template.metadata.links?.map(({ url, icon, title }, index) => /* @__PURE__ */ React.createElement(
28
+ Grid,
29
+ {
30
+ className: styles.linkText,
31
+ item: true,
32
+ xs: 6,
33
+ key: index,
34
+ "data-testid": "template-card-links--metalink"
35
+ },
36
+ /* @__PURE__ */ React.createElement(
37
+ CardLink,
38
+ {
39
+ icon: iconResolver(icon),
40
+ text: title || url,
41
+ url
42
+ }
43
+ )
44
+ )))));
45
+ };
46
+
47
+ export { TemplateCardLinks };
48
+ //# sourceMappingURL=TemplateCardLinks.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateCardLinks.esm.js","sources":["../../../../src/next/components/TemplateCard/TemplateCardLinks.tsx"],"sourcesContent":["/*\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 { IconComponent, useApp } from '@backstage/core-plugin-api';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport Divider from '@material-ui/core/Divider';\nimport Grid from '@material-ui/core/Grid';\nimport { makeStyles, Theme } from '@material-ui/core/styles';\nimport LanguageIcon from '@material-ui/icons/Language';\nimport React from 'react';\nimport { CardLink } from './CardLink';\n\nconst useStyles = makeStyles<Theme>({});\n\n/**\n * The Props for the {@link TemplateCardLinks} component\n * @alpha\n */\nexport interface TemplateCardLinksProps {\n template: TemplateEntityV1beta3;\n additionalLinks?: {\n icon: IconComponent;\n text: string;\n url: string;\n }[];\n}\nexport const TemplateCardLinks = ({\n template,\n additionalLinks,\n}: TemplateCardLinksProps) => {\n const styles = useStyles();\n const app = useApp();\n const iconResolver = (key?: string): IconComponent =>\n key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon;\n return (\n <>\n <Grid item xs={12}>\n <Divider data-testid=\"template-card-separator--links\" />\n </Grid>\n <Grid item xs={12}>\n <Grid container spacing={2} data-testid=\"template-card-links\">\n {additionalLinks?.map(({ icon, text, url }, index) => (\n <Grid\n className={styles.linkText}\n item\n xs={6}\n key={index}\n data-testid=\"template-card-links--item\"\n >\n <CardLink icon={icon} text={text} url={url} />\n </Grid>\n ))}\n {template.metadata.links?.map(({ url, icon, title }, index) => (\n <Grid\n className={styles.linkText}\n item\n xs={6}\n key={index}\n data-testid=\"template-card-links--metalink\"\n >\n <CardLink\n icon={iconResolver(icon)}\n text={title || url}\n url={url}\n />\n </Grid>\n ))}\n </Grid>\n </Grid>\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAyBA,MAAM,SAAA,GAAY,UAAkB,CAAA,EAAE,CAAA;AAc/B,MAAM,oBAAoB,CAAC;AAAA,EAChC,QAAA;AAAA,EACA;AACF,CAA8B,KAAA;AAC5B,EAAA,MAAM,SAAS,SAAU,EAAA;AACzB,EAAA,MAAM,MAAM,MAAO,EAAA;AACnB,EAAM,MAAA,YAAA,GAAe,CAAC,GACpB,KAAA,GAAA,GAAM,IAAI,aAAc,CAAA,GAAG,KAAK,YAAe,GAAA,YAAA;AACjD,EAAA,uBAEI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,MAAC,EAAI,EAAA,EAAA,EAAA,kBACZ,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAQ,eAAY,gCAAiC,EAAA,CACxD,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,IAAI,EAAA,IAAA,EAAC,EAAI,EAAA,EAAA,EAAA,sCACZ,IAAK,EAAA,EAAA,SAAA,EAAS,IAAC,EAAA,OAAA,EAAS,GAAG,aAAY,EAAA,qBAAA,EAAA,EACrC,eAAiB,EAAA,GAAA,CAAI,CAAC,EAAE,IAAA,EAAM,IAAM,EAAA,GAAA,IAAO,KAC1C,qBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAW,MAAO,CAAA,QAAA;AAAA,MAClB,IAAI,EAAA,IAAA;AAAA,MACJ,EAAI,EAAA,CAAA;AAAA,MACJ,GAAK,EAAA,KAAA;AAAA,MACL,aAAY,EAAA;AAAA,KAAA;AAAA,oBAEX,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,IAAY,EAAA,IAAA,EAAY,GAAU,EAAA;AAAA,GAE/C,CAAA,EACA,QAAS,CAAA,QAAA,CAAS,KAAO,EAAA,GAAA,CAAI,CAAC,EAAE,GAAK,EAAA,IAAA,EAAM,KAAM,EAAA,EAAG,KACnD,qBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,WAAW,MAAO,CAAA,QAAA;AAAA,MAClB,IAAI,EAAA,IAAA;AAAA,MACJ,EAAI,EAAA,CAAA;AAAA,MACJ,GAAK,EAAA,KAAA;AAAA,MACL,aAAY,EAAA;AAAA,KAAA;AAAA,oBAEZ,KAAA,CAAA,aAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,aAAa,IAAI,CAAA;AAAA,QACvB,MAAM,KAAS,IAAA,GAAA;AAAA,QACf;AAAA;AAAA;AACF,GAEH,CACH,CACF,CACF,CAAA;AAEJ;;;;"}
@@ -0,0 +1,26 @@
1
+ import Chip from '@material-ui/core/Chip';
2
+ import Divider from '@material-ui/core/Divider';
3
+ import Grid from '@material-ui/core/Grid';
4
+ import React from 'react';
5
+
6
+ const TemplateCardTags = ({ template }) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Divider, { "data-testid": "template-card-separator--tags" })), /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2, "data-testid": "template-card-tags" }, template.metadata.tags?.map((tag) => /* @__PURE__ */ React.createElement(
7
+ Grid,
8
+ {
9
+ key: `grid-${tag}`,
10
+ item: true,
11
+ "data-testid": `template-card-tag-item-${tag}`
12
+ },
13
+ /* @__PURE__ */ React.createElement(
14
+ Chip,
15
+ {
16
+ style: { margin: 0 },
17
+ size: "small",
18
+ "data-testid": `template-card-tag-chip-${tag}`,
19
+ label: tag,
20
+ key: tag
21
+ }
22
+ )
23
+ )))));
24
+
25
+ export { TemplateCardTags };
26
+ //# sourceMappingURL=TemplateCardTags.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateCardTags.esm.js","sources":["../../../../src/next/components/TemplateCard/TemplateCardTags.tsx"],"sourcesContent":["/*\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 type { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport Chip from '@material-ui/core/Chip';\nimport Divider from '@material-ui/core/Divider';\nimport Grid from '@material-ui/core/Grid';\nimport React from 'react';\n\n/**\n * The Props for the {@link TemplateCardTags} component\n * @alpha\n */\nexport interface TemplateCardTagsProps {\n template: TemplateEntityV1beta3;\n}\nexport const TemplateCardTags = ({ template }: TemplateCardTagsProps) => (\n <>\n <Grid item xs={12}>\n <Divider data-testid=\"template-card-separator--tags\" />\n </Grid>\n <Grid item xs={12}>\n <Grid container spacing={2} data-testid=\"template-card-tags\">\n {template.metadata.tags?.map(tag => (\n <Grid\n key={`grid-${tag}`}\n item\n data-testid={`template-card-tag-item-${tag}`}\n >\n <Chip\n style={{ margin: 0 }}\n size=\"small\"\n data-testid={`template-card-tag-chip-${tag}`}\n label={tag}\n key={tag}\n />\n </Grid>\n ))}\n </Grid>\n </Grid>\n </>\n);\n"],"names":[],"mappings":";;;;;AA6BO,MAAM,mBAAmB,CAAC,EAAE,QAAS,EAAA,+EAEvC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,IAAI,EACb,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAQ,EAAA,EAAA,aAAA,EAAY,iCAAgC,CACvD,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,MAAI,IAAC,EAAA,EAAA,EAAI,EACb,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,SAAS,EAAA,IAAA,EAAC,OAAS,EAAA,CAAA,EAAG,eAAY,oBACrC,EAAA,EAAA,QAAA,CAAS,QAAS,CAAA,IAAA,EAAM,IAAI,CAC3B,GAAA,qBAAA,KAAA,CAAA,aAAA;AAAA,EAAC,IAAA;AAAA,EAAA;AAAA,IACC,GAAA,EAAK,QAAQ,GAAG,CAAA,CAAA;AAAA,IAChB,IAAI,EAAA,IAAA;AAAA,IACJ,aAAA,EAAa,0BAA0B,GAAG,CAAA;AAAA,GAAA;AAAA,kBAE1C,KAAA,CAAA,aAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,MAAA,EAAQ,CAAE,EAAA;AAAA,MACnB,IAAK,EAAA,OAAA;AAAA,MACL,aAAA,EAAa,0BAA0B,GAAG,CAAA,CAAA;AAAA,MAC1C,KAAO,EAAA,GAAA;AAAA,MACP,GAAK,EAAA;AAAA;AAAA;AAET,CACD,CACH,CACF,CACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-react",
3
- "version": "1.14.2-next.2",
3
+ "version": "1.14.2",
4
4
  "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder",
5
5
  "backstage": {
6
6
  "role": "web-library",
@@ -66,17 +66,17 @@
66
66
  "test": "backstage-cli package test"
67
67
  },
68
68
  "dependencies": {
69
- "@backstage/catalog-client": "1.9.0-next.2",
70
- "@backstage/catalog-model": "1.7.2-next.0",
71
- "@backstage/core-components": "0.16.2-next.2",
72
- "@backstage/core-plugin-api": "1.10.2-next.0",
73
- "@backstage/frontend-plugin-api": "0.9.3-next.2",
74
- "@backstage/plugin-catalog-react": "1.14.3-next.2",
75
- "@backstage/plugin-permission-react": "0.4.29-next.0",
76
- "@backstage/plugin-scaffolder-common": "1.5.8-next.1",
77
- "@backstage/theme": "0.6.3-next.0",
78
- "@backstage/types": "1.2.0",
79
- "@backstage/version-bridge": "1.0.10",
69
+ "@backstage/catalog-client": "^1.9.0",
70
+ "@backstage/catalog-model": "^1.7.2",
71
+ "@backstage/core-components": "^0.16.2",
72
+ "@backstage/core-plugin-api": "^1.10.2",
73
+ "@backstage/frontend-plugin-api": "^0.9.3",
74
+ "@backstage/plugin-catalog-react": "^1.15.0",
75
+ "@backstage/plugin-permission-react": "^0.4.29",
76
+ "@backstage/plugin-scaffolder-common": "^1.5.8",
77
+ "@backstage/theme": "^0.6.3",
78
+ "@backstage/types": "^1.2.0",
79
+ "@backstage/version-bridge": "^1.0.10",
80
80
  "@material-ui/core": "^4.12.2",
81
81
  "@material-ui/icons": "^4.9.1",
82
82
  "@material-ui/lab": "4.0.0-alpha.61",
@@ -102,12 +102,12 @@
102
102
  "zod-to-json-schema": "^3.20.4"
103
103
  },
104
104
  "devDependencies": {
105
- "@backstage/cli": "0.29.3-next.2",
106
- "@backstage/core-app-api": "1.15.3-next.1",
107
- "@backstage/plugin-catalog": "1.26.0-next.2",
108
- "@backstage/plugin-catalog-common": "1.1.2-next.0",
109
- "@backstage/plugin-permission-common": "0.8.3-next.0",
110
- "@backstage/test-utils": "1.7.3-next.1",
105
+ "@backstage/cli": "^0.29.4",
106
+ "@backstage/core-app-api": "^1.15.3",
107
+ "@backstage/plugin-catalog": "^1.26.0",
108
+ "@backstage/plugin-catalog-common": "^1.1.2",
109
+ "@backstage/plugin-permission-common": "^0.8.3",
110
+ "@backstage/test-utils": "^1.7.3",
111
111
  "@testing-library/dom": "^10.0.0",
112
112
  "@testing-library/jest-dom": "^6.0.0",
113
113
  "@testing-library/react": "^16.0.0",