@backstage-community/plugin-announcements 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/dist/alpha/Router.esm.js +74 -0
- package/dist/alpha/Router.esm.js.map +1 -0
- package/dist/alpha/components/admin/AnnouncementsAdminPage.esm.js +43 -0
- package/dist/alpha/components/admin/AnnouncementsAdminPage.esm.js.map +1 -0
- package/dist/alpha/navItems.esm.js +1 -1
- package/dist/alpha/navItems.esm.js.map +1 -1
- package/dist/alpha/pages.esm.js +1 -1
- package/dist/alpha/pages.esm.js.map +1 -1
- package/dist/alpha.d.ts +5 -13
- package/dist/alpha.esm.js +1 -1
- package/dist/alpha.esm.js.map +1 -1
- package/dist/components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js +14 -22
- package/dist/components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js.map +1 -1
- package/dist/components/Admin/CategoriesContent/CategoriesContent.esm.js +26 -19
- package/dist/components/Admin/CategoriesContent/CategoriesContent.esm.js.map +1 -1
- package/dist/components/Admin/TagsContent/TagsContent.esm.js +31 -19
- package/dist/components/Admin/TagsContent/TagsContent.esm.js.map +1 -1
- package/dist/components/Admin/shared/DeleteDialog/DeleteDialog.esm.js +30 -0
- package/dist/components/Admin/shared/DeleteDialog/DeleteDialog.esm.js.map +1 -0
- package/dist/components/Admin/{TagsContent/useDeleteTagDialogState.esm.js → shared/DeleteDialog/useDeleteDialogState.esm.js} +7 -7
- package/dist/components/Admin/shared/DeleteDialog/useDeleteDialogState.esm.js.map +1 -0
- package/dist/components/Admin/shared/TitleForm/TitleForm.esm.js +71 -0
- package/dist/components/Admin/shared/TitleForm/TitleForm.esm.js.map +1 -0
- package/dist/components/AnnouncementsCard/AnnouncementsCard.esm.js +3 -8
- package/dist/components/AnnouncementsCard/AnnouncementsCard.esm.js.map +1 -1
- package/dist/components/AnnouncementsPage/AnnouncementsPage.esm.js +3 -5
- package/dist/components/AnnouncementsPage/AnnouncementsPage.esm.js.map +1 -1
- package/dist/index.d.ts +14 -6
- package/dist/plugin.esm.js.map +1 -1
- package/dist/routes.esm.js +14 -4
- package/dist/routes.esm.js.map +1 -1
- package/package.json +19 -18
- package/dist/components/Admin/AnnouncementsContent/DeleteAnnouncementDialog.esm.js +0 -31
- package/dist/components/Admin/AnnouncementsContent/DeleteAnnouncementDialog.esm.js.map +0 -1
- package/dist/components/Admin/AnnouncementsContent/useDeleteAnnouncementDialogState.esm.js +0 -29
- package/dist/components/Admin/AnnouncementsContent/useDeleteAnnouncementDialogState.esm.js.map +0 -1
- package/dist/components/Admin/CategoriesContent/CategoriesForm.esm.js +0 -75
- package/dist/components/Admin/CategoriesContent/CategoriesForm.esm.js.map +0 -1
- package/dist/components/Admin/CategoriesContent/DeleteCategoryDialog.esm.js +0 -16
- package/dist/components/Admin/CategoriesContent/DeleteCategoryDialog.esm.js.map +0 -1
- package/dist/components/Admin/CategoriesContent/useDeleteCategoryDialogState.esm.js +0 -29
- package/dist/components/Admin/CategoriesContent/useDeleteCategoryDialogState.esm.js.map +0 -1
- package/dist/components/Admin/TagsContent/DeleteTagDialog.esm.js +0 -16
- package/dist/components/Admin/TagsContent/DeleteTagDialog.esm.js.map +0 -1
- package/dist/components/Admin/TagsContent/TagsForm.esm.js +0 -85
- package/dist/components/Admin/TagsContent/TagsForm.esm.js.map +0 -1
- package/dist/components/Admin/TagsContent/useDeleteTagDialogState.esm.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
# @backstage-community/plugin-announcements
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 411e4c6: Backstage version bump to v1.46.0.
|
|
8
|
+
This release includes fix for frontend error `Package subpath './' is not defined by "exports"`.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- 0768c4e: - New dedicated routes to the admin portal (`/announcements/admin`, `/announcements/admin/categories`, `/announcements/admin/tags`)
|
|
13
|
+
|
|
14
|
+
- The exported `AnnouncementsTimeline` and `AnnouncementsAdminPortal` components have been deprecated as they will not be migrated to the new frontend system. Please see each component's deprecation notice for more details.
|
|
15
|
+
|
|
16
|
+
### New frontend system + @backstage/ui updates
|
|
17
|
+
|
|
18
|
+
We are rebuilding several major components of the announcements plugin from scratch leveraging the `@backstage/ui` library. To start, the admin portal now leverages the new header component from the `@backstage/ui` library. Users who have migrated to the new frontend system will gradually receive these until the plugin is fully migrated. Users on the existing frontend system will not see any changes.
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [411e4c6]
|
|
21
|
+
- @backstage-community/plugin-announcements-common@0.14.0
|
|
22
|
+
- @backstage-community/plugin-announcements-react@0.17.0
|
|
23
|
+
|
|
24
|
+
## 1.1.0
|
|
25
|
+
|
|
26
|
+
### Minor Changes
|
|
27
|
+
|
|
28
|
+
- 40b8d32: Internal refactor to consolidate delete dialog state management in the admin portal. Refactoring categories and tags to the shared component added support for translations which was previously missing.
|
|
29
|
+
|
|
30
|
+
The refactor includes a new set of translation keys for the generic delete dialog.
|
|
31
|
+
|
|
32
|
+
### Translation Changes
|
|
33
|
+
|
|
34
|
+
Added new translation keys for the delete dialog:
|
|
35
|
+
|
|
36
|
+
- `confirmDeleteDialog.title`
|
|
37
|
+
- `confirmDeleteDialog.cancel`
|
|
38
|
+
- `confirmDeleteDialog.delete`
|
|
39
|
+
|
|
40
|
+
Deprecated the following translation keys:
|
|
41
|
+
|
|
42
|
+
- `deleteDialog.title`
|
|
43
|
+
- `deleteDialog.cancel`
|
|
44
|
+
- `deleteDialog.delete`
|
|
45
|
+
|
|
46
|
+
### Patch Changes
|
|
47
|
+
|
|
48
|
+
- e6b9dd8: Replaces global `JSX` namespace with `React.JSX` to resolve deprecation
|
|
49
|
+
- 6b45ee7: Adds a new useAnnouncementsPermissions hook users can leverage when needing quick access to all permissions, something we commonly do throughout the admin portal. All components now leverage this hook instead of using the usePermission hook directly.
|
|
50
|
+
- Updated dependencies [6b45ee7]
|
|
51
|
+
- Updated dependencies [40b8d32]
|
|
52
|
+
- @backstage-community/plugin-announcements-react@0.16.0
|
|
53
|
+
|
|
3
54
|
## 1.0.0
|
|
4
55
|
|
|
5
56
|
### Major Changes
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Routes, Route } from 'react-router-dom';
|
|
3
|
+
import { RequirePermission } from '@backstage/plugin-permission-react';
|
|
4
|
+
import { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';
|
|
5
|
+
import { AnnouncementsAdminPage } from './components/admin/AnnouncementsAdminPage.esm.js';
|
|
6
|
+
import '@backstage/core-plugin-api';
|
|
7
|
+
import 'luxon';
|
|
8
|
+
import '@backstage-community/plugin-announcements-react';
|
|
9
|
+
import '@backstage/core-components';
|
|
10
|
+
import '@material-ui/lab';
|
|
11
|
+
import '@material-ui/core';
|
|
12
|
+
import '@mui/material/Stack';
|
|
13
|
+
import '../routes.esm.js';
|
|
14
|
+
import '../components/Admin/AdminPortal/AdminPortal.esm.js';
|
|
15
|
+
import { AnnouncementsContent } from '../components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js';
|
|
16
|
+
import { AnnouncementsPage } from '../components/AnnouncementsPage/AnnouncementsPage.esm.js';
|
|
17
|
+
import { AnnouncementPage } from '../components/AnnouncementPage/AnnouncementPage.esm.js';
|
|
18
|
+
import { CategoriesContent } from '../components/Admin/CategoriesContent/CategoriesContent.esm.js';
|
|
19
|
+
import { TagsContent } from '../components/Admin/TagsContent/TagsContent.esm.js';
|
|
20
|
+
|
|
21
|
+
const Router = (props) => {
|
|
22
|
+
const propsWithDefaults = {
|
|
23
|
+
themeId: "home",
|
|
24
|
+
title: "Announcements",
|
|
25
|
+
hideInactive: false,
|
|
26
|
+
hideStartAt: false,
|
|
27
|
+
markdownRenderer: "backstage",
|
|
28
|
+
...props
|
|
29
|
+
};
|
|
30
|
+
const announcementPageProps = {
|
|
31
|
+
themeId: propsWithDefaults.themeId,
|
|
32
|
+
title: propsWithDefaults.title,
|
|
33
|
+
subtitle: propsWithDefaults.subtitle,
|
|
34
|
+
markdownRenderer: propsWithDefaults.markdownRenderer,
|
|
35
|
+
titleLength: props.cardOptions?.titleLength
|
|
36
|
+
};
|
|
37
|
+
return /* @__PURE__ */ jsxs(Routes, { children: [
|
|
38
|
+
/* @__PURE__ */ jsx(Route, { path: "/", element: /* @__PURE__ */ jsx(AnnouncementsPage, { ...propsWithDefaults }) }),
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
Route,
|
|
41
|
+
{
|
|
42
|
+
path: "/view/:id",
|
|
43
|
+
element: /* @__PURE__ */ jsx(AnnouncementPage, { ...announcementPageProps })
|
|
44
|
+
}
|
|
45
|
+
),
|
|
46
|
+
/* @__PURE__ */ jsxs(
|
|
47
|
+
Route,
|
|
48
|
+
{
|
|
49
|
+
path: "/admin",
|
|
50
|
+
element: /* @__PURE__ */ jsx(RequirePermission, { permission: announcementCreatePermission, children: /* @__PURE__ */ jsx(
|
|
51
|
+
AnnouncementsAdminPage,
|
|
52
|
+
{
|
|
53
|
+
title: props.title,
|
|
54
|
+
defaultInactive: props.defaultInactive
|
|
55
|
+
}
|
|
56
|
+
) }),
|
|
57
|
+
children: [
|
|
58
|
+
/* @__PURE__ */ jsx(
|
|
59
|
+
Route,
|
|
60
|
+
{
|
|
61
|
+
path: "",
|
|
62
|
+
element: /* @__PURE__ */ jsx(AnnouncementsContent, { defaultInactive: props.defaultInactive })
|
|
63
|
+
}
|
|
64
|
+
),
|
|
65
|
+
/* @__PURE__ */ jsx(Route, { path: "categories", element: /* @__PURE__ */ jsx(CategoriesContent, {}) }),
|
|
66
|
+
/* @__PURE__ */ jsx(Route, { path: "tags", element: /* @__PURE__ */ jsx(TagsContent, {}) })
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
] });
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export { Router };
|
|
74
|
+
//# sourceMappingURL=Router.esm.js.map
|
|
@@ -0,0 +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 { AnnouncementsAdminPage } from './components/admin/AnnouncementsAdminPage';\nimport { AnnouncementsContent, MarkdownRendererTypeProps } from '../components';\nimport {\n AnnouncementsPage,\n AnnouncementsPageProps,\n} from '../components/AnnouncementsPage';\nimport { AnnouncementPage } from '../components/AnnouncementPage';\nimport { CategoriesContent } from '../components/Admin/CategoriesContent';\nimport { TagsContent } from '../components/Admin/TagsContent';\n\ntype RouterProps = {\n themeId?: string;\n title?: string;\n subtitle?: string;\n category?: string;\n hideContextMenu?: boolean;\n cardOptions?: {\n titleLength: number | undefined;\n };\n buttonOptions?: {\n name: string | undefined;\n };\n hideInactive?: boolean;\n hideStartAt?: boolean;\n markdownRenderer?: MarkdownRendererTypeProps;\n defaultInactive?: boolean;\n};\n\nexport const Router = (props: RouterProps) => {\n const propsWithDefaults: AnnouncementsPageProps = {\n themeId: 'home',\n title: 'Announcements',\n hideInactive: false,\n hideStartAt: false,\n markdownRenderer: 'backstage',\n ...props,\n };\n\n // Extract props for AnnouncementPage\n const announcementPageProps = {\n themeId: propsWithDefaults.themeId,\n title: propsWithDefaults.title,\n subtitle: propsWithDefaults.subtitle,\n markdownRenderer: propsWithDefaults.markdownRenderer,\n titleLength: props.cardOptions?.titleLength,\n };\n\n return (\n <Routes>\n <Route path=\"/\" element={<AnnouncementsPage {...propsWithDefaults} />} />\n <Route\n path=\"/view/:id\"\n element={<AnnouncementPage {...announcementPageProps} />}\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":";;;;;;;;;;;;;;;;;;;;AA8Ca,MAAA,MAAA,GAAS,CAAC,KAAuB,KAAA;AAC5C,EAAA,MAAM,iBAA4C,GAAA;AAAA,IAChD,OAAS,EAAA,MAAA;AAAA,IACT,KAAO,EAAA,eAAA;AAAA,IACP,YAAc,EAAA,KAAA;AAAA,IACd,WAAa,EAAA,KAAA;AAAA,IACb,gBAAkB,EAAA,WAAA;AAAA,IAClB,GAAG;AAAA,GACL;AAGA,EAAA,MAAM,qBAAwB,GAAA;AAAA,IAC5B,SAAS,iBAAkB,CAAA,OAAA;AAAA,IAC3B,OAAO,iBAAkB,CAAA,KAAA;AAAA,IACzB,UAAU,iBAAkB,CAAA,QAAA;AAAA,IAC5B,kBAAkB,iBAAkB,CAAA,gBAAA;AAAA,IACpC,WAAA,EAAa,MAAM,WAAa,EAAA;AAAA,GAClC;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,OAAS,kBAAA,GAAA,CAAC,gBAAkB,EAAA,EAAA,GAAG,qBAAuB,EAAA;AAAA;AAAA,KACxD;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;;;;"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { HeaderPage, Container } from '@backstage/ui';
|
|
3
|
+
import { Outlet } from 'react-router-dom';
|
|
4
|
+
import { useRouteRef } from '@backstage/core-plugin-api';
|
|
5
|
+
import { rootRouteRef, announcementAdminRouteRef, adminCategoriesRouteRef, adminTagsRouteRef } from '../../../routes.esm.js';
|
|
6
|
+
|
|
7
|
+
function AnnouncementsAdminPage(props) {
|
|
8
|
+
const { title } = props;
|
|
9
|
+
const announcementsRoute = useRouteRef(rootRouteRef);
|
|
10
|
+
const adminRoute = useRouteRef(announcementAdminRouteRef);
|
|
11
|
+
const adminCategoriesRoute = useRouteRef(adminCategoriesRouteRef);
|
|
12
|
+
const adminTagsRoute = useRouteRef(adminTagsRouteRef);
|
|
13
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14
|
+
/* @__PURE__ */ jsx(
|
|
15
|
+
HeaderPage,
|
|
16
|
+
{
|
|
17
|
+
title: title ?? "Admin Portal",
|
|
18
|
+
breadcrumbs: [{ label: "Announcements", href: announcementsRoute() }],
|
|
19
|
+
tabs: [
|
|
20
|
+
{
|
|
21
|
+
id: "announcements",
|
|
22
|
+
label: "Announcements",
|
|
23
|
+
href: adminRoute()
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "categories",
|
|
27
|
+
label: "Categories",
|
|
28
|
+
href: adminCategoriesRoute()
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "tags",
|
|
32
|
+
label: "Tags",
|
|
33
|
+
href: adminTagsRoute()
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
/* @__PURE__ */ jsx(Container, { "data-testid": "announcements-admin-page-container-outlet", children: /* @__PURE__ */ jsx(Outlet, {}) })
|
|
39
|
+
] });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { AnnouncementsAdminPage };
|
|
43
|
+
//# sourceMappingURL=AnnouncementsAdminPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnnouncementsAdminPage.esm.js","sources":["../../../../src/alpha/components/admin/AnnouncementsAdminPage.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Container, HeaderPage } from '@backstage/ui';\nimport { Outlet } from 'react-router-dom';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport {\n adminCategoriesRouteRef,\n announcementAdminRouteRef,\n adminTagsRouteRef,\n rootRouteRef,\n} from '../../../routes';\n\nexport type AnnouncementsAdminPageProps = {\n title?: string;\n defaultInactive?: boolean;\n};\n\nexport function AnnouncementsAdminPage(props: AnnouncementsAdminPageProps) {\n const { title } = props;\n\n const announcementsRoute = useRouteRef(rootRouteRef);\n const adminRoute = useRouteRef(announcementAdminRouteRef);\n const adminCategoriesRoute = useRouteRef(adminCategoriesRouteRef);\n const adminTagsRoute = useRouteRef(adminTagsRouteRef);\n\n return (\n <>\n <HeaderPage\n title={title ?? 'Admin Portal'}\n breadcrumbs={[{ label: 'Announcements', href: announcementsRoute() }]}\n tabs={[\n {\n id: 'announcements',\n label: 'Announcements',\n href: adminRoute(),\n },\n {\n id: 'categories',\n label: 'Categories',\n href: adminCategoriesRoute(),\n },\n {\n id: 'tags',\n label: 'Tags',\n href: adminTagsRoute(),\n },\n ]}\n />\n\n <Container data-testid=\"announcements-admin-page-container-outlet\">\n <Outlet />\n </Container>\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;AA8BO,SAAS,uBAAuB,KAAoC,EAAA;AACzE,EAAM,MAAA,EAAE,OAAU,GAAA,KAAA;AAElB,EAAM,MAAA,kBAAA,GAAqB,YAAY,YAAY,CAAA;AACnD,EAAM,MAAA,UAAA,GAAa,YAAY,yBAAyB,CAAA;AACxD,EAAM,MAAA,oBAAA,GAAuB,YAAY,uBAAuB,CAAA;AAChE,EAAM,MAAA,cAAA,GAAiB,YAAY,iBAAiB,CAAA;AAEpD,EAAA,uBAEI,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,OAAO,KAAS,IAAA,cAAA;AAAA,QAChB,WAAA,EAAa,CAAC,EAAE,KAAA,EAAO,iBAAiB,IAAM,EAAA,kBAAA,IAAsB,CAAA;AAAA,QACpE,IAAM,EAAA;AAAA,UACJ;AAAA,YACE,EAAI,EAAA,eAAA;AAAA,YACJ,KAAO,EAAA,eAAA;AAAA,YACP,MAAM,UAAW;AAAA,WACnB;AAAA,UACA;AAAA,YACE,EAAI,EAAA,YAAA;AAAA,YACJ,KAAO,EAAA,YAAA;AAAA,YACP,MAAM,oBAAqB;AAAA,WAC7B;AAAA,UACA;AAAA,YACE,EAAI,EAAA,MAAA;AAAA,YACJ,KAAO,EAAA,MAAA;AAAA,YACP,MAAM,cAAe;AAAA;AACvB;AACF;AAAA,KACF;AAAA,wBAEC,SAAU,EAAA,EAAA,aAAA,EAAY,2CACrB,EAAA,QAAA,kBAAA,GAAA,CAAC,UAAO,CACV,EAAA;AAAA,GACF,EAAA,CAAA;AAEJ;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NavItemBlueprint } from '@backstage/frontend-plugin-api
|
|
1
|
+
import { NavItemBlueprint } from '@backstage/frontend-plugin-api';
|
|
2
2
|
import { convertLegacyRouteRef } from '@backstage/core-compat-api';
|
|
3
3
|
import { rootRouteRef } from '../routes.esm.js';
|
|
4
4
|
import RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navItems.esm.js","sources":["../../src/alpha/navItems.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 { NavItemBlueprint } from '@backstage/frontend-plugin-api
|
|
1
|
+
{"version":3,"file":"navItems.esm.js","sources":["../../src/alpha/navItems.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 { NavItemBlueprint } from '@backstage/frontend-plugin-api';\nimport { convertLegacyRouteRef } from '@backstage/core-compat-api';\nimport { rootRouteRef } from '../routes';\nimport RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';\n\n/**\n * @alpha\n */\nexport const announcementsNavItem = NavItemBlueprint.make({\n params: {\n title: 'Announcements',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n icon: RecordVoiceOverIcon,\n },\n});\n\nexport default [announcementsNavItem];\n"],"names":[],"mappings":";;;;;AAuBa,MAAA,oBAAA,GAAuB,iBAAiB,IAAK,CAAA;AAAA,EACxD,MAAQ,EAAA;AAAA,IACN,KAAO,EAAA,eAAA;AAAA,IACP,QAAA,EAAU,sBAAsB,YAAY,CAAA;AAAA,IAC5C,IAAM,EAAA;AAAA;AAEV,CAAC;;;;"}
|
package/dist/alpha/pages.esm.js
CHANGED
|
@@ -7,7 +7,7 @@ const announcementsPage = PageBlueprint.make({
|
|
|
7
7
|
params: {
|
|
8
8
|
path: "/announcements",
|
|
9
9
|
routeRef: convertLegacyRouteRef(rootRouteRef),
|
|
10
|
-
loader: async () => import('
|
|
10
|
+
loader: async () => import('./Router.esm.js').then((m) => compatWrapper(/* @__PURE__ */ jsx(m.Router, {})))
|
|
11
11
|
}
|
|
12
12
|
});
|
|
13
13
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.esm.js","sources":["../../src/alpha/pages.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 {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport { PageBlueprint } from '@backstage/frontend-plugin-api';\nimport { rootRouteRef } from '../routes';\n\n/**\n * @alpha\n */\nexport const announcementsPage = PageBlueprint.make({\n params: {\n path: '/announcements',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n loader: async () =>\n import('
|
|
1
|
+
{"version":3,"file":"pages.esm.js","sources":["../../src/alpha/pages.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 {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport { PageBlueprint } from '@backstage/frontend-plugin-api';\nimport { rootRouteRef } from '../routes';\n\n/**\n * @alpha\n */\nexport const announcementsPage = PageBlueprint.make({\n params: {\n path: '/announcements',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n loader: async () =>\n import('./Router').then(m => compatWrapper(<m.Router />)),\n },\n});\n"],"names":[],"mappings":";;;;;AAyBa,MAAA,iBAAA,GAAoB,cAAc,IAAK,CAAA;AAAA,EAClD,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,gBAAA;AAAA,IACN,QAAA,EAAU,sBAAsB,YAAY,CAAA;AAAA,IAC5C,MAAQ,EAAA,YACN,OAAO,iBAAU,CAAE,CAAA,IAAA,CAAK,CAAK,CAAA,KAAA,aAAA,iBAAe,GAAA,CAAA,CAAA,CAAE,MAAF,EAAA,EAAS,CAAE,CAAC;AAAA;AAE9D,CAAC;;;;"}
|
package/dist/alpha.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ import * as _backstage_plugin_search_react_alpha from '@backstage/plugin-search-
|
|
|
3
3
|
import * as _backstage_catalog_model from '@backstage/catalog-model';
|
|
4
4
|
import * as _backstage_plugin_catalog_react_alpha from '@backstage/plugin-catalog-react/alpha';
|
|
5
5
|
import * as react from 'react';
|
|
6
|
-
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
7
6
|
import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -17,11 +16,11 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
|
|
|
17
16
|
name: undefined;
|
|
18
17
|
config: {};
|
|
19
18
|
configInput: {};
|
|
20
|
-
output: _backstage_frontend_plugin_api.ExtensionDataRef<
|
|
19
|
+
output: _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.AnyApiFactory, "core.api.factory", {}>;
|
|
21
20
|
inputs: {};
|
|
22
21
|
params: <TApi, TImpl extends TApi, TDeps extends {
|
|
23
22
|
[x: string]: unknown;
|
|
24
|
-
}>(params:
|
|
23
|
+
}>(params: _backstage_frontend_plugin_api.ApiFactory<TApi, TImpl, TDeps>) => _backstage_frontend_plugin_api.ExtensionBlueprintParams<_backstage_frontend_plugin_api.AnyApiFactory>;
|
|
25
24
|
}>;
|
|
26
25
|
"app-root-element:announcements/banner": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
|
|
27
26
|
config: {
|
|
@@ -41,14 +40,7 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
|
|
|
41
40
|
category?: string | undefined;
|
|
42
41
|
};
|
|
43
42
|
output: _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}>;
|
|
44
|
-
inputs: {
|
|
45
|
-
[x: string]: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ExtensionDataRef<unknown, string, {
|
|
46
|
-
optional?: true | undefined;
|
|
47
|
-
}>, {
|
|
48
|
-
singleton: boolean;
|
|
49
|
-
optional: boolean;
|
|
50
|
-
}>;
|
|
51
|
-
};
|
|
43
|
+
inputs: {};
|
|
52
44
|
kind: "app-root-element";
|
|
53
45
|
name: "banner";
|
|
54
46
|
params: {
|
|
@@ -87,13 +79,13 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
|
|
|
87
79
|
configInput: {};
|
|
88
80
|
output: _backstage_frontend_plugin_api.ExtensionDataRef<{
|
|
89
81
|
title: string;
|
|
90
|
-
icon:
|
|
82
|
+
icon: _backstage_frontend_plugin_api.IconComponent;
|
|
91
83
|
routeRef: _backstage_frontend_plugin_api.RouteRef<undefined>;
|
|
92
84
|
}, "core.nav-item.target", {}>;
|
|
93
85
|
inputs: {};
|
|
94
86
|
params: {
|
|
95
87
|
title: string;
|
|
96
|
-
icon:
|
|
88
|
+
icon: _backstage_frontend_plugin_api.IconComponent;
|
|
97
89
|
routeRef: _backstage_frontend_plugin_api.RouteRef<undefined>;
|
|
98
90
|
};
|
|
99
91
|
}>;
|
package/dist/alpha.esm.js
CHANGED
|
@@ -4,9 +4,9 @@ import { announcementsApiExtension } from './alpha/apis.esm.js';
|
|
|
4
4
|
import { entityAnnouncementsCard } from './alpha/entityCards.esm.js';
|
|
5
5
|
import { announcementsNavItem } from './alpha/navItems.esm.js';
|
|
6
6
|
import { announcementsPage } from './alpha/pages.esm.js';
|
|
7
|
+
import { announcementsBanner } from './alpha/banner.esm.js';
|
|
7
8
|
import { announcementsSearchResultListItem, announcementsSearchFilterResultType } from './alpha/search.esm.js';
|
|
8
9
|
import { rootRouteRef } from './routes.esm.js';
|
|
9
|
-
import { announcementsBanner } from './alpha/banner.esm.js';
|
|
10
10
|
|
|
11
11
|
var alpha = createFrontendPlugin({
|
|
12
12
|
pluginId: "announcements",
|
package/dist/alpha.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alpha.esm.js","sources":["../src/alpha.ts"],"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 { convertLegacyRouteRefs } from '@backstage/core-compat-api';\nimport { createFrontendPlugin } from '@backstage/frontend-plugin-api';\nimport { announcementsApiExtension } from './alpha/apis';\nimport { entityAnnouncementsCard } from './alpha/entityCards';\nimport { announcementsNavItem } from './alpha/navItems';\nimport { announcementsPage } from './alpha/pages';\nimport {\n announcementsSearchFilterResultType,\n announcementsSearchResultListItem,\n} from './alpha/search';\nimport { rootRouteRef } from './routes';\
|
|
1
|
+
{"version":3,"file":"alpha.esm.js","sources":["../src/alpha.ts"],"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 { convertLegacyRouteRefs } from '@backstage/core-compat-api';\nimport { createFrontendPlugin } from '@backstage/frontend-plugin-api';\nimport { announcementsApiExtension } from './alpha/apis';\nimport { entityAnnouncementsCard } from './alpha/entityCards';\nimport { announcementsNavItem } from './alpha/navItems';\nimport { announcementsPage } from './alpha/pages';\nimport { announcementsBanner } from './alpha/banner';\nimport {\n announcementsSearchFilterResultType,\n announcementsSearchResultListItem,\n} from './alpha/search';\nimport { rootRouteRef } from './routes';\n\n/**\n * @alpha\n */\nexport default createFrontendPlugin({\n pluginId: 'announcements',\n routes: convertLegacyRouteRefs({\n root: rootRouteRef,\n }),\n extensions: [\n announcementsApiExtension,\n entityAnnouncementsCard,\n announcementsPage,\n announcementsNavItem,\n announcementsSearchResultListItem,\n announcementsSearchFilterResultType,\n announcementsBanner,\n ],\n});\n"],"names":[],"mappings":";;;;;;;;;;AA+BA,YAAe,oBAAqB,CAAA;AAAA,EAClC,QAAU,EAAA,eAAA;AAAA,EACV,QAAQ,sBAAuB,CAAA;AAAA,IAC7B,IAAM,EAAA;AAAA,GACP,CAAA;AAAA,EACD,UAAY,EAAA;AAAA,IACV,yBAAA;AAAA,IACA,uBAAA;AAAA,IACA,iBAAA;AAAA,IACA,oBAAA;AAAA,IACA,iCAAA;AAAA,IACA,mCAAA;AAAA,IACA;AAAA;AAEJ,CAAC,CAAA;;;;"}
|
|
@@ -2,16 +2,16 @@ import { jsx, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import { useState, useMemo } from 'react';
|
|
3
3
|
import { Progress, ErrorPanel, StatusOK, StatusPending, Table } from '@backstage/core-components';
|
|
4
4
|
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
|
|
5
|
-
import { announcementsApiRef, useCategories, useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
|
|
6
|
-
import { announcementCreatePermission
|
|
5
|
+
import { announcementsApiRef, useCategories, useAnnouncementsTranslation, useAnnouncementsPermissions } from '@backstage-community/plugin-announcements-react';
|
|
6
|
+
import { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';
|
|
7
7
|
import useAsyncRetry from 'react-use/esm/useAsyncRetry';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { useDeleteDialogState } from '../shared/DeleteDialog/useDeleteDialogState.esm.js';
|
|
9
|
+
import { DeleteDialog } from '../shared/DeleteDialog/DeleteDialog.esm.js';
|
|
10
|
+
import { Typography, Box, IconButton, Grid, Button } from '@material-ui/core';
|
|
10
11
|
import { useNavigate } from 'react-router-dom';
|
|
11
12
|
import { AnnouncementForm } from './AnnouncementForm/AnnouncementForm.esm.js';
|
|
12
13
|
import slugify from 'slugify';
|
|
13
|
-
import {
|
|
14
|
-
import { Typography, Box, IconButton, Grid, Button } from '@material-ui/core';
|
|
14
|
+
import { RequirePermission } from '@backstage/plugin-permission-react';
|
|
15
15
|
import DeleteIcon from '@material-ui/icons/Delete';
|
|
16
16
|
import EditIcon from '@material-ui/icons/Edit';
|
|
17
17
|
import PreviewIcon from '@material-ui/icons/Visibility';
|
|
@@ -25,15 +25,7 @@ const AnnouncementsContent = ({
|
|
|
25
25
|
const navigate = useNavigate();
|
|
26
26
|
const { categories } = useCategories();
|
|
27
27
|
const { t } = useAnnouncementsTranslation();
|
|
28
|
-
const
|
|
29
|
-
permission: announcementCreatePermission
|
|
30
|
-
});
|
|
31
|
-
const { loading: loadingUpdatePermission, allowed: canUpdateAnnouncement } = usePermission({
|
|
32
|
-
permission: announcementUpdatePermission
|
|
33
|
-
});
|
|
34
|
-
const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } = usePermission({
|
|
35
|
-
permission: announcementDeletePermission
|
|
36
|
-
});
|
|
28
|
+
const permissions = useAnnouncementsPermissions();
|
|
37
29
|
const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] = useState(false);
|
|
38
30
|
const [editingAnnouncementId, setEditingAnnouncementId] = useState(null);
|
|
39
31
|
const {
|
|
@@ -46,8 +38,8 @@ const AnnouncementsContent = ({
|
|
|
46
38
|
isOpen: isDeleteDialogOpen,
|
|
47
39
|
open: openDeleteDialog,
|
|
48
40
|
close: closeDeleteDialog,
|
|
49
|
-
|
|
50
|
-
} =
|
|
41
|
+
item: announcementToDelete
|
|
42
|
+
} = useDeleteDialogState();
|
|
51
43
|
const onCreateButtonClick = () => {
|
|
52
44
|
setShowCreateAnnouncementForm(!showCreateAnnouncementForm);
|
|
53
45
|
setEditingAnnouncementId(null);
|
|
@@ -228,7 +220,7 @@ const AnnouncementsContent = ({
|
|
|
228
220
|
IconButton,
|
|
229
221
|
{
|
|
230
222
|
"aria-label": "edit",
|
|
231
|
-
disabled:
|
|
223
|
+
disabled: permissions.update.loading || !permissions.update.allowed || editingAnnouncementId === rowData.id,
|
|
232
224
|
onClick: () => onEdit(rowData),
|
|
233
225
|
size: "small",
|
|
234
226
|
children: /* @__PURE__ */ jsx(EditIcon, { fontSize: "small", "data-testid": "edit-icon" })
|
|
@@ -238,7 +230,7 @@ const AnnouncementsContent = ({
|
|
|
238
230
|
IconButton,
|
|
239
231
|
{
|
|
240
232
|
"aria-label": "delete",
|
|
241
|
-
disabled:
|
|
233
|
+
disabled: permissions.delete.loading || !permissions.delete.allowed,
|
|
242
234
|
onClick: () => openDeleteDialog(rowData),
|
|
243
235
|
size: "small",
|
|
244
236
|
children: /* @__PURE__ */ jsx(DeleteIcon, { fontSize: "small", "data-testid": "delete-icon" })
|
|
@@ -252,7 +244,7 @@ const AnnouncementsContent = ({
|
|
|
252
244
|
!editingAnnouncementId && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
|
|
253
245
|
Button,
|
|
254
246
|
{
|
|
255
|
-
disabled:
|
|
247
|
+
disabled: permissions.create.loading || !permissions.create.allowed,
|
|
256
248
|
variant: "contained",
|
|
257
249
|
onClick: () => onCreateButtonClick(),
|
|
258
250
|
children: showCreateAnnouncementForm ? t("admin.announcementsContent.cancelButton") : t("admin.announcementsContent.createButton")
|
|
@@ -298,9 +290,9 @@ const AnnouncementsContent = ({
|
|
|
298
290
|
}
|
|
299
291
|
),
|
|
300
292
|
/* @__PURE__ */ jsx(
|
|
301
|
-
|
|
293
|
+
DeleteDialog,
|
|
302
294
|
{
|
|
303
|
-
|
|
295
|
+
isOpen: isDeleteDialogOpen,
|
|
304
296
|
onCancel: onCancelDelete,
|
|
305
297
|
onConfirm: onConfirmDelete
|
|
306
298
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnnouncementsContent.esm.js","sources":["../../../../src/components/Admin/AnnouncementsContent/AnnouncementsContent.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useState, useMemo } from 'react';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n StatusOK,\n StatusPending,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n announcementsApiRef,\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n announcementCreatePermission,\n announcementDeletePermission,\n announcementUpdatePermission,\n Category,\n} from '@backstage-community/plugin-announcements-common';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\nimport { useDeleteAnnouncementDialogState } from './useDeleteAnnouncementDialogState';\nimport { DeleteAnnouncementDialog } from './DeleteAnnouncementDialog';\nimport { useNavigate } from 'react-router-dom';\nimport { AnnouncementForm } from './AnnouncementForm';\nimport slugify from 'slugify';\nimport {\n RequirePermission,\n usePermission,\n} from '@backstage/plugin-permission-react';\nimport { Box, Button, Grid, IconButton, Typography } from '@material-ui/core';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport PreviewIcon from '@material-ui/icons/Visibility';\nimport { DateTime } from 'luxon';\n\ntype AnnouncementsContentProps = {\n defaultInactive?: boolean;\n};\n\nexport const AnnouncementsContent = ({\n defaultInactive,\n}: AnnouncementsContentProps) => {\n const alertApi = useApi(alertApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const navigate = useNavigate();\n const { categories } = useCategories();\n const { t } = useAnnouncementsTranslation();\n\n const { loading: loadingCreatePermission, allowed: canCreateAnnouncement } =\n usePermission({\n permission: announcementCreatePermission,\n });\n\n const { loading: loadingUpdatePermission, allowed: canUpdateAnnouncement } =\n usePermission({\n permission: announcementUpdatePermission,\n });\n\n const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } =\n usePermission({\n permission: announcementDeletePermission,\n });\n\n const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] =\n useState(false);\n const [editingAnnouncementId, setEditingAnnouncementId] = useState<\n string | null\n >(null);\n\n const {\n loading,\n error,\n value: announcements,\n retry,\n } = useAsyncRetry(async () => await announcementsApi.announcements({}));\n\n const {\n isOpen: isDeleteDialogOpen,\n open: openDeleteDialog,\n close: closeDeleteDialog,\n announcement: announcementToDelete,\n } = useDeleteAnnouncementDialogState();\n\n const onCreateButtonClick = () => {\n setShowCreateAnnouncementForm(!showCreateAnnouncementForm);\n setEditingAnnouncementId(null);\n };\n\n const onTitleClick = (announcement: Announcement) => {\n navigate(`/announcements/view/${announcement.id}`);\n };\n\n const onEdit = (announcement: Announcement) => {\n setEditingAnnouncementId(announcement.id);\n setShowCreateAnnouncementForm(false);\n };\n\n const onCancelEdit = () => {\n setEditingAnnouncementId(null);\n };\n\n const onCancelDelete = () => {\n closeDeleteDialog();\n };\n const onConfirmDelete = async () => {\n closeDeleteDialog();\n\n try {\n await announcementsApi.deleteAnnouncementByID(announcementToDelete!.id);\n\n alertApi.post({ message: 'Announcement deleted.', severity: 'success' });\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n\n retry();\n };\n\n const onSubmit = async (request: CreateAnnouncementRequest) => {\n const { category } = request;\n\n const slugs = categories.map((c: Category) => c.slug);\n let alertMsg = t('admin.announcementsContent.alertMessage') as string;\n\n try {\n if (category) {\n const categorySlug = slugify(category, {\n lower: true,\n });\n if (slugs.indexOf(categorySlug) === -1) {\n alertMsg = alertMsg.replace('.', '');\n alertMsg = `${alertMsg} ${t(\n 'admin.announcementsContent.alertMessageWithNewCategory',\n )} ${category}.`;\n\n await announcementsApi.createCategory({\n title: category,\n });\n }\n }\n\n await announcementsApi.createAnnouncement({\n ...request,\n category: request.category?.toLocaleLowerCase('en-US'),\n });\n alertApi.post({ message: alertMsg, severity: 'success' });\n\n setShowCreateAnnouncementForm(false);\n retry();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n const onUpdate = async (request: CreateAnnouncementRequest) => {\n if (!editingAnnouncementId) {\n return;\n }\n\n const { category } = request;\n\n const slugs = categories.map((c: Category) => c.slug);\n let updateMsg = t('editAnnouncementPage.updatedMessage') as string;\n\n try {\n if (category) {\n const categorySlug = slugify(category, {\n lower: true,\n });\n\n if (slugs.indexOf(categorySlug) === -1) {\n updateMsg = updateMsg.replace('.', '');\n updateMsg = `${updateMsg} ${t(\n 'editAnnouncementPage.updatedMessageWithNewCategory',\n )} ${category}.`;\n\n await announcementsApi.createCategory({\n title: category,\n });\n }\n }\n\n await announcementsApi.updateAnnouncement(editingAnnouncementId, request);\n alertApi.post({ message: updateMsg, severity: 'success' });\n\n setEditingAnnouncementId(null);\n retry();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n const announcementToEdit = useMemo(() => {\n if (!editingAnnouncementId || !announcements?.results) {\n return null;\n }\n return (\n announcements.results.find(a => a.id === editingAnnouncementId) ?? null\n );\n }, [editingAnnouncementId, announcements?.results]);\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n const columns: TableColumn<Announcement>[] = [\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.title')}</Typography>\n ),\n sorting: true,\n field: 'title',\n render: rowData => rowData.title,\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.body')}</Typography>\n ),\n sorting: true,\n field: 'body',\n render: rowData => rowData.body,\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.publisher')}\n </Typography>\n ),\n sorting: true,\n field: 'publisher',\n render: rowData => rowData.publisher,\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.onBehalfOf')}\n </Typography>\n ),\n sorting: true,\n field: 'on_behalf_of',\n render: rowData => rowData.on_behalf_of,\n },\n\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.category')}\n </Typography>\n ),\n sorting: true,\n field: 'category',\n render: rowData => rowData.category?.title ?? '',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.tags')}</Typography>\n ),\n sorting: true,\n field: 'tags',\n render: rowData => rowData.tags?.map(tag => tag.title).join(', ') || '',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.status')}</Typography>\n ),\n sorting: true,\n field: 'active',\n render: rowData =>\n rowData.active ? (\n <StatusOK>{t('admin.announcementsContent.table.active')}</StatusOK>\n ) : (\n <StatusPending>\n {t('admin.announcementsContent.table.inactive')}\n </StatusPending>\n ),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.created_at')}\n </Typography>\n ),\n sorting: true,\n field: 'created_at',\n type: 'date',\n render: rowData =>\n DateTime.fromISO(rowData.created_at).toFormat('M/d/yyyy'),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.start_at')}\n </Typography>\n ),\n sorting: true,\n field: 'start_at',\n type: 'date',\n render: rowData =>\n DateTime.fromISO(rowData.start_at).toFormat('M/d/yyyy'),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.until_date')}\n </Typography>\n ),\n sorting: true,\n field: 'until_date',\n type: 'date',\n render: rowData =>\n rowData?.until_date\n ? DateTime.fromISO(rowData.until_date).toFormat('M/d/yyyy')\n : '-',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.actions')}</Typography>\n ),\n render: rowData => {\n return (\n <Box display=\"flex\" flexDirection=\"row\">\n <IconButton\n aria-label=\"preview\"\n onClick={() => onTitleClick(rowData)}\n size=\"small\"\n >\n <PreviewIcon fontSize=\"small\" data-testid=\"preview\" />\n </IconButton>\n\n <IconButton\n aria-label=\"edit\"\n disabled={\n loadingUpdatePermission ||\n !canUpdateAnnouncement ||\n editingAnnouncementId === rowData.id\n }\n onClick={() => onEdit(rowData)}\n size=\"small\"\n >\n <EditIcon fontSize=\"small\" data-testid=\"edit-icon\" />\n </IconButton>\n\n <IconButton\n aria-label=\"delete\"\n disabled={loadingDeletePermission || !canDeleteAnnouncement}\n onClick={() => openDeleteDialog(rowData)}\n size=\"small\"\n >\n <DeleteIcon fontSize=\"small\" data-testid=\"delete-icon\" />\n </IconButton>\n </Box>\n );\n },\n },\n ];\n\n return (\n <RequirePermission permission={announcementCreatePermission}>\n <Grid container>\n {!editingAnnouncementId && (\n <Grid item xs={12}>\n <Button\n disabled={loadingCreatePermission || !canCreateAnnouncement}\n variant=\"contained\"\n onClick={() => onCreateButtonClick()}\n >\n {showCreateAnnouncementForm\n ? t('admin.announcementsContent.cancelButton')\n : t('admin.announcementsContent.createButton')}\n </Button>\n </Grid>\n )}\n\n {showCreateAnnouncementForm && (\n <Grid item xs={12}>\n <AnnouncementForm\n initialData={{ active: !defaultInactive } as Announcement}\n onSubmit={onSubmit}\n />\n </Grid>\n )}\n\n {editingAnnouncementId && announcementToEdit && (\n <Grid item xs={12}>\n <Box>\n <Box\n display=\"flex\"\n justifyContent=\"space-between\"\n style={{ marginBottom: 16 }}\n >\n <Typography variant=\"h6\">\n {t('announcementForm.editAnnouncement')}\n </Typography>\n <Button variant=\"outlined\" onClick={onCancelEdit} size=\"small\">\n {t('admin.announcementsContent.cancelButton')}\n </Button>\n </Box>\n <AnnouncementForm\n initialData={announcementToEdit}\n onSubmit={onUpdate}\n />\n </Box>\n </Grid>\n )}\n\n <Grid item xs={12}>\n <Table\n title={t('admin.announcementsContent.announcements')}\n options={{ pageSize: 20, search: true }}\n columns={columns}\n data={announcements?.results ?? []}\n emptyContent={\n <Typography style={{ padding: 2, textAlign: 'center' }}>\n {t('admin.announcementsContent.noAnnouncementsFound')}\n </Typography>\n }\n />\n\n <DeleteAnnouncementDialog\n open={isDeleteDialogOpen}\n onCancel={onCancelDelete}\n onConfirm={onConfirmDelete}\n />\n </Grid>\n </Grid>\n </RequirePermission>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnnouncementsContent.esm.js","sources":["../../../../src/components/Admin/AnnouncementsContent/AnnouncementsContent.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useState, useMemo } from 'react';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n StatusOK,\n StatusPending,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n announcementsApiRef,\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n useCategories,\n useAnnouncementsPermissions,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n announcementCreatePermission,\n Category,\n} from '@backstage-community/plugin-announcements-common';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\nimport { useDeleteDialogState, DeleteDialog } from '../shared';\nimport { useNavigate } from 'react-router-dom';\nimport { AnnouncementForm } from './AnnouncementForm';\nimport slugify from 'slugify';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { Box, Button, Grid, IconButton, Typography } from '@material-ui/core';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport PreviewIcon from '@material-ui/icons/Visibility';\nimport { DateTime } from 'luxon';\n\ntype AnnouncementsContentProps = {\n defaultInactive?: boolean;\n};\n\nexport const AnnouncementsContent = ({\n defaultInactive,\n}: AnnouncementsContentProps) => {\n const alertApi = useApi(alertApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const navigate = useNavigate();\n const { categories } = useCategories();\n const { t } = useAnnouncementsTranslation();\n const permissions = useAnnouncementsPermissions();\n\n const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] =\n useState(false);\n const [editingAnnouncementId, setEditingAnnouncementId] = useState<\n string | null\n >(null);\n\n const {\n loading,\n error,\n value: announcements,\n retry,\n } = useAsyncRetry(async () => await announcementsApi.announcements({}));\n\n const {\n isOpen: isDeleteDialogOpen,\n open: openDeleteDialog,\n close: closeDeleteDialog,\n item: announcementToDelete,\n } = useDeleteDialogState<Announcement>();\n\n const onCreateButtonClick = () => {\n setShowCreateAnnouncementForm(!showCreateAnnouncementForm);\n setEditingAnnouncementId(null);\n };\n\n const onTitleClick = (announcement: Announcement) => {\n navigate(`/announcements/view/${announcement.id}`);\n };\n\n const onEdit = (announcement: Announcement) => {\n setEditingAnnouncementId(announcement.id);\n setShowCreateAnnouncementForm(false);\n };\n\n const onCancelEdit = () => {\n setEditingAnnouncementId(null);\n };\n\n const onCancelDelete = () => {\n closeDeleteDialog();\n };\n const onConfirmDelete = async () => {\n closeDeleteDialog();\n\n try {\n await announcementsApi.deleteAnnouncementByID(announcementToDelete!.id);\n\n alertApi.post({ message: 'Announcement deleted.', severity: 'success' });\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n\n retry();\n };\n\n const onSubmit = async (request: CreateAnnouncementRequest) => {\n const { category } = request;\n\n const slugs = categories.map((c: Category) => c.slug);\n let alertMsg = t('admin.announcementsContent.alertMessage') as string;\n\n try {\n if (category) {\n const categorySlug = slugify(category, {\n lower: true,\n });\n if (slugs.indexOf(categorySlug) === -1) {\n alertMsg = alertMsg.replace('.', '');\n alertMsg = `${alertMsg} ${t(\n 'admin.announcementsContent.alertMessageWithNewCategory',\n )} ${category}.`;\n\n await announcementsApi.createCategory({\n title: category,\n });\n }\n }\n\n await announcementsApi.createAnnouncement({\n ...request,\n category: request.category?.toLocaleLowerCase('en-US'),\n });\n alertApi.post({ message: alertMsg, severity: 'success' });\n\n setShowCreateAnnouncementForm(false);\n retry();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n const onUpdate = async (request: CreateAnnouncementRequest) => {\n if (!editingAnnouncementId) {\n return;\n }\n\n const { category } = request;\n\n const slugs = categories.map((c: Category) => c.slug);\n let updateMsg = t('editAnnouncementPage.updatedMessage') as string;\n\n try {\n if (category) {\n const categorySlug = slugify(category, {\n lower: true,\n });\n\n if (slugs.indexOf(categorySlug) === -1) {\n updateMsg = updateMsg.replace('.', '');\n updateMsg = `${updateMsg} ${t(\n 'editAnnouncementPage.updatedMessageWithNewCategory',\n )} ${category}.`;\n\n await announcementsApi.createCategory({\n title: category,\n });\n }\n }\n\n await announcementsApi.updateAnnouncement(editingAnnouncementId, request);\n alertApi.post({ message: updateMsg, severity: 'success' });\n\n setEditingAnnouncementId(null);\n retry();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n const announcementToEdit = useMemo(() => {\n if (!editingAnnouncementId || !announcements?.results) {\n return null;\n }\n return (\n announcements.results.find(a => a.id === editingAnnouncementId) ?? null\n );\n }, [editingAnnouncementId, announcements?.results]);\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n const columns: TableColumn<Announcement>[] = [\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.title')}</Typography>\n ),\n sorting: true,\n field: 'title',\n render: rowData => rowData.title,\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.body')}</Typography>\n ),\n sorting: true,\n field: 'body',\n render: rowData => rowData.body,\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.publisher')}\n </Typography>\n ),\n sorting: true,\n field: 'publisher',\n render: rowData => rowData.publisher,\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.onBehalfOf')}\n </Typography>\n ),\n sorting: true,\n field: 'on_behalf_of',\n render: rowData => rowData.on_behalf_of,\n },\n\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.category')}\n </Typography>\n ),\n sorting: true,\n field: 'category',\n render: rowData => rowData.category?.title ?? '',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.tags')}</Typography>\n ),\n sorting: true,\n field: 'tags',\n render: rowData => rowData.tags?.map(tag => tag.title).join(', ') || '',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.status')}</Typography>\n ),\n sorting: true,\n field: 'active',\n render: rowData =>\n rowData.active ? (\n <StatusOK>{t('admin.announcementsContent.table.active')}</StatusOK>\n ) : (\n <StatusPending>\n {t('admin.announcementsContent.table.inactive')}\n </StatusPending>\n ),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.created_at')}\n </Typography>\n ),\n sorting: true,\n field: 'created_at',\n type: 'date',\n render: rowData =>\n DateTime.fromISO(rowData.created_at).toFormat('M/d/yyyy'),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.start_at')}\n </Typography>\n ),\n sorting: true,\n field: 'start_at',\n type: 'date',\n render: rowData =>\n DateTime.fromISO(rowData.start_at).toFormat('M/d/yyyy'),\n },\n {\n title: (\n <Typography>\n {t('admin.announcementsContent.table.until_date')}\n </Typography>\n ),\n sorting: true,\n field: 'until_date',\n type: 'date',\n render: rowData =>\n rowData?.until_date\n ? DateTime.fromISO(rowData.until_date).toFormat('M/d/yyyy')\n : '-',\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.actions')}</Typography>\n ),\n render: rowData => {\n return (\n <Box display=\"flex\" flexDirection=\"row\">\n <IconButton\n aria-label=\"preview\"\n onClick={() => onTitleClick(rowData)}\n size=\"small\"\n >\n <PreviewIcon fontSize=\"small\" data-testid=\"preview\" />\n </IconButton>\n\n <IconButton\n aria-label=\"edit\"\n disabled={\n permissions.update.loading ||\n !permissions.update.allowed ||\n editingAnnouncementId === rowData.id\n }\n onClick={() => onEdit(rowData)}\n size=\"small\"\n >\n <EditIcon fontSize=\"small\" data-testid=\"edit-icon\" />\n </IconButton>\n\n <IconButton\n aria-label=\"delete\"\n disabled={\n permissions.delete.loading || !permissions.delete.allowed\n }\n onClick={() => openDeleteDialog(rowData)}\n size=\"small\"\n >\n <DeleteIcon fontSize=\"small\" data-testid=\"delete-icon\" />\n </IconButton>\n </Box>\n );\n },\n },\n ];\n\n return (\n <RequirePermission permission={announcementCreatePermission}>\n <Grid container>\n {!editingAnnouncementId && (\n <Grid item xs={12}>\n <Button\n disabled={\n permissions.create.loading || !permissions.create.allowed\n }\n variant=\"contained\"\n onClick={() => onCreateButtonClick()}\n >\n {showCreateAnnouncementForm\n ? t('admin.announcementsContent.cancelButton')\n : t('admin.announcementsContent.createButton')}\n </Button>\n </Grid>\n )}\n\n {showCreateAnnouncementForm && (\n <Grid item xs={12}>\n <AnnouncementForm\n initialData={{ active: !defaultInactive } as Announcement}\n onSubmit={onSubmit}\n />\n </Grid>\n )}\n\n {editingAnnouncementId && announcementToEdit && (\n <Grid item xs={12}>\n <Box>\n <Box\n display=\"flex\"\n justifyContent=\"space-between\"\n style={{ marginBottom: 16 }}\n >\n <Typography variant=\"h6\">\n {t('announcementForm.editAnnouncement')}\n </Typography>\n <Button variant=\"outlined\" onClick={onCancelEdit} size=\"small\">\n {t('admin.announcementsContent.cancelButton')}\n </Button>\n </Box>\n <AnnouncementForm\n initialData={announcementToEdit}\n onSubmit={onUpdate}\n />\n </Box>\n </Grid>\n )}\n\n <Grid item xs={12}>\n <Table\n title={t('admin.announcementsContent.announcements')}\n options={{ pageSize: 20, search: true }}\n columns={columns}\n data={announcements?.results ?? []}\n emptyContent={\n <Typography style={{ padding: 2, textAlign: 'center' }}>\n {t('admin.announcementsContent.noAnnouncementsFound')}\n </Typography>\n }\n />\n\n <DeleteDialog\n isOpen={isDeleteDialogOpen}\n onCancel={onCancelDelete}\n onConfirm={onConfirmDelete}\n />\n </Grid>\n </Grid>\n </RequirePermission>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Progress, ErrorPanel, Table } from '@backstage/core-components';
|
|
4
|
-
import { useCategories, announcementsApiRef, useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
|
|
5
|
-
import { announcementCreatePermission
|
|
4
|
+
import { useCategories, announcementsApiRef, useAnnouncementsTranslation, useAnnouncementsPermissions } from '@backstage-community/plugin-announcements-react';
|
|
5
|
+
import { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';
|
|
6
6
|
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
|
|
7
|
-
import {
|
|
7
|
+
import { RequirePermission } from '@backstage/plugin-permission-react';
|
|
8
8
|
import { Typography, IconButton, Grid, Button } from '@material-ui/core';
|
|
9
9
|
import DeleteIcon from '@material-ui/icons/Delete';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { useDeleteDialogState } from '../shared/DeleteDialog/useDeleteDialogState.esm.js';
|
|
11
|
+
import { DeleteDialog } from '../shared/DeleteDialog/DeleteDialog.esm.js';
|
|
12
|
+
import { TitleForm } from '../shared/TitleForm/TitleForm.esm.js';
|
|
13
13
|
|
|
14
14
|
const CategoriesContent = () => {
|
|
15
15
|
const [showNewCategoryForm, setShowNewCategoryForm] = useState(false);
|
|
@@ -21,14 +21,15 @@ const CategoriesContent = () => {
|
|
|
21
21
|
isOpen: isDeleteDialogOpen,
|
|
22
22
|
open: openDeleteDialog,
|
|
23
23
|
close: closeDeleteDialog,
|
|
24
|
-
|
|
25
|
-
} =
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
item: categoryToDelete
|
|
25
|
+
} = useDeleteDialogState();
|
|
26
|
+
const permissions = useAnnouncementsPermissions();
|
|
27
|
+
const translationKeys = {
|
|
28
|
+
new: t("categoriesForm.newCategory"),
|
|
29
|
+
edit: t("categoriesForm.editCategory"),
|
|
30
|
+
titleLabel: t("categoriesForm.titleLabel"),
|
|
31
|
+
submit: t("categoriesForm.submit")
|
|
32
|
+
};
|
|
32
33
|
const onSubmit = async (request) => {
|
|
33
34
|
const { title } = request;
|
|
34
35
|
try {
|
|
@@ -92,7 +93,7 @@ const CategoriesContent = () => {
|
|
|
92
93
|
IconButton,
|
|
93
94
|
{
|
|
94
95
|
"aria-label": "delete",
|
|
95
|
-
disabled:
|
|
96
|
+
disabled: permissions.delete.loading || !permissions.delete.allowed,
|
|
96
97
|
onClick: () => openDeleteDialog(rowData),
|
|
97
98
|
children: /* @__PURE__ */ jsx(DeleteIcon, { fontSize: "small", "data-testid": "delete-icon" })
|
|
98
99
|
}
|
|
@@ -104,13 +105,19 @@ const CategoriesContent = () => {
|
|
|
104
105
|
/* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
|
|
105
106
|
Button,
|
|
106
107
|
{
|
|
107
|
-
disabled:
|
|
108
|
+
disabled: permissions.create.loading || !permissions.create.allowed,
|
|
108
109
|
variant: "contained",
|
|
109
110
|
onClick: () => onCreateButtonClick(),
|
|
110
111
|
children: showNewCategoryForm ? t("admin.categoriesContent.cancelButton") : t("admin.categoriesContent.createButton")
|
|
111
112
|
}
|
|
112
113
|
) }),
|
|
113
|
-
showNewCategoryForm && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
|
|
114
|
+
showNewCategoryForm && /* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
|
|
115
|
+
TitleForm,
|
|
116
|
+
{
|
|
117
|
+
translationKeys,
|
|
118
|
+
onSubmit
|
|
119
|
+
}
|
|
120
|
+
) }),
|
|
114
121
|
/* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
|
|
115
122
|
Table,
|
|
116
123
|
{
|
|
@@ -122,9 +129,9 @@ const CategoriesContent = () => {
|
|
|
122
129
|
}
|
|
123
130
|
) }),
|
|
124
131
|
/* @__PURE__ */ jsx(
|
|
125
|
-
|
|
132
|
+
DeleteDialog,
|
|
126
133
|
{
|
|
127
|
-
|
|
134
|
+
isOpen: isDeleteDialogOpen,
|
|
128
135
|
onCancel: onCancelDelete,
|
|
129
136
|
onConfirm: onConfirmDelete
|
|
130
137
|
}
|