@backstage-community/plugin-announcements 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/alpha/Router.esm.js +7 -13
  3. package/dist/alpha/Router.esm.js.map +1 -1
  4. package/dist/alpha/components/admin/announcements/ActiveInactiveAnnouncementIndicator.esm.js +49 -0
  5. package/dist/alpha/components/admin/announcements/ActiveInactiveAnnouncementIndicator.esm.js.map +1 -0
  6. package/dist/alpha/components/admin/announcements/AnnouncementsContent.esm.js +196 -0
  7. package/dist/alpha/components/admin/announcements/AnnouncementsContent.esm.js.map +1 -0
  8. package/dist/alpha/components/admin/announcements/AnnouncementsTable.esm.js +159 -0
  9. package/dist/alpha/components/admin/announcements/AnnouncementsTable.esm.js.map +1 -0
  10. package/dist/alpha/components/admin/announcements/AnnouncementsTableCard.esm.js +54 -0
  11. package/dist/alpha/components/admin/announcements/AnnouncementsTableCard.esm.js.map +1 -0
  12. package/dist/alpha/components/announcements/AnnouncementCard.esm.js +12 -41
  13. package/dist/alpha/components/announcements/AnnouncementCard.esm.js.map +1 -1
  14. package/dist/alpha/components/announcements/AnnouncementsFilterBar.esm.js +88 -0
  15. package/dist/alpha/components/announcements/AnnouncementsFilterBar.esm.js.map +1 -0
  16. package/dist/alpha/components/announcements/AnnouncementsGrid.esm.js +20 -23
  17. package/dist/alpha/components/announcements/AnnouncementsGrid.esm.js.map +1 -1
  18. package/dist/alpha/components/announcements/AnnouncementsPage.esm.js +20 -25
  19. package/dist/alpha/components/announcements/AnnouncementsPage.esm.js.map +1 -1
  20. package/dist/alpha/components/announcements/ViewAnnouncementPage.esm.js +5 -14
  21. package/dist/alpha/components/announcements/ViewAnnouncementPage.esm.js.map +1 -1
  22. package/dist/alpha/components/shared/AnnouncementPublishedBy/AnnouncementPublishedBy.esm.js +42 -0
  23. package/dist/alpha/components/shared/AnnouncementPublishedBy/AnnouncementPublishedBy.esm.js.map +1 -0
  24. package/dist/alpha/components/shared/AnnouncementTags/AnnouncementTags.esm.js +22 -0
  25. package/dist/alpha/components/shared/AnnouncementTags/AnnouncementTags.esm.js.map +1 -0
  26. package/dist/alpha/components/shared/BackToAnnouncementsButton/BackToAnnouncementsButton.esm.js +28 -0
  27. package/dist/alpha/components/shared/BackToAnnouncementsButton/BackToAnnouncementsButton.esm.js.map +1 -0
  28. package/dist/alpha/components/shared/CategorySelectInput/CategorySelectInput.esm.js +67 -0
  29. package/dist/alpha/components/shared/CategorySelectInput/CategorySelectInput.esm.js.map +1 -0
  30. package/dist/alpha/components/shared/TagsSelectInput/TagsSelectInput.esm.js +67 -0
  31. package/dist/alpha/components/shared/TagsSelectInput/TagsSelectInput.esm.js.map +1 -0
  32. package/package.json +2 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @backstage-community/plugin-announcements
2
2
 
3
+ ## 1.3.2
4
+
5
+ ### Patch Changes
6
+
7
+ - ee5069b: Adds filtering components for categories and tags to the announcements page in the new frontend system.
8
+ - d901927: Removed unused dependencies from the package
9
+ - Updated dependencies [d901927]
10
+ - Updated dependencies [ee5069b]
11
+ - @backstage-community/plugin-announcements-react@0.18.2
12
+
13
+ ## 1.3.1
14
+
15
+ ### Patch Changes
16
+
17
+ - c107e8f: For users on the new frontend system:
18
+
19
+ - Prevents announcements table from erroring on invalid publisher ref
20
+ - Fixes the size of the active status indicator and prevents it from stretching next to a smaller announcement title
21
+
22
+ - a065bb2: The announcements table in the admin portal has been rewritten with `@backstage/ui` for users on the new frontend system. Users on the existing frontend system will not see any changes.
23
+ - a6d55dd: Update the back to announcements button to recognize whether to take you back to list of announcements or admin portal depending on where you came from.
24
+ - cd38562: The announcements page in the new frontend system now shows only active announcements by default. For the existing frontend system, the `hideInactive` prop must still be passed to the `AnnouncementsPage` component to hide inactive announcements.
25
+ - Updated dependencies [a6d55dd]
26
+ - Updated dependencies [a065bb2]
27
+ - @backstage-community/plugin-announcements-react@0.18.1
28
+
3
29
  ## 1.3.0
4
30
 
5
31
  ### Minor Changes
@@ -3,26 +3,15 @@ import { Routes, Route } from 'react-router-dom';
3
3
  import { RequirePermission } from '@backstage/plugin-permission-react';
