@backstage-community/plugin-bazaar 0.2.27 → 0.2.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/dist/api.esm.js +120 -0
  4. package/dist/api.esm.js.map +1 -0
  5. package/dist/{esm/index-CM8Pdxty.esm.js → components/About/About.esm.js} +3 -70
  6. package/dist/components/About/About.esm.js.map +1 -0
  7. package/dist/components/AddProjectDialog/AddProjectDialog.esm.js +76 -0
  8. package/dist/components/AddProjectDialog/AddProjectDialog.esm.js.map +1 -0
  9. package/dist/components/BazaarOverviewCard/BazaarOverviewCard.esm.js +107 -0
  10. package/dist/components/BazaarOverviewCard/BazaarOverviewCard.esm.js.map +1 -0
  11. package/dist/components/CardContentFields/AboutField.esm.js +33 -0
  12. package/dist/components/CardContentFields/AboutField.esm.js.map +1 -0
  13. package/dist/components/CardContentFields/CardContentFields.esm.js +87 -0
  14. package/dist/components/CardContentFields/CardContentFields.esm.js.map +1 -0
  15. package/dist/components/ConfirmationDialog/ConfirmationDialog.esm.js +29 -0
  16. package/dist/components/ConfirmationDialog/ConfirmationDialog.esm.js.map +1 -0
  17. package/dist/components/CustomDialogTitle/CustomDialogTitle.esm.js +49 -0
  18. package/dist/components/CustomDialogTitle/CustomDialogTitle.esm.js.map +1 -0
  19. package/dist/components/DateSelector/DateSelector.esm.js +40 -0
  20. package/dist/components/DateSelector/DateSelector.esm.js.map +1 -0
  21. package/dist/components/DoubleDateSelector/DoubleDateSelector.esm.js +34 -0
  22. package/dist/components/DoubleDateSelector/DoubleDateSelector.esm.js.map +1 -0
  23. package/dist/components/EditProjectDialog/EditProjectDialog.esm.js +115 -0
  24. package/dist/components/EditProjectDialog/EditProjectDialog.esm.js.map +1 -0
  25. package/dist/components/EntityBazaarInfoCard/EntityBazaarInfoCard.esm.js +41 -0
  26. package/dist/components/EntityBazaarInfoCard/EntityBazaarInfoCard.esm.js.map +1 -0
  27. package/dist/components/EntityBazaarInfoContent/EntityBazaarInfoContent.esm.js +177 -0
  28. package/dist/components/EntityBazaarInfoContent/EntityBazaarInfoContent.esm.js.map +1 -0
  29. package/dist/components/HomePage/HomePage.esm.js +30 -0
  30. package/dist/components/HomePage/HomePage.esm.js.map +1 -0
  31. package/dist/components/HomePage/index.esm.js +2 -0
  32. package/dist/components/HomePage/index.esm.js.map +1 -0
  33. package/dist/components/HomePageBazaarInfoCard/HomePageBazaarInfoCard.esm.js +218 -0
  34. package/dist/components/HomePageBazaarInfoCard/HomePageBazaarInfoCard.esm.js.map +1 -0
  35. package/dist/components/InputField/InputField.esm.js +41 -0
  36. package/dist/components/InputField/InputField.esm.js.map +1 -0
  37. package/dist/components/InputSelector/InputSelector.esm.js +47 -0
  38. package/dist/components/InputSelector/InputSelector.esm.js.map +1 -0
  39. package/dist/components/LinkProjectDialog/LinkProjectDialog.esm.js +68 -0
  40. package/dist/components/LinkProjectDialog/LinkProjectDialog.esm.js.map +1 -0
  41. package/dist/components/ProjectCard/ProjectCard.esm.js +70 -0
  42. package/dist/components/ProjectCard/ProjectCard.esm.js.map +1 -0
  43. package/dist/components/ProjectDialog/ProjectDialog.esm.js +143 -0
  44. package/dist/components/ProjectDialog/ProjectDialog.esm.js.map +1 -0
  45. package/dist/components/ProjectPreview/ProjectPreview.esm.js +79 -0
  46. package/dist/components/ProjectPreview/ProjectPreview.esm.js.map +1 -0
  47. package/dist/components/ProjectSelector/ProjectSelector.esm.js +38 -0
  48. package/dist/components/ProjectSelector/ProjectSelector.esm.js.map +1 -0
  49. package/dist/components/SortMethodSelector/SortMethodSelector.esm.js +35 -0
  50. package/dist/components/SortMethodSelector/SortMethodSelector.esm.js.map +1 -0
  51. package/dist/components/SortView/SortView.esm.js +176 -0
  52. package/dist/components/SortView/SortView.esm.js.map +1 -0
  53. package/dist/components/StatusTag/StatusTag.esm.js +13 -0
  54. package/dist/components/StatusTag/StatusTag.esm.js.map +1 -0
  55. package/dist/index.esm.js +5 -1749
  56. package/dist/index.esm.js.map +1 -1
  57. package/dist/plugin.esm.js +31 -0
  58. package/dist/plugin.esm.js.map +1 -0
  59. package/dist/routes.esm.js +8 -0
  60. package/dist/routes.esm.js.map +1 -0
  61. package/dist/util/fetchMethods.esm.js +26 -0
  62. package/dist/util/fetchMethods.esm.js.map +1 -0
  63. package/dist/util/parseMethods.esm.js +38 -0
  64. package/dist/util/parseMethods.esm.js.map +1 -0
  65. package/dist/util/sortMethods.esm.js +20 -0
  66. package/dist/util/sortMethods.esm.js.map +1 -0
  67. package/package.json +14 -9
  68. package/dist/esm/index-CM8Pdxty.esm.js.map +0 -1
