@backstage-community/plugin-announcements 0.17.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/dist/components/Admin/AnnouncementsContent/AnnouncementForm/AnnouncementForm.esm.js.map +1 -0
  3. package/dist/components/Admin/AnnouncementsContent/AnnouncementForm/CategoryInput.esm.js.map +1 -0
  4. package/dist/components/Admin/AnnouncementsContent/AnnouncementForm/OnBehalfTeamDropdown.esm.js.map +1 -0
  5. package/dist/components/Admin/AnnouncementsContent/AnnouncementForm/TagsInput.esm.js.map +1 -0
  6. package/dist/components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js +80 -25
  7. package/dist/components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js.map +1 -1
  8. package/dist/components/Admin/CategoriesContent/CategoriesContent.esm.js +13 -18
  9. package/dist/components/Admin/CategoriesContent/CategoriesContent.esm.js.map +1 -1
  10. package/dist/components/{CategoriesForm → Admin/CategoriesContent}/CategoriesForm.esm.js +3 -7
  11. package/dist/components/Admin/CategoriesContent/CategoriesForm.esm.js.map +1 -0
  12. package/dist/components/Admin/DeleteDialog/DeleteDialog.esm.js +30 -0
  13. package/dist/components/Admin/DeleteDialog/DeleteDialog.esm.js.map +1 -0
  14. package/dist/components/{TagsPage/useDeleteTagDialogState.esm.js → Admin/DeleteDialog/useDeleteDialogState.esm.js} +7 -7
  15. package/dist/components/Admin/DeleteDialog/useDeleteDialogState.esm.js.map +1 -0
  16. package/dist/components/Admin/TagsContent/TagsContent.esm.js +13 -18
  17. package/dist/components/Admin/TagsContent/TagsContent.esm.js.map +1 -1
  18. package/dist/components/{TagsForm → Admin/TagsContent}/TagsForm.esm.js +3 -7
  19. package/dist/components/Admin/TagsContent/TagsForm.esm.js.map +1 -0
  20. package/dist/components/AnnouncementPage/AnnouncementPage.esm.js +1 -1
  21. package/dist/components/AnnouncementPage/AnnouncementPage.esm.js.map +1 -1
  22. package/dist/components/AnnouncementsCard/AnnouncementsCard.esm.js +6 -11
  23. package/dist/components/AnnouncementsCard/AnnouncementsCard.esm.js.map +1 -1
  24. package/dist/components/AnnouncementsPage/AnnouncementsPage.esm.js +24 -140
  25. package/dist/components/AnnouncementsPage/AnnouncementsPage.esm.js.map +1 -1
  26. package/dist/components/AnnouncementsPage/ContextMenu.esm.js +5 -22
  27. package/dist/components/AnnouncementsPage/ContextMenu.esm.js.map +1 -1
  28. package/dist/components/AnnouncementsTimeline/AnnouncementsTimeline.esm.js +1 -1
  29. package/dist/components/AnnouncementsTimeline/AnnouncementsTimeline.esm.js.map +1 -1
  30. package/dist/components/NewAnnouncementBanner/NewAnnouncementBanner.esm.js +1 -1
  31. package/dist/components/NewAnnouncementBanner/NewAnnouncementBanner.esm.js.map +1 -1
  32. package/dist/components/Router.esm.js +6 -31
  33. package/dist/components/Router.esm.js.map +1 -1
  34. package/dist/index.d.ts +4 -4
  35. package/dist/plugin.esm.js.map +1 -1
  36. package/dist/routes.esm.js +1 -21
  37. package/dist/routes.esm.js.map +1 -1
  38. package/package.json +2 -2
  39. package/dist/components/AnnouncementForm/AnnouncementForm.esm.js.map +0 -1
  40. package/dist/components/AnnouncementForm/CategoryInput.esm.js.map +0 -1
  41. package/dist/components/AnnouncementForm/OnBehalfTeamDropdown.esm.js.map +0 -1
  42. package/dist/components/AnnouncementForm/TagsInput.esm.js.map +0 -1
  43. package/dist/components/AnnouncementsPage/DeleteAnnouncementDialog.esm.js +0 -31
  44. package/dist/components/AnnouncementsPage/DeleteAnnouncementDialog.esm.js.map +0 -1
  45. package/dist/components/AnnouncementsPage/useDeleteAnnouncementDialogState.esm.js +0 -29
  46. package/dist/components/AnnouncementsPage/useDeleteAnnouncementDialogState.esm.js.map +0 -1
  47. package/dist/components/CategoriesForm/CategoriesForm.esm.js.map +0 -1
  48. package/dist/components/CategoriesPage/CategoriesPage.esm.js +0 -129
  49. package/dist/components/CategoriesPage/CategoriesPage.esm.js.map +0 -1
  50. package/dist/components/CategoriesPage/DeleteCategoryDialog.esm.js +0 -16
  51. package/dist/components/CategoriesPage/DeleteCategoryDialog.esm.js.map +0 -1
  52. package/dist/components/CategoriesPage/useDeleteCategoryDialogState.esm.js +0 -29
  53. package/dist/components/CategoriesPage/useDeleteCategoryDialogState.esm.js.map +0 -1
  54. package/dist/components/CreateAnnouncementPage/CreateAnnouncementPage.esm.js +0 -63
  55. package/dist/components/CreateAnnouncementPage/CreateAnnouncementPage.esm.js.map +0 -1
  56. package/dist/components/EditAnnouncementPage/EditAnnouncementPage.esm.js +0 -72
  57. package/dist/components/EditAnnouncementPage/EditAnnouncementPage.esm.js.map +0 -1
  58. package/dist/components/NewCategoryDialog/NewCategoryDialog.esm.js +0 -58
  59. package/dist/components/NewCategoryDialog/NewCategoryDialog.esm.js.map +0 -1
  60. package/dist/components/NewTagDialog/NewTagDialog.esm.js +0 -71
  61. package/dist/components/NewTagDialog/NewTagDialog.esm.js.map +0 -1
  62. package/dist/components/TagsForm/TagsForm.esm.js.map +0 -1
  63. package/dist/components/TagsPage/DeleteTagDialog.esm.js +0 -16
  64. package/dist/components/TagsPage/DeleteTagDialog.esm.js.map +0 -1
  65. package/dist/components/TagsPage/TagsPage.esm.js +0 -122
  66. package/dist/components/TagsPage/TagsPage.esm.js.map +0 -1
  67. package/dist/components/TagsPage/useDeleteTagDialogState.esm.js.map +0 -1
  68. /package/dist/components/{AnnouncementForm → Admin/AnnouncementsContent/AnnouncementForm}/AnnouncementForm.esm.js +0 -0
  69. /package/dist/components/{AnnouncementForm → Admin/AnnouncementsContent/AnnouncementForm}/CategoryInput.esm.js +0 -0
  70. /package/dist/components/{AnnouncementForm → Admin/AnnouncementsContent/AnnouncementForm}/OnBehalfTeamDropdown.esm.js +0 -0
  71. /package/dist/components/{AnnouncementForm → Admin/AnnouncementsContent/AnnouncementForm}/TagsInput.esm.js +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,124 @@