4
4
  import { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';
5
5
  import { AnnouncementsAdminPage } from './components/admin/AnnouncementsAdminPage.esm.js';
6
+ import { AnnouncementsContent } from './components/admin/announcements/AnnouncementsContent.esm.js';
6
7
  import { CategoriesContent } from './components/admin/categories/CategoriesContent.esm.js';
7
8
  import { TagsContent } from './components/admin/tags/TagsContent.esm.js';
8
9
  import { AnnouncementsPage } from './components/announcements/AnnouncementsPage.esm.js';
9
10
  import { ViewAnnouncementPage } from './components/announcements/ViewAnnouncementPage.esm.js';
10
- import '@backstage/core-plugin-api';
11
- import 'luxon';
12
- import '@backstage-community/plugin-announcements-react';
13
- import '@backstage/core-components';
14
- import '@material-ui/lab';
15
- import '@material-ui/core';
16
- import '@mui/material/Stack';
17
- import '../routes.esm.js';
18
- import '../components/Admin/AdminPortal/AdminPortal.esm.js';
19
- import { AnnouncementsContent } from '../components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js';
20
- import '../components/MarkdownRenderer/MarkdownRenderer.esm.js';
21
11
 
22
12
  const Router = (props) => {
23
13
  const propsWithDefaults = {
24
14
  title: "Announcements",
25
- hideInactive: false,
26
15
  hideStartAt: false,
27
16
  markdownRenderer: "backstage",
28
17
  ...props
@@ -58,7 +47,12 @@ const Router = (props) => {
58
47
  Route,
59
48
  {
60
49
  path: "",
61
- element: /* @__PURE__ */ jsx(AnnouncementsContent, { defaultInactive: props.defaultInactive })
50
+ element: /* @__PURE__ */ jsx(
51
+ AnnouncementsContent,
52
+ {
53
+ formDefaults: { defaultInactive: props.defaultInactive }
54
+ }
55
+ )
62
56
  }
63
57
  ),
64
58
  /* @__PURE__ */ jsx(Route, { path: "categories", element: /* @__PURE__ */ jsx(CategoriesContent, {}) }),
@@ -1 +1 @@
1
- {"version":3,"file":"Router.esm.js","sources":["../../src/alpha/Router.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 { Routes, Route } from 'react-router-dom';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';\nimport {\n AnnouncementsAdminPage,\n CategoriesContent,\n TagsContent,\n AnnouncementsPage,\n AnnouncementsPageProps,\n ViewAnnouncementPage,\n} from './components';\n\n// todo: pending rebuild for nfs with `@backstage/ui`\nimport { AnnouncementsContent, MarkdownRendererTypeProps } from '../components';\n\ntype RouterProps = {\n title?: string;\n category?: string;\n hideInactive?: boolean;\n hideStartAt?: boolean;\n markdownRenderer?: MarkdownRendererTypeProps;\n defaultInactive?: boolean;\n};\n\nexport const Router = (props: RouterProps) => {\n const propsWithDefaults: AnnouncementsPageProps = {\n title: 'Announcements',\n hideInactive: false,\n hideStartAt: false,\n markdownRenderer: 'backstage',\n ...props,\n };\n\n return (\n <Routes>\n <Route path=\"/\" element={<AnnouncementsPage {...propsWithDefaults} />} />\n <Route\n path=\"/view/:id\"\n element={\n <ViewAnnouncementPage\n markdownRenderer={propsWithDefaults.markdownRenderer}\n title={propsWithDefaults.title}\n />\n }\n />\n <Route\n path=\"/admin\"\n element={\n <RequirePermission permission={announcementCreatePermission}>\n <AnnouncementsAdminPage\n title={props.title}\n defaultInactive={props.defaultInactive}\n />\n </RequirePermission>\n }\n >\n <Route\n path=\"\"\n element={\n <AnnouncementsContent defaultInactive={props.defaultInactive} />\n }\n />\n <Route path=\"categories\" element={<CategoriesContent />} />\n <Route path=\"tags\" element={<TagsContent />} />\n </Route>\n </Routes>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuCa,MAAA,MAAA,GAAS,CAAC,KAAuB,KAAA;AAC5C,EAAA,MAAM,iBAA4C,GAAA;AAAA,IAChD,KAAO,EAAA,eAAA;AAAA,IACP,YAAc,EAAA,KAAA;AAAA,IACd,WAAa,EAAA,KAAA;AAAA,IACb,gBAAkB,EAAA,WAAA;AAAA,IAClB,GAAG;AAAA,GACL;AAEA,EAAA,4BACG,MACC,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,KAAA,EAAA,EAAM,MAAK,GAAI,EAAA,OAAA,sBAAU,iBAAmB,EAAA,EAAA,GAAG,mBAAmB,CAAI,EAAA,CAAA;AAAA,oBACvE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAK,EAAA,WAAA;AAAA,QACL,OACE,kBAAA,GAAA;AAAA,UAAC,oBAAA;AAAA,UAAA;AAAA,YACC,kBAAkB,iBAAkB,CAAA,gBAAA;AAAA,YACpC,OAAO,iBAAkB,CAAA;AAAA;AAAA;AAC3B;AAAA,KAEJ;AAAA,oBACA,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAK,EAAA,QAAA;AAAA,QACL,OACE,kBAAA,GAAA,CAAC,iBAAkB,EAAA,EAAA,UAAA,EAAY,4BAC7B,EAAA,QAAA,kBAAA,GAAA;AAAA,UAAC,sBAAA;AAAA,UAAA;AAAA,YACC,OAAO,KAAM,CAAA,KAAA;AAAA,YACb,iBAAiB,KAAM,CAAA;AAAA;AAAA,SAE3B,EAAA,CAAA;AAAA,QAGF,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,IAAK,EAAA,EAAA;AAAA,cACL,OACE,kBAAA,GAAA,CAAC,oBAAqB,EAAA,EAAA,eAAA,EAAiB,MAAM,eAAiB,EAAA;AAAA;AAAA,WAElE;AAAA,8BACC,KAAM,EAAA,EAAA,IAAA,EAAK,cAAa,OAAS,kBAAA,GAAA,CAAC,qBAAkB,CAAI,EAAA,CAAA;AAAA,8BACxD,KAAM,EAAA,EAAA,IAAA,EAAK,QAAO,OAAS,kBAAA,GAAA,CAAC,eAAY,CAAI,EAAA;AAAA;AAAA;AAAA;AAC/C,GACF,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"Router.esm.js","sources":["../../src/alpha/Router.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 { Routes, Route } from 'react-router-dom';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';\nimport {\n AnnouncementsAdminPage,\n AnnouncementsContent,\n CategoriesContent,\n TagsContent,\n AnnouncementsPage,\n AnnouncementsPageProps,\n ViewAnnouncementPage,\n} from './components';\n\n// todo: pending rebuild for nfs with `@backstage/ui`\nimport { MarkdownRendererTypeProps } from '../components';\n\ntype RouterProps = {\n title?: string;\n category?: string;\n hideStartAt?: boolean;\n markdownRenderer?: MarkdownRendererTypeProps;\n defaultInactive?: boolean;\n};\n\nexport const Router = (props: RouterProps) => {\n const propsWithDefaults: AnnouncementsPageProps = {\n title: 'Announcements',\n hideStartAt: false,\n markdownRenderer: 'backstage',\n ...props,\n };\n\n return (\n <Routes>\n <Route path=\"/\" element={<AnnouncementsPage {...propsWithDefaults} />} />\n <Route\n path=\"/view/:id\"\n element={\n <ViewAnnouncementPage\n markdownRenderer={propsWithDefaults.markdownRenderer}\n title={propsWithDefaults.title}\n />\n }\n />\n <Route\n path=\"/admin\"\n element={\n <RequirePermission permission={announcementCreatePermission}>\n <AnnouncementsAdminPage\n title={props.title}\n defaultInactive={props.defaultInactive}\n />\n </RequirePermission>\n }\n >\n <Route\n path=\"\"\n element={\n <AnnouncementsContent\n formDefaults={{ defaultInactive: props.defaultInactive }}\n />\n }\n />\n <Route path=\"categories\" element={<CategoriesContent />} />\n <Route path=\"tags\" element={<TagsContent />} />\n </Route>\n </Routes>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;AAuCa,MAAA,MAAA,GAAS,CAAC,KAAuB,KAAA;AAC5C,EAAA,MAAM,iBAA4C,GAAA;AAAA,IAChD,KAAO,EAAA,eAAA;AAAA,IACP,WAAa,EAAA,KAAA;AAAA,IACb,gBAAkB,EAAA,WAAA;AAAA,IAClB,GAAG;AAAA,GACL;AAEA,EAAA,4BACG,MACC,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,KAAA,EAAA,EAAM,MAAK,GAAI,EAAA,OAAA,sBAAU,iBAAmB,EAAA,EAAA,GAAG,mBAAmB,CAAI,EAAA,CAAA;AAAA,oBACvE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAK,EAAA,WAAA;AAAA,QACL,OACE,kBAAA,GAAA;AAAA,UAAC,oBAAA;AAAA,UAAA;AAAA,YACC,kBAAkB,iBAAkB,CAAA,gBAAA;AAAA,YACpC,OAAO,iBAAkB,CAAA;AAAA;AAAA;AAC3B;AAAA,KAEJ;AAAA,oBACA,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAK,EAAA,QAAA;AAAA,QACL,OACE,kBAAA,GAAA,CAAC,iBAAkB,EAAA,EAAA,UAAA,EAAY,4BAC7B,EAAA,QAAA,kBAAA,GAAA;AAAA,UAAC,sBAAA;AAAA,UAAA;AAAA,YACC,OAAO,KAAM,CAAA,KAAA;AAAA,YACb,iBAAiB,KAAM,CAAA;AAAA;AAAA,SAE3B,EAAA,CAAA;AAAA,QAGF,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,IAAK,EAAA,EAAA;AAAA,cACL,OACE,kBAAA,GAAA;AAAA,gBAAC,oBAAA;AAAA,gBAAA;AAAA,kBACC,YAAc,EAAA,EAAE,eAAiB,EAAA,KAAA,CAAM,eAAgB;AAAA;AAAA;AACzD;AAAA,WAEJ;AAAA,8BACC,KAAM,EAAA,EAAA,IAAA,EAAK,cAAa,OAAS,kBAAA,GAAA,CAAC,qBAAkB,CAAI,EAAA,CAAA;AAAA,8BACxD,KAAM,EAAA,EAAA,IAAA,EAAK,QAAO,OAAS,kBAAA,GAAA,CAAC,eAAY,CAAI,EAAA;AAAA;AAAA;AAAA;AAC/C,GACF,EAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,49 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
3
+ import { Flex, Text } from '@backstage/ui';
4
+ import { RiCircleFill } from '@remixicon/react';
5
+
6
+ const ACTIVE_INDICATOR_COLOR = "#4caf50";
7
+ const INACTIVE_INDICATOR_COLOR = "#f44336";
8
+ const ActiveInactiveAnnouncementIndicator = () => {
9
+ const { t } = useAnnouncementsTranslation();
10
+ return /* @__PURE__ */ jsxs(Flex, { justify: "end", gap: "6", mb: "3", children: [
11
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "1", children: [
12
+ /* @__PURE__ */ jsx(
13
+ RiCircleFill,
14
+ {
15
+ size: "12",
16
+ color: ACTIVE_INDICATOR_COLOR,
17
+ "aria-label": t("admin.announcementsContent.table.active")
18
+ }
19
+ ),
20
+ /* @__PURE__ */ jsx(Text, { variant: "body-small", children: t("admin.announcementsContent.table.active") })
21
+ ] }),
22
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "1", children: [
23
+ /* @__PURE__ */ jsx(
24
+ RiCircleFill,
25
+ {
26
+ size: "12",
27
+ color: INACTIVE_INDICATOR_COLOR,
28
+ "aria-label": t("admin.announcementsContent.table.inactive")
29
+ }
30
+ ),
31
+ /* @__PURE__ */ jsx(Text, { variant: "body-small", children: t("admin.announcementsContent.table.inactive") })
32
+ ] })
33
+ ] });
34
+ };
35
+ const ActiveInactiveAnnouncementIndicatorIcon = (props) => {
36
+ const { announcement } = props;
37
+ const { t } = useAnnouncementsTranslation();
38
+ return /* @__PURE__ */ jsx(Flex, { style: { flexShrink: 0 }, align: "center", children: /* @__PURE__ */ jsx(
39
+ RiCircleFill,
40
+ {
41
+ size: "12",
42
+ color: announcement.active ? ACTIVE_INDICATOR_COLOR : INACTIVE_INDICATOR_COLOR,
43
+ "aria-label": announcement.active ? t("admin.announcementsContent.table.active") : t("admin.announcementsContent.table.inactive")
44
+ }
45
+ ) });
46
+ };
47
+
48
+ export { ACTIVE_INDICATOR_COLOR, ActiveInactiveAnnouncementIndicator, ActiveInactiveAnnouncementIndicatorIcon, INACTIVE_INDICATOR_COLOR };
49
+ //# sourceMappingURL=ActiveInactiveAnnouncementIndicator.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActiveInactiveAnnouncementIndicator.esm.js","sources":["../../../../../src/alpha/components/admin/announcements/ActiveInactiveAnnouncementIndicator.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Announcement } from '@backstage-community/plugin-announcements-common';\nimport { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';\nimport { Flex, Text } from '@backstage/ui';\nimport { RiCircleFill } from '@remixicon/react';\n\nexport const ACTIVE_INDICATOR_COLOR = '#4caf50';\nexport const INACTIVE_INDICATOR_COLOR = '#f44336';\n\n/**\n * A toolbar style component that displays the active and inactive announcement indicators with labels.\n *\n * @returns\n */\nexport const ActiveInactiveAnnouncementIndicator = () => {\n const { t } = useAnnouncementsTranslation();\n\n return (\n <Flex justify=\"end\" gap=\"6\" mb=\"3\">\n <Flex align=\"center\" gap=\"1\">\n <RiCircleFill\n size=\"12\"\n color={ACTIVE_INDICATOR_COLOR}\n aria-label={t('admin.announcementsContent.table.active')}\n />\n <Text variant=\"body-small\">\n {t('admin.announcementsContent.table.active')}\n </Text>\n </Flex>\n <Flex align=\"center\" gap=\"1\">\n <RiCircleFill\n size=\"12\"\n color={INACTIVE_INDICATOR_COLOR}\n aria-label={t('admin.announcementsContent.table.inactive')}\n />\n <Text variant=\"body-small\">\n {t('admin.announcementsContent.table.inactive')}\n </Text>\n </Flex>\n </Flex>\n );\n};\n\n/**\n * An icon component that displays the active or inactive announcement indicator.\n *\n * @returns a green or red circle icon indicating the status of the announcement.\n */\nexport const ActiveInactiveAnnouncementIndicatorIcon = (props: {\n announcement: Announcement;\n}) => {\n const { announcement } = props;\n const { t } = useAnnouncementsTranslation();\n\n return (\n <Flex style={{ flexShrink: 0 }} align=\"center\">\n <RiCircleFill\n size=\"12\"\n color={\n announcement.active\n ? ACTIVE_INDICATOR_COLOR\n : INACTIVE_INDICATOR_COLOR\n }\n aria-label={\n announcement.active\n ? t('admin.announcementsContent.table.active')\n : t('admin.announcementsContent.table.inactive')\n }\n />\n </Flex>\n );\n};\n"],"names":[],"mappings":";;;;;AAqBO,MAAM,sBAAyB,GAAA;AAC/B,MAAM,wBAA2B,GAAA;AAOjC,MAAM,sCAAsC,MAAM;AACvD,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,2BAA4B,EAAA;AAE1C,EAAA,4BACG,IAAK,EAAA,EAAA,OAAA,EAAQ,OAAM,GAAI,EAAA,GAAA,EAAI,IAAG,GAC7B,EAAA,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAM,QAAS,EAAA,GAAA,EAAI,GACvB,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,IAAK,EAAA,IAAA;AAAA,UACL,KAAO,EAAA,sBAAA;AAAA,UACP,YAAA,EAAY,EAAE,yCAAyC;AAAA;AAAA,OACzD;AAAA,0BACC,IAAK,EAAA,EAAA,OAAA,EAAQ,YACX,EAAA,QAAA,EAAA,CAAA,CAAE,yCAAyC,CAC9C,EAAA;AAAA,KACF,EAAA,CAAA;AAAA,oBACC,IAAA,CAAA,IAAA,EAAA,EAAK,KAAM,EAAA,QAAA,EAAS,KAAI,GACvB,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,IAAK,EAAA,IAAA;AAAA,UACL,KAAO,EAAA,wBAAA;AAAA,UACP,YAAA,EAAY,EAAE,2CAA2C;AAAA;AAAA,OAC3D;AAAA,0BACC,IAAK,EAAA,EAAA,OAAA,EAAQ,YACX,EAAA,QAAA,EAAA,CAAA,CAAE,2CAA2C,CAChD,EAAA;AAAA,KACF,EAAA;AAAA,GACF,EAAA,CAAA;AAEJ;AAOa,MAAA,uCAAA,GAA0C,CAAC,KAElD,KAAA;AACJ,EAAM,MAAA,EAAE,cAAiB,GAAA,KAAA;AACzB,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,2BAA4B,EAAA;AAE1C,EACE,uBAAA,GAAA,CAAC,QAAK,KAAO,EAAA,EAAE,YAAY,CAAE,EAAA,EAAG,OAAM,QACpC,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACC,IAAK,EAAA,IAAA;AAAA,MACL,KAAA,EACE,YAAa,CAAA,MAAA,GACT,sBACA,GAAA,wBAAA;AAAA,MAEN,cACE,YAAa,CAAA,MAAA,GACT,EAAE,yCAAyC,CAAA,GAC3C,EAAE,2CAA2C;AAAA;AAAA,GAGvD,EAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1,196 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useMemo } from 'react';
3
+ import { useApi, alertApiRef } from '@backstage/core-plugin-api';
4
+ import { announcementsApiRef, useAnnouncementsTranslation, useAnnouncementsPermissions, useCategories, useAnnouncements } from '@backstage-community/plugin-announcements-react';
5
+ import { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';
6
+ import { useRouteRef } from '@backstage/frontend-plugin-api';
7
+ import { useNavigate } from 'react-router-dom';
8
+ import { RequirePermission } from '@backstage/plugin-permission-react';
9
+ import { Grid, Button, Box } from '@backstage/ui';
10
+ import slugify from 'slugify';
11
+ import { useDeleteConfirmationDialogState } from '../shared/DeleteConfirmationDialog/useDeleteConfirmationDialogState.esm.js';
12
+ import { DeleteConfirmationDialog } from '../shared/DeleteConfirmationDialog/DeleteConfirmationDialog.esm.js';
13
+ import { AnnouncementForm } from '../../../../components/Admin/AnnouncementsContent/AnnouncementForm/AnnouncementForm.esm.js';
14
+ import { AnnouncementsTableCard } from './AnnouncementsTableCard.esm.js';
15
+ import { announcementViewRouteRef } from '../../../../routes.esm.js';
16
+
17
+ const AnnouncementsContent = ({
18
+ formDefaults: { defaultInactive }
19
+ }) => {
20
+ const announcementsApi = useApi(announcementsApiRef);
21
+ const alertApi = useApi(alertApiRef);
22
+ const { t } = useAnnouncementsTranslation();
23
+ const permissions = useAnnouncementsPermissions();
24
+ const { categories } = useCategories();
25
+ const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] = useState(false);
26
+ const [editingAnnouncementId, setEditingAnnouncementId] = useState(null);
27
+ const { announcements, retry: refresh } = useAnnouncements({});
28
+ const {
29
+ isOpen: isDeleteDialogOpen,
30
+ close: closeDeleteDialog,
31
+ open: openDeleteDialog,
32
+ item: announcementToDelete
33
+ } = useDeleteConfirmationDialogState();
34
+ const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);
35
+ const navigate = useNavigate();
36
+ const onCreateButtonClick = () => {
37
+ if (editingAnnouncementId) {
38
+ setEditingAnnouncementId(null);
39
+ setShowCreateAnnouncementForm(false);
40
+ } else {
41
+ setShowCreateAnnouncementForm(!showCreateAnnouncementForm);
42
+ }
43
+ };
44
+ const onPreviewClick = (announcement) => {
45
+ const link = viewAnnouncementLink?.({ id: announcement.id }) ?? "";
46
+ navigate(`${link}?from=admin`);
47
+ };
48
+ const onEditClick = (announcement) => {
49
+ setEditingAnnouncementId(announcement.id);
50
+ setShowCreateAnnouncementForm(false);
51
+ };
52
+ const onSubmit = async (request) => {
53
+ const { category } = request;
54
+ const slugs = categories.map((c) => c.slug);
55
+ let alertMsg = t("admin.announcementsContent.alertMessage");
56
+ try {
57
+ if (category) {
58
+ const categorySlug = slugify(category, {
59
+ lower: true
60
+ });
61
+ if (slugs.indexOf(categorySlug) === -1) {
62
+ alertMsg = alertMsg.replace(".", "");
63
+ alertMsg = `${alertMsg} ${t(
64
+ "admin.announcementsContent.alertMessageWithNewCategory"
65
+ )} ${category}.`;
66
+ await announcementsApi.createCategory({
67
+ title: category
68
+ });
69
+ }
70
+ }
71
+ await announcementsApi.createAnnouncement({
72
+ ...request,
73
+ category: request.category?.toLocaleLowerCase("en-US")
74
+ });
75
+ alertApi.post({ message: alertMsg, severity: "success" });
76
+ setShowCreateAnnouncementForm(false);
77
+ refresh();
78
+ } catch (err) {
79
+ alertApi.post({ message: err.message, severity: "error" });
80
+ }
81
+ };
82
+ const onUpdate = async (request) => {
83
+ if (!editingAnnouncementId) {
84
+ return;
85
+ }
86
+ const { category } = request;
87
+ const slugs = categories.map((c) => c.slug);
88
+ let updateMsg = t("editAnnouncementPage.updatedMessage");
89
+ try {
90
+ if (category) {
91
+ const categorySlug = slugify(category, {
92
+ lower: true
93
+ });
94
+ if (slugs.indexOf(categorySlug) === -1) {
95
+ updateMsg = updateMsg.replace(".", "");
96
+ updateMsg = `${updateMsg} ${t(
97
+ "editAnnouncementPage.updatedMessageWithNewCategory"
98
+ )} ${category}.`;
99
+ await announcementsApi.createCategory({
100
+ title: category
101
+ });
102
+ }
103
+ }
104
+ await announcementsApi.updateAnnouncement(editingAnnouncementId, request);
105
+ alertApi.post({ message: updateMsg, severity: "success" });
106
+ setEditingAnnouncementId(null);
107
+ refresh();
108
+ } catch (err) {
109
+ alertApi.post({ message: err.message, severity: "error" });
110
+ }
111
+ };
112
+ const announcementToEdit = useMemo(() => {
113
+ if (!editingAnnouncementId || !announcements?.results) {
114
+ return null;
115
+ }
116
+ return announcements.results.find((a) => a.id === editingAnnouncementId) ?? null;
117
+ }, [editingAnnouncementId, announcements?.results]);
118
+ const onCancelDelete = () => {
119
+ closeDeleteDialog();
120
+ };
121
+ const onConfirmDelete = async () => {
122
+ closeDeleteDialog();
123
+ try {
124
+ await announcementsApi.deleteAnnouncementByID(announcementToDelete.id);
125
+ alertApi.post({
126
+ message: t("admin.announcementsContent.deletedMessage"),
127
+ severity: "success"
128
+ });
129
+ } catch (err) {
130
+ alertApi.post({
131
+ message: err.body?.error?.message || err.message,
132
+ severity: "error"
133
+ });
134
+ }
135
+ refresh();
136
+ };
137
+ const onDeleteClick = (announcement) => {
138
+ openDeleteDialog(announcement);
139
+ };
140
+ const canCreate = !permissions.create.loading && permissions.create.allowed;
141
+ const canEdit = !permissions.update.loading && permissions.update.allowed;
142
+ const canDelete = !permissions.delete.loading && permissions.delete.allowed;
143
+ return /* @__PURE__ */ jsx(RequirePermission, { permission: announcementCreatePermission, children: /* @__PURE__ */ jsxs(Grid.Root, { columns: "1", children: [
144
+ /* @__PURE__ */ jsx(Grid.Item, { children: /* @__PURE__ */ jsx(
145
+ Button,
146
+ {
147
+ isDisabled: !canCreate,
148
+ variant: "primary",
149
+ onClick: () => onCreateButtonClick(),
150
+ children: showCreateAnnouncementForm || editingAnnouncementId ? t("admin.announcementsContent.cancelButton") : t("admin.announcementsContent.createButton")
151
+ }
152
+ ) }),
153
+ showCreateAnnouncementForm && /* @__PURE__ */ jsx(Grid.Item, { children: /* @__PURE__ */ jsx(
154
+ AnnouncementForm,
155
+ {
156
+ initialData: { active: !defaultInactive },
157
+ onSubmit
158
+ }
159
+ ) }),
160
+ editingAnnouncementId && announcementToEdit && /* @__PURE__ */ jsx(Grid.Item, { children: /* @__PURE__ */ jsx(
161
+ AnnouncementForm,
162
+ {
163
+ initialData: announcementToEdit,
164
+ onSubmit: onUpdate
165
+ }
166
+ ) }),
167
+ /* @__PURE__ */ jsxs(Grid.Item, { children: [
168
+ /* @__PURE__ */ jsx(Box, { mb: "12", children: /* @__PURE__ */ jsx(
169
+ AnnouncementsTableCard,
170
+ {
171
+ announcements: announcements?.results ?? [],
172
+ onPreviewClick,
173
+ onEditClick,
174
+ onDeleteClick,
175
+ canEdit,
176
+ canDelete,
177
+ editingAnnouncementId
178
+ }
179
+ ) }),
180
+ /* @__PURE__ */ jsx(
181
+ DeleteConfirmationDialog,
182
+ {
183
+ type: "announcement",
184
+ itemTitle: announcementToDelete?.title,
185
+ open: isDeleteDialogOpen,
186
+ onCancel: onCancelDelete,
187
+ onConfirm: onConfirmDelete,
188
+ canDelete
189
+ }
190
+ )
191
+ ] })
192
+ ] }) });
193
+ };
194
+
195
+ export { AnnouncementsContent };
196
+ //# sourceMappingURL=AnnouncementsContent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnouncementsContent.esm.js","sources":["../../../../../src/alpha/components/admin/announcements/AnnouncementsContent.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 { useApi, alertApiRef } from '@backstage/core-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport {\n CreateAnnouncementRequest,\n announcementsApiRef,\n useAnnouncementsTranslation,\n useAnnouncements,\n useAnnouncementsPermissions,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n Category,\n announcementCreatePermission,\n} from '@backstage-community/plugin-announcements-common';\nimport { useRouteRef } from '@backstage/frontend-plugin-api';\nimport { useNavigate } from 'react-router-dom';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { Box, Button, Grid } from '@backstage/ui';\nimport slugify from 'slugify';\n\nimport {\n useDeleteConfirmationDialogState,\n DeleteConfirmationDialog,\n} from '../shared';\nimport { AnnouncementForm } from '../../../../components/Admin/AnnouncementsContent/AnnouncementForm';\nimport { AnnouncementsTableCard } from './AnnouncementsTableCard';\nimport { announcementViewRouteRef } from '../../../../routes';\n\n/**\n * @internal\n */\nexport type AnnouncementsContentProps = {\n /** default form values when creating a new announcement */\n formDefaults: {\n /** sets active switch form input to false by default when creating a new announcement */\n defaultInactive?: boolean;\n };\n};\n\n/**\n * @internal\n */\nexport const AnnouncementsContent = ({\n formDefaults: { defaultInactive },\n}: AnnouncementsContentProps) => {\n const announcementsApi = useApi(announcementsApiRef);\n const alertApi = useApi(alertApiRef);\n const { t } = useAnnouncementsTranslation();\n const permissions = useAnnouncementsPermissions();\n const { categories } = useCategories();\n\n const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] =\n useState(false);\n const [editingAnnouncementId, setEditingAnnouncementId] = useState<\n string | null\n >(null);\n\n const { announcements, retry: refresh } = useAnnouncements({});\n\n const {\n isOpen: isDeleteDialogOpen,\n close: closeDeleteDialog,\n open: openDeleteDialog,\n item: announcementToDelete,\n } = useDeleteConfirmationDialogState<Announcement>();\n\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n const navigate = useNavigate();\n\n const onCreateButtonClick = () => {\n if (editingAnnouncementId) {\n // If editing, cancel the edit\n setEditingAnnouncementId(null);\n setShowCreateAnnouncementForm(false);\n } else {\n // If not editing, toggle create form\n setShowCreateAnnouncementForm(!showCreateAnnouncementForm);\n }\n };\n\n const onPreviewClick = (announcement: Announcement) => {\n const link = viewAnnouncementLink?.({ id: announcement.id }) ?? '';\n navigate(`${link}?from=admin`);\n };\n\n const onEditClick = (announcement: Announcement) => {\n setEditingAnnouncementId(announcement.id);\n setShowCreateAnnouncementForm(false);\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\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\n alertApi.post({ message: alertMsg, severity: 'success' });\n\n setShowCreateAnnouncementForm(false);\n refresh();\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 refresh();\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 const onCancelDelete = () => {\n closeDeleteDialog();\n };\n\n const onConfirmDelete = async () => {\n closeDeleteDialog();\n\n try {\n await announcementsApi.deleteAnnouncementByID(announcementToDelete!.id);\n\n alertApi.post({\n message: t('admin.announcementsContent.deletedMessage'),\n severity: 'success',\n });\n } catch (err) {\n alertApi.post({\n message:\n (err as ResponseError).body?.error?.message || (err as Error).message,\n severity: 'error',\n });\n }\n\n refresh();\n };\n\n const onDeleteClick = (announcement: Announcement) => {\n openDeleteDialog(announcement);\n };\n\n const canCreate = !permissions.create.loading && permissions.create.allowed;\n const canEdit = !permissions.update.loading && permissions.update.allowed;\n const canDelete = !permissions.delete.loading && permissions.delete.allowed;\n\n return (\n <RequirePermission permission={announcementCreatePermission}>\n <Grid.Root columns=\"1\">\n <Grid.Item>\n <Button\n isDisabled={!canCreate}\n variant=\"primary\"\n onClick={() => onCreateButtonClick()}\n >\n {showCreateAnnouncementForm || editingAnnouncementId\n ? t('admin.announcementsContent.cancelButton')\n : t('admin.announcementsContent.createButton')}\n </Button>\n </Grid.Item>\n\n {showCreateAnnouncementForm && (\n <Grid.Item>\n <AnnouncementForm\n initialData={{ active: !defaultInactive } as Announcement}\n onSubmit={onSubmit}\n />\n </Grid.Item>\n )}\n\n {editingAnnouncementId && announcementToEdit && (\n <Grid.Item>\n <AnnouncementForm\n initialData={announcementToEdit}\n onSubmit={onUpdate}\n />\n </Grid.Item>\n )}\n\n <Grid.Item>\n <Box mb=\"12\">\n <AnnouncementsTableCard\n announcements={announcements?.results ?? []}\n onPreviewClick={onPreviewClick}\n onEditClick={onEditClick}\n onDeleteClick={onDeleteClick}\n canEdit={canEdit}\n canDelete={canDelete}\n editingAnnouncementId={editingAnnouncementId}\n />\n </Box>\n\n <DeleteConfirmationDialog\n type=\"announcement\"\n itemTitle={announcementToDelete?.title}\n open={isDeleteDialogOpen}\n onCancel={onCancelDelete}\n onConfirm={onConfirmDelete}\n canDelete={canDelete}\n />\n </Grid.Item>\n </Grid.Root>\n </RequirePermission>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { DateTime } from 'luxon';
3
+ import { parseEntityRef } from '@backstage/catalog-model';
4
+ import { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
5
+ import { Table, TableHeader, Column, TableBody, Row, CellText, Cell, Flex, Text, TagGroup, Tag, ButtonIcon } from '@backstage/ui';
6
+ import { RiEyeLine, RiEditLine, RiDeleteBinLine } from '@remixicon/react';
7
+ import { EntityRefLink } from '@backstage/plugin-catalog-react';
8
+ import { ActiveInactiveAnnouncementIndicatorIcon } from './ActiveInactiveAnnouncementIndicator.esm.js';
9
+
10
+ const AnnouncementsTableEmptyState = () => {
11
+ const { t } = useAnnouncementsTranslation();
12
+ return /* @__PURE__ */ jsx(Row, { children: /* @__PURE__ */ jsx(
13
+ CellText,
14
+ {
15
+ colSpan: 9,
16
+ title: t("admin.announcementsContent.noAnnouncementsFound")
17
+ }
18
+ ) });
19
+ };
20
+ const EmptyPlaceholder = () => {
21
+ return /* @__PURE__ */ jsx(CellText, { title: "-" });
22
+ };
23
+ const isValidEntityRef = (entityRef) => {
24
+ if (!entityRef) {
25
+ return false;
26
+ }
27
+ try {
28
+ parseEntityRef(entityRef);
29
+ return true;
30
+ } catch {
31
+ return false;
32
+ }
33
+ };
34
+ const AnnouncementTableRow = (props) => {
35
+ const {
36
+ announcement,
37
+ onPreviewClick,
38
+ onEditClick,
39
+ onDeleteClick,
40
+ canEdit,
41
+ canDelete,
42
+ editingAnnouncementId
43
+ } = props;
44
+ const isCurrentlyEditing = editingAnnouncementId === announcement.id;
45
+ const isEditDisabled = editingAnnouncementId !== null && !isCurrentlyEditing;
46
+ const truncateText = (text, maxLength = 50) => {
47
+ if (text.length <= maxLength) return text;
48
+ return `${text.substring(0, maxLength)}...`;
49
+ };
50
+ const hasValidPublisher = announcement.publisher && isValidEntityRef(announcement.publisher);
51
+ return /* @__PURE__ */ jsxs(Row, { children: [
52
+ /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsxs(Flex, { children: [
53
+ /* @__PURE__ */ jsx(
54
+ ActiveInactiveAnnouncementIndicatorIcon,
55
+ {
56
+ announcement
57
+ }
58
+ ),
59
+ /* @__PURE__ */ jsx(Text, { variant: "body-small", title: announcement.title, children: announcement.title })
60
+ ] }) }),
61
+ /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx(Text, { variant: "body-small", children: truncateText(announcement.body) }) }),
62
+ hasValidPublisher ? /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx(EntityRefLink, { entityRef: parseEntityRef(announcement.publisher) }) }) : /* @__PURE__ */ jsx(EmptyPlaceholder, {}),
63
+ announcement.category ? /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx(Text, { variant: "body-small", children: announcement.category.title }) }) : /* @__PURE__ */ jsx(EmptyPlaceholder, {}),
64
+ announcement.tags && announcement.tags.length > 0 ? /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx(TagGroup, { children: announcement.tags.map((tag) => /* @__PURE__ */ jsx(Tag, { size: "small", children: tag.title }, tag.slug)) }) }) : /* @__PURE__ */ jsx(EmptyPlaceholder, {}),
65
+ /* @__PURE__ */ jsx(
66
+ CellText,
67
+ {
68
+ title: DateTime.fromISO(announcement.created_at).toFormat("M/d/yy")
69
+ }
70
+ ),
71
+ /* @__PURE__ */ jsx(
72
+ CellText,
73
+ {
74
+ title: DateTime.fromISO(announcement.start_at).toFormat("M/d/yy")
75
+ }
76
+ ),
77
+ /* @__PURE__ */ jsx(
78
+ CellText,
79
+ {
80
+ title: announcement.until_date ? DateTime.fromISO(announcement.until_date).toFormat("M/d/yy") : "-"
81
+ }
82
+ ),
83
+ /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsxs(Flex, { gap: "small", children: [
84
+ /* @__PURE__ */ jsx(
85
+ ButtonIcon,
86
+ {
87
+ icon: /* @__PURE__ */ jsx(RiEyeLine, {}),
88
+ variant: "tertiary",
89
+ onClick: () => onPreviewClick?.(announcement),
90
+ "aria-label": "preview",
91
+ "data-testid": "preview"
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsx(
95
+ ButtonIcon,
96
+ {
97
+ icon: /* @__PURE__ */ jsx(RiEditLine, {}),
98
+ variant: "tertiary",
99
+ onClick: () => onEditClick?.(announcement),
100
+ "aria-label": "edit",
101
+ "data-testid": "edit-icon",
102
+ isDisabled: !canEdit || isEditDisabled
103
+ }
104
+ ),
105
+ /* @__PURE__ */ jsx(
106
+ ButtonIcon,
107
+ {
108
+ icon: /* @__PURE__ */ jsx(RiDeleteBinLine, {}),
109
+ variant: "tertiary",
110
+ onClick: () => onDeleteClick?.(announcement),
111
+ "aria-label": "delete",
112
+ "data-testid": "delete-icon",
113
+ isDisabled: !canDelete
114
+ }
115
+ )
116
+ ] }) })
117
+ ] }, announcement.id);
118
+ };
119
+ const AnnouncementsTable = (props) => {
120
+ const {
121
+ data,
122
+ onPreviewClick,
123
+ onEditClick,
124
+ onDeleteClick,
125
+ canEdit,
126
+ canDelete,
127
+ editingAnnouncementId
128
+ } = props;
129
+ const { t } = useAnnouncementsTranslation();
130
+ return /* @__PURE__ */ jsxs(Table, { children: [
131
+ /* @__PURE__ */ jsxs(TableHeader, { children: [
132
+ /* @__PURE__ */ jsx(Column, { isRowHeader: true, children: t("admin.announcementsContent.table.title") }),
133
+ /* @__PURE__ */ jsx(Column, { children: t("admin.announcementsContent.table.body") }),
134
+ /* @__PURE__ */ jsx(Column, { children: t("admin.announcementsContent.table.publisher") }),
135
+ /* @__PURE__ */ jsx(Column, { children: t("admin.announcementsContent.table.category") }),
136
+ /* @__PURE__ */ jsx(Column, { children: t("admin.announcementsContent.table.tags") }),
137
+ /* @__PURE__ */ jsx(Column, { children: t("admin.announcementsContent.table.created_at") }),
138
+ /* @__PURE__ */ jsx(Column, { children: t("admin.announcementsContent.table.start_at") }),
139
+ /* @__PURE__ */ jsx(Column, { children: t("admin.announcementsContent.table.until_date") }),
140
+ /* @__PURE__ */ jsx(Column, { children: t("admin.announcementsContent.table.actions") })
141
+ ] }),
142
+ /* @__PURE__ */ jsx(TableBody, { children: data?.length > 0 ? data.map((announcement) => /* @__PURE__ */ jsx(
143
+ AnnouncementTableRow,
144
+ {
145
+ announcement,
146
+ onPreviewClick,
147
+ onEditClick,
148
+ onDeleteClick,
149
+ canEdit,
150
+ canDelete,
151
+ editingAnnouncementId
152
+ },
153
+ announcement.id
154
+ )) : /* @__PURE__ */ jsx(AnnouncementsTableEmptyState, {}) })
155
+ ] });
156
+ };
157
+
158
+ export { AnnouncementsTable };
159
+ //# sourceMappingURL=AnnouncementsTable.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnouncementsTable.esm.js","sources":["../../../../../src/alpha/components/admin/announcements/AnnouncementsTable.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 { DateTime } from 'luxon';\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport { Announcement } from '@backstage-community/plugin-announcements-common';\nimport { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';\nimport {\n Cell,\n CellText,\n Column,\n Row,\n Table,\n TableBody,\n TableHeader,\n ButtonIcon,\n Flex,\n Tag,\n TagGroup,\n Text,\n} from '@backstage/ui';\nimport { RiEyeLine, RiEditLine, RiDeleteBinLine } from '@remixicon/react';\nimport { EntityRefLink } from '@backstage/plugin-catalog-react';\n\nimport { ActiveInactiveAnnouncementIndicatorIcon } from './ActiveInactiveAnnouncementIndicator';\n\nconst AnnouncementsTableEmptyState = () => {\n const { t } = useAnnouncementsTranslation();\n\n return (\n <Row>\n <CellText\n colSpan={9}\n title={t('admin.announcementsContent.noAnnouncementsFound')}\n />\n </Row>\n );\n};\n\ntype AnnouncementTableRowProps = {\n announcement: Announcement;\n onPreviewClick?: (announcement: Announcement) => void;\n onEditClick?: (announcement: Announcement) => void;\n onDeleteClick?: (announcement: Announcement) => void;\n canEdit?: boolean;\n canDelete?: boolean;\n editingAnnouncementId?: string | null;\n};\n\nconst EmptyPlaceholder = () => {\n return <CellText title=\"-\" />;\n};\n\nconst isValidEntityRef = (entityRef: string): boolean => {\n if (!entityRef) {\n return false;\n }\n try {\n parseEntityRef(entityRef);\n return true;\n } catch {\n return false;\n }\n};\n\nconst AnnouncementTableRow = (props: AnnouncementTableRowProps) => {\n const {\n announcement,\n onPreviewClick,\n onEditClick,\n onDeleteClick,\n canEdit,\n canDelete,\n editingAnnouncementId,\n } = props;\n const isCurrentlyEditing = editingAnnouncementId === announcement.id;\n const isEditDisabled = editingAnnouncementId !== null && !isCurrentlyEditing;\n\n const truncateText = (text: string, maxLength: number = 50) => {\n if (text.length <= maxLength) return text;\n return `${text.substring(0, maxLength)}...`;\n };\n\n const hasValidPublisher =\n announcement.publisher && isValidEntityRef(announcement.publisher);\n\n return (\n <Row key={announcement.id}>\n <Cell>\n <Flex>\n <ActiveInactiveAnnouncementIndicatorIcon\n announcement={announcement}\n />\n <Text variant=\"body-small\" title={announcement.title}>\n {announcement.title}\n </Text>\n </Flex>\n </Cell>\n <Cell>\n <Text variant=\"body-small\">{truncateText(announcement.body)}</Text>\n </Cell>\n\n {hasValidPublisher ? (\n <Cell>\n <EntityRefLink entityRef={parseEntityRef(announcement.publisher)} />\n </Cell>\n ) : (\n <EmptyPlaceholder />\n )}\n\n {announcement.category ? (\n <Cell>\n <Text variant=\"body-small\">{announcement.category.title}</Text>\n </Cell>\n ) : (\n <EmptyPlaceholder />\n )}\n {announcement.tags && announcement.tags.length > 0 ? (\n <Cell>\n <TagGroup>\n {announcement.tags.map(tag => (\n <Tag key={tag.slug} size=\"small\">\n {tag.title}\n </Tag>\n ))}\n </TagGroup>\n </Cell>\n ) : (\n <EmptyPlaceholder />\n )}\n\n <CellText\n title={DateTime.fromISO(announcement.created_at).toFormat('M/d/yy')}\n />\n <CellText\n title={DateTime.fromISO(announcement.start_at).toFormat('M/d/yy')}\n />\n <CellText\n title={\n announcement.until_date\n ? DateTime.fromISO(announcement.until_date).toFormat('M/d/yy')\n : '-'\n }\n />\n <Cell>\n <Flex gap=\"small\">\n <ButtonIcon\n icon={<RiEyeLine />}\n variant=\"tertiary\"\n onClick={() => onPreviewClick?.(announcement)}\n aria-label=\"preview\"\n data-testid=\"preview\"\n />\n <ButtonIcon\n icon={<RiEditLine />}\n variant=\"tertiary\"\n onClick={() => onEditClick?.(announcement)}\n aria-label=\"edit\"\n data-testid=\"edit-icon\"\n isDisabled={!canEdit || isEditDisabled}\n />\n <ButtonIcon\n icon={<RiDeleteBinLine />}\n variant=\"tertiary\"\n onClick={() => onDeleteClick?.(announcement)}\n aria-label=\"delete\"\n data-testid=\"delete-icon\"\n isDisabled={!canDelete}\n />\n </Flex>\n </Cell>\n </Row>\n );\n};\n\n/**\n * @internal\n */\ntype AnnouncementsTableProps = {\n data: Announcement[];\n onPreviewClick?: (announcement: Announcement) => void;\n onEditClick?: (announcement: Announcement) => void;\n onDeleteClick?: (announcement: Announcement) => void;\n canEdit?: boolean;\n canDelete?: boolean;\n editingAnnouncementId?: string | null;\n};\n\n/**\n * @internal\n */\nexport const AnnouncementsTable = (props: AnnouncementsTableProps) => {\n const {\n data,\n onPreviewClick,\n onEditClick,\n onDeleteClick,\n canEdit,\n canDelete,\n editingAnnouncementId,\n } = props;\n const { t } = useAnnouncementsTranslation();\n\n return (\n <Table>\n <TableHeader>\n <Column isRowHeader>\n {t('admin.announcementsContent.table.title')}\n </Column>\n <Column>{t('admin.announcementsContent.table.body')}</Column>\n <Column>{t('admin.announcementsContent.table.publisher')}</Column>\n <Column>{t('admin.announcementsContent.table.category')}</Column>\n <Column>{t('admin.announcementsContent.table.tags')}</Column>\n <Column>{t('admin.announcementsContent.table.created_at')}</Column>\n <Column>{t('admin.announcementsContent.table.start_at')}</Column>\n <Column>{t('admin.announcementsContent.table.until_date')}</Column>\n <Column>{t('admin.announcementsContent.table.actions')}</Column>\n </TableHeader>\n <TableBody>\n {data?.length > 0 ? (\n data.map(announcement => (\n <AnnouncementTableRow\n key={announcement.id}\n announcement={announcement}\n onPreviewClick={onPreviewClick}\n onEditClick={onEditClick}\n onDeleteClick={onDeleteClick}\n canEdit={canEdit}\n canDelete={canDelete}\n editingAnnouncementId={editingAnnouncementId}\n />\n ))\n ) : (\n <AnnouncementsTableEmptyState />\n )}\n </TableBody>\n </Table>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useMemo } from 'react';
3
+ import { Card, CardBody, CardFooter, TablePagination } from '@backstage/ui';
4
+ import { AnnouncementsTable } from './AnnouncementsTable.esm.js';
5
+ import { ActiveInactiveAnnouncementIndicator } from './ActiveInactiveAnnouncementIndicator.esm.js';
6
+
7
+ const AnnouncementsTableCard = (props) => {
8
+ const {
9
+ announcements,
10
+ onPreviewClick,
11
+ onEditClick,
12
+ onDeleteClick,
13
+ canEdit,
14
+ canDelete,
15
+ editingAnnouncementId
16
+ } = props;
17
+ const [pageSize, setPageSize] = useState(10);
18
+ const [offset, setOffset] = useState(0);
19
+ const paginatedAnnouncements = useMemo(() => {
20
+ const start = offset;
21
+ const end = offset + pageSize;
22
+ return announcements.slice(start, end);
23
+ }, [announcements, offset, pageSize]);
24
+ return /* @__PURE__ */ jsxs(Card, { children: [
25
+ /* @__PURE__ */ jsxs(CardBody, { children: [
26
+ /* @__PURE__ */ jsx(ActiveInactiveAnnouncementIndicator, {}),
27
+ /* @__PURE__ */ jsx(
28
+ AnnouncementsTable,
29
+ {
30
+ data: paginatedAnnouncements,
31
+ onPreviewClick,
32
+ onEditClick,
33
+ onDeleteClick,
34
+ canEdit,
35
+ canDelete,
36
+ editingAnnouncementId
37
+ }
38
+ )
39
+ ] }),
40
+ announcements.length > 0 && /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(
41
+ TablePagination,
42
+ {
43
+ offset,
44
+ pageSize,
45
+ setOffset,
46
+ setPageSize,
47
+ rowCount: announcements.length
48
+ }
49
+ ) })
50
+ ] });
51
+ };
52
+
53
+ export { AnnouncementsTableCard };
54
+ //# sourceMappingURL=AnnouncementsTableCard.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnouncementsTableCard.esm.js","sources":["../../../../../src/alpha/components/admin/announcements/AnnouncementsTableCard.tsx"],"sourcesContent":["/*\n * Copyright 2026 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 { Announcement } from '@backstage-community/plugin-announcements-common';\nimport { TablePagination, Card, CardBody, CardFooter } from '@backstage/ui';\n\nimport { AnnouncementsTable } from './AnnouncementsTable';\nimport { ActiveInactiveAnnouncementIndicator } from './ActiveInactiveAnnouncementIndicator';\n\n/**\n * @internal\n */\ntype AnnouncementsTableCardProps = {\n announcements: Announcement[];\n onPreviewClick: (announcement: Announcement) => void;\n onEditClick: (announcement: Announcement) => void;\n onDeleteClick: (announcement: Announcement) => void;\n canEdit: boolean;\n canDelete: boolean;\n editingAnnouncementId?: string | null;\n};\n\n/**\n * @internal\n */\nexport const AnnouncementsTableCard = (props: AnnouncementsTableCardProps) => {\n const {\n announcements,\n onPreviewClick,\n onEditClick,\n onDeleteClick,\n canEdit,\n canDelete,\n editingAnnouncementId,\n } = props;\n\n const [pageSize, setPageSize] = useState(10);\n const [offset, setOffset] = useState(0);\n\n const paginatedAnnouncements = useMemo(() => {\n const start = offset;\n const end = offset + pageSize;\n return announcements.slice(start, end);\n }, [announcements, offset, pageSize]);\n\n return (\n <Card>\n <CardBody>\n <ActiveInactiveAnnouncementIndicator />\n\n <AnnouncementsTable\n data={paginatedAnnouncements}\n onPreviewClick={onPreviewClick}\n onEditClick={onEditClick}\n onDeleteClick={onDeleteClick}\n canEdit={canEdit}\n canDelete={canDelete}\n editingAnnouncementId={editingAnnouncementId}\n />\n </CardBody>\n\n {announcements.length > 0 && (\n <CardFooter>\n <TablePagination\n offset={offset}\n pageSize={pageSize}\n setOffset={setOffset}\n setPageSize={setPageSize}\n rowCount={announcements.length}\n />\n </CardFooter>\n )}\n </Card>\n );\n};\n"],"names":[],"mappings":";;;;;;AAsCa,MAAA,sBAAA,GAAyB,CAAC,KAAuC,KAAA;AAC5E,EAAM,MAAA;AAAA,IACJ,aAAA;AAAA,IACA,cAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AAEJ,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,EAAE,CAAA;AAC3C,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,CAAC,CAAA;AAEtC,EAAM,MAAA,sBAAA,GAAyB,QAAQ,MAAM;AAC3C,IAAA,MAAM,KAAQ,GAAA,MAAA;AACd,IAAA,MAAM,MAAM,MAAS,GAAA,QAAA;AACrB,IAAO,OAAA,aAAA,CAAc,KAAM,CAAA,KAAA,EAAO,GAAG,CAAA;AAAA,GACpC,EAAA,CAAC,aAAe,EAAA,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAEpC,EAAA,4BACG,IACC,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,QACC,EAAA,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,mCAAoC,EAAA,EAAA,CAAA;AAAA,sBAErC,GAAA;AAAA,QAAC,kBAAA;AAAA,QAAA;AAAA,UACC,IAAM,EAAA,sBAAA;AAAA,UACN,cAAA;AAAA,UACA,WAAA;AAAA,UACA,aAAA;AAAA,UACA,OAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA;AAAA;AACF,KACF,EAAA,CAAA;AAAA,IAEC,aAAc,CAAA,MAAA,GAAS,CACtB,oBAAA,GAAA,CAAC,UACC,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,eAAA;AAAA,MAAA;AAAA,QACC,MAAA;AAAA,QACA,QAAA;AAAA,QACA,SAAA;AAAA,QACA,WAAA;AAAA,QACA,UAAU,aAAc,CAAA;AAAA;AAAA,KAE5B,EAAA;AAAA,GAEJ,EAAA,CAAA;AAEJ;;;;"}