@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.
- package/CHANGELOG.md +26 -0
- package/dist/alpha/Router.esm.js +7 -13
- package/dist/alpha/Router.esm.js.map +1 -1
- package/dist/alpha/components/admin/announcements/ActiveInactiveAnnouncementIndicator.esm.js +49 -0
- package/dist/alpha/components/admin/announcements/ActiveInactiveAnnouncementIndicator.esm.js.map +1 -0
- package/dist/alpha/components/admin/announcements/AnnouncementsContent.esm.js +196 -0
- package/dist/alpha/components/admin/announcements/AnnouncementsContent.esm.js.map +1 -0
- package/dist/alpha/components/admin/announcements/AnnouncementsTable.esm.js +159 -0
- package/dist/alpha/components/admin/announcements/AnnouncementsTable.esm.js.map +1 -0
- package/dist/alpha/components/admin/announcements/AnnouncementsTableCard.esm.js +54 -0
- package/dist/alpha/components/admin/announcements/AnnouncementsTableCard.esm.js.map +1 -0
- package/dist/alpha/components/announcements/AnnouncementCard.esm.js +12 -41
- package/dist/alpha/components/announcements/AnnouncementCard.esm.js.map +1 -1
- package/dist/alpha/components/announcements/AnnouncementsFilterBar.esm.js +88 -0
- package/dist/alpha/components/announcements/AnnouncementsFilterBar.esm.js.map +1 -0
- package/dist/alpha/components/announcements/AnnouncementsGrid.esm.js +20 -23
- package/dist/alpha/components/announcements/AnnouncementsGrid.esm.js.map +1 -1
- package/dist/alpha/components/announcements/AnnouncementsPage.esm.js +20 -25
- package/dist/alpha/components/announcements/AnnouncementsPage.esm.js.map +1 -1
- package/dist/alpha/components/announcements/ViewAnnouncementPage.esm.js +5 -14
- package/dist/alpha/components/announcements/ViewAnnouncementPage.esm.js.map +1 -1
- package/dist/alpha/components/shared/AnnouncementPublishedBy/AnnouncementPublishedBy.esm.js +42 -0
- package/dist/alpha/components/shared/AnnouncementPublishedBy/AnnouncementPublishedBy.esm.js.map +1 -0
- package/dist/alpha/components/shared/AnnouncementTags/AnnouncementTags.esm.js +22 -0
- package/dist/alpha/components/shared/AnnouncementTags/AnnouncementTags.esm.js.map +1 -0
- package/dist/alpha/components/shared/BackToAnnouncementsButton/BackToAnnouncementsButton.esm.js +28 -0
- package/dist/alpha/components/shared/BackToAnnouncementsButton/BackToAnnouncementsButton.esm.js.map +1 -0
- package/dist/alpha/components/shared/CategorySelectInput/CategorySelectInput.esm.js +67 -0
- package/dist/alpha/components/shared/CategorySelectInput/CategorySelectInput.esm.js.map +1 -0
- package/dist/alpha/components/shared/TagsSelectInput/TagsSelectInput.esm.js +67 -0
- package/dist/alpha/components/shared/TagsSelectInput/TagsSelectInput.esm.js.map +1 -0
- 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
|
package/dist/alpha/Router.esm.js
CHANGED
|
@@ -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(
|
|
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
|
|
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
|
package/dist/alpha/components/admin/announcements/ActiveInactiveAnnouncementIndicator.esm.js.map
ADDED
|
@@ -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;;;;"}
|