1
1
  # @backstage-community/plugin-announcements
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 40b8d32: Internal refactor to consolidate delete dialog state management in the admin portal. Refactoring categories and tags to the shared component added support for translations which was previously missing.
8
+
9
+ The refactor includes a new set of translation keys for the generic delete dialog.
10
+
11
+ ### Translation Changes
12
+
13
+ Added new translation keys for the delete dialog:
14
+
15
+ - `confirmDeleteDialog.title`
16
+ - `confirmDeleteDialog.cancel`
17
+ - `confirmDeleteDialog.delete`
18
+
19
+ Deprecated the following translation keys:
20
+
21
+ - `deleteDialog.title`
22
+ - `deleteDialog.cancel`
23
+ - `deleteDialog.delete`
24
+
25
+ ### Patch Changes
26
+
27
+ - e6b9dd8: Replaces global `JSX` namespace with `React.JSX` to resolve deprecation
28
+ - 6b45ee7: Adds a new useAnnouncementsPermissions hook users can leverage when needing quick access to all permissions, something we commonly do throughout the admin portal. All components now leverage this hook instead of using the usePermission hook directly.
29
+ - Updated dependencies [6b45ee7]
30
+ - Updated dependencies [40b8d32]
31
+ - @backstage-community/plugin-announcements-react@0.16.0
32
+
33
+ ## 1.0.0
34
+
35
+ ### Major Changes
36
+
37
+ - dc3ce7f: # Major Release: Admin Portal Consolidation
38
+
39
+ Releases the first major version of the plugin with support for two primary entry points:
40
+
41
+ - `AnnouncementsPage` - A page that displays all announcements that end users consume
42
+ - `AdminPortal` - A unified portal for managing announcements, categories, and tags
43
+
44
+ With this major release, we are consolidating all functionality into the admin portal. The previous version provides individual pages for each of these entry points which have now been removed.
45
+
46
+ As the plugin's adoption grew, more requests to hide UI components based on permissions came in. This decision was made to simplify the plugin and reduce the complexity of the codebase. It also provides a more consistent UX for admin operations and allows for more flexibility in the future.
47
+
48
+ ## Highlights
49
+
50
+ - The button to create a new announcement has been removed from the announcements page. This button is now only available in the admin portal.
51
+ - The context menu has been updated to only include a link to the admin portal. Links to the individual pages for categories and tags have been removed.
52
+ - All admin operations (create/edit announcements, manage categories, manage tags) are now accessible through a unified tabbed interface in the Admin Portal.
53
+ - The `AnnouncementsCard` component now links to the admin portal instead of the create page.
54
+
55
+ ## Breaking Changes
56
+
57
+ ### Removed Routes
58
+
59
+ The following route references have been removed and are no longer available:
60
+
61
+ - `announcementCreateRouteRef` - Use `announcementAdminRouteRef` instead
62
+ - `announcementEditRouteRef` - Use `announcementAdminRouteRef` instead
63
+ - `categoriesListRouteRef` - Categories are now managed within the Admin Portal
64
+ - `tagsListRouteRef` - Tags are now managed within the Admin Portal
65
+
66
+ ## Translation Changes
67
+
68
+ The following translation keys have been removed:
69
+
70
+ - `announcementsPage.contextMenu.categories`
71
+ - `announcementsPage.contextMenu.tags`
72
+
73
+ The following translation keys have been updated:
74
+
75
+ - `announcementsPage.contextMenu.admin` - Updated to "Manage announcements"
76
+
77
+ ### Removed Components
78
+
79
+ The following components have been removed:
80
+
81
+ - `CreateAnnouncementPage` - Replaced by `AdminPortal` with Announcements tab
82
+ - `EditAnnouncementPage` - Replaced by `AdminPortal` with Announcements tab
83
+ - `CategoriesPage` - Replaced by `AdminPortal` with Categories tab
84
+ - `TagsPage` - Replaced by `AdminPortal` with Tags tab
85
+ - `NewCategoryDialog` - Category creation is now handled inline within the Categories tab
86
+ - `NewTagDialog` - Tag creation is now handled inline within the Tags tab
87
+
88
+ ## Benefits
89
+
90
+ A big benefit of this consolidation is it reduces the amount of code we must migrate to support both the new frontend system and the new `@backstage/ui` library which we are in the process of doing. Others include:
91
+
92
+ - Single entry point for all admin operations (`/announcements/admin`)
93
+ - Less code to maintain - removed duplicate page components
94
+ - Reduction in code duplication - shared form logic consolidated
95
+ - Improved UX with tabbed interface for related admin operations
96
+ - Better permission handling - all admin operations gated through one portal
97
+
98
+ ## Migration Guide
99
+
100
+ If you have custom integrations or links to the old routes, update them as follows:
101
+
102
+ **Before:**
103
+
104
+ ```tsx
105
+ import { announcementCreateRouteRef } from '@backstage-community/plugin-announcements';
106
+ const createLink = useRouteRef(announcementCreateRouteRef);
107
+ ```
108
+
109
+ **After:**
110
+
111
+ ```tsx
112
+ import { announcementAdminRouteRef } from '@backstage-community/plugin-announcements';
113
+ const adminLink = useRouteRef(announcementAdminRouteRef);
114
+ ```
115
+
116
+ All admin functionality is now accessible at the `/announcements/admin` route.
117
+
118
+ ### Patch Changes
119
+
120
+ - 0fb63ba: Adds support for editing an announcement in the admin portal. Clicking the edit icon will no longer take the end user to a separate edit page.
121
+
3
122
  ## 0.17.0
4
123
 
