@backstage-community/plugin-announcements 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +142 -0
  3. package/dist/alpha/apis.esm.js +26 -0
  4. package/dist/alpha/apis.esm.js.map +1 -0
  5. package/dist/alpha/entityCards.esm.js +16 -0
  6. package/dist/alpha/entityCards.esm.js.map +1 -0
  7. package/dist/alpha/navItems.esm.js +15 -0
  8. package/dist/alpha/navItems.esm.js.map +1 -0
  9. package/dist/alpha/pages.esm.js +18 -0
  10. package/dist/alpha/pages.esm.js.map +1 -0
  11. package/dist/alpha.d.ts +11 -0
  12. package/dist/alpha.esm.js +23 -0
  13. package/dist/alpha.esm.js.map +1 -0
  14. package/dist/api.esm.js +117 -0
  15. package/dist/api.esm.js.map +1 -0
  16. package/dist/components/Admin/AdminPortal/AdminPortal.esm.js +51 -0
  17. package/dist/components/Admin/AdminPortal/AdminPortal.esm.js.map +1 -0
  18. package/dist/components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js +199 -0
  19. package/dist/components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js.map +1 -0
  20. package/dist/components/Admin/CategoriesContent/CategoriesContent.esm.js +130 -0
  21. package/dist/components/Admin/CategoriesContent/CategoriesContent.esm.js.map +1 -0
  22. package/dist/components/Admin/index.esm.js +3 -0
  23. package/dist/components/Admin/index.esm.js.map +1 -0
  24. package/dist/components/AnnouncementForm/AnnouncementForm.esm.js +123 -0
  25. package/dist/components/AnnouncementForm/AnnouncementForm.esm.js.map +1 -0
  26. package/dist/components/AnnouncementForm/CategoryInput.esm.js +79 -0
  27. package/dist/components/AnnouncementForm/CategoryInput.esm.js.map +1 -0
  28. package/dist/components/AnnouncementPage/AnnouncementPage.esm.js +59 -0
  29. package/dist/components/AnnouncementPage/AnnouncementPage.esm.js.map +1 -0
  30. package/dist/components/AnnouncementSearchResultListItem/AnnouncementSearchResultListItem.esm.js +67 -0
  31. package/dist/components/AnnouncementSearchResultListItem/AnnouncementSearchResultListItem.esm.js.map +1 -0
  32. package/dist/components/AnnouncementSearchResultListItem/index.esm.js +2 -0
  33. package/dist/components/AnnouncementSearchResultListItem/index.esm.js.map +1 -0
  34. package/dist/components/AnnouncementsCard/AnnouncementsCard.esm.js +81 -0
  35. package/dist/components/AnnouncementsCard/AnnouncementsCard.esm.js.map +1 -0
  36. package/dist/components/AnnouncementsCard/index.esm.js +2 -0
  37. package/dist/components/AnnouncementsCard/index.esm.js.map +1 -0
  38. package/dist/components/AnnouncementsPage/AnnouncementsPage.esm.js +233 -0
  39. package/dist/components/AnnouncementsPage/AnnouncementsPage.esm.js.map +1 -0
  40. package/dist/components/AnnouncementsPage/ContextMenu.esm.js +59 -0
  41. package/dist/components/AnnouncementsPage/ContextMenu.esm.js.map +1 -0
  42. package/dist/components/AnnouncementsPage/DeleteAnnouncementDialog.esm.js +25 -0
  43. package/dist/components/AnnouncementsPage/DeleteAnnouncementDialog.esm.js.map +1 -0
  44. package/dist/components/AnnouncementsPage/useDeleteAnnouncementDialogState.esm.js +29 -0
  45. package/dist/components/AnnouncementsPage/useDeleteAnnouncementDialogState.esm.js.map +1 -0
  46. package/dist/components/AnnouncementsTimeline/AnnouncementsTimeline.esm.js +55 -0
  47. package/dist/components/AnnouncementsTimeline/AnnouncementsTimeline.esm.js.map +1 -0
  48. package/dist/components/CategoriesForm/CategoriesForm.esm.js +71 -0
  49. package/dist/components/CategoriesForm/CategoriesForm.esm.js.map +1 -0
  50. package/dist/components/CategoriesPage/CategoriesPage.esm.js +113 -0
  51. package/dist/components/CategoriesPage/CategoriesPage.esm.js.map +1 -0
  52. package/dist/components/CategoriesPage/DeleteCategoryDialog.esm.js +10 -0
  53. package/dist/components/CategoriesPage/DeleteCategoryDialog.esm.js.map +1 -0
  54. package/dist/components/CategoriesPage/useDeleteCategoryDialogState.esm.js +29 -0
  55. package/dist/components/CategoriesPage/useDeleteCategoryDialogState.esm.js.map +1 -0
  56. package/dist/components/CreateAnnouncementPage/CreateAnnouncementPage.esm.js +56 -0
  57. package/dist/components/CreateAnnouncementPage/CreateAnnouncementPage.esm.js.map +1 -0
  58. package/dist/components/EditAnnouncementPage/EditAnnouncementPage.esm.js +45 -0
  59. package/dist/components/EditAnnouncementPage/EditAnnouncementPage.esm.js.map +1 -0
  60. package/dist/components/NewAnnouncementBanner/NewAnnouncementBanner.esm.js +136 -0
  61. package/dist/components/NewAnnouncementBanner/NewAnnouncementBanner.esm.js.map +1 -0
  62. package/dist/components/NewAnnouncementBanner/index.esm.js +2 -0
  63. package/dist/components/NewAnnouncementBanner/index.esm.js.map +1 -0
  64. package/dist/components/NewCategoryDialog/NewCategoryDialog.esm.js +46 -0
  65. package/dist/components/NewCategoryDialog/NewCategoryDialog.esm.js.map +1 -0
  66. package/dist/components/Router.esm.js +64 -0
  67. package/dist/components/Router.esm.js.map +1 -0
  68. package/dist/components/index.esm.js +4 -0
  69. package/dist/components/index.esm.js.map +1 -0
  70. package/dist/index.d.ts +42 -0
  71. package/dist/index.esm.js +7 -0
  72. package/dist/index.esm.js.map +1 -0
  73. package/dist/plugin.esm.js +83 -0
  74. package/dist/plugin.esm.js.map +1 -0
  75. package/dist/routes.esm.js +33 -0
  76. package/dist/routes.esm.js.map +1 -0
  77. package/package.json +113 -0