@@ -0,0 +1,143 @@
1
+ import React from 'react';
2
+ import Button from '@material-ui/core/Button';
3
+ import Dialog from '@material-ui/core/Dialog';
4
+ import { useForm } from 'react-hook-form';
5
+ import { InputField } from '../InputField/InputField.esm.js';
6
+ import { InputSelector } from '../InputSelector/InputSelector.esm.js';
7
+ import { DoubleDateSelector } from '../DoubleDateSelector/DoubleDateSelector.esm.js';
8
+ import { CustomDialogTitle, DialogContent, DialogActions } from '../CustomDialogTitle/CustomDialogTitle.esm.js';
9
+
10
+ const ProjectDialog = ({
11
+ handleSave,
12
+ isAddForm,
13
+ title,
14
+ defaultValues,
15
+ open,
16
+ projectSelector,
17
+ deleteButton,
18
+ handleClose
19
+ }) => {
20
+ const {
21
+ handleSubmit,
22
+ reset,
23
+ control,
24
+ getValues,
25
+ formState: { errors },
26
+ setValue
27
+ } = useForm({
28
+ mode: "onChange",
29
+ defaultValues
30
+ });
31
+ const handleSaveForm = () => {
32
+ handleSave(getValues, reset);
33
+ };
34
+ const handleCloseDialog = () => {
35
+ handleClose();
36
+ reset(defaultValues);
37
+ };
38
+ return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
39
+ Dialog,
40
+ {
41
+ fullWidth: true,
42
+ maxWidth: "xs",
43
+ onClose: handleCloseDialog,
44
+ "aria-labelledby": "customized-dialog-title",
45
+ open
46
+ },
47
+ /* @__PURE__ */ React.createElement(
48
+ CustomDialogTitle,
49
+ {
50
+ id: "customized-dialog-title",
51
+ onClose: handleCloseDialog
52
+ },
53
+ title
54
+ ),
55
+ /* @__PURE__ */ React.createElement(DialogContent, { style: { padding: "1rem", paddingTop: "0rem" }, dividers: true }, /* @__PURE__ */ React.createElement(
56
+ InputField,
57
+ {
58
+ error: errors.title,
59
+ control,
60
+ rules: {
61
+ required: true
62
+ },
63
+ inputType: "title",
64
+ helperText: "Please enter a title for your project"
65
+ }
66
+ ), /* @__PURE__ */ React.createElement(
67
+ InputField,
68
+ {
69
+ error: errors.description,
70
+ control,
71
+ rules: {
72
+ required: true
73
+ },
74
+ inputType: "description",
75
+ helperText: "Please enter a description"
76
+ }
77
+ ), /* @__PURE__ */ React.createElement(
78
+ InputSelector,
79
+ {
80
+ control,
81
+ name: "status",
82
+ options: ["proposed", "ongoing"]
83
+ }
84
+ ), /* @__PURE__ */ React.createElement(
85
+ InputSelector,
86
+ {
87
+ control,
88
+ name: "size",
89
+ options: ["small", "medium", "large"]
90
+ }
91
+ ), /* @__PURE__ */ React.createElement(
92
+ InputField,
93
+ {
94
+ error: errors.responsible,
95
+ control,
96
+ rules: {
97
+ required: true
98
+ },
99
+ inputType: "responsible",
100
+ helperText: "Please enter a contact person",
101
+ placeholder: "Contact person of the project"
102
+ }
103
+ ), isAddForm && projectSelector, /* @__PURE__ */ React.createElement(
104
+ InputField,
105
+ {
106
+ error: errors.community,
107
+ control,
108
+ rules: {
109
+ required: false,
110
+ pattern: RegExp("^(https?)://")
111
+ },
112
+ inputType: "community",
113
+ helperText: "Please enter a link starting with http/https",
114
+ placeholder: "Community link to e.g. Teams or Discord"
115
+ }
116
+ ), /* @__PURE__ */ React.createElement(
117
+ InputField,
118
+ {
119
+ error: errors.docs,
120
+ control,
121
+ rules: {
122
+ required: false,
123
+ pattern: RegExp("^(https?)://")
124
+ },
125
+ inputType: "docs",
126
+ helperText: "Please enter a link starting with http/https",
127
+ placeholder: "Project docs link"
128
+ }
129
+ ), /* @__PURE__ */ React.createElement(DoubleDateSelector, { setValue, control })),
130
+ /* @__PURE__ */ React.createElement(DialogActions, null, !isAddForm && deleteButton, /* @__PURE__ */ React.createElement(
131
+ Button,
132
+ {
133
+ onClick: handleSubmit(handleSaveForm),
134
+ color: "primary",
135
+ type: "submit"
136
+ },
137
+ "Submit"
138
+ ))
139
+ ));
140
+ };
141
+
142
+ export { ProjectDialog };
143
+ //# sourceMappingURL=ProjectDialog.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectDialog.esm.js","sources":["../../../src/components/ProjectDialog/ProjectDialog.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 */\n\nimport React from 'react';\nimport Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport { useForm, UseFormReset, UseFormGetValues } from 'react-hook-form';\nimport { InputField } from '../InputField/InputField';\nimport { InputSelector } from '../InputSelector/InputSelector';\nimport { FormValues } from '../../types';\nimport { DoubleDateSelector } from '../DoubleDateSelector/DoubleDateSelector';\nimport {\n CustomDialogTitle,\n DialogActions,\n DialogContent,\n} from '../CustomDialogTitle';\n\ntype Props = {\n handleSave: (\n getValues: UseFormGetValues<FormValues>,\n reset: UseFormReset<FormValues>,\n ) => Promise<void>;\n isAddForm: boolean;\n title: string;\n defaultValues: FormValues;\n open: boolean;\n projectSelector?: JSX.Element;\n deleteButton?: JSX.Element;\n handleClose: () => void;\n};\n\nexport const ProjectDialog = ({\n handleSave,\n isAddForm,\n title,\n defaultValues,\n open,\n projectSelector,\n deleteButton,\n handleClose,\n}: Props) => {\n const {\n handleSubmit,\n reset,\n control,\n getValues,\n formState: { errors },\n setValue,\n } = useForm<FormValues>({\n mode: 'onChange',\n defaultValues,\n });\n\n const handleSaveForm = () => {\n handleSave(getValues, reset);\n };\n\n const handleCloseDialog = () => {\n handleClose();\n reset(defaultValues);\n };\n\n return (\n <div>\n <Dialog\n fullWidth\n maxWidth=\"xs\"\n onClose={handleCloseDialog}\n aria-labelledby=\"customized-dialog-title\"\n open={open}\n >\n <CustomDialogTitle\n id=\"customized-dialog-title\"\n onClose={handleCloseDialog}\n >\n {title}\n </CustomDialogTitle>\n <DialogContent style={{ padding: '1rem', paddingTop: '0rem' }} dividers>\n <InputField\n error={errors.title}\n control={control}\n rules={{\n required: true,\n }}\n inputType=\"title\"\n helperText=\"Please enter a title for your project\"\n />\n <InputField\n error={errors.description}\n control={control}\n rules={{\n required: true,\n }}\n inputType=\"description\"\n helperText=\"Please enter a description\"\n />\n\n <InputSelector\n control={control}\n name=\"status\"\n options={['proposed', 'ongoing']}\n />\n\n <InputSelector\n control={control}\n name=\"size\"\n options={['small', 'medium', 'large']}\n />\n\n <InputField\n error={errors.responsible}\n control={control}\n rules={{\n required: true,\n }}\n inputType=\"responsible\"\n helperText=\"Please enter a contact person\"\n placeholder=\"Contact person of the project\"\n />\n\n {isAddForm && projectSelector}\n\n <InputField\n error={errors.community}\n control={control}\n rules={{\n required: false,\n pattern: RegExp('^(https?)://'),\n }}\n inputType=\"community\"\n helperText=\"Please enter a link starting with http/https\"\n placeholder=\"Community link to e.g. Teams or Discord\"\n />\n\n <InputField\n error={errors.docs}\n control={control}\n rules={{\n required: false,\n pattern: RegExp('^(https?)://'),\n }}\n inputType=\"docs\"\n helperText=\"Please enter a link starting with http/https\"\n placeholder=\"Project docs link\"\n />\n\n <DoubleDateSelector setValue={setValue} control={control} />\n </DialogContent>\n\n <DialogActions>\n {!isAddForm && deleteButton}\n <Button\n onClick={handleSubmit(handleSaveForm)}\n color=\"primary\"\n type=\"submit\"\n >\n Submit\n </Button>\n </DialogActions>\n </Dialog>\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import React, { useState } from 'react';
2
+ import { ProjectCard } from '../ProjectCard/ProjectCard.esm.js';
3
+ import Box from '@material-ui/core/Box';
4
+ import Grid from '@material-ui/core/Grid';
5
+ import TablePagination from '@material-ui/core/TablePagination';
6
+ import { makeStyles } from '@material-ui/core/styles';
7
+
8
+ const useStyles = makeStyles({
9
+ content: {
10
+ width: "100%",
11
+ display: "flex",
12
+ flexWrap: "wrap",
13
+ alignItems: "center"
14
+ },
15
+ empty: {
16
+ height: "10rem",
17
+ textAlign: "center",
18
+ verticalAlign: "middle",
19
+ lineHeight: "10rem"
20
+ },
21
+ pagination: {
22
+ marginTop: "1rem",
23
+ marginLeft: "auto",
24
+ marginRight: "0"
25
+ }
26
+ });
27
+ const ProjectPreview = ({
28
+ bazaarProjects,
29
+ fetchBazaarProjects,
30
+ catalogEntities,
31
+ useTablePagination = true,
32
+ gridSize = 2,
33
+ height = "large"
34
+ }) => {
35
+ const classes = useStyles();
36
+ const [page, setPage] = useState(1);
37
+ const [rows, setRows] = useState(12);
38
+ const handlePageChange = (_, newPage) => {
39
+ setPage(newPage + 1);
40
+ };
41
+ const handleRowChange = (event) => {
42
+ setRows(parseInt(event.target.value, 10));
43
+ setPage(1);
44
+ };
45
+ if (!bazaarProjects.length) {
46
+ return /* @__PURE__ */ React.createElement("div", { className: classes.empty }, "Please add projects to the Bazaar.");
47
+ }
48
+ return /* @__PURE__ */ React.createElement(Box, { className: classes.content }, /* @__PURE__ */ React.createElement(Grid, { wrap: "wrap", container: true, spacing: 3 }, bazaarProjects.slice((page - 1) * rows, rows * page).map((bazaarProject, i) => {
49
+ return /* @__PURE__ */ React.createElement(Grid, { key: i, item: true, xs: gridSize }, /* @__PURE__ */ React.createElement(
50
+ ProjectCard,
51
+ {
52
+ project: bazaarProject,
53
+ key: i,
54
+ fetchBazaarProjects,
55
+ catalogEntities,
56
+ height
57
+ }
58
+ ));
59
+ })), useTablePagination && /* @__PURE__ */ React.createElement(
60
+ TablePagination,
61
+ {
62
+ component: "div",
63
+ className: classes.pagination,
64
+ rowsPerPageOptions: [12, 24, 48, 96],
65
+ count: bazaarProjects?.length,
66
+ page: page - 1,
67
+ onPageChange: handlePageChange,
68
+ rowsPerPage: rows,
69
+ onRowsPerPageChange: handleRowChange,
70
+ backIconButtonProps: { disabled: page === 1 },
71
+ nextIconButtonProps: {
72
+ disabled: rows * page >= bazaarProjects.length
73
+ }
74
+ }
75
+ ));
76
+ };
77
+
78
+ export { ProjectPreview };
79
+ //# sourceMappingURL=ProjectPreview.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectPreview.esm.js","sources":["../../../src/components/ProjectPreview/ProjectPreview.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 */\n\nimport React, { ChangeEvent, useState } from 'react';\nimport { ProjectCard } from '../ProjectCard/ProjectCard';\nimport Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport TablePagination from '@material-ui/core/TablePagination';\nimport { GridSize } from '@material-ui/core/Grid';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { BazaarProject } from '../../types';\nimport { Entity } from '@backstage/catalog-model';\n\ntype Props = {\n bazaarProjects: BazaarProject[];\n fetchBazaarProjects: () => Promise<BazaarProject[]>;\n catalogEntities: Entity[];\n useTablePagination?: boolean;\n gridSize?: GridSize;\n height: 'large' | 'small';\n};\n\nconst useStyles = makeStyles({\n content: {\n width: '100%',\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n },\n empty: {\n height: '10rem',\n textAlign: 'center',\n verticalAlign: 'middle',\n lineHeight: '10rem',\n },\n pagination: {\n marginTop: '1rem',\n marginLeft: 'auto',\n marginRight: '0',\n },\n});\n\nexport const ProjectPreview = ({\n bazaarProjects,\n fetchBazaarProjects,\n catalogEntities,\n useTablePagination = true,\n gridSize = 2,\n height = 'large',\n}: Props) => {\n const classes = useStyles();\n const [page, setPage] = useState(1);\n const [rows, setRows] = useState(12);\n\n const handlePageChange = (_: any, newPage: number) => {\n setPage(newPage + 1);\n };\n\n const handleRowChange = (\n event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,\n ) => {\n setRows(parseInt(event.target.value, 10));\n setPage(1);\n };\n\n if (!bazaarProjects.length) {\n return (\n <div className={classes.empty}>Please add projects to the Bazaar.</div>\n );\n }\n\n return (\n <Box className={classes.content}>\n <Grid wrap=\"wrap\" container spacing={3}>\n {bazaarProjects\n .slice((page - 1) * rows, rows * page)\n .map((bazaarProject: BazaarProject, i: number) => {\n return (\n <Grid key={i} item xs={gridSize}>\n <ProjectCard\n project={bazaarProject}\n key={i}\n fetchBazaarProjects={fetchBazaarProjects}\n catalogEntities={catalogEntities}\n height={height}\n />\n </Grid>\n );\n })}\n </Grid>\n\n {useTablePagination && (\n <TablePagination\n component=\"div\"\n className={classes.pagination}\n rowsPerPageOptions={[12, 24, 48, 96]}\n count={bazaarProjects?.length}\n page={page - 1}\n onPageChange={handlePageChange}\n rowsPerPage={rows}\n onRowsPerPageChange={handleRowChange}\n backIconButtonProps={{ disabled: page === 1 }}\n nextIconButtonProps={{\n disabled: rows * page >= bazaarProjects.length,\n }}\n />\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import Typography from '@material-ui/core/Typography';
3
+ import Autocomplete from '@material-ui/lab/Autocomplete';
4
+ import TextField from '@material-ui/core/TextField';
5
+ import { makeStyles } from '@material-ui/core/styles';
6
+
7
+ const useStyles = makeStyles({
8
+ container: { width: "100%", minWidth: "22rem" },
9
+ autocomplete: { overflow: "hidden" }
10
+ });
11
+ const ProjectSelector = ({
12
+ catalogEntities,
13
+ onChange,
14
+ disableClearable,
15
+ defaultValue,
16
+ label
17
+ }) => {
18
+ const classes = useStyles();
19
+ return /* @__PURE__ */ React.createElement("div", { className: classes.container }, /* @__PURE__ */ React.createElement(
20
+ Autocomplete,
21
+ {
22
+ className: classes.autocomplete,
23
+ fullWidth: true,
24
+ disableClearable,
25
+ defaultValue,
26
+ options: catalogEntities,
27
+ getOptionLabel: (option) => option?.metadata?.name,
28
+ renderOption: (option) => /* @__PURE__ */ React.createElement(Typography, { component: "span" }, option?.metadata?.name),
29
+ renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, { ...params, label }),
30
+ onChange: (_, data) => {
31
+ onChange(data);
32
+ }
33
+ }
34
+ ));
35
+ };
36
+
37
+ export { ProjectSelector };
38
+ //# sourceMappingURL=ProjectSelector.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProjectSelector.esm.js","sources":["../../../src/components/ProjectSelector/ProjectSelector.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 */\n\nimport React from 'react';\nimport { Entity } from '@backstage/catalog-model';\nimport Typography from '@material-ui/core/Typography';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport TextField from '@material-ui/core/TextField';\nimport { makeStyles } from '@material-ui/core/styles';\n\ntype Props = {\n catalogEntities: Entity[];\n onChange: (entity: Entity) => void;\n disableClearable: boolean;\n defaultValue: Entity | null | undefined;\n label: string;\n};\n\nconst useStyles = makeStyles({\n container: { width: '100%', minWidth: '22rem' },\n autocomplete: { overflow: 'hidden' },\n});\n\nexport const ProjectSelector = ({\n catalogEntities,\n onChange,\n disableClearable,\n defaultValue,\n label,\n}: Props) => {\n const classes = useStyles();\n return (\n <div className={classes.container}>\n <Autocomplete\n className={classes.autocomplete}\n fullWidth\n disableClearable={disableClearable}\n defaultValue={defaultValue}\n options={catalogEntities}\n getOptionLabel={option => option?.metadata?.name}\n renderOption={option => (\n <Typography component=\"span\">{option?.metadata?.name}</Typography>\n )}\n renderInput={params => <TextField {...params} label={label} />}\n onChange={(_, data) => {\n onChange(data!);\n }}\n />\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;;AA+BA,MAAM,YAAY,UAAW,CAAA;AAAA,EAC3B,SAAW,EAAA,EAAE,KAAO,EAAA,MAAA,EAAQ,UAAU,OAAQ,EAAA;AAAA,EAC9C,YAAA,EAAc,EAAE,QAAA,EAAU,QAAS,EAAA;AACrC,CAAC,CAAA,CAAA;AAEM,MAAM,kBAAkB,CAAC;AAAA,EAC9B,eAAA;AAAA,EACA,QAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AAAA,EACA,KAAA;AACF,CAAa,KAAA;AACX,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,SACtB,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACC,WAAW,OAAQ,CAAA,YAAA;AAAA,MACnB,SAAS,EAAA,IAAA;AAAA,MACT,gBAAA;AAAA,MACA,YAAA;AAAA,MACA,OAAS,EAAA,eAAA;AAAA,MACT,cAAA,EAAgB,CAAU,MAAA,KAAA,MAAA,EAAQ,QAAU,EAAA,IAAA;AAAA,MAC5C,YAAA,EAAc,4BACX,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,WAAU,MAAQ,EAAA,EAAA,MAAA,EAAQ,UAAU,IAAK,CAAA;AAAA,MAEvD,aAAa,CAAU,MAAA,qBAAA,KAAA,CAAA,aAAA,CAAC,SAAW,EAAA,EAAA,GAAG,QAAQ,KAAc,EAAA,CAAA;AAAA,MAC5D,QAAA,EAAU,CAAC,CAAA,EAAG,IAAS,KAAA;AACrB,QAAA,QAAA,CAAS,IAAK,CAAA,CAAA;AAAA,OAChB;AAAA,KAAA;AAAA,GAEJ,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import FormControl from '@material-ui/core/FormControl';
3
+ import MenuItem from '@material-ui/core/MenuItem';
4
+ import Select from '@material-ui/core/Select';
5
+ import { makeStyles } from '@material-ui/core/styles';
6
+
7
+ const useStyles = makeStyles({
8
+ select: {
9
+ fontSize: "xx-large",
10
+ fontWeight: "bold",
11
+ width: "16rem"
12
+ }
13
+ });
14
+ const SortMethodSelector = ({
15
+ sortMethodNbr,
16
+ handleSortMethodChange
17
+ }) => {
18
+ const classes = useStyles();
19
+ return /* @__PURE__ */ React.createElement(FormControl, { fullWidth: true }, /* @__PURE__ */ React.createElement(
20
+ Select,
21
+ {
22
+ className: classes.select,
23
+ disableUnderline: true,
24
+ value: sortMethodNbr,
25
+ onChange: handleSortMethodChange
26
+ },
27
+ /* @__PURE__ */ React.createElement(MenuItem, { value: 0 }, "Latest updated"),
28
+ /* @__PURE__ */ React.createElement(MenuItem, { value: 1 }, "A-Z"),
29
+ /* @__PURE__ */ React.createElement(MenuItem, { value: 2 }, "Z-A"),
30
+ /* @__PURE__ */ React.createElement(MenuItem, { value: 3 }, "Most members")
31
+ ));
32
+ };
33
+
34
+ export { SortMethodSelector };
35
+ //# sourceMappingURL=SortMethodSelector.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SortMethodSelector.esm.js","sources":["../../../src/components/SortMethodSelector/SortMethodSelector.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 */\n\nimport React, { ChangeEvent, ReactNode } from 'react';\nimport FormControl from '@material-ui/core/FormControl';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\nimport { makeStyles } from '@material-ui/core/styles';\n\nconst useStyles = makeStyles({\n select: {\n fontSize: 'xx-large',\n fontWeight: 'bold',\n width: '16rem',\n },\n});\n\ntype Props = {\n sortMethodNbr: number;\n handleSortMethodChange:\n | ((\n event: ChangeEvent<{ name?: string | undefined; value: unknown }>,\n child: ReactNode,\n ) => void)\n | undefined;\n};\n\nexport const SortMethodSelector = ({\n sortMethodNbr,\n handleSortMethodChange,\n}: Props) => {\n const classes = useStyles();\n return (\n <FormControl fullWidth>\n <Select\n className={classes.select}\n disableUnderline\n value={sortMethodNbr}\n onChange={handleSortMethodChange}\n >\n <MenuItem value={0}>Latest updated</MenuItem>\n <MenuItem value={1}>A-Z</MenuItem>\n <MenuItem value={2}>Z-A</MenuItem>\n <MenuItem value={3}>Most members</MenuItem>\n </Select>\n </FormControl>\n );\n};\n"],"names":[],"mappings":";;;;;;AAsBA,MAAM,YAAY,UAAW,CAAA;AAAA,EAC3B,MAAQ,EAAA;AAAA,IACN,QAAU,EAAA,UAAA;AAAA,IACV,UAAY,EAAA,MAAA;AAAA,IACZ,KAAO,EAAA,OAAA;AAAA,GACT;AACF,CAAC,CAAA,CAAA;AAYM,MAAM,qBAAqB,CAAC;AAAA,EACjC,aAAA;AAAA,EACA,sBAAA;AACF,CAAa,KAAA;AACX,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,WAAY,EAAA,EAAA,SAAA,EAAS,IACpB,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,WAAW,OAAQ,CAAA,MAAA;AAAA,MACnB,gBAAgB,EAAA,IAAA;AAAA,MAChB,KAAO,EAAA,aAAA;AAAA,MACP,QAAU,EAAA,sBAAA;AAAA,KAAA;AAAA,oBAET,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,KAAO,EAAA,CAAA,EAAA,EAAG,gBAAc,CAAA;AAAA,oBACjC,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,KAAO,EAAA,CAAA,EAAA,EAAG,KAAG,CAAA;AAAA,oBACtB,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,KAAO,EAAA,CAAA,EAAA,EAAG,KAAG,CAAA;AAAA,oBACtB,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAS,KAAO,EAAA,CAAA,EAAA,EAAG,cAAY,CAAA;AAAA,GAEpC,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,176 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { Content, SupportButton } from '@backstage/core-components';
3
+ import { AddProjectDialog } from '../AddProjectDialog/AddProjectDialog.esm.js';
4
+ import { ProjectPreview } from '../ProjectPreview/ProjectPreview.esm.js';
5
+ import Button from '@material-ui/core/Button';
6
+ import { makeStyles } from '@material-ui/core/styles';
7
+ import useAsyncFn from 'react-use/esm/useAsyncFn';
8
+ import { stringifyEntityRef } from '@backstage/catalog-model';
9
+ import { useApi } from '@backstage/core-plugin-api';
10
+ import { catalogApiRef } from '@backstage/plugin-catalog-react';
11
+ import { bazaarApiRef } from '../../api.esm.js';
12
+ import Alert from '@material-ui/lab/Alert';
13
+ import SearchBar from 'material-ui-search-bar';
14
+ import { sortByDate, sortByTitle, sortByTitleDescending, sortByMembers } from '../../util/sortMethods.esm.js';
15
+ import { SortMethodSelector } from '../SortMethodSelector/SortMethodSelector.esm.js';
16
+ import { fetchCatalogItems } from '../../util/fetchMethods.esm.js';
17
+ import { parseBazaarProject } from '../../util/parseMethods.esm.js';
18
+
19
+ const useStyles = makeStyles({
20
+ button: { minWidth: "11rem" },
21
+ container: {
22
+ marginTop: "2rem"
23
+ },
24
+ header: {
25
+ width: "100%",
26
+ display: "flex",
27
+ flexDirection: "row",
28
+ justifyContent: "center",
29
+ alignItems: "center",
30
+ margin: "0 auto",
31
+ marginBottom: "1.2rem"
32
+ },
33
+ search: {
34
+ marginRight: "1rem",
35
+ height: "2.5rem",
36
+ width: "35rem"
37
+ }
38
+ });
39
+ const getUnlinkedCatalogEntities = (bazaarProjects, catalogEntities) => {
40
+ const bazaarProjectRefs = bazaarProjects.map(
41
+ (project) => project.entityRef
42
+ );
43
+ return catalogEntities.filter((entity) => {
44
+ return !bazaarProjectRefs?.includes(stringifyEntityRef(entity));
45
+ });
46
+ };
47
+ const SortView = (props) => {
48
+ const { fullWidth = true, fullHeight = true } = props;
49
+ const bazaarApi = useApi(bazaarApiRef);
50
+ const catalogApi = useApi(catalogApiRef);
51
+ const classes = useStyles();
52
+ const sortMethods = [
53
+ sortByDate,
54
+ sortByTitle,
55
+ sortByTitleDescending,
56
+ sortByMembers
57
+ ];
58
+ const [sortMethodNbr, setSortMethodNbr] = useState(0);
59
+ const [openAdd, setOpenAdd] = useState(false);
60
+ const [searchValue, setSearchValue] = useState("");
61
+ const [unlinkedCatalogEntities, setUnlinkedCatalogEntities] = useState();
62
+ const [catalogEntities, fetchCatalogEntities] = useAsyncFn(async () => {
63
+ return await fetchCatalogItems(catalogApi);
64
+ });
65
+ const [bazaarProjects, fetchBazaarProjects] = useAsyncFn(async () => {
66
+ const response = await bazaarApi.getProjects();
67
+ const dbProjects = [];
68
+ response.data.forEach((project) => {
69
+ dbProjects.push(parseBazaarProject(project));
70
+ });
71
+ return dbProjects;
72
+ });
73
+ const catalogEntityRefs = catalogEntities.value?.map(
74
+ (project) => stringifyEntityRef(project)
75
+ );
76
+ const getSearchResults = () => {
77
+ return bazaarProjects.value?.filter((project) => project.title.includes(searchValue)).sort(sortMethods[sortMethodNbr]);
78
+ };
79
+ useEffect(() => {
80
+ const filterBrokenLinks = () => {
81
+ if (catalogEntityRefs) {
82
+ bazaarProjects.value?.forEach(async (project) => {
83
+ if (project.entityRef) {
84
+ if (!catalogEntityRefs?.includes(project.entityRef)) {
85
+ await bazaarApi.updateProject({
86
+ ...project,
87
+ entityRef: null
88
+ });
89
+ }
90
+ }
91
+ });
92
+ }
93
+ };
94
+ filterBrokenLinks();
95
+ }, [
96
+ bazaarApi,
97
+ bazaarProjects.value,
98
+ catalogEntityRefs,
99
+ catalogEntities.value
100
+ ]);
101
+ useEffect(() => {
102
+ fetchCatalogEntities();
103
+ fetchBazaarProjects();
104
+ }, [fetchBazaarProjects, fetchCatalogEntities]);
105
+ useEffect(() => {
106
+ const unlinkedCEntities = getUnlinkedCatalogEntities(
107
+ bazaarProjects.value || [],
108
+ catalogEntities.value || []
109
+ );
110
+ if (unlinkedCEntities) {
111
+ setUnlinkedCatalogEntities(unlinkedCEntities);
112
+ }
113
+ }, [bazaarProjects, catalogEntities]);
114
+ const handleSortMethodChange = (event) => {
115
+ setSortMethodNbr(
116
+ typeof event.target.value === "number" ? event.target.value : 0
117
+ );
118
+ };
119
+ if (catalogEntities.error)
120
+ return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, catalogEntities.error.message);
121
+ if (bazaarProjects.error)
122
+ return /* @__PURE__ */ React.createElement(Alert, { severity: "error" }, bazaarProjects.error.message);
123
+ return /* @__PURE__ */ React.createElement(Content, { noPadding: true }, /* @__PURE__ */ React.createElement("div", { className: classes.header }, /* @__PURE__ */ React.createElement(
124
+ SortMethodSelector,
125
+ {
126
+ sortMethodNbr,
127
+ handleSortMethodChange
128
+ }
129
+ ), /* @__PURE__ */ React.createElement(
130
+ SearchBar,
131
+ {
132
+ className: classes.search,
133
+ value: searchValue,
134
+ onChange: (newSortMethod) => {
135
+ setSearchValue(newSortMethod);
136
+ },
137
+ onCancelSearch: () => {
138
+ setSearchValue("");
139
+ }
140
+ }
141
+ ), /* @__PURE__ */ React.createElement(
142
+ Button,
143
+ {
144
+ className: classes.button,
145
+ variant: "contained",
146
+ color: "primary",
147
+ onClick: () => {
148
+ setOpenAdd(true);
149
+ }
150
+ },
151
+ "Add project"
152
+ ), /* @__PURE__ */ React.createElement(
153
+ AddProjectDialog,
154
+ {
155
+ catalogEntities: unlinkedCatalogEntities || [],
156
+ handleClose: () => {
157
+ setOpenAdd(false);
158
+ },
159
+ open: openAdd,
160
+ fetchBazaarProjects,
161
+ fetchCatalogEntities
162
+ }
163
+ ), /* @__PURE__ */ React.createElement(SupportButton, null)), /* @__PURE__ */ React.createElement(
164
+ ProjectPreview,
165
+ {
166
+ bazaarProjects: getSearchResults() || [],
167
+ fetchBazaarProjects,
168
+ catalogEntities: unlinkedCatalogEntities || [],
169
+ gridSize: fullWidth ? 2 : 4,
170
+ height: fullHeight ? "large" : "small"
171
+ }
172
+ ), /* @__PURE__ */ React.createElement(Content, { noPadding: true, className: classes.container }));
173
+ };
174
+
175
+ export { SortView };
176
+ //# sourceMappingURL=SortView.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SortView.esm.js","sources":["../../../src/components/SortView/SortView.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 */\n\nimport React, { ChangeEvent, useEffect, useState } from 'react';\nimport { Content, SupportButton } from '@backstage/core-components';\nimport { AddProjectDialog } from '../AddProjectDialog';\nimport { ProjectPreview } from '../ProjectPreview/ProjectPreview';\nimport Button from '@material-ui/core/Button';\nimport { makeStyles } from '@material-ui/core/styles';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { BazaarProject } from '../../types';\nimport { bazaarApiRef } from '../../api';\nimport Alert from '@material-ui/lab/Alert';\nimport SearchBar from 'material-ui-search-bar';\nimport {\n sortByDate,\n sortByMembers,\n sortByTitle,\n sortByTitleDescending,\n} from '../../util/sortMethods';\nimport { SortMethodSelector } from '../SortMethodSelector';\nimport { fetchCatalogItems } from '../../util/fetchMethods';\nimport { parseBazaarProject } from '../../util/parseMethods';\n\nconst useStyles = makeStyles({\n button: { minWidth: '11rem' },\n container: {\n marginTop: '2rem',\n },\n header: {\n width: '100%',\n display: 'flex',\n flexDirection: 'row',\n justifyContent: 'center',\n alignItems: 'center',\n margin: '0 auto',\n marginBottom: '1.2rem',\n },\n search: {\n marginRight: '1rem',\n height: '2.5rem',\n width: '35rem',\n },\n});\n\nconst getUnlinkedCatalogEntities = (\n bazaarProjects: BazaarProject[],\n catalogEntities: Entity[],\n) => {\n const bazaarProjectRefs = bazaarProjects.map(\n (project: BazaarProject) => project.entityRef,\n );\n\n return catalogEntities.filter((entity: Entity) => {\n return !bazaarProjectRefs?.includes(stringifyEntityRef(entity));\n });\n};\n\n/** @public */\nexport type SortViewProps = {\n fullWidth?: boolean;\n fullHeight?: boolean;\n};\n\n/** @public */\nexport const SortView = (props: SortViewProps) => {\n const { fullWidth = true, fullHeight = true } = props;\n const bazaarApi = useApi(bazaarApiRef);\n const catalogApi = useApi(catalogApiRef);\n const classes = useStyles();\n const sortMethods = [\n sortByDate,\n sortByTitle,\n sortByTitleDescending,\n sortByMembers,\n ];\n const [sortMethodNbr, setSortMethodNbr] = useState(0);\n const [openAdd, setOpenAdd] = useState(false);\n const [searchValue, setSearchValue] = useState('');\n const [unlinkedCatalogEntities, setUnlinkedCatalogEntities] =\n useState<Entity[]>();\n\n const [catalogEntities, fetchCatalogEntities] = useAsyncFn(async () => {\n return await fetchCatalogItems(catalogApi);\n });\n\n const [bazaarProjects, fetchBazaarProjects] = useAsyncFn(async () => {\n const response = await bazaarApi.getProjects();\n const dbProjects: BazaarProject[] = [];\n\n response.data.forEach((project: any) => {\n dbProjects.push(parseBazaarProject(project));\n });\n\n return dbProjects;\n });\n\n const catalogEntityRefs = catalogEntities.value?.map((project: Entity) =>\n stringifyEntityRef(project),\n );\n\n const getSearchResults = () => {\n return bazaarProjects.value\n ?.filter(project => project.title.includes(searchValue))\n .sort(sortMethods[sortMethodNbr]);\n };\n\n useEffect(() => {\n const filterBrokenLinks = () => {\n if (catalogEntityRefs) {\n bazaarProjects.value?.forEach(async (project: BazaarProject) => {\n if (project.entityRef) {\n if (!catalogEntityRefs?.includes(project.entityRef)) {\n await bazaarApi.updateProject({\n ...project,\n entityRef: null,\n });\n }\n }\n });\n }\n };\n filterBrokenLinks();\n }, [\n bazaarApi,\n bazaarProjects.value,\n catalogEntityRefs,\n catalogEntities.value,\n ]);\n\n useEffect(() => {\n fetchCatalogEntities();\n fetchBazaarProjects();\n }, [fetchBazaarProjects, fetchCatalogEntities]);\n\n useEffect(() => {\n const unlinkedCEntities = getUnlinkedCatalogEntities(\n bazaarProjects.value || [],\n catalogEntities.value || [],\n );\n\n if (unlinkedCEntities) {\n setUnlinkedCatalogEntities(unlinkedCEntities);\n }\n }, [bazaarProjects, catalogEntities]);\n\n const handleSortMethodChange = (\n event: ChangeEvent<{ name?: string | undefined; value: unknown }>,\n ) => {\n setSortMethodNbr(\n typeof event.target.value === 'number' ? event.target.value : 0,\n );\n };\n\n if (catalogEntities.error)\n return <Alert severity=\"error\">{catalogEntities.error.message}</Alert>;\n\n if (bazaarProjects.error)\n return <Alert severity=\"error\">{bazaarProjects.error.message}</Alert>;\n\n return (\n <Content noPadding>\n <div className={classes.header}>\n <SortMethodSelector\n sortMethodNbr={sortMethodNbr}\n handleSortMethodChange={handleSortMethodChange}\n />\n\n <SearchBar\n className={classes.search}\n value={searchValue}\n onChange={newSortMethod => {\n setSearchValue(newSortMethod);\n }}\n onCancelSearch={() => {\n setSearchValue('');\n }}\n />\n <Button\n className={classes.button}\n variant=\"contained\"\n color=\"primary\"\n onClick={() => {\n setOpenAdd(true);\n }}\n >\n Add project\n </Button>\n <AddProjectDialog\n catalogEntities={unlinkedCatalogEntities || []}\n handleClose={() => {\n setOpenAdd(false);\n }}\n open={openAdd}\n fetchBazaarProjects={fetchBazaarProjects}\n fetchCatalogEntities={fetchCatalogEntities}\n />\n <SupportButton />\n </div>\n <ProjectPreview\n bazaarProjects={getSearchResults() || []}\n fetchBazaarProjects={fetchBazaarProjects}\n catalogEntities={unlinkedCatalogEntities || []}\n gridSize={fullWidth ? 2 : 4}\n height={fullHeight ? 'large' : 'small'}\n />\n <Content noPadding className={classes.container} />\n </Content>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { StatusWarning, StatusOK } from '@backstage/core-components';
3
+
4
+ const statuses = {
5
+ proposed: /* @__PURE__ */ React.createElement(StatusWarning, null, "proposed"),
6
+ ongoing: /* @__PURE__ */ React.createElement(StatusOK, null, "ongoing")
7
+ };
8
+ const StatusTag = ({ status, styles }) => {
9
+ return /* @__PURE__ */ React.createElement("div", { className: styles }, statuses[status]);
10
+ };
11
+
12
+ export { StatusTag };
13
+ //# sourceMappingURL=StatusTag.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusTag.esm.js","sources":["../../../src/components/StatusTag/StatusTag.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 */\n\nimport React from 'react';\nimport { StatusOK, StatusWarning } from '@backstage/core-components';\nimport { Status } from '../../types';\n\ninterface StatusComponent {\n [key: string]: JSX.Element | undefined;\n}\n\nconst statuses: StatusComponent = {\n proposed: <StatusWarning>proposed</StatusWarning>,\n ongoing: <StatusOK>ongoing</StatusOK>,\n};\n\ntype Props = {\n status: Status;\n styles?: string;\n};\n\nexport const StatusTag = ({ status, styles }: Props) => {\n return <div className={styles}>{statuses[status]}</div>;\n};\n"],"names":[],"mappings":";;;AAwBA,MAAM,QAA4B,GAAA;AAAA,EAChC,QAAA,kBAAW,KAAA,CAAA,aAAA,CAAA,aAAA,EAAA,IAAA,EAAc,UAAQ,CAAA;AAAA,EACjC,OAAA,kBAAU,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAA,EAAS,SAAO,CAAA;AAC5B,CAAA,CAAA;AAOO,MAAM,SAAY,GAAA,CAAC,EAAE,MAAA,EAAQ,QAAoB,KAAA;AACtD,EAAA,2CAAQ,KAAI,EAAA,EAAA,SAAA,EAAW,MAAS,EAAA,EAAA,QAAA,CAAS,MAAM,CAAE,CAAA,CAAA;AACnD;;;;"}