5
124
  ### Minor Changes
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnouncementForm.esm.js","sources":["../../../../../src/components/Admin/AnnouncementsContent/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 { useState, type ChangeEvent, type FormEvent } from 'react';\nimport MDEditor from '@uiw/react-md-editor';\nimport { DateTime } from 'luxon';\nimport slugify from 'slugify';\nimport { InfoCard } from '@backstage/core-components';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport {\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n announcementsApiRef,\n} from '@backstage-community/plugin-announcements-react';\nimport { Announcement } from '@backstage-community/plugin-announcements-common';\n\nimport CategoryInput from './CategoryInput';\nimport OnBehalfTeamDropdown from './OnBehalfTeamDropdown';\nimport TagsInput from './TagsInput';\n\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Divider from '@mui/material/Divider';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport FormGroup from '@mui/material/FormGroup';\nimport Grid from '@mui/material/Grid';\nimport Paper from '@mui/material/Paper';\nimport SaveAltIcon from '@mui/icons-material/SaveAlt';\nimport Switch from '@mui/material/Switch';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\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 identityApi = useApi(identityApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const { t } = useAnnouncementsTranslation();\n\n const formattedStartAt = initialData.start_at\n ? DateTime.fromISO(initialData.start_at).toISODate()\n : DateTime.now().toISODate();\n\n const formattedUntilDate = initialData.until_date\n ? DateTime.fromISO(initialData.until_date).toISODate()\n : DateTime.now().endOf('day').plus({ days: 7 }).toISODate();\n\n const [form, setForm] = useState({\n ...initialData,\n active: initialData.active ?? true,\n category: initialData.category?.slug,\n start_at: formattedStartAt || '',\n until_date: formattedUntilDate || '',\n tags: initialData.tags?.map(tag => tag.slug) || undefined,\n sendNotification: initialData.sendNotification ?? false,\n });\n const [loading, setLoading] = useState(false);\n const [onBehalfOfSelectedTeam, setOnBehalfOfSelectedTeam] = useState(\n initialData.on_behalf_of || '',\n );\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.id]: event.target.value,\n });\n };\n\n const handleChangeActive = (event: ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.name]: event.target.checked,\n });\n };\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n setLoading(true);\n event.preventDefault();\n\n const userIdentity = await identityApi.getBackstageIdentity();\n\n if (form.tags && form.tags.length > 0) {\n const existingTags = await announcementsApi.tags();\n\n const processedTags = [];\n\n for (const tagValue of form.tags) {\n const slugifiedTag = slugify(tagValue.trim(), { lower: true });\n\n if (existingTags.some(tag => tag.slug === slugifiedTag)) {\n processedTags.push(slugifiedTag);\n } else {\n try {\n await announcementsApi.createTag({ title: tagValue });\n processedTags.push(slugifiedTag);\n } catch (error) {\n if (error.status === 409) {\n processedTags.push(slugifiedTag);\n } else {\n throw error;\n }\n }\n }\n }\n\n form.tags = processedTags;\n }\n\n const { id, created_at, ...announcementData } = form;\n\n const createRequest: CreateAnnouncementRequest = {\n ...announcementData,\n publisher: userIdentity.userEntityRef,\n on_behalf_of: onBehalfOfSelectedTeam,\n };\n\n try {\n await onSubmit(createRequest);\n } catch (error) {\n throw error;\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <InfoCard>\n <Box p={3}>\n <Typography variant=\"h5\" gutterBottom>\n {initialData.title\n ? t('announcementForm.editAnnouncement')\n : t('announcementForm.newAnnouncement')}\n </Typography>\n <Divider sx={{ mb: 3 }} />\n <form onSubmit={handleSubmit}>\n <Grid container spacing={3}>\n <Grid item xs={12}>\n <TextField\n id=\"title\"\n label={t('announcementForm.title')}\n value={form.title}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n />\n </Grid>\n\n <Grid item xs={12}>\n <TextField\n id=\"excerpt\"\n label={t('announcementForm.excerpt')}\n value={form.excerpt}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n multiline\n />\n </Grid>\n\n <Grid item xs={12}>\n <Paper\n variant=\"outlined\"\n sx={{ borderRadius: 2, borderColor: 'divider', p: 2 }}\n >\n <MDEditor\n value={form.body}\n style={{ minHeight: '30rem' }}\n onChange={value =>\n setForm({ ...form, ...{ body: value || '' } })\n }\n />\n </Paper>\n </Grid>\n\n <Grid item xs={12} sm={6}>\n <CategoryInput\n setForm={setForm}\n form={form}\n initialValue={initialData.category?.title ?? ''}\n />\n </Grid>\n\n <Grid item xs={12} sm={6}>\n <OnBehalfTeamDropdown\n selectedTeam={onBehalfOfSelectedTeam}\n onChange={setOnBehalfOfSelectedTeam}\n />\n </Grid>\n\n <Grid item xs={12} sm={6}>\n <TagsInput setForm={setForm} form={form} />\n </Grid>\n\n <Grid item xs={12} sm={3}>\n <TextField\n variant=\"outlined\"\n label={t('announcementForm.startAt')}\n id=\"start-at-date\"\n type=\"date\"\n value={form.start_at}\n InputLabelProps={{ shrink: true }}\n required\n fullWidth\n onChange={e =>\n setForm({\n ...form,\n start_at: e.target.value,\n })\n }\n />\n </Grid>\n\n <Grid item xs={12} sm={3}>\n <TextField\n variant=\"outlined\"\n label={t('announcementForm.untilDate')}\n id=\"until-date\"\n type=\"date\"\n value={form.until_date}\n InputLabelProps={{ shrink: true }}\n fullWidth\n onChange={e =>\n setForm({\n ...form,\n until_date: e.target.value,\n })\n }\n inputProps={{\n min: DateTime.fromISO(form.start_at)\n .endOf('day')\n .plus({ days: 1 })\n .toISODate(),\n }}\n />\n </Grid>\n\n <Grid item xs={12}>\n <Divider />\n </Grid>\n\n <Grid item xs={12}>\n <FormGroup row style={{ justifyContent: 'flex-end' }}>\n <FormControlLabel\n control={\n <Switch\n name=\"active\"\n checked={form.active}\n onChange={handleChangeActive}\n color=\"primary\"\n />\n }\n label={t('announcementForm.active')}\n />\n <FormControlLabel\n control={\n <Switch\n name=\"sendNotification\"\n checked={form.sendNotification}\n onChange={handleChangeActive}\n color=\"primary\"\n />\n }\n label=\"Send Notification\"\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={loading || !form.body}\n size=\"large\"\n startIcon={<SaveAltIcon />}\n >\n {t('announcementForm.submit')}\n </Button>\n </FormGroup>\n </Grid>\n </Grid>\n </form>\n </Box>\n </InfoCard>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CategoryInput.esm.js","sources":["../../../../../src/components/Admin/AnnouncementsContent/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 { SetStateAction } 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: SetStateAction<{\n category: string | undefined;\n tags: 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 start_at: string;\n until_date: string;\n sendNotification: boolean;\n updated_at: string;\n }>,\n ) => void;\n form: {\n category: string | undefined;\n tags: 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 start_at: string;\n until_date: string;\n sendNotification: boolean;\n updated_at: string;\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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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OnBehalfTeamDropdown.esm.js","sources":["../../../../../src/components/Admin/AnnouncementsContent/AnnouncementForm/OnBehalfTeamDropdown.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport TextField from '@mui/material/TextField';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n useAnnouncementsTranslation,\n useCatalogEntities,\n} from '@backstage-community/plugin-announcements-react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { useMemo } from 'react';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\n\ntype OnBehalfTeamDropdownProps = {\n selectedTeam: string;\n onChange: (team: string) => void;\n};\n\nfunction getTeamDisplayName(team: any): string {\n if (team.kind && team.kind.toLowerCase() === 'group') {\n return team.spec?.profile?.displayName ?? '';\n }\n return '';\n}\n\nexport default function OnBehalfTeamDropdown({\n selectedTeam,\n onChange,\n}: OnBehalfTeamDropdownProps) {\n const { t } = useAnnouncementsTranslation();\n const identityApi = useApi(identityApiRef);\n\n const { value: userOwns } = useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n return [identity.userEntityRef, ...identity.ownershipEntityRefs];\n }, [identityApi]);\n\n const { entities: teams, loading: teamsLoading } = useCatalogEntities(\n userOwns, // refs\n '', // searchTerm\n 25, // limit\n 'Group', // kind\n );\n\n const teamOptions = useMemo(() => {\n return teams.map(team => ({\n entityRef: stringifyEntityRef(team),\n displayName: getTeamDisplayName(team),\n }));\n }, [teams]);\n\n const selectedTeamOption = useMemo(() => {\n return teamOptions.find(team => team.entityRef === selectedTeam) || null;\n }, [teamOptions, selectedTeam]);\n\n return (\n <Autocomplete\n value={selectedTeamOption}\n onChange={(_, newValue) => {\n onChange(newValue?.entityRef || '');\n }}\n options={teamOptions}\n getOptionLabel={team => team.entityRef}\n loading={teamsLoading}\n id=\"team-dropdown-field\"\n renderOption={(props, team) => (\n <Box component=\"li\" {...props}>\n <Box sx={{ display: 'flex', flexDirection: 'column' }}>\n <Typography variant=\"body1\">{team.entityRef}</Typography>\n {team.displayName && (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {team.displayName}\n </Typography>\n )}\n </Box>\n </Box>\n )}\n renderInput={params => (\n <TextField\n {...params}\n id=\"team\"\n label={t('announcementForm.onBehalfOf')}\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {teamsLoading ? (\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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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TagsInput.esm.js","sources":["../../../../../src/components/Admin/AnnouncementsContent/AnnouncementForm/TagsInput.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 { useMemo } from 'react';\nimport Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete';\nimport TextField from '@mui/material/TextField';\nimport Chip from '@mui/material/Chip';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport {\n useTags,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport { Tag } from '@backstage-community/plugin-announcements-common';\n\nexport interface TagOption extends Tag {\n inputValue?: string;\n isNew?: boolean;\n}\n\nconst filter = createFilterOptions<TagOption>();\n\nfunction prepareTagFromInput(input: string | TagOption): string {\n if (typeof input === 'string') {\n return input.toLocaleLowerCase('en-US');\n }\n if (input.inputValue) {\n return input.inputValue.toLocaleLowerCase('en-US');\n }\n return input.title.toLocaleLowerCase('en-US');\n}\n\ninterface TagsInputProps {\n setForm: (form: any) => void;\n form: any;\n}\n\nexport default function TagsInput({ setForm, form }: TagsInputProps) {\n const { tags, loading } = useTags();\n const { t } = useAnnouncementsTranslation();\n const createLabel = t('announcementForm.tagsInput.create');\n\n const existingTags = useMemo(() => {\n if (!form.tags || form.tags.length === 0) return [];\n return form.tags.map((tagSlug: string) => {\n const foundTag = tags?.find(tag => tag.slug === tagSlug);\n return foundTag || { title: tagSlug, slug: tagSlug };\n });\n }, [form.tags, tags]);\n\n const handleTagChange = (_event: any, newValue: (string | TagOption)[]) => {\n if (!newValue || newValue.length === 0) {\n setForm({ ...form, tags: [] });\n return;\n }\n\n const processedTags = newValue.map(item => prepareTagFromInput(item));\n const uniqueTags = Array.from(new Set(processedTags));\n\n setForm({ ...form, tags: uniqueTags });\n };\n\n return (\n <Autocomplete\n fullWidth\n multiple\n freeSolo\n clearOnBlur\n value={existingTags}\n onChange={handleTagChange}\n options={tags || []}\n loading={loading}\n getOptionLabel={(option: string | TagOption) =>\n typeof option === 'string' ? option : option.title\n }\n filterOptions={(options, params) => {\n const filtered = filter(options as TagOption[], params);\n const { inputValue } = params;\n if (\n inputValue.trim() !== '' &&\n !options.some(\n option =>\n typeof option !== 'string' &&\n inputValue.toLocaleLowerCase('en-US') ===\n option.title.toLocaleLowerCase('en-US'),\n )\n ) {\n filtered.push({\n title: `${createLabel} \"${inputValue}\"`,\n slug: inputValue.toLocaleLowerCase('en-US'),\n inputValue,\n isNew: true,\n });\n }\n return filtered;\n }}\n renderTags={(value: (string | TagOption)[], getTagProps) =>\n value.map((option, index) => {\n const tag =\n typeof option === 'string'\n ? { title: option, slug: option.toLocaleLowerCase('en-US') }\n : option;\n\n const tagProps = getTagProps({ index });\n const { key, ...chipProps } = tagProps;\n\n return (\n <Chip\n key={key}\n variant=\"outlined\"\n label={tag.title}\n {...chipProps}\n />\n );\n })\n }\n renderInput={params => (\n <TextField\n {...params}\n label=\"Tags\"\n variant=\"outlined\"\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {loading ? (\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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"}
@@ -1,16 +1,16 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { useState } from 'react';
2
+ import { useState, useMemo } from 'react';
3
3
  import { Progress, ErrorPanel, StatusOK, StatusPending, Table } from '@backstage/core-components';
4
4
  import { useApi, alertApiRef } from '@backstage/core-plugin-api';
5
- import { announcementsApiRef, useCategories, useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
6
- import { announcementCreatePermission, announcementUpdatePermission, announcementDeletePermission } from '@backstage-community/plugin-announcements-common';
5
+ import { announcementsApiRef, useCategories, useAnnouncementsTranslation, useAnnouncementsPermissions } from '@backstage-community/plugin-announcements-react';
6
+ import { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';
7
7
  import useAsyncRetry from 'react-use/esm/useAsyncRetry';
8
- import { useDeleteAnnouncementDialogState } from '../../AnnouncementsPage/useDeleteAnnouncementDialogState.esm.js';
9
- import { DeleteAnnouncementDialog } from '../../AnnouncementsPage/DeleteAnnouncementDialog.esm.js';
8
+ import { useDeleteDialogState } from '../DeleteDialog/useDeleteDialogState.esm.js';
9
+ import { DeleteDialog } from '../DeleteDialog/DeleteDialog.esm.js';
10
10
  import { useNavigate } from 'react-router-dom';
11
- import { AnnouncementForm } from '../../AnnouncementForm/AnnouncementForm.esm.js';
11
+ import { AnnouncementForm } from './AnnouncementForm/AnnouncementForm.esm.js';
12
12
  import slugify from 'slugify';
13
- import { usePermission, RequirePermission } from '@backstage/plugin-permission-react';
13
+ import { RequirePermission } from '@backstage/plugin-permission-react';
14
14
  import { Typography, Box, IconButton, Grid, Button } from '@material-ui/core';
15
15
  import DeleteIcon from '@material-ui/icons/Delete';
16
16
  import EditIcon from '@material-ui/icons/Edit';
@@ -25,16 +25,9 @@ const AnnouncementsContent = ({
25
25
  const navigate = useNavigate();
26
26
  const { categories } = useCategories();
27
27
  const { t } = useAnnouncementsTranslation();
28
- const { loading: loadingCreatePermission, allowed: canCreateAnnouncement } = usePermission({
29
- permission: announcementCreatePermission
30
- });
31
- const { loading: loadingUpdatePermission, allowed: canUpdateAnnouncement } = usePermission({
32
- permission: announcementUpdatePermission
33
- });
34
- const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } = usePermission({
35
- permission: announcementDeletePermission
36
- });
28
+ const permissions = useAnnouncementsPermissions();
37
29
  const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] = useState(false);
30
+ const [editingAnnouncementId, setEditingAnnouncementId] = useState(null);
38
31
  const {
39
32
  loading,
40
33
  error,
@@ -45,16 +38,21 @@ const AnnouncementsContent = ({
45
38
  isOpen: isDeleteDialogOpen,
46
39
  open: openDeleteDialog,
47
40
  close: closeDeleteDialog,
48
- announcement: announcementToDelete
49
- } = useDeleteAnnouncementDialogState();
41
+ item: announcementToDelete
42
+ } = useDeleteDialogState();
50
43
  const onCreateButtonClick = () => {
51
44
  setShowCreateAnnouncementForm(!showCreateAnnouncementForm);
45
+ setEditingAnnouncementId(null);
52
46
  };
53
47
  const onTitleClick = (announcement) => {
54
48
  navigate(`/announcements/view/${announcement.id}`);
55
49
  };
56
50
  const onEdit = (announcement) => {
57
- navigate(`/announcements/edit/${announcement.id}`);
51
+ setEditingAnnouncementId(announcement.id);
52
+ setShowCreateAnnouncementForm(false);
53
+ };
54
+ const onCancelEdit = () => {
55
+ setEditingAnnouncementId(null);
58
56
  };
59
57
  const onCancelDelete = () => {
60
58
  closeDeleteDialog();
@@ -99,6 +97,42 @@ const AnnouncementsContent = ({
99
97
  alertApi.post({ message: err.message, severity: "error" });
100
98
  }
101
99
  };
100
+ const onUpdate = async (request) => {
101
+ if (!editingAnnouncementId) {
102
+ return;
103
+ }
104
+ const { category } = request;
105
+ const slugs = categories.map((c) => c.slug);
106
+ let updateMsg = t("editAnnouncementPage.updatedMessage");
107
+ try {
108
+ if (category) {
109
+ const categorySlug = slugify(category, {
110
+ lower: true
111
+ });
112
+ if (slugs.indexOf(categorySlug) === -1) {
113
+ updateMsg = updateMsg.replace(".", "");
114
+ updateMsg = `${updateMsg} ${t(
115
+ "editAnnouncementPage.updatedMessageWithNewCategory"
116
+ )} ${category}.`;
117
+ await announcementsApi.createCategory({
118
+ title: category
119
+ });
120
+ }
121
+ }
122
+ await announcementsApi.updateAnnouncement(editingAnnouncementId, request);
123
+ alertApi.post({ message: updateMsg, severity: "success" });
124
+ setEditingAnnouncementId(null);
125
+ retry();
126
+ } catch (err) {
127
+ alertApi.post({ message: err.message, severity: "error" });
128
+ }
129
+ };
130
+ const announcementToEdit = useMemo(() => {
131
+ if (!editingAnnouncementId || !announcements?.results) {
132
+ return null;
133
+ }
134
+ return announcements.results.find((a) => a.id === editingAnnouncementId) ?? null;
135
+ }, [editingAnnouncementId, announcements?.results]);
102
136
  if (loading) {
103
137
  return /* @__PURE__ */ jsx(Progress, {});
104
138
  }
@@ -186,7 +220,7 @@ const AnnouncementsContent = ({
186
220
  IconButton,
187
221
  {
188
222
  "aria-label": "edit",
189
- disabled: loadingUpdatePermission || !canUpdateAnnouncement,
223
+ disabled: permissions.update.loading || !permissions.update.allowed || editingAnnouncementId === rowData.id,
190
224
  onClick: () => onEdit(rowData),
191
225
  size: "small",
192
226
  children: /* @__PURE__ */ jsx(EditIcon, { fontSize: "small", "data-testid": "edit-icon" })
@@ -196,7 +230,7 @@ const AnnouncementsContent = ({
196
230
  IconButton,
197
231
  {
198
232
  "aria-label": "delete",
199
- disabled: loadingDeletePermission || !canDeleteAnnouncement,
233
+ disabled: permissions.delete.loading || !permissions.delete.allowed,
200
234
  onClick: () => openDeleteDialog(rowData),
201
235
  size: "small",
202
236
  children: /* @__PURE__ */ jsx(DeleteIcon, { fontSize: "small", "data-testid": "delete-icon" })
@@ -207,10 +241,10 @@ const AnnouncementsContent = ({
207
241
  }
208
242
  ];
209
243
  return /* @__PURE__ */ jsx(RequirePermission, { permission: announcementCreatePermission, children: /* @__PURE__ */ jsxs(Grid, { container: true, children: [
210
- /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
244
+ !editingAnnouncementId && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
211
245
  Button,
212
246
  {
213
- disabled: loadingCreatePermission || !canCreateAnnouncement,
247
+ disabled: permissions.create.loading || !permissions.create.allowed,
214
248
  variant: "contained",
215
249
  onClick: () => onCreateButtonClick(),
216
250
  children: showCreateAnnouncementForm ? t("admin.announcementsContent.cancelButton") : t("admin.announcementsContent.createButton")
@@ -223,6 +257,27 @@ const AnnouncementsContent = ({
223
257
  onSubmit
224
258
  }
225
259
  ) }),
260
+ editingAnnouncementId && announcementToEdit && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
261
+ /* @__PURE__ */ jsxs(
262
+ Box,
263
+ {
264
+ display: "flex",
265
+ justifyContent: "space-between",
266
+ style: { marginBottom: 16 },
267
+ children: [
268
+ /* @__PURE__ */ jsx(Typography, { variant: "h6", children: t("announcementForm.editAnnouncement") }),
269
+ /* @__PURE__ */ jsx(Button, { variant: "outlined", onClick: onCancelEdit, size: "small", children: t("admin.announcementsContent.cancelButton") })
270
+ ]
271
+ }
272
+ ),
273
+ /* @__PURE__ */ jsx(
274
+ AnnouncementForm,
275
+ {
276
+ initialData: announcementToEdit,
277
+ onSubmit: onUpdate
278
+ }
279
+ )
280
+ ] }) }),
226
281
  /* @__PURE__ */ jsxs(Grid, { item: true, xs: 12, children: [
227
282
  /* @__PURE__ */ jsx(
228
283
  Table,
@@ -235,9 +290,9 @@ const AnnouncementsContent = ({
235
290
  }
236
291
  ),
237
292
  /* @__PURE__ */ jsx(
238
- DeleteAnnouncementDialog,
293
+ DeleteDialog,
239
294
  {
240
- open: isDeleteDialogOpen,
295
+ isOpen: isDeleteDialogOpen,
241
296
  onCancel: onCancelDelete,
242
297
  onConfirm: onConfirmDelete
243
298
  }
@@ -1 +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 { useState } from 'react';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n StatusOK,\n StatusPending,\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 { Box, 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';\nimport { DateTime } from 'luxon';\n\ntype AnnouncementsContentProps = {\n defaultInactive?: boolean;\n};\n\nexport const AnnouncementsContent = ({\n defaultInactive,\n}: AnnouncementsContentProps) => {\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.announcementsContent.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.announcementsContent.alertMessageWithNewCategory',\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.announcementsContent.table.title')}</Typography>\n ),\n sorting: true,\n field: 'title',\n render: rowData => rowData.title,\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.body')}</Typography>\n ),\n sorting: true,\n field: 'body',\n render: rowData => rowData.body,\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.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.announcementsContent.table.onBehalfOf')}\n </Typography>\n ),\n sorting: true,\n field: 'on_behalf_of',\n render: rowData => rowData.on_behalf_of,\n },\n\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.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.announcementsContent.table.tags')}</Typography>\n ),\n sorting: true,\n field: 'tags',\n render: rowData => rowData.tags?.map(tag => tag.title).join(', ') || '',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.status')}</Typography>\n ),\n sorting: true,\n field: 'active',\n render: rowData =>\n rowData.active ? (\n <StatusOK>{t('admin.announcementsContent.table.active')}</StatusOK>\n ) : (\n <StatusPending>\n {t('admin.announcementsContent.table.inactive')}\n </StatusPending>\n ),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.created_at')}\n </Typography>\n ),\n sorting: true,\n field: 'created_at',\n type: 'date',\n render: rowData =>\n DateTime.fromISO(rowData.created_at).toFormat('M/d/yyyy'),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.start_at')}\n </Typography>\n ),\n sorting: true,\n field: 'start_at',\n type: 'date',\n render: rowData =>\n DateTime.fromISO(rowData.start_at).toFormat('M/d/yyyy'),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.until_date')}\n </Typography>\n ),\n sorting: true,\n field: 'until_date',\n type: 'date',\n render: rowData =>\n rowData?.until_date\n ? DateTime.fromISO(rowData.until_date).toFormat('M/d/yyyy')\n : '-',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.actions')}</Typography>\n ),\n render: rowData => {\n return (\n <Box display=\"flex\" flexDirection=\"row\">\n <IconButton\n aria-label=\"preview\"\n onClick={() => onTitleClick(rowData)}\n size=\"small\"\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 size=\"small\"\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 size=\"small\"\n >\n <DeleteIcon fontSize=\"small\" data-testid=\"delete-icon\" />\n </IconButton>\n </Box>\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.announcementsContent.cancelButton')\n : t('admin.announcementsContent.createButton')}\n </Button>\n </Grid>\n\n {showCreateAnnouncementForm && (\n <Grid item xs={12}>\n <AnnouncementForm\n initialData={{ active: !defaultInactive } as Announcement}\n onSubmit={onSubmit}\n />\n </Grid>\n )}\n\n <Grid item xs={12}>\n <Table\n title={t('admin.announcementsContent.announcements')}\n options={{ pageSize: 20, search: true }}\n columns={columns}\n data={announcements?.results ?? []}\n emptyContent={\n <Typography style={{ padding: 2, textAlign: 'center' }}>\n {t('admin.announcementsContent.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":[],"mappings":";;;;;;;;;;;;;;;;;;;AA0DO,MAAM,uBAAuB,CAAC;AAAA,EACnC;AACF,CAAiC,KAAA;AAC/B,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAM,MAAA,gBAAA,GAAmB,OAAO,mBAAmB,CAAA;AACnD,EAAA,MAAM,WAAW,WAAY,EAAA;AAC7B,EAAM,MAAA,EAAE,UAAW,EAAA,GAAI,aAAc,EAAA;AACrC,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,2BAA4B,EAAA;AAE1C,EAAA,MAAM,EAAE,OAAS,EAAA,uBAAA,EAAyB,OAAS,EAAA,qBAAA,KACjD,aAAc,CAAA;AAAA,IACZ,UAAY,EAAA;AAAA,GACb,CAAA;AAEH,EAAA,MAAM,EAAE,OAAS,EAAA,uBAAA,EAAyB,OAAS,EAAA,qBAAA,KACjD,aAAc,CAAA;AAAA,IACZ,UAAY,EAAA;AAAA,GACb,CAAA;AAEH,EAAA,MAAM,EAAE,OAAS,EAAA,uBAAA,EAAyB,OAAS,EAAA,qBAAA,KACjD,aAAc,CAAA;AAAA,IACZ,UAAY,EAAA;AAAA,GACb,CAAA;AAEH,EAAA,MAAM,CAAC,0BAAA,EAA4B,6BAA6B,CAAA,GAC9D,SAAS,KAAK,CAAA;AAEhB,EAAM,MAAA;AAAA,IACJ,OAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAO,EAAA,aAAA;AAAA,IACP;AAAA,GACF,GAAI,cAAc,YAAY,MAAM,iBAAiB,aAAc,CAAA,EAAE,CAAC,CAAA;AAEtE,EAAM,MAAA;AAAA,IACJ,MAAQ,EAAA,kBAAA;AAAA,IACR,IAAM,EAAA,gBAAA;AAAA,IACN,KAAO,EAAA,iBAAA;AAAA,IACP,YAAc,EAAA;AAAA,MACZ,gCAAiC,EAAA;AAErC,EAAA,MAAM,sBAAsB,MAAM;AAChC,IAAA,6BAAA,CAA8B,CAAC,0BAA0B,CAAA;AAAA,GAC3D;AAEA,EAAM,MAAA,YAAA,GAAe,CAAC,YAA+B,KAAA;AACnD,IAAS,QAAA,CAAA,CAAA,oBAAA,EAAuB,YAAa,CAAA,EAAE,CAAE,CAAA,CAAA;AAAA,GACnD;AAEA,EAAM,MAAA,MAAA,GAAS,CAAC,YAA+B,KAAA;AAC7C,IAAS,QAAA,CAAA,CAAA,oBAAA,EAAuB,YAAa,CAAA,EAAE,CAAE,CAAA,CAAA;AAAA,GACnD;AAEA,EAAA,MAAM,iBAAiB,MAAM;AAC3B,IAAkB,iBAAA,EAAA;AAAA,GACpB;AACA,EAAA,MAAM,kBAAkB,YAAY;AAClC,IAAkB,iBAAA,EAAA;AAElB,IAAI,IAAA;AACF,MAAM,MAAA,gBAAA,CAAiB,sBAAuB,CAAA,oBAAA,CAAsB,EAAE,CAAA;AAEtE,MAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,uBAAyB,EAAA,QAAA,EAAU,WAAW,CAAA;AAAA,aAChE,GAAK,EAAA;AACZ,MAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAU,IAAc,OAAS,EAAA,QAAA,EAAU,SAAS,CAAA;AAAA;AAGtE,IAAM,KAAA,EAAA;AAAA,GACR;AAEA,EAAM,MAAA,QAAA,GAAW,OAAO,OAAuC,KAAA;AAC7D,IAAM,MAAA,EAAE,UAAa,GAAA,OAAA;AAErB,IAAA,MAAM,QAAQ,UAAW,CAAA,GAAA,CAAI,CAAC,CAAA,KAAgB,EAAE,IAAI,CAAA;AACpD,IAAI,IAAA,QAAA,GAAW,EAAE,yCAAyC,CAAA;AAE1D,IAAI,IAAA;AACF,MAAA,IAAI,QAAU,EAAA;AACZ,QAAM,MAAA,YAAA,GAAe,QAAQ,QAAU,EAAA;AAAA,UACrC,KAAO,EAAA;AAAA,SACR,CAAA;AACD,QAAA,IAAI,KAAM,CAAA,OAAA,CAAQ,YAAY,CAAA,KAAM,CAAI,CAAA,EAAA;AACtC,UAAW,QAAA,GAAA,QAAA,CAAS,OAAQ,CAAA,GAAA,EAAK,EAAE,CAAA;AACnC,UAAW,QAAA,GAAA,CAAA,EAAG,QAAQ,CAAI,CAAA,EAAA,CAAA;AAAA,YACxB;AAAA,WACD,IAAI,QAAQ,CAAA,CAAA,CAAA;AAEb,UAAA,MAAM,iBAAiB,cAAe,CAAA;AAAA,YACpC,KAAO,EAAA;AAAA,WACR,CAAA;AAAA;AACH;AAGF,MAAA,MAAM,iBAAiB,kBAAmB,CAAA;AAAA,QACxC,GAAG,OAAA;AAAA,QACH,QAAU,EAAA,OAAA,CAAQ,QAAU,EAAA,iBAAA,CAAkB,OAAO;AAAA,OACtD,CAAA;AACD,MAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,QAAU,EAAA,QAAA,EAAU,WAAW,CAAA;AAExD,MAAA,6BAAA,CAA8B,KAAK,CAAA;AACnC,MAAM,KAAA,EAAA;AAAA,aACC,GAAK,EAAA;AACZ,MAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAU,IAAc,OAAS,EAAA,QAAA,EAAU,SAAS,CAAA;AAAA;AACtE,GACF;AAEA,EAAA,IAAI,OAAS,EAAA;AACX,IAAA,2BAAQ,QAAS,EAAA,EAAA,CAAA;AAAA;AAEnB,EAAA,IAAI,KAAO,EAAA;AACT,IAAO,uBAAA,GAAA,CAAC,cAAW,KAAc,EAAA,CAAA;AAAA;AAGnC,EAAA,MAAM,OAAuC,GAAA;AAAA,IAC3C;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UAAY,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,wCAAwC,CAAE,EAAA,CAAA;AAAA,MAE3D,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,OAAA;AAAA,MACP,MAAA,EAAQ,aAAW,OAAQ,CAAA;AAAA,KAC7B;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UAAY,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,uCAAuC,CAAE,EAAA,CAAA;AAAA,MAE1D,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,MAAA;AAAA,MACP,MAAA,EAAQ,aAAW,OAAQ,CAAA;AAAA,KAC7B;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UACE,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,4CAA4C,CACjD,EAAA,CAAA;AAAA,MAEF,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,WAAA;AAAA,MACP,MAAA,EAAQ,aAAW,OAAQ,CAAA;AAAA,KAC7B;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UACE,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,6CAA6C,CAClD,EAAA,CAAA;AAAA,MAEF,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,cAAA;AAAA,MACP,MAAA,EAAQ,aAAW,OAAQ,CAAA;AAAA,KAC7B;AAAA,IAEA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UACE,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,2CAA2C,CAChD,EAAA,CAAA;AAAA,MAEF,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,UAAA;AAAA,MACP,MAAQ,EAAA,CAAA,OAAA,KAAW,OAAQ,CAAA,QAAA,EAAU,KAAS,IAAA;AAAA,KAChD;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UAAY,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,uCAAuC,CAAE,EAAA,CAAA;AAAA,MAE1D,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,MAAA;AAAA,MACP,MAAA,EAAQ,CAAW,OAAA,KAAA,OAAA,CAAQ,IAAM,EAAA,GAAA,CAAI,CAAO,GAAA,KAAA,GAAA,CAAI,KAAK,CAAA,CAAE,IAAK,CAAA,IAAI,CAAK,IAAA;AAAA,KACvE;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UAAY,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,yCAAyC,CAAE,EAAA,CAAA;AAAA,MAE5D,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,QAAA;AAAA,MACP,MAAQ,EAAA,CAAA,OAAA,KACN,OAAQ,CAAA,MAAA,uBACL,QAAU,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,yCAAyC,CAAA,EAAE,CAExD,mBAAA,GAAA,CAAC,aACE,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,2CAA2C,CAChD,EAAA;AAAA,KAEN;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UACE,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,6CAA6C,CAClD,EAAA,CAAA;AAAA,MAEF,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,YAAA;AAAA,MACP,IAAM,EAAA,MAAA;AAAA,MACN,MAAA,EAAQ,aACN,QAAS,CAAA,OAAA,CAAQ,QAAQ,UAAU,CAAA,CAAE,SAAS,UAAU;AAAA,KAC5D;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UACE,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,2CAA2C,CAChD,EAAA,CAAA;AAAA,MAEF,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,UAAA;AAAA,MACP,IAAM,EAAA,MAAA;AAAA,MACN,MAAA,EAAQ,aACN,QAAS,CAAA,OAAA,CAAQ,QAAQ,QAAQ,CAAA,CAAE,SAAS,UAAU;AAAA,KAC1D;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UACE,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,6CAA6C,CAClD,EAAA,CAAA;AAAA,MAEF,OAAS,EAAA,IAAA;AAAA,MACT,KAAO,EAAA,YAAA;AAAA,MACP,IAAM,EAAA,MAAA;AAAA,MACN,MAAA,EAAQ,CACN,OAAA,KAAA,OAAA,EAAS,UACL,GAAA,QAAA,CAAS,OAAQ,CAAA,OAAA,CAAQ,UAAU,CAAA,CAAE,QAAS,CAAA,UAAU,CACxD,GAAA;AAAA,KACR;AAAA,IACA;AAAA,MACE,KACE,kBAAA,GAAA,CAAC,UAAY,EAAA,EAAA,QAAA,EAAA,CAAA,CAAE,0CAA0C,CAAE,EAAA,CAAA;AAAA,MAE7D,QAAQ,CAAW,OAAA,KAAA;AACjB,QAAA,uBACG,IAAA,CAAA,GAAA,EAAA,EAAI,OAAQ,EAAA,MAAA,EAAO,eAAc,KAChC,EAAA,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,YAAW,EAAA,SAAA;AAAA,cACX,OAAA,EAAS,MAAM,YAAA,CAAa,OAAO,CAAA;AAAA,cACnC,IAAK,EAAA,OAAA;AAAA,cAEL,QAAC,kBAAA,GAAA,CAAA,WAAA,EAAA,EAAY,QAAS,EAAA,OAAA,EAAQ,eAAY,SAAU,EAAA;AAAA;AAAA,WACtD;AAAA,0BAEA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,YAAW,EAAA,MAAA;AAAA,cACX,QAAA,EAAU,2BAA2B,CAAC,qBAAA;AAAA,cACtC,OAAA,EAAS,MAAM,MAAA,CAAO,OAAO,CAAA;AAAA,cAC7B,IAAK,EAAA,OAAA;AAAA,cAEL,QAAC,kBAAA,GAAA,CAAA,QAAA,EAAA,EAAS,QAAS,EAAA,OAAA,EAAQ,eAAY,WAAY,EAAA;AAAA;AAAA,WACrD;AAAA,0BAEA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,YAAW,EAAA,QAAA;AAAA,cACX,QAAA,EAAU,2BAA2B,CAAC,qBAAA;AAAA,cACtC,OAAA,EAAS,MAAM,gBAAA,CAAiB,OAAO,CAAA;AAAA,cACvC,IAAK,EAAA,OAAA;AAAA,cAEL,QAAC,kBAAA,GAAA,CAAA,UAAA,EAAA,EAAW,QAAS,EAAA,OAAA,EAAQ,eAAY,aAAc,EAAA;AAAA;AAAA;AACzD,SACF,EAAA,CAAA;AAAA;AAEJ;AACF,GACF;AAEA,EAAA,2BACG,iBAAkB,EAAA,EAAA,UAAA,EAAY,8BAC7B,QAAC,kBAAA,IAAA,CAAA,IAAA,EAAA,EAAK,WAAS,IACb,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EACb,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,QAAA,EAAU,2BAA2B,CAAC,qBAAA;AAAA,QACtC,OAAQ,EAAA,WAAA;AAAA,QACR,OAAA,EAAS,MAAM,mBAAoB,EAAA;AAAA,QAElC,QACG,EAAA,0BAAA,GAAA,CAAA,CAAE,yCAAyC,CAAA,GAC3C,EAAE,yCAAyC;AAAA;AAAA,KAEnD,EAAA,CAAA;AAAA,IAEC,8CACE,GAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,IAAI,EACb,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,gBAAA;AAAA,MAAA;AAAA,QACC,WAAa,EAAA,EAAE,MAAQ,EAAA,CAAC,eAAgB,EAAA;AAAA,QACxC;AAAA;AAAA,KAEJ,EAAA,CAAA;AAAA,oBAGD,IAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAC,IAAI,EACb,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,EAAE,0CAA0C,CAAA;AAAA,UACnD,OAAS,EAAA,EAAE,QAAU,EAAA,EAAA,EAAI,QAAQ,IAAK,EAAA;AAAA,UACtC,OAAA;AAAA,UACA,IAAA,EAAM,aAAe,EAAA,OAAA,IAAW,EAAC;AAAA,UACjC,YACE,kBAAA,GAAA,CAAC,UAAW,EAAA,EAAA,KAAA,EAAO,EAAE,OAAA,EAAS,CAAG,EAAA,SAAA,EAAW,QAAS,EAAA,EAClD,QAAE,EAAA,CAAA,CAAA,iDAAiD,CACtD,EAAA;AAAA;AAAA,OAEJ;AAAA,sBAEA,GAAA;AAAA,QAAC,wBAAA;AAAA,QAAA;AAAA,UACC,IAAM,EAAA,kBAAA;AAAA,UACN,QAAU,EAAA,cAAA;AAAA,UACV,SAAW,EAAA;AAAA;AAAA;AACb,KACF,EAAA;AAAA,GAAA,EACF,CACF,EAAA,CAAA;AAEJ;;;;"}
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 { useState, useMemo } from 'react';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n StatusOK,\n StatusPending,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n announcementsApiRef,\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n useCategories,\n useAnnouncementsPermissions,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n announcementCreatePermission,\n Category,\n} from '@backstage-community/plugin-announcements-common';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\nimport { useDeleteDialogState, DeleteDialog } from '../DeleteDialog';\nimport { useNavigate } from 'react-router-dom';\nimport { AnnouncementForm } from './AnnouncementForm';\nimport slugify from 'slugify';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { Box, 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';\nimport { DateTime } from 'luxon';\n\ntype AnnouncementsContentProps = {\n defaultInactive?: boolean;\n};\n\nexport const AnnouncementsContent = ({\n defaultInactive,\n}: AnnouncementsContentProps) => {\n const alertApi = useApi(alertApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const navigate = useNavigate();\n const { categories } = useCategories();\n const { t } = useAnnouncementsTranslation();\n const permissions = useAnnouncementsPermissions();\n\n const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] =\n useState(false);\n const [editingAnnouncementId, setEditingAnnouncementId] = useState<\n string | null\n >(null);\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 item: announcementToDelete,\n } = useDeleteDialogState<Announcement>();\n\n const onCreateButtonClick = () => {\n setShowCreateAnnouncementForm(!showCreateAnnouncementForm);\n setEditingAnnouncementId(null);\n };\n\n const onTitleClick = (announcement: Announcement) => {\n navigate(`/announcements/view/${announcement.id}`);\n };\n\n const onEdit = (announcement: Announcement) => {\n setEditingAnnouncementId(announcement.id);\n setShowCreateAnnouncementForm(false);\n };\n\n const onCancelEdit = () => {\n setEditingAnnouncementId(null);\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.announcementsContent.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.announcementsContent.alertMessageWithNewCategory',\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 const onUpdate = async (request: CreateAnnouncementRequest) => {\n if (!editingAnnouncementId) {\n return;\n }\n\n const { category } = request;\n\n const slugs = categories.map((c: Category) => c.slug);\n let updateMsg = t('editAnnouncementPage.updatedMessage') as string;\n\n try {\n if (category) {\n const categorySlug = slugify(category, {\n lower: true,\n });\n\n if (slugs.indexOf(categorySlug) === -1) {\n updateMsg = updateMsg.replace('.', '');\n updateMsg = `${updateMsg} ${t(\n 'editAnnouncementPage.updatedMessageWithNewCategory',\n )} ${category}.`;\n\n await announcementsApi.createCategory({\n title: category,\n });\n }\n }\n\n await announcementsApi.updateAnnouncement(editingAnnouncementId, request);\n alertApi.post({ message: updateMsg, severity: 'success' });\n\n setEditingAnnouncementId(null);\n retry();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n const announcementToEdit = useMemo(() => {\n if (!editingAnnouncementId || !announcements?.results) {\n return null;\n }\n return (\n announcements.results.find(a => a.id === editingAnnouncementId) ?? null\n );\n }, [editingAnnouncementId, announcements?.results]);\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.announcementsContent.table.title')}</Typography>\n ),\n sorting: true,\n field: 'title',\n render: rowData => rowData.title,\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.body')}</Typography>\n ),\n sorting: true,\n field: 'body',\n render: rowData => rowData.body,\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.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.announcementsContent.table.onBehalfOf')}\n </Typography>\n ),\n sorting: true,\n field: 'on_behalf_of',\n render: rowData => rowData.on_behalf_of,\n },\n\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.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.announcementsContent.table.tags')}</Typography>\n ),\n sorting: true,\n field: 'tags',\n render: rowData => rowData.tags?.map(tag => tag.title).join(', ') || '',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.status')}</Typography>\n ),\n sorting: true,\n field: 'active',\n render: rowData =>\n rowData.active ? (\n <StatusOK>{t('admin.announcementsContent.table.active')}</StatusOK>\n ) : (\n <StatusPending>\n {t('admin.announcementsContent.table.inactive')}\n </StatusPending>\n ),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.created_at')}\n </Typography>\n ),\n sorting: true,\n field: 'created_at',\n type: 'date',\n render: rowData =>\n DateTime.fromISO(rowData.created_at).toFormat('M/d/yyyy'),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.start_at')}\n </Typography>\n ),\n sorting: true,\n field: 'start_at',\n type: 'date',\n render: rowData =>\n DateTime.fromISO(rowData.start_at).toFormat('M/d/yyyy'),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.until_date')}\n </Typography>\n ),\n sorting: true,\n field: 'until_date',\n type: 'date',\n render: rowData =>\n rowData?.until_date\n ? DateTime.fromISO(rowData.until_date).toFormat('M/d/yyyy')\n : '-',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.actions')}</Typography>\n ),\n render: rowData => {\n return (\n <Box display=\"flex\" flexDirection=\"row\">\n <IconButton\n aria-label=\"preview\"\n onClick={() => onTitleClick(rowData)}\n size=\"small\"\n >\n <PreviewIcon fontSize=\"small\" data-testid=\"preview\" />\n </IconButton>\n\n <IconButton\n aria-label=\"edit\"\n disabled={\n permissions.update.loading ||\n !permissions.update.allowed ||\n editingAnnouncementId === rowData.id\n }\n onClick={() => onEdit(rowData)}\n size=\"small\"\n >\n <EditIcon fontSize=\"small\" data-testid=\"edit-icon\" />\n </IconButton>\n\n <IconButton\n aria-label=\"delete\"\n disabled={\n permissions.delete.loading || !permissions.delete.allowed\n }\n onClick={() => openDeleteDialog(rowData)}\n size=\"small\"\n >\n <DeleteIcon fontSize=\"small\" data-testid=\"delete-icon\" />\n </IconButton>\n </Box>\n );\n },\n },\n ];\n\n return (\n <RequirePermission permission={announcementCreatePermission}>\n <Grid container>\n {!editingAnnouncementId && (\n <Grid item xs={12}>\n <Button\n disabled={\n permissions.create.loading || !permissions.create.allowed\n }\n variant=\"contained\"\n onClick={() => onCreateButtonClick()}\n >\n {showCreateAnnouncementForm\n ? t('admin.announcementsContent.cancelButton')\n : t('admin.announcementsContent.createButton')}\n </Button>\n </Grid>\n )}\n\n {showCreateAnnouncementForm && (\n <Grid item xs={12}>\n <AnnouncementForm\n initialData={{ active: !defaultInactive } as Announcement}\n onSubmit={onSubmit}\n />\n </Grid>\n )}\n\n {editingAnnouncementId && announcementToEdit && (\n <Grid item xs={12}>\n <Box>\n <Box\n display=\"flex\"\n justifyContent=\"space-between\"\n style={{ marginBottom: 16 }}\n >\n <Typography variant=\"h6\">\n {t('announcementForm.editAnnouncement')}\n </Typography>\n <Button variant=\"outlined\" onClick={onCancelEdit} size=\"small\">\n {t('admin.announcementsContent.cancelButton')}\n </Button>\n </Box>\n <AnnouncementForm\n initialData={announcementToEdit}\n onSubmit={onUpdate}\n />\n </Box>\n </Grid>\n )}\n\n <Grid item xs={12}>\n <Table\n title={t('admin.announcementsContent.announcements')}\n options={{ pageSize: 20, search: true }}\n columns={columns}\n data={announcements?.results ?? []}\n emptyContent={\n <Typography style={{ padding: 2, textAlign: 'center' }}>\n {t('admin.announcementsContent.noAnnouncementsFound')}\n </Typography>\n }\n />\n\n <DeleteDialog\n isOpen={isDeleteDialogOpen}\n onCancel={onCancelDelete}\n onConfirm={onConfirmDelete}\n />\n </Grid>\n </Grid>\n </RequirePermission>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,15 +1,15 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { useState } from 'react';
3
3
  import { Progress, ErrorPanel, Table } from '@backstage/core-components';