@@ -0,0 +1,199 @@
1
+ import React__default, { useState } from 'react';
2
+ import { Progress, ErrorPanel, Table } from '@backstage/core-components';
3
+ import { useApi, alertApiRef } from '@backstage/core-plugin-api';
4
+ import { announcementsApiRef, useCategories, useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
5
+ import { announcementCreatePermission, announcementUpdatePermission, announcementDeletePermission } from '@backstage-community/plugin-announcements-common';
6
+ import useAsyncRetry from 'react-use/esm/useAsyncRetry';
7
+ import { useDeleteAnnouncementDialogState } from '../../AnnouncementsPage/useDeleteAnnouncementDialogState.esm.js';
8
+ import { DeleteAnnouncementDialog } from '../../AnnouncementsPage/DeleteAnnouncementDialog.esm.js';
9
+ import { useNavigate } from 'react-router-dom';
10
+ import { AnnouncementForm } from '../../AnnouncementForm/AnnouncementForm.esm.js';
11
+ import slugify from 'slugify';
12
+ import { usePermission, RequirePermission } from '@backstage/plugin-permission-react';
13
+ import { Typography, IconButton, Grid, Button } from '@material-ui/core';
14
+ import DeleteIcon from '@material-ui/icons/Delete';
15
+ import EditIcon from '@material-ui/icons/Edit';
16
+ import PreviewIcon from '@material-ui/icons/Visibility';
17
+
18
+ const AnnouncementsContent = () => {
19
+ const alertApi = useApi(alertApiRef);
20
+ const announcementsApi = useApi(announcementsApiRef);
21
+ const navigate = useNavigate();
22
+ const { categories } = useCategories();
23
+ const { t } = useAnnouncementsTranslation();
24
+ const { loading: loadingCreatePermission, allowed: canCreateAnnouncement } = usePermission({
25
+ permission: announcementCreatePermission
26
+ });
27
+ const { loading: loadingUpdatePermission, allowed: canUpdateAnnouncement } = usePermission({
28
+ permission: announcementUpdatePermission
29
+ });
30
+ const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } = usePermission({
31
+ permission: announcementDeletePermission
32
+ });
33
+ const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] = useState(false);
34
+ const {
35
+ loading,
36
+ error,
37
+ value: announcements,
38
+ retry
39
+ } = useAsyncRetry(async () => await announcementsApi.announcements({}));
40
+ const {
41
+ isOpen: isDeleteDialogOpen,
42
+ open: openDeleteDialog,
43
+ close: closeDeleteDialog,
44
+ announcement: announcementToDelete
45
+ } = useDeleteAnnouncementDialogState();
46
+ const onCreateButtonClick = () => {
47
+ setShowCreateAnnouncementForm(!showCreateAnnouncementForm);
48
+ };
49
+ const onTitleClick = (announcement) => {
50
+ navigate(`/announcements/view/${announcement.id}`);
51
+ };
52
+ const onEdit = (announcement) => {
53
+ navigate(`/announcements/edit/${announcement.id}`);
54
+ };
55
+ const onCancelDelete = () => {
56
+ closeDeleteDialog();
57
+ };
58
+ const onConfirmDelete = async () => {
59
+ closeDeleteDialog();
60
+ try {
61
+ await announcementsApi.deleteAnnouncementByID(announcementToDelete.id);
62
+ alertApi.post({ message: "Announcement deleted.", severity: "success" });
63
+ } catch (err) {
64
+ alertApi.post({ message: err.message, severity: "error" });
65
+ }
66
+ retry();
67
+ };
68
+ const onSubmit = async (request) => {
69
+ const { category } = request;
70
+ const slugs = categories.map((c) => c.slug);
71
+ let alertMsg = t("admin.announecementsContent.alertMessage");
72
+ try {
73
+ if (category) {
74
+ const categorySlug = slugify(category, {
75
+ lower: true
76
+ });
77
+ if (slugs.indexOf(categorySlug) === -1) {
78
+ alertMsg = alertMsg.replace(".", "");
79
+ alertMsg = `${alertMsg} ${t(
80
+ "admin.announecementsContent.alertMessage"
81
+ )} ${category}.`;
82
+ await announcementsApi.createCategory({
83
+ title: category
84
+ });
85
+ }
86
+ }
87
+ await announcementsApi.createAnnouncement({
88
+ ...request,
89
+ category: request.category?.toLocaleLowerCase("en-US")
90
+ });
91
+ alertApi.post({ message: alertMsg, severity: "success" });
92
+ setShowCreateAnnouncementForm(false);
93
+ retry();
94
+ } catch (err) {
95
+ alertApi.post({ message: err.message, severity: "error" });
96
+ }
97
+ };
98
+ if (loading) {
99
+ return /* @__PURE__ */ React__default.createElement(Progress, null);
100
+ }
101
+ if (error) {
102
+ return /* @__PURE__ */ React__default.createElement(ErrorPanel, { error });
103
+ }
104
+ const columns = [
105
+ {
106
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announecementsContent.table.title")),
107
+ sorting: true,
108
+ field: "title",
109
+ render: (rowData) => rowData.title
110
+ },
111
+ {
112
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announecementsContent.table.body")),
113
+ sorting: true,
114
+ field: "body",
115
+ render: (rowData) => rowData.body
116
+ },
117
+ {
118
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announecementsContent.table.publisher")),
119
+ sorting: true,
120
+ field: "publisher",
121
+ render: (rowData) => rowData.publisher
122
+ },
123
+ {
124
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announecementsContent.table.category")),
125
+ sorting: true,
126
+ field: "category",
127
+ render: (rowData) => rowData.category?.title ?? ""
128
+ },
129
+ {
130
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announecementsContent.table.status")),
131
+ sorting: true,
132
+ field: "category",
133
+ render: (rowData) => rowData.active ? t("admin.announecementsContent.table.active") : t("admin.announecementsContent.table.inactive")
134
+ },
135
+ {
136
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announecementsContent.table.actions")),
137
+ render: (rowData) => {
138
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
139
+ IconButton,
140
+ {
141
+ "aria-label": "preview",
142
+ onClick: () => onTitleClick(rowData)
143
+ },
144
+ /* @__PURE__ */ React__default.createElement(PreviewIcon, { fontSize: "small", "data-testid": "preview" })
145
+ ), /* @__PURE__ */ React__default.createElement(
146
+ IconButton,
147
+ {
148
+ "aria-label": "edit",
149
+ disabled: loadingUpdatePermission || !canUpdateAnnouncement,
150
+ onClick: () => onEdit(rowData)
151
+ },
152
+ /* @__PURE__ */ React__default.createElement(EditIcon, { fontSize: "small", "data-testid": "edit-icon" })
153
+ ), /* @__PURE__ */ React__default.createElement(
154
+ IconButton,
155
+ {
156
+ "aria-label": "delete",
157
+ disabled: loadingDeletePermission || !canDeleteAnnouncement,
158
+ onClick: () => openDeleteDialog(rowData)
159
+ },
160
+ /* @__PURE__ */ React__default.createElement(DeleteIcon, { fontSize: "small", "data-testid": "delete-icon" })
161
+ ));
162
+ }
163
+ }
164
+ ];
165
+ return /* @__PURE__ */ React__default.createElement(RequirePermission, { permission: announcementCreatePermission }, /* @__PURE__ */ React__default.createElement(Grid, { container: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
166
+ Button,
167
+ {
168
+ disabled: loadingCreatePermission || !canCreateAnnouncement,
169
+ variant: "contained",
170
+ onClick: () => onCreateButtonClick()
171
+ },
172
+ showCreateAnnouncementForm ? t("admin.announecementsContent.cancelButton") : t("admin.announecementsContent.createButton")
173
+ )), showCreateAnnouncementForm && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
174
+ AnnouncementForm,
175
+ {
176
+ initialData: {},
177
+ onSubmit
178
+ }
179
+ )), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
180
+ Table,
181
+ {
182
+ title: t("admin.announecementsContent.announcements"),
183
+ options: { pageSize: 20, search: true },
184
+ columns,
185
+ data: announcements?.results ?? [],
186
+ emptyContent: /* @__PURE__ */ React__default.createElement(Typography, { style: { padding: 2 } }, t("admin.announecementsContent.noAnnouncementsFound"))
187
+ }
188
+ ), /* @__PURE__ */ React__default.createElement(
189
+ DeleteAnnouncementDialog,
190
+ {
191
+ open: isDeleteDialogOpen,
192
+ onCancel: onCancelDelete,
193
+ onConfirm: onConfirmDelete
194
+ }
195
+ ))));
196
+ };
197
+
198
+ export { AnnouncementsContent };
199
+ //# sourceMappingURL=AnnouncementsContent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnouncementsContent.esm.js","sources":["../../../../src/components/Admin/AnnouncementsContent/AnnouncementsContent.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 */\nimport React, { useState } from 'react';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n announcementsApiRef,\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n announcementCreatePermission,\n announcementDeletePermission,\n announcementUpdatePermission,\n Category,\n} from '@backstage-community/plugin-announcements-common';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\nimport { useDeleteAnnouncementDialogState } from '../../AnnouncementsPage/useDeleteAnnouncementDialogState';\nimport { DeleteAnnouncementDialog } from '../../AnnouncementsPage/DeleteAnnouncementDialog';\nimport { useNavigate } from 'react-router-dom';\nimport { AnnouncementForm } from '../../AnnouncementForm';\nimport slugify from 'slugify';\nimport {\n RequirePermission,\n usePermission,\n} from '@backstage/plugin-permission-react';\nimport { Button, Grid, IconButton, Typography } from '@material-ui/core';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport PreviewIcon from '@material-ui/icons/Visibility';\n\nexport const AnnouncementsContent = () => {\n const alertApi = useApi(alertApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const navigate = useNavigate();\n const { categories } = useCategories();\n const { t } = useAnnouncementsTranslation();\n\n const { loading: loadingCreatePermission, allowed: canCreateAnnouncement } =\n usePermission({\n permission: announcementCreatePermission,\n });\n\n const { loading: loadingUpdatePermission, allowed: canUpdateAnnouncement } =\n usePermission({\n permission: announcementUpdatePermission,\n });\n\n const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } =\n usePermission({\n permission: announcementDeletePermission,\n });\n\n const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] =\n useState(false);\n\n const {\n loading,\n error,\n value: announcements,\n retry,\n } = useAsyncRetry(async () => await announcementsApi.announcements({}));\n\n const {\n isOpen: isDeleteDialogOpen,\n open: openDeleteDialog,\n close: closeDeleteDialog,\n announcement: announcementToDelete,\n } = useDeleteAnnouncementDialogState();\n\n const onCreateButtonClick = () => {\n setShowCreateAnnouncementForm(!showCreateAnnouncementForm);\n };\n\n const onTitleClick = (announcement: Announcement) => {\n navigate(`/announcements/view/${announcement.id}`);\n };\n\n const onEdit = (announcement: Announcement) => {\n navigate(`/announcements/edit/${announcement.id}`);\n };\n\n const onCancelDelete = () => {\n closeDeleteDialog();\n };\n const onConfirmDelete = async () => {\n closeDeleteDialog();\n\n try {\n await announcementsApi.deleteAnnouncementByID(announcementToDelete!.id);\n\n alertApi.post({ message: 'Announcement deleted.', severity: 'success' });\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n\n retry();\n };\n\n const onSubmit = async (request: CreateAnnouncementRequest) => {\n const { category } = request;\n\n const slugs = categories.map((c: Category) => c.slug);\n let alertMsg = t('admin.announecementsContent.alertMessage') as string;\n\n try {\n if (category) {\n const categorySlug = slugify(category, {\n lower: true,\n });\n if (slugs.indexOf(categorySlug) === -1) {\n alertMsg = alertMsg.replace('.', '');\n alertMsg = `${alertMsg} ${t(\n 'admin.announecementsContent.alertMessage',\n )} ${category}.`;\n\n await announcementsApi.createCategory({\n title: category,\n });\n }\n }\n\n await announcementsApi.createAnnouncement({\n ...request,\n category: request.category?.toLocaleLowerCase('en-US'),\n });\n alertApi.post({ message: alertMsg, severity: 'success' });\n\n setShowCreateAnnouncementForm(false);\n retry();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n const columns: TableColumn<Announcement>[] = [\n {\n title: (\n <Typography>{t('admin.announecementsContent.table.title')}</Typography>\n ),\n sorting: true,\n field: 'title',\n render: rowData => rowData.title,\n },\n {\n title: (\n <Typography>{t('admin.announecementsContent.table.body')}</Typography>\n ),\n sorting: true,\n field: 'body',\n render: rowData => rowData.body,\n },\n {\n title: (\n <Typography>\n {t('admin.announecementsContent.table.publisher')}\n </Typography>\n ),\n sorting: true,\n field: 'publisher',\n render: rowData => rowData.publisher,\n },\n {\n title: (\n <Typography>\n {t('admin.announecementsContent.table.category')}\n </Typography>\n ),\n sorting: true,\n field: 'category',\n render: rowData => rowData.category?.title ?? '',\n },\n {\n title: (\n <Typography>{t('admin.announecementsContent.table.status')}</Typography>\n ),\n sorting: true,\n field: 'category',\n render: rowData =>\n rowData.active\n ? t('admin.announecementsContent.table.active')\n : t('admin.announecementsContent.table.inactive'),\n },\n {\n title: (\n <Typography>\n {t('admin.announecementsContent.table.actions')}\n </Typography>\n ),\n render: rowData => {\n return (\n <>\n <IconButton\n aria-label=\"preview\"\n onClick={() => onTitleClick(rowData)}\n >\n <PreviewIcon fontSize=\"small\" data-testid=\"preview\" />\n </IconButton>\n\n <IconButton\n aria-label=\"edit\"\n disabled={loadingUpdatePermission || !canUpdateAnnouncement}\n onClick={() => onEdit(rowData)}\n >\n <EditIcon fontSize=\"small\" data-testid=\"edit-icon\" />\n </IconButton>\n\n <IconButton\n aria-label=\"delete\"\n disabled={loadingDeletePermission || !canDeleteAnnouncement}\n onClick={() => openDeleteDialog(rowData)}\n >\n <DeleteIcon fontSize=\"small\" data-testid=\"delete-icon\" />\n </IconButton>\n </>\n );\n },\n },\n ];\n\n return (\n <RequirePermission permission={announcementCreatePermission}>\n <Grid container>\n <Grid item xs={12}>\n <Button\n disabled={loadingCreatePermission || !canCreateAnnouncement}\n variant=\"contained\"\n onClick={() => onCreateButtonClick()}\n >\n {showCreateAnnouncementForm\n ? t('admin.announecementsContent.cancelButton')\n : t('admin.announecementsContent.createButton')}\n </Button>\n </Grid>\n\n {showCreateAnnouncementForm && (\n <Grid item xs={12}>\n <AnnouncementForm\n initialData={{} as Announcement}\n onSubmit={onSubmit}\n />\n </Grid>\n )}\n\n <Grid item xs={12}>\n <Table\n title={t('admin.announecementsContent.announcements')}\n options={{ pageSize: 20, search: true }}\n columns={columns}\n data={announcements?.results ?? []}\n emptyContent={\n <Typography style={{ padding: 2 }}>\n {t('admin.announecementsContent.noAnnouncementsFound')}\n </Typography>\n }\n />\n\n <DeleteAnnouncementDialog\n open={isDeleteDialogOpen}\n onCancel={onCancelDelete}\n onConfirm={onConfirmDelete}\n />\n </Grid>\n </Grid>\n </RequirePermission>\n );\n};\n"],"names":["React"],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import React__default, { useState } from 'react';
2
+ import { Progress, ErrorPanel, Table } from '@backstage/core-components';
3
+ import { useCategories, announcementsApiRef, useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
4
+ import { announcementCreatePermission, announcementDeletePermission } from '@backstage-community/plugin-announcements-common';
5
+ import { CategoriesForm } from '../../CategoriesForm/CategoriesForm.esm.js';
6
+ import { useApi, alertApiRef } from '@backstage/core-plugin-api';
7
+ import { usePermission, RequirePermission } from '@backstage/plugin-permission-react';
8
+ import { useDeleteCategoryDialogState } from '../../CategoriesPage/useDeleteCategoryDialogState.esm.js';
9
+ import { DeleteCategoryDialog } from '../../CategoriesPage/DeleteCategoryDialog.esm.js';
10
+ import { Typography, IconButton, Grid, Button } from '@material-ui/core';
11
+ import DeleteIcon from '@material-ui/icons/Delete';
12
+
13
+ const CategoriesContent = () => {
14
+ const [showNewCategoryForm, setShowNewCategoryForm] = useState(false);
15
+ const { categories, loading, error, retry: refresh } = useCategories();
16
+ const announcementsApi = useApi(announcementsApiRef);
17
+ const alertApi = useApi(alertApiRef);
18
+ const { t } = useAnnouncementsTranslation();
19
+ const {
20
+ isOpen: isDeleteDialogOpen,
21
+ open: openDeleteDialog,
22
+ close: closeDeleteDialog,
23
+ category: categoryToDelete
24
+ } = useDeleteCategoryDialogState();
25
+ const { loading: loadingCreatePermission, allowed: canCreateCategory } = usePermission({
26
+ permission: announcementCreatePermission
27
+ });
28
+ const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } = usePermission({
29
+ permission: announcementDeletePermission
30
+ });
31
+ const onSubmit = async (request) => {
32
+ const { title } = request;
33
+ try {
34
+ await announcementsApi.createCategory({
35
+ title
36
+ });
37
+ alertApi.post({
38
+ message: `${title} ${t("admin.categoriesContent.createdMessage")}`,
39
+ severity: "success"
40
+ });
41
+ refresh();
42
+ } catch (err) {
43
+ alertApi.post({ message: err.message, severity: "error" });
44
+ }
45
+ };
46
+ const onCreateButtonClick = () => {
47
+ setShowNewCategoryForm(!showNewCategoryForm);
48
+ };
49
+ const onCancelDelete = () => {
50
+ closeDeleteDialog();
51
+ };
52
+ const onConfirmDelete = async () => {
53
+ closeDeleteDialog();
54
+ try {
55
+ await announcementsApi.deleteCategory(categoryToDelete.slug);
56
+ alertApi.post({
57
+ message: t("admin.categoriesContent.table.categoryDeleted"),
58
+ severity: "success"
59
+ });
60
+ } catch (err) {
61
+ alertApi.post({
62
+ message: err.body.error.message,
63
+ severity: "error"
64
+ });
65
+ }
66
+ refresh();
67
+ };
68
+ if (loading) {
69
+ return /* @__PURE__ */ React__default.createElement(Progress, null);
70
+ }
71
+ if (error) {
72
+ return /* @__PURE__ */ React__default.createElement(ErrorPanel, { error });
73
+ }
74
+ const columns = [
75
+ {
76
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.categoriesContent.table.title")),
77
+ sorting: true,
78
+ field: "title",
79
+ render: (rowData) => rowData.title
80
+ },
81
+ {
82
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.categoriesContent.table.slug")),
83
+ sorting: true,
84
+ field: "slug",
85
+ render: (rowData) => rowData.slug
86
+ },
87
+ {
88
+ title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.categoriesContent.table.actions")),
89
+ render: (rowData) => {
90
+ return /* @__PURE__ */ React__default.createElement(
91
+ IconButton,
92
+ {
93
+ "aria-label": "delete",
94
+ disabled: loadingDeletePermission || !canDeleteAnnouncement,
95
+ onClick: () => openDeleteDialog(rowData)
96
+ },
97
+ /* @__PURE__ */ React__default.createElement(DeleteIcon, { fontSize: "small", "data-testid": "delete-icon" })
98
+ );
99
+ }
100
+ }
101
+ ];
102
+ return /* @__PURE__ */ React__default.createElement(RequirePermission, { permission: announcementCreatePermission }, /* @__PURE__ */ React__default.createElement(Grid, { container: true }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
103
+ Button,
104
+ {
105
+ disabled: loadingCreatePermission || !canCreateCategory,
106
+ variant: "contained",
107
+ onClick: () => onCreateButtonClick()
108
+ },
109
+ showNewCategoryForm ? t("admin.categoriesContent.cancelButton") : t("admin.categoriesContent.createButton")
110
+ )), showNewCategoryForm && /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(CategoriesForm, { initialData: {}, onSubmit })), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
111
+ Table,
112
+ {
113
+ title: "Categories",
114
+ options: { pageSize: 20, search: true },
115
+ columns,
116
+ data: categories ?? [],
117
+ emptyContent: /* @__PURE__ */ React__default.createElement(Typography, { style: { padding: 2 } }, t("admin.categoriesContent.table.noCategoriesFound"))
118
+ }
119
+ )), /* @__PURE__ */ React__default.createElement(
120
+ DeleteCategoryDialog,
121
+ {
122
+ open: isDeleteDialogOpen,
123
+ onCancel: onCancelDelete,
124
+ onConfirm: onConfirmDelete
125
+ }
126
+ )));
127
+ };
128
+
129
+ export { CategoriesContent };
130
+ //# sourceMappingURL=CategoriesContent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CategoriesContent.esm.js","sources":["../../../../src/components/Admin/CategoriesContent/CategoriesContent.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 */\nimport React, { useState } from 'react';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport {\n CreateCategoryRequest,\n announcementsApiRef,\n useAnnouncementsTranslation,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n announcementCreatePermission,\n announcementDeletePermission,\n Category,\n} from '@backstage-community/plugin-announcements-common';\nimport { CategoriesForm } from '../../CategoriesForm';\nimport { useApi, alertApiRef } from '@backstage/core-plugin-api';\nimport {\n RequirePermission,\n usePermission,\n} from '@backstage/plugin-permission-react';\nimport { useDeleteCategoryDialogState } from '../../CategoriesPage/useDeleteCategoryDialogState';\nimport { ResponseError } from '@backstage/errors';\nimport { DeleteCategoryDialog } from '../../CategoriesPage/DeleteCategoryDialog';\nimport { Button, Grid, IconButton, Typography } from '@material-ui/core';\nimport DeleteIcon from '@material-ui/icons/Delete';\n\nexport const CategoriesContent = () => {\n const [showNewCategoryForm, setShowNewCategoryForm] = useState(false);\n const { categories, loading, error, retry: refresh } = useCategories();\n const announcementsApi = useApi(announcementsApiRef);\n const alertApi = useApi(alertApiRef);\n const { t } = useAnnouncementsTranslation();\n\n const {\n isOpen: isDeleteDialogOpen,\n open: openDeleteDialog,\n close: closeDeleteDialog,\n category: categoryToDelete,\n } = useDeleteCategoryDialogState();\n\n const { loading: loadingCreatePermission, allowed: canCreateCategory } =\n usePermission({\n permission: announcementCreatePermission,\n });\n\n const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } =\n usePermission({\n permission: announcementDeletePermission,\n });\n\n const onSubmit = async (request: CreateCategoryRequest) => {\n const { title } = request;\n\n try {\n await announcementsApi.createCategory({\n title,\n });\n\n alertApi.post({\n message: `${title} ${t('admin.categoriesContent.createdMessage')}`,\n severity: 'success',\n });\n\n refresh();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n const onCreateButtonClick = () => {\n setShowNewCategoryForm(!showNewCategoryForm);\n };\n\n const onCancelDelete = () => {\n closeDeleteDialog();\n };\n\n const onConfirmDelete = async () => {\n closeDeleteDialog();\n\n try {\n await announcementsApi.deleteCategory(categoryToDelete!.slug);\n\n alertApi.post({\n message: t('admin.categoriesContent.table.categoryDeleted'),\n severity: 'success',\n });\n } catch (err) {\n alertApi.post({\n message: (err as ResponseError).body.error.message,\n severity: 'error',\n });\n }\n\n refresh();\n };\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n const columns: TableColumn<Category>[] = [\n {\n title: (\n <Typography>{t('admin.categoriesContent.table.title')}</Typography>\n ),\n sorting: true,\n field: 'title',\n render: rowData => rowData.title,\n },\n {\n title: <Typography>{t('admin.categoriesContent.table.slug')}</Typography>,\n sorting: true,\n field: 'slug',\n render: rowData => rowData.slug,\n },\n {\n title: (\n <Typography>{t('admin.categoriesContent.table.actions')}</Typography>\n ),\n render: rowData => {\n return (\n <IconButton\n aria-label=\"delete\"\n disabled={loadingDeletePermission || !canDeleteAnnouncement}\n onClick={() => openDeleteDialog(rowData)}\n >\n <DeleteIcon fontSize=\"small\" data-testid=\"delete-icon\" />\n </IconButton>\n );\n },\n },\n ];\n\n return (\n <RequirePermission permission={announcementCreatePermission}>\n <Grid container>\n <Grid item xs={12}>\n <Button\n disabled={loadingCreatePermission || !canCreateCategory}\n variant=\"contained\"\n onClick={() => onCreateButtonClick()}\n >\n {showNewCategoryForm\n ? t('admin.categoriesContent.cancelButton')\n : t('admin.categoriesContent.createButton')}\n </Button>\n </Grid>\n\n {showNewCategoryForm && (\n <Grid item xs={12}>\n <CategoriesForm initialData={{} as Category} onSubmit={onSubmit} />\n </Grid>\n )}\n\n <Grid item xs={12}>\n <Table\n title=\"Categories\"\n options={{ pageSize: 20, search: true }}\n columns={columns}\n data={categories ?? []}\n emptyContent={\n <Typography style={{ padding: 2 }}>\n {t('admin.categoriesContent.table.noCategoriesFound')}\n </Typography>\n }\n />\n </Grid>\n\n <DeleteCategoryDialog\n open={isDeleteDialogOpen}\n onCancel={onCancelDelete}\n onConfirm={onConfirmDelete}\n />\n </Grid>\n </RequirePermission>\n );\n};\n"],"names":["React"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { AdminPortal } from './AdminPortal/AdminPortal.esm.js';
2
+ export { AnnouncementsContent } from './AnnouncementsContent/AnnouncementsContent.esm.js';
3
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,123 @@
1
+ import React__default, { useState } from 'react';
2
+ import MDEditor from '@uiw/react-md-editor';
3
+ import { InfoCard } from '@backstage/core-components';
4
+ import { useApi, identityApiRef } from '@backstage/core-plugin-api';
5
+ import { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
6
+ import CategoryInput from './CategoryInput.esm.js';
7
+ import { makeStyles, TextField, FormGroup, FormControlLabel, Switch, Button } from '@material-ui/core';
8
+
9
+ const useStyles = makeStyles((theme) => ({
10
+ formRoot: {
11
+ "& > *": {
12
+ margin: theme.spacing(1) ?? "8px"
13
+ }
14
+ }
15
+ }));
16
+ const AnnouncementForm = ({
17
+ initialData,
18
+ onSubmit
19
+ }) => {
20
+ const classes = useStyles();
21
+ const identityApi = useApi(identityApiRef);
22
+ const { t } = useAnnouncementsTranslation();
23
+ const [form, setForm] = React__default.useState({
24
+ ...initialData,
25
+ category: initialData.category?.slug
26
+ });
27
+ const [loading, setLoading] = useState(false);
28
+ const handleChange = (event) => {
29
+ setForm({
30
+ ...form,
31
+ [event.target.id]: event.target.value
32
+ });
33
+ };
34
+ const handleChangeActive = (event) => {
35
+ setForm({
36
+ ...form,
37
+ [event.target.name]: event.target.checked
38
+ });
39
+ };
40
+ const handleSubmit = async (event) => {
41
+ setLoading(true);
42
+ event.preventDefault();
43
+ const userIdentity = await identityApi.getBackstageIdentity();
44
+ const createRequest = {
45
+ ...form,
46
+ ...{
47
+ publisher: userIdentity.userEntityRef
48
+ }
49
+ };
50
+ await onSubmit(createRequest);
51
+ setLoading(false);
52
+ };
53
+ return /* @__PURE__ */ React__default.createElement(
54
+ InfoCard,
55
+ {
56
+ title: initialData.title ? t("announcementForm.editAnnouncement") : t("announcementForm.newAnnouncement")
57
+ },
58
+ /* @__PURE__ */ React__default.createElement("form", { className: classes.formRoot, onSubmit: handleSubmit }, /* @__PURE__ */ React__default.createElement(
59
+ TextField,
60
+ {
61
+ id: "title",
62
+ type: "text",
63
+ label: t("announcementForm.title"),
64
+ value: form.title,
65
+ onChange: handleChange,
66
+ variant: "outlined",
67
+ fullWidth: true,
68
+ required: true
69
+ }
70
+ ), /* @__PURE__ */ React__default.createElement(
71
+ CategoryInput,
72
+ {
73
+ setForm,
74
+ form,
75
+ initialValue: initialData.category?.title ?? ""
76
+ }
77
+ ), /* @__PURE__ */ React__default.createElement(
78
+ TextField,
79
+ {
80
+ id: "excerpt",
81
+ type: "text",
82
+ label: t("announcementForm.excerpt"),
83
+ value: form.excerpt,
84
+ onChange: handleChange,
85
+ variant: "outlined",
86
+ fullWidth: true,
87
+ required: true
88
+ }
89
+ ), /* @__PURE__ */ React__default.createElement(
90
+ MDEditor,
91
+ {
92
+ value: form.body,
93
+ style: { minHeight: "30rem" },
94
+ onChange: (value) => setForm({ ...form, ...{ body: value || "" } })
95
+ }
96
+ ), /* @__PURE__ */ React__default.createElement(FormGroup, null, /* @__PURE__ */ React__default.createElement(
97
+ FormControlLabel,
98
+ {
99
+ control: /* @__PURE__ */ React__default.createElement(
100
+ Switch,
101
+ {
102
+ name: "active",
103
+ checked: form.active,
104
+ onChange: handleChangeActive
105
+ }
106
+ ),
107
+ label: t("announcementForm.active")
108
+ }
109
+ )), /* @__PURE__ */ React__default.createElement(
110
+ Button,
111
+ {
112
+ variant: "contained",
113
+ color: "primary",
114
+ type: "submit",
115
+ disabled: loading || !form.body
116
+ },
117
+ t("announcementForm.submit")
118
+ ))
119
+ );
120
+ };
121
+
122
+ export { AnnouncementForm };
123
+ //# sourceMappingURL=AnnouncementForm.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnouncementForm.esm.js","sources":["../../../src/components/AnnouncementForm/AnnouncementForm.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 */\nimport React, { useState } from 'react';\nimport MDEditor from '@uiw/react-md-editor';\nimport { InfoCard } from '@backstage/core-components';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport { Announcement } from '@backstage-community/plugin-announcements-common';\nimport CategoryInput from './CategoryInput';\nimport {\n makeStyles,\n TextField,\n FormGroup,\n FormControlLabel,\n Switch,\n Button,\n} from '@material-ui/core';\n\nconst useStyles = makeStyles(theme => ({\n formRoot: {\n '& > *': {\n margin: theme.spacing(1) ?? '8px',\n },\n },\n}));\n\ntype AnnouncementFormProps = {\n initialData: Announcement;\n onSubmit: (data: CreateAnnouncementRequest) => Promise<void>;\n};\n\nexport const AnnouncementForm = ({\n initialData,\n onSubmit,\n}: AnnouncementFormProps) => {\n const classes = useStyles();\n const identityApi = useApi(identityApiRef);\n const { t } = useAnnouncementsTranslation();\n\n const [form, setForm] = React.useState({\n ...initialData,\n category: initialData.category?.slug,\n });\n const [loading, setLoading] = useState(false);\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.id]: event.target.value,\n });\n };\n\n const handleChangeActive = (event: React.ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.name]: event.target.checked,\n });\n };\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n setLoading(true);\n event.preventDefault();\n\n const userIdentity = await identityApi.getBackstageIdentity();\n const createRequest = {\n ...form,\n ...{\n publisher: userIdentity.userEntityRef,\n },\n };\n\n await onSubmit(createRequest);\n setLoading(false);\n };\n\n return (\n <InfoCard\n title={\n initialData.title\n ? t('announcementForm.editAnnouncement')\n : t('announcementForm.newAnnouncement')\n }\n >\n <form className={classes.formRoot} onSubmit={handleSubmit}>\n <TextField\n id=\"title\"\n type=\"text\"\n label={t('announcementForm.title')}\n value={form.title}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n />\n <CategoryInput\n setForm={setForm}\n form={form}\n initialValue={initialData.category?.title ?? ''}\n />\n <TextField\n id=\"excerpt\"\n type=\"text\"\n label={t('announcementForm.excerpt')}\n value={form.excerpt}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n />\n <MDEditor\n value={form.body}\n style={{ minHeight: '30rem' }}\n onChange={value => setForm({ ...form, ...{ body: value || '' } })}\n />\n <FormGroup>\n <FormControlLabel\n control={\n <Switch\n name=\"active\"\n checked={form.active}\n onChange={handleChangeActive}\n />\n }\n label={t('announcementForm.active')}\n />\n </FormGroup>\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={loading || !form.body}\n >\n {t('announcementForm.submit')}\n </Button>\n </form>\n </InfoCard>\n );\n};\n"],"names":["React"],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import * as React from 'react';
2
+ import TextField from '@mui/material/TextField';
3
+ import Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete';
4
+ import { useCategories, useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
5
+ import CircularProgress from '@mui/material/CircularProgress';
6
+
7
+ const filter = createFilterOptions();
8
+ function prepareCategoryFromInput(inputCategory, localizedCreate) {
9
+ return (typeof inputCategory === "string" ? inputCategory : inputCategory.title).replace(localizedCreate ? `${localizedCreate} ` : "Create ", "").replaceAll('"', "");
10
+ }
11
+ function CategoryInput({
12
+ setForm,
13
+ form,
14
+ initialValue
15
+ }) {
16
+ const { categories, loading: categoriesLoading } = useCategories();
17
+ const { t } = useAnnouncementsTranslation();
18
+ return /* @__PURE__ */ React.createElement(
19
+ Autocomplete,
20
+ {
21
+ fullWidth: true,
22
+ value: initialValue ?? "",
23
+ onChange: async (_, newValue) => {
24
+ if (!newValue) {
25
+ setForm({ ...form, category: void 0 });
26
+ return;
27
+ }
28
+ const newCategory = prepareCategoryFromInput(
29
+ newValue,
30
+ t("announcementForm.categoryInput.create")
31
+ );
32
+ setForm({ ...form, category: newCategory });
33
+ },
34
+ filterOptions: (options, params) => {
35
+ const filtered = filter(options, params);
36
+ const { inputValue } = params;
37
+ const isExisting = options.some(
38
+ (option) => inputValue.toLocaleLowerCase("en-US") === option.title.toLocaleLowerCase("en-US")
39
+ );
40
+ if (inputValue !== "" && !isExisting) {
41
+ filtered.push({
42
+ title: `${t(
43
+ "announcementForm.categoryInput.create"
44
+ )} "${inputValue}"`,
45
+ slug: inputValue.toLocaleLowerCase("en-US")
46
+ });
47
+ }
48
+ return filtered;
49
+ },
50
+ selectOnFocus: true,
51
+ handleHomeEndKeys: true,
52
+ loading: categoriesLoading,
53
+ id: "category-input-field",
54
+ options: categories || [],
55
+ getOptionLabel: (option) => {
56
+ return prepareCategoryFromInput(option);
57
+ },
58
+ renderOption: (props, option) => /* @__PURE__ */ React.createElement("li", { ...props }, option.title),
59
+ freeSolo: true,
60
+ renderInput: (params) => /* @__PURE__ */ React.createElement(
61
+ TextField,
62
+ {
63
+ ...params,
64
+ id: "category",
65
+ label: t("announcementForm.categoryInput.label"),
66
+ variant: "outlined",
67
+ fullWidth: true,
68
+ InputProps: {
69
+ ...params.InputProps,
70
+ endAdornment: /* @__PURE__ */ React.createElement(React.Fragment, null, categoriesLoading ? /* @__PURE__ */ React.createElement(CircularProgress, { color: "inherit", size: 20 }) : null, params.InputProps.endAdornment)
71
+ }
72
+ }
73
+ )
74
+ }
75
+ );
76
+ }
77
+
78
+ export { CategoryInput as default };
79
+ //# sourceMappingURL=CategoryInput.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CategoryInput.esm.js","sources":["../../../src/components/AnnouncementForm/CategoryInput.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 */\nimport * as React from 'react';\nimport TextField from '@mui/material/TextField';\nimport Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete';\nimport { Category } from '@backstage-community/plugin-announcements-common';\nimport {\n useAnnouncementsTranslation,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport CircularProgress from '@mui/material/CircularProgress';\n\ntype CategoryInputProps = {\n setForm: (\n value: React.SetStateAction<{\n category: string | undefined;\n id: string;\n publisher: string;\n title: string;\n excerpt: string;\n body: string;\n created_at: string;\n active: boolean;\n }>,\n ) => void;\n form: {\n category: string | undefined;\n id: string;\n publisher: string;\n title: string;\n excerpt: string;\n body: string;\n created_at: string;\n active: boolean;\n };\n initialValue: string;\n};\n\nconst filter = createFilterOptions<Category>();\n\nfunction prepareCategoryFromInput(\n inputCategory: Category | string,\n localizedCreate?: string,\n): string {\n return (\n typeof inputCategory === 'string' ? inputCategory : inputCategory.title\n )\n .replace(localizedCreate ? `${localizedCreate} ` : 'Create ', '')\n .replaceAll('\"', '');\n}\n\nexport default function CategoryInput({\n setForm,\n form,\n initialValue,\n}: CategoryInputProps) {\n const { categories, loading: categoriesLoading } = useCategories();\n const { t } = useAnnouncementsTranslation();\n\n return (\n <Autocomplete\n fullWidth\n value={initialValue ?? ''}\n onChange={async (_, newValue) => {\n if (!newValue) {\n setForm({ ...form, category: undefined });\n return;\n }\n\n const newCategory = prepareCategoryFromInput(\n newValue,\n t('announcementForm.categoryInput.create'),\n );\n setForm({ ...form, category: newCategory });\n }}\n filterOptions={(options, params) => {\n const filtered = filter(options, params);\n const { inputValue } = params;\n\n /*\n Suggest the creation of a new category. This adds the new value to the list of options\n and creates the new category when the form is submitted.\n */\n const isExisting = options.some(\n option =>\n inputValue.toLocaleLowerCase('en-US') ===\n option.title.toLocaleLowerCase('en-US'),\n );\n if (inputValue !== '' && !isExisting) {\n filtered.push({\n title: `${t(\n 'announcementForm.categoryInput.create',\n )} \"${inputValue}\"`,\n slug: inputValue.toLocaleLowerCase('en-US'),\n });\n }\n\n return filtered;\n }}\n selectOnFocus\n handleHomeEndKeys\n loading={categoriesLoading}\n id=\"category-input-field\"\n options={categories || []}\n getOptionLabel={option => {\n // Value selected with enter, right from the input\n return prepareCategoryFromInput(option);\n }}\n renderOption={(props, option) => <li {...props}>{option.title}</li>}\n freeSolo\n renderInput={params => (\n <TextField\n {...params}\n id=\"category\"\n label={t('announcementForm.categoryInput.label')}\n variant=\"outlined\"\n fullWidth\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {categoriesLoading ? (\n <CircularProgress color=\"inherit\" size={20} />\n ) : null}\n {params.InputProps.endAdornment}\n </>\n ),\n }}\n />\n )}\n />\n );\n}\n"],"names":[],"mappings":"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"}