4
- import { useCategories, announcementsApiRef, useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
5
- import { announcementCreatePermission, announcementDeletePermission } from '@backstage-community/plugin-announcements-common';
6
- import { CategoriesForm } from '../../CategoriesForm/CategoriesForm.esm.js';
4
+ import { useCategories, announcementsApiRef, useAnnouncementsTranslation, useAnnouncementsPermissions } from '@backstage-community/plugin-announcements-react';
5
+ import { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';
7
6
  import { useApi, alertApiRef } from '@backstage/core-plugin-api';
8
- import { usePermission, RequirePermission } from '@backstage/plugin-permission-react';
9
- import { useDeleteCategoryDialogState } from '../../CategoriesPage/useDeleteCategoryDialogState.esm.js';
10
- import { DeleteCategoryDialog } from '../../CategoriesPage/DeleteCategoryDialog.esm.js';
7
+ import { RequirePermission } from '@backstage/plugin-permission-react';
11
8
  import { Typography, IconButton, Grid, Button } from '@material-ui/core';
12
9
  import DeleteIcon from '@material-ui/icons/Delete';
10
+ import { CategoriesForm } from './CategoriesForm.esm.js';
11
+ import { useDeleteDialogState } from '../DeleteDialog/useDeleteDialogState.esm.js';
12
+ import { DeleteDialog } from '../DeleteDialog/DeleteDialog.esm.js';
13
13
 
14
14
  const CategoriesContent = () => {
15
15
  const [showNewCategoryForm, setShowNewCategoryForm] = useState(false);
@@ -21,14 +21,9 @@ const CategoriesContent = () => {
21
21
  isOpen: isDeleteDialogOpen,
22
22
  open: openDeleteDialog,
23
23
  close: closeDeleteDialog,
24
- category: categoryToDelete
25
- } = useDeleteCategoryDialogState();
26
- const { loading: loadingCreatePermission, allowed: canCreateCategory } = usePermission({
27
- permission: announcementCreatePermission
28
- });
29
- const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } = usePermission({
30
- permission: announcementDeletePermission
31
- });
24
+ item: categoryToDelete
25
+ } = useDeleteDialogState();
26
+ const permissions = useAnnouncementsPermissions();
32
27
  const onSubmit = async (request) => {
33
28
  const { title } = request;
34
29
  try {
@@ -92,7 +87,7 @@ const CategoriesContent = () => {
92
87
  IconButton,
93
88
  {
94
89
  "aria-label": "delete",
95
- disabled: loadingDeletePermission || !canDeleteAnnouncement,
90
+ disabled: permissions.delete.loading || !permissions.delete.allowed,
96
91
  onClick: () => openDeleteDialog(rowData),
97
92
  children: /* @__PURE__ */ jsx(DeleteIcon, { fontSize: "small", "data-testid": "delete-icon" })
98
93
  }
@@ -104,7 +99,7 @@ const CategoriesContent = () => {
104
99
  /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
105
100
  Button,
106
101
  {
107
- disabled: loadingCreatePermission || !canCreateCategory,
102
+ disabled: permissions.create.loading || !permissions.create.allowed,
108
103
  variant: "contained",
109
104
  onClick: () => onCreateButtonClick(),
110
105
  children: showNewCategoryForm ? t("admin.categoriesContent.cancelButton") : t("admin.categoriesContent.createButton")
@@ -122,9 +117,9 @@ const CategoriesContent = () => {
122
117
  }
123
118
  ) }),
124
119
  /* @__PURE__ */ jsx(
125
- DeleteCategoryDialog,
120
+ DeleteDialog,
126
121
  {
127
- open: isDeleteDialogOpen,
122
+ isOpen: isDeleteDialogOpen,
128
123
  onCancel: onCancelDelete,
129
124
  onConfirm: onConfirmDelete
130
125
  }