@backstage-community/plugin-announcements 0.4.0 → 0.5.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 +15 -0
- package/dist/components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js +15 -0
- package/dist/components/Admin/AnnouncementsContent/AnnouncementsContent.esm.js.map +1 -1
- package/dist/components/AnnouncementForm/AnnouncementForm.esm.js +82 -75
- package/dist/components/AnnouncementForm/AnnouncementForm.esm.js.map +1 -1
- package/dist/components/AnnouncementForm/CategoryInput.esm.js.map +1 -1
- package/dist/components/AnnouncementsCard/AnnouncementsCard.esm.js +14 -7
- package/dist/components/AnnouncementsCard/AnnouncementsCard.esm.js.map +1 -1
- package/dist/components/AnnouncementsPage/AnnouncementsPage.esm.js +15 -7
- package/dist/components/AnnouncementsPage/AnnouncementsPage.esm.js.map +1 -1
- package/dist/components/AnnouncementsTimeline/AnnouncementsTimeline.esm.js +8 -2
- package/dist/components/AnnouncementsTimeline/AnnouncementsTimeline.esm.js.map +1 -1
- package/dist/components/Router.esm.js +4 -1
- package/dist/components/Router.esm.js.map +1 -1
- package/dist/index.d.ts +16 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @backstage-community/plugin-announcements
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 22d99d3: - Added a `start at` field to allow users to set the date when an announcement occurred.
|
|
8
|
+
- Announcements can now be sorted by `createdAt` (default) or `startAt` date, with customizable order (`desc` or `asc`).
|
|
9
|
+
- Updated the New Announcement form to accommodate `start at` and future fields.
|
|
10
|
+
- Added `Created at` and `Start at` columns to the admin view table.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [22d99d3]
|
|
15
|
+
- @backstage-community/plugin-announcements-common@0.3.0
|
|
16
|
+
- @backstage-community/plugin-announcements-react@0.4.0
|
|
17
|
+
|
|
3
18
|
## 0.4.0
|
|
4
19
|
|
|
5
20
|
### Minor Changes
|
|
@@ -14,6 +14,7 @@ import { Typography, IconButton, Grid, Button } from '@material-ui/core';
|
|
|
14
14
|
import DeleteIcon from '@material-ui/icons/Delete';
|
|
15
15
|
import EditIcon from '@material-ui/icons/Edit';
|
|
16
16
|
import PreviewIcon from '@material-ui/icons/Visibility';
|
|
17
|
+
import { DateTime } from 'luxon';
|
|
17
18
|
|
|
18
19
|
const AnnouncementsContent = () => {
|
|
19
20
|
const alertApi = useApi(alertApiRef);
|
|
@@ -132,6 +133,20 @@ const AnnouncementsContent = () => {
|
|
|
132
133
|
field: "category",
|
|
133
134
|
render: (rowData) => rowData.active ? t("admin.announcementsContent.table.active") : t("admin.announcementsContent.table.inactive")
|
|
134
135
|
},
|
|
136
|
+
{
|
|
137
|
+
title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announcementsContent.table.created_at")),
|
|
138
|
+
sorting: true,
|
|
139
|
+
field: "created_at",
|
|
140
|
+
type: "date",
|
|
141
|
+
render: (rowData) => DateTime.fromISO(rowData.created_at).toFormat("M/d/yyyy")
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announcementsContent.table.start_at")),
|
|
145
|
+
sorting: true,
|
|
146
|
+
field: "start_at",
|
|
147
|
+
type: "date",
|
|
148
|
+
render: (rowData) => DateTime.fromISO(rowData.start_at).toFormat("M/d/yyyy")
|
|
149
|
+
},
|
|
135
150
|
{
|
|
136
151
|
title: /* @__PURE__ */ React__default.createElement(Typography, null, t("admin.announcementsContent.table.actions")),
|
|
137
152
|
render: (rowData) => {
|
|
@@ -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 React, { useState } from 'react';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n announcementsApiRef,\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n announcementCreatePermission,\n announcementDeletePermission,\n announcementUpdatePermission,\n Category,\n} from '@backstage-community/plugin-announcements-common';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\nimport { useDeleteAnnouncementDialogState } from '../../AnnouncementsPage/useDeleteAnnouncementDialogState';\nimport { DeleteAnnouncementDialog } from '../../AnnouncementsPage/DeleteAnnouncementDialog';\nimport { useNavigate } from 'react-router-dom';\nimport { AnnouncementForm } from '../../AnnouncementForm';\nimport slugify from 'slugify';\nimport {\n RequirePermission,\n usePermission,\n} from '@backstage/plugin-permission-react';\nimport { Button, Grid, IconButton, Typography } from '@material-ui/core';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport PreviewIcon from '@material-ui/icons/Visibility';\n\nexport const AnnouncementsContent = () => {\n const alertApi = useApi(alertApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const navigate = useNavigate();\n const { categories } = useCategories();\n const { t } = useAnnouncementsTranslation();\n\n const { loading: loadingCreatePermission, allowed: canCreateAnnouncement } =\n usePermission({\n permission: announcementCreatePermission,\n });\n\n const { loading: loadingUpdatePermission, allowed: canUpdateAnnouncement } =\n usePermission({\n permission: announcementUpdatePermission,\n });\n\n const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } =\n usePermission({\n permission: announcementDeletePermission,\n });\n\n const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] =\n useState(false);\n\n const {\n loading,\n error,\n value: announcements,\n retry,\n } = useAsyncRetry(async () => await announcementsApi.announcements({}));\n\n const {\n isOpen: isDeleteDialogOpen,\n open: openDeleteDialog,\n close: closeDeleteDialog,\n announcement: announcementToDelete,\n } = useDeleteAnnouncementDialogState();\n\n const onCreateButtonClick = () => {\n setShowCreateAnnouncementForm(!showCreateAnnouncementForm);\n };\n\n const onTitleClick = (announcement: Announcement) => {\n navigate(`/announcements/view/${announcement.id}`);\n };\n\n const onEdit = (announcement: Announcement) => {\n navigate(`/announcements/edit/${announcement.id}`);\n };\n\n const onCancelDelete = () => {\n closeDeleteDialog();\n };\n const onConfirmDelete = async () => {\n closeDeleteDialog();\n\n try {\n await announcementsApi.deleteAnnouncementByID(announcementToDelete!.id);\n\n alertApi.post({ message: 'Announcement deleted.', severity: 'success' });\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n\n retry();\n };\n\n const onSubmit = async (request: CreateAnnouncementRequest) => {\n const { category } = request;\n\n const slugs = categories.map((c: Category) => c.slug);\n let alertMsg = t('admin.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.alertMessage',\n )} ${category}.`;\n\n await announcementsApi.createCategory({\n title: category,\n });\n }\n }\n\n await announcementsApi.createAnnouncement({\n ...request,\n category: request.category?.toLocaleLowerCase('en-US'),\n });\n alertApi.post({ message: alertMsg, severity: 'success' });\n\n setShowCreateAnnouncementForm(false);\n retry();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n const columns: TableColumn<Announcement>[] = [\n {\n title: (\n <Typography>{t('admin.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.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.status')}</Typography>\n ),\n sorting: true,\n field: 'category',\n render: rowData =>\n rowData.active\n ? t('admin.announcementsContent.table.active')\n : t('admin.announcementsContent.table.inactive'),\n },\n {\n title: (\n <Typography>{t('admin.announcementsContent.table.actions')}</Typography>\n ),\n render: rowData => {\n return (\n <>\n <IconButton\n aria-label=\"preview\"\n onClick={() => onTitleClick(rowData)}\n >\n <PreviewIcon fontSize=\"small\" data-testid=\"preview\" />\n </IconButton>\n\n <IconButton\n aria-label=\"edit\"\n disabled={loadingUpdatePermission || !canUpdateAnnouncement}\n onClick={() => onEdit(rowData)}\n >\n <EditIcon fontSize=\"small\" data-testid=\"edit-icon\" />\n </IconButton>\n\n <IconButton\n aria-label=\"delete\"\n disabled={loadingDeletePermission || !canDeleteAnnouncement}\n onClick={() => openDeleteDialog(rowData)}\n >\n <DeleteIcon fontSize=\"small\" data-testid=\"delete-icon\" />\n </IconButton>\n </>\n );\n },\n },\n ];\n\n return (\n <RequirePermission permission={announcementCreatePermission}>\n <Grid container>\n <Grid item xs={12}>\n <Button\n disabled={loadingCreatePermission || !canCreateAnnouncement}\n variant=\"contained\"\n onClick={() => onCreateButtonClick()}\n >\n {showCreateAnnouncementForm\n ? t('admin.announcementsContent.cancelButton')\n : t('admin.announcementsContent.createButton')}\n </Button>\n </Grid>\n\n {showCreateAnnouncementForm && (\n <Grid item xs={12}>\n <AnnouncementForm\n initialData={{} as Announcement}\n onSubmit={onSubmit}\n />\n </Grid>\n )}\n\n <Grid item xs={12}>\n <Table\n title={t('admin.announcementsContent.announcements')}\n options={{ pageSize: 20, search: true }}\n columns={columns}\n data={announcements?.results ?? []}\n emptyContent={\n <Typography style={{ padding: 2 }}>\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":["React"],"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 React, { useState } from 'react';\nimport {\n ErrorPanel,\n Progress,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n announcementsApiRef,\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n announcementCreatePermission,\n announcementDeletePermission,\n announcementUpdatePermission,\n Category,\n} from '@backstage-community/plugin-announcements-common';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\nimport { useDeleteAnnouncementDialogState } from '../../AnnouncementsPage/useDeleteAnnouncementDialogState';\nimport { DeleteAnnouncementDialog } from '../../AnnouncementsPage/DeleteAnnouncementDialog';\nimport { useNavigate } from 'react-router-dom';\nimport { AnnouncementForm } from '../../AnnouncementForm';\nimport slugify from 'slugify';\nimport {\n RequirePermission,\n usePermission,\n} from '@backstage/plugin-permission-react';\nimport { Button, Grid, IconButton, Typography } from '@material-ui/core';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport PreviewIcon from '@material-ui/icons/Visibility';\nimport { DateTime } from 'luxon';\n\nexport const AnnouncementsContent = () => {\n const alertApi = useApi(alertApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const navigate = useNavigate();\n const { categories } = useCategories();\n const { t } = useAnnouncementsTranslation();\n\n const { loading: loadingCreatePermission, allowed: canCreateAnnouncement } =\n usePermission({\n permission: announcementCreatePermission,\n });\n\n const { loading: loadingUpdatePermission, allowed: canUpdateAnnouncement } =\n usePermission({\n permission: announcementUpdatePermission,\n });\n\n const { loading: loadingDeletePermission, allowed: canDeleteAnnouncement } =\n usePermission({\n permission: announcementDeletePermission,\n });\n\n const [showCreateAnnouncementForm, setShowCreateAnnouncementForm] =\n useState(false);\n\n const {\n loading,\n error,\n value: announcements,\n retry,\n } = useAsyncRetry(async () => await announcementsApi.announcements({}));\n\n const {\n isOpen: isDeleteDialogOpen,\n open: openDeleteDialog,\n close: closeDeleteDialog,\n announcement: announcementToDelete,\n } = useDeleteAnnouncementDialogState();\n\n const onCreateButtonClick = () => {\n setShowCreateAnnouncementForm(!showCreateAnnouncementForm);\n };\n\n const onTitleClick = (announcement: Announcement) => {\n navigate(`/announcements/view/${announcement.id}`);\n };\n\n const onEdit = (announcement: Announcement) => {\n navigate(`/announcements/edit/${announcement.id}`);\n };\n\n const onCancelDelete = () => {\n closeDeleteDialog();\n };\n const onConfirmDelete = async () => {\n closeDeleteDialog();\n\n try {\n await announcementsApi.deleteAnnouncementByID(announcementToDelete!.id);\n\n alertApi.post({ message: 'Announcement deleted.', severity: 'success' });\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n\n retry();\n };\n\n const onSubmit = async (request: CreateAnnouncementRequest) => {\n const { category } = request;\n\n const slugs = categories.map((c: Category) => c.slug);\n let alertMsg = t('admin.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.alertMessage',\n )} ${category}.`;\n\n await announcementsApi.createCategory({\n title: category,\n });\n }\n }\n\n await announcementsApi.createAnnouncement({\n ...request,\n category: request.category?.toLocaleLowerCase('en-US'),\n });\n alertApi.post({ message: alertMsg, severity: 'success' });\n\n setShowCreateAnnouncementForm(false);\n retry();\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n };\n\n if (loading) {\n return <Progress />;\n }\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n const columns: TableColumn<Announcement>[] = [\n {\n title: (\n <Typography>{t('admin.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.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.status')}</Typography>\n ),\n sorting: true,\n field: 'category',\n render: rowData =>\n rowData.active\n ? t('admin.announcementsContent.table.active')\n : t('admin.announcementsContent.table.inactive'),\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>{t('admin.announcementsContent.table.actions')}</Typography>\n ),\n render: rowData => {\n return (\n <>\n <IconButton\n aria-label=\"preview\"\n onClick={() => onTitleClick(rowData)}\n >\n <PreviewIcon fontSize=\"small\" data-testid=\"preview\" />\n </IconButton>\n\n <IconButton\n aria-label=\"edit\"\n disabled={loadingUpdatePermission || !canUpdateAnnouncement}\n onClick={() => onEdit(rowData)}\n >\n <EditIcon fontSize=\"small\" data-testid=\"edit-icon\" />\n </IconButton>\n\n <IconButton\n aria-label=\"delete\"\n disabled={loadingDeletePermission || !canDeleteAnnouncement}\n onClick={() => openDeleteDialog(rowData)}\n >\n <DeleteIcon fontSize=\"small\" data-testid=\"delete-icon\" />\n </IconButton>\n </>\n );\n },\n },\n ];\n\n return (\n <RequirePermission permission={announcementCreatePermission}>\n <Grid container>\n <Grid item xs={12}>\n <Button\n disabled={loadingCreatePermission || !canCreateAnnouncement}\n variant=\"contained\"\n onClick={() => onCreateButtonClick()}\n >\n {showCreateAnnouncementForm\n ? t('admin.announcementsContent.cancelButton')\n : t('admin.announcementsContent.createButton')}\n </Button>\n </Grid>\n\n {showCreateAnnouncementForm && (\n <Grid item xs={12}>\n <AnnouncementForm\n initialData={{} as Announcement}\n onSubmit={onSubmit}\n />\n </Grid>\n )}\n\n <Grid item xs={12}>\n <Table\n title={t('admin.announcementsContent.announcements')}\n options={{ pageSize: 20, search: true }}\n columns={columns}\n data={announcements?.results ?? []}\n emptyContent={\n <Typography style={{ padding: 2 }}>\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":["React"],"mappings":"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"}
|
|
@@ -4,25 +4,21 @@ import { InfoCard } from '@backstage/core-components';
|
|
|
4
4
|
import { useApi, identityApiRef } from '@backstage/core-plugin-api';
|
|
5
5
|
import { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
|
|
6
6
|
import CategoryInput from './CategoryInput.esm.js';
|
|
7
|
-
import {
|
|
7
|
+
import { Box, Typography, Grid, TextField, Divider, FormGroup, FormControlLabel, Switch, Button } from '@material-ui/core';
|
|
8
|
+
import SaveAltIcon from '@material-ui/icons/SaveAlt';
|
|
9
|
+
import { DateTime } from 'luxon';
|
|
8
10
|
|
|
9
|
-
const useStyles = makeStyles((theme) => ({
|
|
10
|
-
formRoot: {
|
|
11
|
-
"& > *": {
|
|
12
|
-
margin: theme.spacing(1) ?? "8px"
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}));
|
|
16
11
|
const AnnouncementForm = ({
|
|
17
12
|
initialData,
|
|
18
13
|
onSubmit
|
|
19
14
|
}) => {
|
|
20
|
-
const classes = useStyles();
|
|
21
15
|
const identityApi = useApi(identityApiRef);
|
|
22
16
|
const { t } = useAnnouncementsTranslation();
|
|
17
|
+
const formattedStartAt = initialData.start_at ? DateTime.fromISO(initialData.start_at).toISODate() : DateTime.now().toISODate();
|
|
23
18
|
const [form, setForm] = React__default.useState({
|
|
24
19
|
...initialData,
|
|
25
|
-
category: initialData.category?.slug
|
|
20
|
+
category: initialData.category?.slug,
|
|
21
|
+
start_at: formattedStartAt || ""
|
|
26
22
|
});
|
|
27
23
|
const [loading, setLoading] = useState(false);
|
|
28
24
|
const handleChange = (event) => {
|
|
@@ -50,73 +46,84 @@ const AnnouncementForm = ({
|
|
|
50
46
|
await onSubmit(createRequest);
|
|
51
47
|
setLoading(false);
|
|
52
48
|
};
|
|
53
|
-
return /* @__PURE__ */ React__default.createElement(
|
|
54
|
-
|
|
49
|
+
return /* @__PURE__ */ React__default.createElement(InfoCard, null, /* @__PURE__ */ React__default.createElement(Box, { p: 3 }, /* @__PURE__ */ React__default.createElement(Typography, { variant: "h5", gutterBottom: true }, initialData.title ? t("announcementForm.editAnnouncement") : t("announcementForm.newAnnouncement")), /* @__PURE__ */ React__default.createElement("form", { onSubmit: handleSubmit }, /* @__PURE__ */ React__default.createElement(Grid, { container: true, spacing: 3 }, /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
|
|
50
|
+
TextField,
|
|
51
|
+
{
|
|
52
|
+
id: "title",
|
|
53
|
+
label: t("announcementForm.title"),
|
|
54
|
+
value: form.title,
|
|
55
|
+
onChange: handleChange,
|
|
56
|
+
variant: "outlined",
|
|
57
|
+
fullWidth: true,
|
|
58
|
+
required: true
|
|
59
|
+
}
|
|
60
|
+
)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12, sm: 6 }, /* @__PURE__ */ React__default.createElement(
|
|
61
|
+
CategoryInput,
|
|
62
|
+
{
|
|
63
|
+
setForm,
|
|
64
|
+
form,
|
|
65
|
+
initialValue: initialData.category?.title ?? ""
|
|
66
|
+
}
|
|
67
|
+
)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12, sm: 6 }, /* @__PURE__ */ React__default.createElement(
|
|
68
|
+
TextField,
|
|
69
|
+
{
|
|
70
|
+
variant: "outlined",
|
|
71
|
+
label: t("announcementForm.startAt"),
|
|
72
|
+
id: "start-at-date",
|
|
73
|
+
type: "date",
|
|
74
|
+
value: form.start_at,
|
|
75
|
+
InputLabelProps: { shrink: true },
|
|
76
|
+
required: true,
|
|
77
|
+
onChange: (e) => setForm({
|
|
78
|
+
...form,
|
|
79
|
+
start_at: e.target.value
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
|
|
83
|
+
TextField,
|
|
84
|
+
{
|
|
85
|
+
id: "excerpt",
|
|
86
|
+
label: t("announcementForm.excerpt"),
|
|
87
|
+
value: form.excerpt,
|
|
88
|
+
onChange: handleChange,
|
|
89
|
+
variant: "outlined",
|
|
90
|
+
fullWidth: true,
|
|
91
|
+
required: true,
|
|
92
|
+
multiline: true
|
|
93
|
+
}
|
|
94
|
+
)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(
|
|
95
|
+
MDEditor,
|
|
55
96
|
{
|
|
56
|
-
|
|
97
|
+
value: form.body,
|
|
98
|
+
style: { minHeight: "30rem" },
|
|
99
|
+
onChange: (value) => setForm({ ...form, ...{ body: value || "" } })
|
|
100
|
+
}
|
|
101
|
+
)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(Divider, null)), /* @__PURE__ */ React__default.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React__default.createElement(FormGroup, { row: true, style: { justifyContent: "flex-end" } }, /* @__PURE__ */ React__default.createElement(
|
|
102
|
+
FormControlLabel,
|
|
103
|
+
{
|
|
104
|
+
control: /* @__PURE__ */ React__default.createElement(
|
|
105
|
+
Switch,
|
|
106
|
+
{
|
|
107
|
+
name: "active",
|
|
108
|
+
checked: form.active,
|
|
109
|
+
onChange: handleChangeActive,
|
|
110
|
+
color: "primary"
|
|
111
|
+
}
|
|
112
|
+
),
|
|
113
|
+
label: t("announcementForm.active")
|
|
114
|
+
}
|
|
115
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
116
|
+
Button,
|
|
117
|
+
{
|
|
118
|
+
variant: "contained",
|
|
119
|
+
color: "primary",
|
|
120
|
+
type: "submit",
|
|
121
|
+
disabled: loading || !form.body,
|
|
122
|
+
size: "large",
|
|
123
|
+
startIcon: /* @__PURE__ */ React__default.createElement(SaveAltIcon, null)
|
|
57
124
|
},
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
{
|
|
61
|
-
id: "title",
|
|
62
|
-
type: "text",
|
|
63
|
-
label: t("announcementForm.title"),
|
|
64
|
-
value: form.title,
|
|
65
|
-
onChange: handleChange,
|
|
66
|
-
variant: "outlined",
|
|
67
|
-
fullWidth: true,
|
|
68
|
-
required: true
|
|
69
|
-
}
|
|
70
|
-
), /* @__PURE__ */ React__default.createElement(
|
|
71
|
-
CategoryInput,
|
|
72
|
-
{
|
|
73
|
-
setForm,
|
|
74
|
-
form,
|
|
75
|
-
initialValue: initialData.category?.title ?? ""
|
|
76
|
-
}
|
|
77
|
-
), /* @__PURE__ */ React__default.createElement(
|
|
78
|
-
TextField,
|
|
79
|
-
{
|
|
80
|
-
id: "excerpt",
|
|
81
|
-
type: "text",
|
|
82
|
-
label: t("announcementForm.excerpt"),
|
|
83
|
-
value: form.excerpt,
|
|
84
|
-
onChange: handleChange,
|
|
85
|
-
variant: "outlined",
|
|
86
|
-
fullWidth: true,
|
|
87
|
-
required: true
|
|
88
|
-
}
|
|
89
|
-
), /* @__PURE__ */ React__default.createElement(
|
|
90
|
-
MDEditor,
|
|
91
|
-
{
|
|
92
|
-
value: form.body,
|
|
93
|
-
style: { minHeight: "30rem" },
|
|
94
|
-
onChange: (value) => setForm({ ...form, ...{ body: value || "" } })
|
|
95
|
-
}
|
|
96
|
-
), /* @__PURE__ */ React__default.createElement(FormGroup, null, /* @__PURE__ */ React__default.createElement(
|
|
97
|
-
FormControlLabel,
|
|
98
|
-
{
|
|
99
|
-
control: /* @__PURE__ */ React__default.createElement(
|
|
100
|
-
Switch,
|
|
101
|
-
{
|
|
102
|
-
name: "active",
|
|
103
|
-
checked: form.active,
|
|
104
|
-
onChange: handleChangeActive
|
|
105
|
-
}
|
|
106
|
-
),
|
|
107
|
-
label: t("announcementForm.active")
|
|
108
|
-
}
|
|
109
|
-
)), /* @__PURE__ */ React__default.createElement(
|
|
110
|
-
Button,
|
|
111
|
-
{
|
|
112
|
-
variant: "contained",
|
|
113
|
-
color: "primary",
|
|
114
|
-
type: "submit",
|
|
115
|
-
disabled: loading || !form.body
|
|
116
|
-
},
|
|
117
|
-
t("announcementForm.submit")
|
|
118
|
-
))
|
|
119
|
-
);
|
|
125
|
+
t("announcementForm.submit")
|
|
126
|
+
)))))));
|
|
120
127
|
};
|
|
121
128
|
|
|
122
129
|
export { AnnouncementForm };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnnouncementForm.esm.js","sources":["../../../src/components/AnnouncementForm/AnnouncementForm.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useState } from 'react';\nimport MDEditor from '@uiw/react-md-editor';\nimport { InfoCard } from '@backstage/core-components';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport { Announcement } from '@backstage-community/plugin-announcements-common';\nimport CategoryInput from './CategoryInput';\nimport {\n makeStyles,\n TextField,\n FormGroup,\n FormControlLabel,\n Switch,\n Button,\n} from '@material-ui/core';\n\nconst useStyles = makeStyles(theme => ({\n formRoot: {\n '& > *': {\n margin: theme.spacing(1) ?? '8px',\n },\n },\n}));\n\ntype AnnouncementFormProps = {\n initialData: Announcement;\n onSubmit: (data: CreateAnnouncementRequest) => Promise<void>;\n};\n\nexport const AnnouncementForm = ({\n initialData,\n onSubmit,\n}: AnnouncementFormProps) => {\n const classes = useStyles();\n const identityApi = useApi(identityApiRef);\n const { t } = useAnnouncementsTranslation();\n\n const [form, setForm] = React.useState({\n ...initialData,\n category: initialData.category?.slug,\n });\n const [loading, setLoading] = useState(false);\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.id]: event.target.value,\n });\n };\n\n const handleChangeActive = (event: React.ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.name]: event.target.checked,\n });\n };\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n setLoading(true);\n event.preventDefault();\n\n const userIdentity = await identityApi.getBackstageIdentity();\n const createRequest = {\n ...form,\n ...{\n publisher: userIdentity.userEntityRef,\n },\n };\n\n await onSubmit(createRequest);\n setLoading(false);\n };\n\n return (\n <InfoCard\n title={\n initialData.title\n ? t('announcementForm.editAnnouncement')\n : t('announcementForm.newAnnouncement')\n }\n >\n <form className={classes.formRoot} onSubmit={handleSubmit}>\n <TextField\n id=\"title\"\n type=\"text\"\n label={t('announcementForm.title')}\n value={form.title}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n />\n <CategoryInput\n setForm={setForm}\n form={form}\n initialValue={initialData.category?.title ?? ''}\n />\n <TextField\n id=\"excerpt\"\n type=\"text\"\n label={t('announcementForm.excerpt')}\n value={form.excerpt}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n />\n <MDEditor\n value={form.body}\n style={{ minHeight: '30rem' }}\n onChange={value => setForm({ ...form, ...{ body: value || '' } })}\n />\n <FormGroup>\n <FormControlLabel\n control={\n <Switch\n name=\"active\"\n checked={form.active}\n onChange={handleChangeActive}\n />\n }\n label={t('announcementForm.active')}\n />\n </FormGroup>\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={loading || !form.body}\n >\n {t('announcementForm.submit')}\n </Button>\n </form>\n </InfoCard>\n );\n};\n"],"names":["React"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnnouncementForm.esm.js","sources":["../../../src/components/AnnouncementForm/AnnouncementForm.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useState } from 'react';\nimport MDEditor from '@uiw/react-md-editor';\nimport { InfoCard } from '@backstage/core-components';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport { Announcement } from '@backstage-community/plugin-announcements-common';\nimport CategoryInput from './CategoryInput';\nimport {\n TextField,\n FormGroup,\n FormControlLabel,\n Switch,\n Button,\n Box,\n Grid,\n Typography,\n Divider,\n} from '@material-ui/core';\nimport SaveAltIcon from '@material-ui/icons/SaveAlt';\nimport { DateTime } from 'luxon';\n\ntype AnnouncementFormProps = {\n initialData: Announcement;\n onSubmit: (data: CreateAnnouncementRequest) => Promise<void>;\n};\n\nexport const AnnouncementForm = ({\n initialData,\n onSubmit,\n}: AnnouncementFormProps) => {\n const identityApi = useApi(identityApiRef);\n const { t } = useAnnouncementsTranslation();\n\n // Ensure `start_at` is properly formatted as an ISO date string\n const formattedStartAt = initialData.start_at\n ? DateTime.fromISO(initialData.start_at).toISODate()\n : DateTime.now().toISODate();\n\n const [form, setForm] = React.useState({\n ...initialData,\n category: initialData.category?.slug,\n start_at: formattedStartAt || '',\n });\n const [loading, setLoading] = useState(false);\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.id]: event.target.value,\n });\n };\n\n const handleChangeActive = (event: React.ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.name]: event.target.checked,\n });\n };\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n setLoading(true);\n event.preventDefault();\n\n const userIdentity = await identityApi.getBackstageIdentity();\n const createRequest = {\n ...form,\n ...{\n publisher: userIdentity.userEntityRef,\n },\n };\n\n await onSubmit(createRequest);\n setLoading(false);\n };\n\n return (\n <InfoCard>\n <Box p={3}>\n <Typography variant=\"h5\" gutterBottom>\n {initialData.title\n ? t('announcementForm.editAnnouncement')\n : t('announcementForm.newAnnouncement')}\n </Typography>\n <form onSubmit={handleSubmit}>\n <Grid container spacing={3}>\n <Grid item xs={12}>\n <TextField\n id=\"title\"\n label={t('announcementForm.title')}\n value={form.title}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n />\n </Grid>\n\n <Grid item xs={12} sm={6}>\n <CategoryInput\n setForm={setForm}\n form={form}\n initialValue={initialData.category?.title ?? ''}\n />\n </Grid>\n\n <Grid item xs={12} sm={6}>\n <TextField\n variant=\"outlined\"\n label={t('announcementForm.startAt')}\n id=\"start-at-date\"\n type=\"date\"\n value={form.start_at}\n InputLabelProps={{ shrink: true }}\n required\n onChange={e =>\n setForm({\n ...form,\n start_at: e.target.value,\n })\n }\n />\n </Grid>\n\n <Grid item xs={12}>\n <TextField\n id=\"excerpt\"\n label={t('announcementForm.excerpt')}\n value={form.excerpt}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n multiline\n />\n </Grid>\n\n <Grid item xs={12}>\n <MDEditor\n value={form.body}\n style={{ minHeight: '30rem' }}\n onChange={value =>\n setForm({ ...form, ...{ body: value || '' } })\n }\n />\n </Grid>\n\n <Grid item xs={12}>\n <Divider />\n </Grid>\n\n <Grid item xs={12}>\n <FormGroup row style={{ justifyContent: 'flex-end' }}>\n <FormControlLabel\n control={\n <Switch\n name=\"active\"\n checked={form.active}\n onChange={handleChangeActive}\n color=\"primary\"\n />\n }\n label={t('announcementForm.active')}\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={loading || !form.body}\n size=\"large\"\n startIcon={<SaveAltIcon />}\n >\n {t('announcementForm.submit')}\n </Button>\n </FormGroup>\n </Grid>\n </Grid>\n </form>\n </Box>\n </InfoCard>\n );\n};\n"],"names":["React"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CategoryInput.esm.js","sources":["../../../src/components/AnnouncementForm/CategoryInput.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as React from 'react';\nimport TextField from '@mui/material/TextField';\nimport Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete';\nimport { Category } from '@backstage-community/plugin-announcements-common';\nimport {\n useAnnouncementsTranslation,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport CircularProgress from '@mui/material/CircularProgress';\n\ntype CategoryInputProps = {\n setForm: (\n value: React.SetStateAction<{\n category: string | undefined;\n id: string;\n publisher: string;\n title: string;\n excerpt: string;\n body: string;\n created_at: string;\n active: boolean;\n }>,\n ) => void;\n form: {\n category: string | undefined;\n id: string;\n publisher: string;\n title: string;\n excerpt: string;\n body: string;\n created_at: string;\n active: boolean;\n };\n initialValue: string;\n};\n\nconst filter = createFilterOptions<Category>();\n\nfunction prepareCategoryFromInput(\n inputCategory: Category | string,\n localizedCreate?: string,\n): string {\n return (\n typeof inputCategory === 'string' ? inputCategory : inputCategory.title\n )\n .replace(localizedCreate ? `${localizedCreate} ` : 'Create ', '')\n .replaceAll('\"', '');\n}\n\nexport default function CategoryInput({\n setForm,\n form,\n initialValue,\n}: CategoryInputProps) {\n const { categories, loading: categoriesLoading } = useCategories();\n const { t } = useAnnouncementsTranslation();\n\n return (\n <Autocomplete\n fullWidth\n value={initialValue ?? ''}\n onChange={async (_, newValue) => {\n if (!newValue) {\n setForm({ ...form, category: undefined });\n return;\n }\n\n const newCategory = prepareCategoryFromInput(\n newValue,\n t('announcementForm.categoryInput.create'),\n );\n setForm({ ...form, category: newCategory });\n }}\n filterOptions={(options, params) => {\n const filtered = filter(options, params);\n const { inputValue } = params;\n\n /*\n Suggest the creation of a new category. This adds the new value to the list of options\n and creates the new category when the form is submitted.\n */\n const isExisting = options.some(\n option =>\n inputValue.toLocaleLowerCase('en-US') ===\n option.title.toLocaleLowerCase('en-US'),\n );\n if (inputValue !== '' && !isExisting) {\n filtered.push({\n title: `${t(\n 'announcementForm.categoryInput.create',\n )} \"${inputValue}\"`,\n slug: inputValue.toLocaleLowerCase('en-US'),\n });\n }\n\n return filtered;\n }}\n selectOnFocus\n handleHomeEndKeys\n loading={categoriesLoading}\n id=\"category-input-field\"\n options={categories || []}\n getOptionLabel={option => {\n // Value selected with enter, right from the input\n return prepareCategoryFromInput(option);\n }}\n renderOption={(props, option) => <li {...props}>{option.title}</li>}\n freeSolo\n renderInput={params => (\n <TextField\n {...params}\n id=\"category\"\n label={t('announcementForm.categoryInput.label')}\n variant=\"outlined\"\n fullWidth\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {categoriesLoading ? (\n <CircularProgress color=\"inherit\" size={20} />\n ) : null}\n {params.InputProps.endAdornment}\n </>\n ),\n }}\n />\n )}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"CategoryInput.esm.js","sources":["../../../src/components/AnnouncementForm/CategoryInput.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport * as React from 'react';\nimport TextField from '@mui/material/TextField';\nimport Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete';\nimport { Category } from '@backstage-community/plugin-announcements-common';\nimport {\n useAnnouncementsTranslation,\n useCategories,\n} from '@backstage-community/plugin-announcements-react';\nimport CircularProgress from '@mui/material/CircularProgress';\n\ntype CategoryInputProps = {\n setForm: (\n value: React.SetStateAction<{\n category: string | undefined;\n id: string;\n publisher: string;\n title: string;\n excerpt: string;\n body: string;\n created_at: string;\n active: boolean;\n start_at: string;\n }>,\n ) => void;\n form: {\n category: string | undefined;\n id: string;\n publisher: string;\n title: string;\n excerpt: string;\n body: string;\n created_at: string;\n active: boolean;\n start_at: string;\n };\n initialValue: string;\n};\n\nconst filter = createFilterOptions<Category>();\n\nfunction prepareCategoryFromInput(\n inputCategory: Category | string,\n localizedCreate?: string,\n): string {\n return (\n typeof inputCategory === 'string' ? inputCategory : inputCategory.title\n )\n .replace(localizedCreate ? `${localizedCreate} ` : 'Create ', '')\n .replaceAll('\"', '');\n}\n\nexport default function CategoryInput({\n setForm,\n form,\n initialValue,\n}: CategoryInputProps) {\n const { categories, loading: categoriesLoading } = useCategories();\n const { t } = useAnnouncementsTranslation();\n\n return (\n <Autocomplete\n fullWidth\n value={initialValue ?? ''}\n onChange={async (_, newValue) => {\n if (!newValue) {\n setForm({ ...form, category: undefined });\n return;\n }\n\n const newCategory = prepareCategoryFromInput(\n newValue,\n t('announcementForm.categoryInput.create'),\n );\n setForm({ ...form, category: newCategory });\n }}\n filterOptions={(options, params) => {\n const filtered = filter(options, params);\n const { inputValue } = params;\n\n /*\n Suggest the creation of a new category. This adds the new value to the list of options\n and creates the new category when the form is submitted.\n */\n const isExisting = options.some(\n option =>\n inputValue.toLocaleLowerCase('en-US') ===\n option.title.toLocaleLowerCase('en-US'),\n );\n if (inputValue !== '' && !isExisting) {\n filtered.push({\n title: `${t(\n 'announcementForm.categoryInput.create',\n )} \"${inputValue}\"`,\n slug: inputValue.toLocaleLowerCase('en-US'),\n });\n }\n\n return filtered;\n }}\n selectOnFocus\n handleHomeEndKeys\n loading={categoriesLoading}\n id=\"category-input-field\"\n options={categories || []}\n getOptionLabel={option => {\n // Value selected with enter, right from the input\n return prepareCategoryFromInput(option);\n }}\n renderOption={(props, option) => <li {...props}>{option.title}</li>}\n freeSolo\n renderInput={params => (\n <TextField\n {...params}\n id=\"category\"\n label={t('announcementForm.categoryInput.label')}\n variant=\"outlined\"\n fullWidth\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {categoriesLoading ? (\n <CircularProgress color=\"inherit\" size={20} />\n ) : null}\n {params.InputProps.endAdornment}\n </>\n ),\n }}\n />\n )}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;AAqDA,MAAM,SAAS,mBAA8B,EAAA;AAE7C,SAAS,wBAAA,CACP,eACA,eACQ,EAAA;AACR,EAAA,OAAA,CACE,OAAO,aAAkB,KAAA,QAAA,GAAW,aAAgB,GAAA,aAAA,CAAc,OAEjE,OAAQ,CAAA,eAAA,GAAkB,CAAG,EAAA,eAAe,MAAM,SAAW,EAAA,EAAE,CAC/D,CAAA,UAAA,CAAW,KAAK,EAAE,CAAA;AACvB;AAEA,SAAwB,aAAc,CAAA;AAAA,EACpC,OAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAuB,EAAA;AACrB,EAAA,MAAM,EAAE,UAAA,EAAY,OAAS,EAAA,iBAAA,KAAsB,aAAc,EAAA;AACjE,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,2BAA4B,EAAA;AAE1C,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MACC,SAAS,EAAA,IAAA;AAAA,MACT,OAAO,YAAgB,IAAA,EAAA;AAAA,MACvB,QAAA,EAAU,OAAO,CAAA,EAAG,QAAa,KAAA;AAC/B,QAAA,IAAI,CAAC,QAAU,EAAA;AACb,UAAA,OAAA,CAAQ,EAAE,GAAG,IAAM,EAAA,QAAA,EAAU,QAAW,CAAA;AACxC,UAAA;AAAA;AAGF,QAAA,MAAM,WAAc,GAAA,wBAAA;AAAA,UAClB,QAAA;AAAA,UACA,EAAE,uCAAuC;AAAA,SAC3C;AACA,QAAA,OAAA,CAAQ,EAAE,GAAG,IAAM,EAAA,QAAA,EAAU,aAAa,CAAA;AAAA,OAC5C;AAAA,MACA,aAAA,EAAe,CAAC,OAAA,EAAS,MAAW,KAAA;AAClC,QAAM,MAAA,QAAA,GAAW,MAAO,CAAA,OAAA,EAAS,MAAM,CAAA;AACvC,QAAM,MAAA,EAAE,YAAe,GAAA,MAAA;AAMvB,QAAA,MAAM,aAAa,OAAQ,CAAA,IAAA;AAAA,UACzB,CAAA,MAAA,KACE,WAAW,iBAAkB,CAAA,OAAO,MACpC,MAAO,CAAA,KAAA,CAAM,kBAAkB,OAAO;AAAA,SAC1C;AACA,QAAI,IAAA,UAAA,KAAe,EAAM,IAAA,CAAC,UAAY,EAAA;AACpC,UAAA,QAAA,CAAS,IAAK,CAAA;AAAA,YACZ,OAAO,CAAG,EAAA,CAAA;AAAA,cACR;AAAA,aACD,KAAK,UAAU,CAAA,CAAA,CAAA;AAAA,YAChB,IAAA,EAAM,UAAW,CAAA,iBAAA,CAAkB,OAAO;AAAA,WAC3C,CAAA;AAAA;AAGH,QAAO,OAAA,QAAA;AAAA,OACT;AAAA,MACA,aAAa,EAAA,IAAA;AAAA,MACb,iBAAiB,EAAA,IAAA;AAAA,MACjB,OAAS,EAAA,iBAAA;AAAA,MACT,EAAG,EAAA,sBAAA;AAAA,MACH,OAAA,EAAS,cAAc,EAAC;AAAA,MACxB,gBAAgB,CAAU,MAAA,KAAA;AAExB,QAAA,OAAO,yBAAyB,MAAM,CAAA;AAAA,OACxC;AAAA,MACA,YAAA,EAAc,CAAC,KAAO,EAAA,MAAA,yCAAY,IAAI,EAAA,EAAA,GAAG,KAAQ,EAAA,EAAA,MAAA,CAAO,KAAM,CAAA;AAAA,MAC9D,QAAQ,EAAA,IAAA;AAAA,MACR,aAAa,CACX,MAAA,qBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACE,GAAG,MAAA;AAAA,UACJ,EAAG,EAAA,UAAA;AAAA,UACH,KAAA,EAAO,EAAE,sCAAsC,CAAA;AAAA,UAC/C,OAAQ,EAAA,UAAA;AAAA,UACR,SAAS,EAAA,IAAA;AAAA,UACT,UAAY,EAAA;AAAA,YACV,GAAG,MAAO,CAAA,UAAA;AAAA,YACV,YACE,kBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EACG,iBACC,mBAAA,KAAA,CAAA,aAAA,CAAC,gBAAiB,EAAA,EAAA,KAAA,EAAM,SAAU,EAAA,IAAA,EAAM,EAAI,EAAA,CAAA,GAC1C,IACH,EAAA,MAAA,CAAO,WAAW,YACrB;AAAA;AAEJ;AAAA;AACF;AAAA,GAEJ;AAEJ;;;;"}
|
|
@@ -6,7 +6,7 @@ import { useApi, useRouteRef } from '@backstage/core-plugin-api';
|
|
|
6
6
|
import { announcementEntityPermissions } from '@backstage-community/plugin-announcements-common';
|
|
7
7
|
import { rootRouteRef, announcementViewRouteRef, announcementCreateRouteRef } from '../../routes.esm.js';
|
|
8
8
|
import { announcementsApiRef, useAnnouncementsTranslation, useAnnouncements } from '@backstage-community/plugin-announcements-react';
|
|
9
|
-
import { makeStyles, List, ListItem, ListItemIcon, ListItemText } from '@material-ui/core';
|
|
9
|
+
import { makeStyles, List, ListItem, ListItemIcon, ListItemText, Typography } from '@material-ui/core';
|
|
10
10
|
import { Alert } from '@material-ui/lab';
|
|
11
11
|
import NewReleasesIcon from '@material-ui/icons/NewReleases';
|
|
12
12
|
|
|
@@ -20,7 +20,9 @@ const AnnouncementsCard = ({
|
|
|
20
20
|
max,
|
|
21
21
|
category,
|
|
22
22
|
active,
|
|
23
|
-
variant = "gridItem"
|
|
23
|
+
variant = "gridItem",
|
|
24
|
+
sortBy,
|
|
25
|
+
order
|
|
24
26
|
}) => {
|
|
25
27
|
const classes = useStyles();
|
|
26
28
|
const announcementsApi = useApi(announcementsApiRef);
|
|
@@ -32,7 +34,9 @@ const AnnouncementsCard = ({
|
|
|
32
34
|
const { announcements, loading, error } = useAnnouncements({
|
|
33
35
|
max: max || 5,
|
|
34
36
|
category,
|
|
35
|
-
active
|
|
37
|
+
active,
|
|
38
|
+
sortBy,
|
|
39
|
+
order
|
|
36
40
|
});
|
|
37
41
|
const { announcementCreatePermission } = announcementEntityPermissions;
|
|
38
42
|
const { loading: loadingPermission, allowed: canAdd } = usePermission({
|
|
@@ -54,10 +58,13 @@ const AnnouncementsCard = ({
|
|
|
54
58
|
variant,
|
|
55
59
|
deepLink
|
|
56
60
|
},
|
|
57
|
-
/* @__PURE__ */ React__default.createElement(List, { dense: true }, announcements.results.map((announcement) => /* @__PURE__ */ React__default.createElement(ListItem, { key: announcement.id }, /* @__PURE__ */ React__default.createElement(
|
|
61
|
+
/* @__PURE__ */ React__default.createElement(List, { dense: true }, announcements.results.map((announcement) => /* @__PURE__ */ React__default.createElement(ListItem, { key: announcement.id }, /* @__PURE__ */ React__default.createElement(
|
|
58
62
|
ListItemIcon,
|
|
59
63
|
{
|
|
60
64
|
className: classes.newAnnouncementIcon,
|
|
65
|
+
style: {
|
|
66
|
+
visibility: lastSeen < DateTime.fromISO(announcement.created_at) ? "visible" : "hidden"
|
|
67
|
+
},
|
|
61
68
|
title: t("announcementsCard.new")
|
|
62
69
|
},
|
|
63
70
|
/* @__PURE__ */ React__default.createElement(NewReleasesIcon, null)
|
|
@@ -65,15 +72,15 @@ const AnnouncementsCard = ({
|
|
|
65
72
|
ListItemText,
|
|
66
73
|
{
|
|
67
74
|
primary: /* @__PURE__ */ React__default.createElement(Link, { to: viewAnnouncementLink({ id: announcement.id }) }, announcement.title),
|
|
68
|
-
secondary: /* @__PURE__ */ React__default.createElement(React__default.
|
|
75
|
+
secondary: /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2", color: "textSecondary" }, DateTime.fromISO(announcement.created_at).toRelative(), announcement.category && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, ` ${t("announcementsCard.in")} `, /* @__PURE__ */ React__default.createElement(
|
|
69
76
|
Link,
|
|
70
77
|
{
|
|
71
78
|
to: `${announcementsLink()}?category=${announcement.category.slug}`
|
|
72
79
|
},
|
|
73
80
|
announcement.category.title
|
|
74
|
-
)), " ", "
|
|
81
|
+
))), /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2", color: "textSecondary" }, announcement.excerpt), /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2", color: "textSecondary" }, /* @__PURE__ */ React__default.createElement("small", null, DateTime.fromISO(announcement.start_at) < DateTime.now() ? `${t("announcementsCard.occurred")} ` : `${t("announcementsCard.scheduled")} `, DateTime.fromISO(announcement.start_at).toRelative())))
|
|
75
82
|
}
|
|
76
|
-
)))
|
|
83
|
+
), " ")), announcements.count === 0 && !loadingPermission && canAdd && /* @__PURE__ */ React__default.createElement(ListItem, null, /* @__PURE__ */ React__default.createElement(ListItemText, null, `${t("announcementsCard.noAnnouncements")} `, /* @__PURE__ */ React__default.createElement(Link, { to: createAnnouncementLink() }, t("announcementsCard.addOne")), "?")))
|
|
77
84
|
);
|
|
78
85
|
};
|
|
79
86
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnnouncementsCard.esm.js","sources":["../../../src/components/AnnouncementsCard/AnnouncementsCard.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { DateTime } from 'luxon';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n InfoCard,\n InfoCardVariants,\n Link,\n Progress,\n} from '@backstage/core-components';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { announcementEntityPermissions } from '@backstage-community/plugin-announcements-common';\nimport {\n announcementCreateRouteRef,\n announcementViewRouteRef,\n rootRouteRef,\n} from '../../routes';\nimport {\n announcementsApiRef,\n useAnnouncements,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n makeStyles,\n List,\n ListItem,\n ListItemIcon,\n ListItemText,\n} from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport NewReleasesIcon from '@material-ui/icons/NewReleases';\n\nconst useStyles = makeStyles({\n newAnnouncementIcon: {\n minWidth: '36px',\n },\n});\n\ntype AnnouncementsCardOpts = {\n title?: string;\n max?: number;\n category?: string;\n active?: boolean;\n variant?: InfoCardVariants;\n};\n\nexport const AnnouncementsCard = ({\n title,\n max,\n category,\n active,\n variant = 'gridItem',\n}: AnnouncementsCardOpts) => {\n const classes = useStyles();\n const announcementsApi = useApi(announcementsApiRef);\n const announcementsLink = useRouteRef(rootRouteRef);\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n const createAnnouncementLink = useRouteRef(announcementCreateRouteRef);\n const lastSeen = announcementsApi.lastSeenDate();\n const { t } = useAnnouncementsTranslation();\n\n const { announcements, loading, error } = useAnnouncements({\n max: max || 5,\n category,\n active,\n });\n\n const { announcementCreatePermission } = announcementEntityPermissions;\n const { loading: loadingPermission, allowed: canAdd } = usePermission({\n permission: announcementCreatePermission,\n });\n\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\n }\n\n const deepLink = {\n link: announcementsLink(),\n title: t('announcementsCard.seeAll'),\n };\n\n return (\n <InfoCard\n title={title || t('announcementsCard.announcements')}\n variant={variant}\n deepLink={deepLink}\n >\n <List dense>\n {announcements.results.map(announcement => (\n <ListItem key={announcement.id}>\n <
|
|
1
|
+
{"version":3,"file":"AnnouncementsCard.esm.js","sources":["../../../src/components/AnnouncementsCard/AnnouncementsCard.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { DateTime } from 'luxon';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n InfoCard,\n InfoCardVariants,\n Link,\n Progress,\n} from '@backstage/core-components';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { announcementEntityPermissions } from '@backstage-community/plugin-announcements-common';\nimport {\n announcementCreateRouteRef,\n announcementViewRouteRef,\n rootRouteRef,\n} from '../../routes';\nimport {\n announcementsApiRef,\n useAnnouncements,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n makeStyles,\n List,\n ListItem,\n ListItemIcon,\n ListItemText,\n Typography,\n} from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport NewReleasesIcon from '@material-ui/icons/NewReleases';\n\nconst useStyles = makeStyles({\n newAnnouncementIcon: {\n minWidth: '36px',\n },\n});\n\ntype AnnouncementsCardOpts = {\n title?: string;\n max?: number;\n category?: string;\n active?: boolean;\n variant?: InfoCardVariants;\n sortBy?: 'created_at' | 'start_at';\n order?: 'asc' | 'desc';\n};\n\nexport const AnnouncementsCard = ({\n title,\n max,\n category,\n active,\n variant = 'gridItem',\n sortBy,\n order,\n}: AnnouncementsCardOpts) => {\n const classes = useStyles();\n const announcementsApi = useApi(announcementsApiRef);\n const announcementsLink = useRouteRef(rootRouteRef);\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n const createAnnouncementLink = useRouteRef(announcementCreateRouteRef);\n const lastSeen = announcementsApi.lastSeenDate();\n const { t } = useAnnouncementsTranslation();\n\n const { announcements, loading, error } = useAnnouncements({\n max: max || 5,\n category,\n active,\n sortBy,\n order,\n });\n\n const { announcementCreatePermission } = announcementEntityPermissions;\n const { loading: loadingPermission, allowed: canAdd } = usePermission({\n permission: announcementCreatePermission,\n });\n\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\n }\n\n const deepLink = {\n link: announcementsLink(),\n title: t('announcementsCard.seeAll'),\n };\n\n return (\n <InfoCard\n title={title || t('announcementsCard.announcements')}\n variant={variant}\n deepLink={deepLink}\n >\n <List dense>\n {announcements.results.map(announcement => (\n <ListItem key={announcement.id}>\n <ListItemIcon\n className={classes.newAnnouncementIcon}\n style={{\n visibility:\n lastSeen < DateTime.fromISO(announcement.created_at)\n ? 'visible'\n : 'hidden',\n }}\n title={t('announcementsCard.new')}\n >\n <NewReleasesIcon />\n </ListItemIcon>\n <ListItemText\n primary={\n <Link to={viewAnnouncementLink({ id: announcement.id })}>\n {announcement.title}\n </Link>\n }\n secondary={\n <div>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {DateTime.fromISO(announcement.created_at).toRelative()}\n {announcement.category && (\n <>\n {` ${t('announcementsCard.in')} `}\n <Link\n to={`${announcementsLink()}?category=${\n announcement.category.slug\n }`}\n >\n {announcement.category.title}\n </Link>\n </>\n )}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {announcement.excerpt}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n <small>\n {DateTime.fromISO(announcement.start_at) < DateTime.now()\n ? `${t('announcementsCard.occurred')} `\n : `${t('announcementsCard.scheduled')} `}\n {DateTime.fromISO(announcement.start_at).toRelative()}\n </small>\n </Typography>\n </div>\n }\n />{' '}\n </ListItem>\n ))}\n {announcements.count === 0 && !loadingPermission && canAdd && (\n <ListItem>\n <ListItemText>\n {`${t('announcementsCard.noAnnouncements')} `}\n <Link to={createAnnouncementLink()}>\n {t('announcementsCard.addOne')}\n </Link>\n ?\n </ListItemText>\n </ListItem>\n )}\n </List>\n </InfoCard>\n );\n};\n"],"names":["React"],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@ import { DeleteAnnouncementDialog } from './DeleteAnnouncementDialog.esm.js';
|
|
|
15
15
|
import { useDeleteAnnouncementDialogState } from './useDeleteAnnouncementDialogState.esm.js';
|
|
16
16
|
import { ContextMenu } from './ContextMenu.esm.js';
|
|
17
17
|
import { useAnnouncementsTranslation, announcementsApiRef, useAnnouncements } from '@backstage-community/plugin-announcements-react';
|
|
18
|
-
import { makeStyles, Tooltip, Card, CardHeader, CardContent, IconButton, Menu, MenuItem, ListItemIcon } from '@material-ui/core';
|
|
18
|
+
import { makeStyles, Tooltip, Typography, Card, CardHeader, CardContent, IconButton, Menu, MenuItem, ListItemIcon } from '@material-ui/core';
|
|
19
19
|
import { Alert, Pagination } from '@material-ui/lab';
|
|
20
20
|
|
|
21
21
|
const useStyles = makeStyles((theme) => {
|
|
@@ -62,13 +62,13 @@ const AnnouncementCard = ({
|
|
|
62
62
|
truncate(announcement.title, titleLength)
|
|
63
63
|
)
|
|
64
64
|
);
|
|
65
|
-
const subTitle = /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, t("announcementsPage.card.by"), " ", /* @__PURE__ */ React__default.createElement(EntityPeekAheadPopover, { entityRef: announcement.publisher }, /* @__PURE__ */ React__default.createElement(Link, { to: entityLink(publisherRef) }, /* @__PURE__ */ React__default.createElement(EntityDisplayName, { entityRef: announcement.publisher, hideIcon: true }))), announcement.category && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, " ", t("announcementsPage.card.in"), " ", /* @__PURE__ */ React__default.createElement(
|
|
65
|
+
const subTitle = /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2", color: "textSecondary", component: "span" }, t("announcementsPage.card.by"), " ", /* @__PURE__ */ React__default.createElement(EntityPeekAheadPopover, { entityRef: announcement.publisher }, /* @__PURE__ */ React__default.createElement(Link, { to: entityLink(publisherRef) }, /* @__PURE__ */ React__default.createElement(EntityDisplayName, { entityRef: announcement.publisher, hideIcon: true }))), announcement.category && /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, " ", t("announcementsPage.card.in"), " ", /* @__PURE__ */ React__default.createElement(
|
|
66
66
|
Link,
|
|
67
67
|
{
|
|
68
68
|
to: `${announcementsLink()}?category=${announcement.category.slug}`
|
|
69
69
|
},
|
|
70
70
|
announcement.category.title
|
|
71
|
-
)), ", ", DateTime.fromISO(announcement.created_at).toRelative());
|
|
71
|
+
)), ", ", DateTime.fromISO(announcement.created_at).toRelative()), /* @__PURE__ */ React__default.createElement(Typography, { variant: "body2", color: "textSecondary" }, /* @__PURE__ */ React__default.createElement("small", null, DateTime.fromISO(announcement.start_at) < DateTime.now() ? `${t("announcementsPage.card.occurred")} ` : `${t("announcementsPage.card.scheduled")} `, DateTime.fromISO(announcement.start_at).toRelative())));
|
|
72
72
|
const { loading: loadingDeletePermission, allowed: canDelete } = usePermission({ permission: announcementDeletePermission });
|
|
73
73
|
const { loading: loadingUpdatePermission, allowed: canUpdate } = usePermission({ permission: announcementUpdatePermission });
|
|
74
74
|
const AnnouncementEditMenu = () => {
|
|
@@ -117,7 +117,9 @@ const AnnouncementsGrid = ({
|
|
|
117
117
|
maxPerPage,
|
|
118
118
|
category,
|
|
119
119
|
cardTitleLength,
|
|
120
|
-
active
|
|
120
|
+
active,
|
|
121
|
+
sortBy,
|
|
122
|
+
order
|
|
121
123
|
}) => {
|
|
122
124
|
const classes = useStyles();
|
|
123
125
|
const announcementsApi = useApi(announcementsApiRef);
|
|
@@ -136,7 +138,9 @@ const AnnouncementsGrid = ({
|
|
|
136
138
|
max: maxPerPage,
|
|
137
139
|
page,
|
|
138
140
|
category,
|
|
139
|
-
active
|
|
141
|
+
active,
|
|
142
|
+
sortBy,
|
|
143
|
+
order
|
|
140
144
|
},
|
|
141
145
|
{ dependencies: [maxPerPage, page, category] }
|
|
142
146
|
);
|
|
@@ -207,7 +211,9 @@ const AnnouncementsPage = (props) => {
|
|
|
207
211
|
buttonOptions,
|
|
208
212
|
maxPerPage,
|
|
209
213
|
category,
|
|
210
|
-
cardOptions
|
|
214
|
+
cardOptions,
|
|
215
|
+
sortby,
|
|
216
|
+
order
|
|
211
217
|
} = props;
|
|
212
218
|
return /* @__PURE__ */ React__default.createElement(Page, { themeId }, /* @__PURE__ */ React__default.createElement(Header, { title, subtitle }, !hideContextMenu && /* @__PURE__ */ React__default.createElement(ContextMenu, null)), /* @__PURE__ */ React__default.createElement(Content, null, /* @__PURE__ */ React__default.createElement(ContentHeader, { title: "" }, !loadingCreatePermission && /* @__PURE__ */ React__default.createElement(
|
|
213
219
|
LinkButton,
|
|
@@ -224,7 +230,9 @@ const AnnouncementsPage = (props) => {
|
|
|
224
230
|
maxPerPage: maxPerPage ?? 10,
|
|
225
231
|
category: category ?? queryParams.get("category") ?? void 0,
|
|
226
232
|
cardTitleLength: cardOptions?.titleLength,
|
|
227
|
-
active: hideInactive ? true : false
|
|
233
|
+
active: hideInactive ? true : false,
|
|
234
|
+
sortBy: sortby ?? "created_at",
|
|
235
|
+
order: order ?? "desc"
|
|
228
236
|
}
|
|
229
237
|
)));
|
|
230
238
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnnouncementsPage.esm.js","sources":["../../../src/components/AnnouncementsPage/AnnouncementsPage.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { ReactNode } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n announcementCreatePermission,\n announcementUpdatePermission,\n announcementDeletePermission,\n Announcement,\n} from '@backstage-community/plugin-announcements-common';\nimport { DateTime } from 'luxon';\nimport {\n Page,\n Header,\n Content,\n Link,\n ItemCardGrid,\n Progress,\n ContentHeader,\n LinkButton,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport {\n EntityDisplayName,\n EntityPeekAheadPopover,\n entityRouteRef,\n} from '@backstage/plugin-catalog-react';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport MoreVertIcon from '@material-ui/icons/MoreVert';\nimport {\n announcementCreateRouteRef,\n announcementEditRouteRef,\n announcementViewRouteRef,\n rootRouteRef,\n} from '../../routes';\nimport { DeleteAnnouncementDialog } from './DeleteAnnouncementDialog';\nimport { useDeleteAnnouncementDialogState } from './useDeleteAnnouncementDialogState';\nimport { ContextMenu } from './ContextMenu';\nimport {\n announcementsApiRef,\n useAnnouncements,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Card,\n CardContent,\n CardHeader,\n IconButton,\n ListItemIcon,\n makeStyles,\n Menu,\n MenuItem,\n Tooltip,\n} from '@material-ui/core';\nimport { Alert, Pagination } from '@material-ui/lab';\n\nconst useStyles = makeStyles(theme => {\n return {\n cardHeader: {\n color: theme?.palette?.text?.primary || '#000',\n fontSize: '1.5rem',\n },\n pagination: {\n display: 'flex',\n justifyContent: 'center',\n marginTop: theme?.spacing?.(4) || 32,\n },\n };\n});\n/**\n * Truncate text to a given length and add ellipsis\n * @param text the text to truncate\n * @param length the length to truncate to\n * @returns the truncated text\n */\nconst truncate = (text: string, length: number) => {\n return text.length > length ? `${text.substring(0, length)}...` : text;\n};\n\nconst AnnouncementCard = ({\n announcement,\n onDelete,\n options: { titleLength = 50 },\n}: {\n announcement: Announcement;\n onDelete: () => void;\n options: AnnouncementCardProps;\n}) => {\n const classes = useStyles();\n const announcementsLink = useRouteRef(rootRouteRef);\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n const editAnnouncementLink = useRouteRef(announcementEditRouteRef);\n const entityLink = useRouteRef(entityRouteRef);\n const { t } = useAnnouncementsTranslation();\n\n const publisherRef = parseEntityRef(announcement.publisher);\n const title = (\n <Tooltip\n title={announcement.title}\n disableFocusListener\n data-testid=\"announcement-card-title-tooltip\"\n >\n <Link\n className={classes.cardHeader}\n to={viewAnnouncementLink({ id: announcement.id })}\n >\n {truncate(announcement.title, titleLength)}\n </Link>\n </Tooltip>\n );\n const subTitle = (\n <>\n {t('announcementsPage.card.by')}{' '}\n <EntityPeekAheadPopover entityRef={announcement.publisher}>\n <Link to={entityLink(publisherRef)}>\n <EntityDisplayName entityRef={announcement.publisher} hideIcon />\n </Link>\n </EntityPeekAheadPopover>\n {announcement.category && (\n <>\n {' '}\n {t('announcementsPage.card.in')}{' '}\n <Link\n to={`${announcementsLink()}?category=${announcement.category.slug}`}\n >\n {announcement.category.title}\n </Link>\n </>\n )}\n , {DateTime.fromISO(announcement.created_at).toRelative()}\n </>\n );\n const { loading: loadingDeletePermission, allowed: canDelete } =\n usePermission({ permission: announcementDeletePermission });\n const { loading: loadingUpdatePermission, allowed: canUpdate } =\n usePermission({ permission: announcementUpdatePermission });\n\n const AnnouncementEditMenu = () => {\n const [open, setOpen] = React.useState(false);\n const [anchorEl, setAnchorEl] = React.useState<undefined | HTMLElement>(\n undefined,\n );\n\n const handleOpenEditMenu = (event: React.MouseEvent<HTMLButtonElement>) => {\n setAnchorEl(event.currentTarget);\n setOpen(true);\n };\n\n const handleCloseEditClose = () => {\n setAnchorEl(undefined);\n setOpen(false);\n };\n\n const canShowMenu =\n (!loadingUpdatePermission && canUpdate) ||\n (!loadingDeletePermission && canDelete);\n\n return (\n <>\n {canShowMenu && (\n <IconButton\n data-testid=\"announcement-edit-menu\"\n aria-label=\"more\"\n onClick={handleOpenEditMenu}\n >\n <MoreVertIcon />\n </IconButton>\n )}\n <Menu anchorEl={anchorEl} open={open} onClose={handleCloseEditClose}>\n {!loadingUpdatePermission && canUpdate && (\n <MenuItem\n data-testid=\"edit-announcement\"\n component={LinkButton}\n to={editAnnouncementLink({ id: announcement.id })}\n >\n <ListItemIcon>\n <EditIcon />\n </ListItemIcon>\n {t('announcementsPage.card.edit')}\n </MenuItem>\n )}\n {!loadingDeletePermission && canDelete && (\n <MenuItem onClick={onDelete}>\n <ListItemIcon>\n <DeleteIcon />\n </ListItemIcon>\n {t('announcementsPage.card.delete')}\n </MenuItem>\n )}\n </Menu>\n </>\n );\n };\n\n return (\n <Card>\n <CardHeader\n action={<AnnouncementEditMenu />}\n title={title}\n subheader={subTitle}\n />\n <CardContent>{announcement.excerpt}</CardContent>\n </Card>\n );\n};\n\nconst AnnouncementsGrid = ({\n maxPerPage,\n category,\n cardTitleLength,\n active,\n}: {\n maxPerPage: number;\n category?: string;\n cardTitleLength?: number;\n active?: boolean;\n}) => {\n const classes = useStyles();\n const announcementsApi = useApi(announcementsApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [page, setPage] = React.useState(1);\n const handleChange = (_event: any, value: number) => {\n setPage(value);\n };\n\n const {\n announcements,\n loading,\n error,\n retry: refresh,\n } = useAnnouncements(\n {\n max: maxPerPage,\n page: page,\n category,\n active,\n },\n { dependencies: [maxPerPage, page, category] },\n );\n\n const { t } = useAnnouncementsTranslation();\n\n const {\n isOpen: isDeleteDialogOpen,\n open: openDeleteDialog,\n close: closeDeleteDialog,\n announcement: announcementToDelete,\n } = useDeleteAnnouncementDialogState();\n\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\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({\n message: t('announcementsPage.grid.announcementDeleted'),\n severity: 'success',\n });\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n\n refresh();\n };\n\n return (\n <>\n <ItemCardGrid>\n {announcements.results.map(announcement => (\n <AnnouncementCard\n key={announcement.id}\n announcement={announcement}\n onDelete={() => openDeleteDialog(announcement)}\n options={{ titleLength: cardTitleLength }}\n />\n ))}\n </ItemCardGrid>\n\n {announcements && announcements.count !== 0 && (\n <div className={classes.pagination}>\n <Pagination\n count={Math.ceil(announcements.count / maxPerPage)}\n page={page}\n onChange={handleChange}\n />\n </div>\n )}\n\n <DeleteAnnouncementDialog\n open={isDeleteDialogOpen}\n onCancel={onCancelDelete}\n onConfirm={onConfirmDelete}\n />\n </>\n );\n};\n\ntype AnnouncementCardProps = {\n titleLength?: number;\n};\n\ntype AnnouncementCreateButtonProps = {\n name?: string;\n};\n\nexport type AnnouncementsPageProps = {\n themeId: string;\n title: string;\n subtitle?: ReactNode;\n maxPerPage?: number;\n category?: string;\n buttonOptions?: AnnouncementCreateButtonProps;\n cardOptions?: AnnouncementCardProps;\n hideContextMenu?: boolean;\n hideInactive?: boolean;\n};\n\nexport const AnnouncementsPage = (props: AnnouncementsPageProps) => {\n const location = useLocation();\n const queryParams = new URLSearchParams(location.search);\n const newAnnouncementLink = useRouteRef(announcementCreateRouteRef);\n const { loading: loadingCreatePermission, allowed: canCreate } =\n usePermission({ permission: announcementCreatePermission });\n const { t } = useAnnouncementsTranslation();\n\n const {\n hideContextMenu,\n hideInactive,\n themeId,\n title,\n subtitle,\n buttonOptions,\n maxPerPage,\n category,\n cardOptions,\n } = props;\n\n return (\n <Page themeId={themeId}>\n <Header title={title} subtitle={subtitle}>\n {!hideContextMenu && <ContextMenu />}\n </Header>\n\n <Content>\n <ContentHeader title=\"\">\n {!loadingCreatePermission && (\n <LinkButton\n disabled={!canCreate}\n to={newAnnouncementLink()}\n color=\"primary\"\n variant=\"contained\"\n >\n {buttonOptions\n ? `${t('announcementsPage.genericNew')} ${buttonOptions.name}`\n : t('announcementsPage.newAnnouncement')}\n </LinkButton>\n )}\n </ContentHeader>\n\n <AnnouncementsGrid\n maxPerPage={maxPerPage ?? 10}\n category={category ?? queryParams.get('category') ?? undefined}\n cardTitleLength={cardOptions?.titleLength}\n active={hideInactive ? true : false}\n />\n </Content>\n </Page>\n );\n};\n"],"names":["React","MoreVertIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnnouncementsPage.esm.js","sources":["../../../src/components/AnnouncementsPage/AnnouncementsPage.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { ReactNode } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n announcementCreatePermission,\n announcementUpdatePermission,\n announcementDeletePermission,\n Announcement,\n} from '@backstage-community/plugin-announcements-common';\nimport { DateTime } from 'luxon';\nimport {\n Page,\n Header,\n Content,\n Link,\n ItemCardGrid,\n Progress,\n ContentHeader,\n LinkButton,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { parseEntityRef } from '@backstage/catalog-model';\nimport {\n EntityDisplayName,\n EntityPeekAheadPopover,\n entityRouteRef,\n} from '@backstage/plugin-catalog-react';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport MoreVertIcon from '@material-ui/icons/MoreVert';\nimport {\n announcementCreateRouteRef,\n announcementEditRouteRef,\n announcementViewRouteRef,\n rootRouteRef,\n} from '../../routes';\nimport { DeleteAnnouncementDialog } from './DeleteAnnouncementDialog';\nimport { useDeleteAnnouncementDialogState } from './useDeleteAnnouncementDialogState';\nimport { ContextMenu } from './ContextMenu';\nimport {\n announcementsApiRef,\n useAnnouncements,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Card,\n CardContent,\n CardHeader,\n IconButton,\n ListItemIcon,\n makeStyles,\n Menu,\n MenuItem,\n Tooltip,\n Typography,\n} from '@material-ui/core';\nimport { Alert, Pagination } from '@material-ui/lab';\n\nconst useStyles = makeStyles(theme => {\n return {\n cardHeader: {\n color: theme?.palette?.text?.primary || '#000',\n fontSize: '1.5rem',\n },\n pagination: {\n display: 'flex',\n justifyContent: 'center',\n marginTop: theme?.spacing?.(4) || 32,\n },\n };\n});\n/**\n * Truncate text to a given length and add ellipsis\n * @param text the text to truncate\n * @param length the length to truncate to\n * @returns the truncated text\n */\nconst truncate = (text: string, length: number) => {\n return text.length > length ? `${text.substring(0, length)}...` : text;\n};\n\nconst AnnouncementCard = ({\n announcement,\n onDelete,\n options: { titleLength = 50 },\n}: {\n announcement: Announcement;\n onDelete: () => void;\n options: AnnouncementCardProps;\n}) => {\n const classes = useStyles();\n const announcementsLink = useRouteRef(rootRouteRef);\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n const editAnnouncementLink = useRouteRef(announcementEditRouteRef);\n const entityLink = useRouteRef(entityRouteRef);\n const { t } = useAnnouncementsTranslation();\n\n const publisherRef = parseEntityRef(announcement.publisher);\n const title = (\n <Tooltip\n title={announcement.title}\n disableFocusListener\n data-testid=\"announcement-card-title-tooltip\"\n >\n <Link\n className={classes.cardHeader}\n to={viewAnnouncementLink({ id: announcement.id })}\n >\n {truncate(announcement.title, titleLength)}\n </Link>\n </Tooltip>\n );\n const subTitle = (\n <>\n <Typography variant=\"body2\" color=\"textSecondary\" component=\"span\">\n {t('announcementsPage.card.by')}{' '}\n <EntityPeekAheadPopover entityRef={announcement.publisher}>\n <Link to={entityLink(publisherRef)}>\n <EntityDisplayName entityRef={announcement.publisher} hideIcon />\n </Link>\n </EntityPeekAheadPopover>\n {announcement.category && (\n <>\n {' '}\n {t('announcementsPage.card.in')}{' '}\n <Link\n to={`${announcementsLink()}?category=${\n announcement.category.slug\n }`}\n >\n {announcement.category.title}\n </Link>\n </>\n )}\n , {DateTime.fromISO(announcement.created_at).toRelative()}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n <small>\n {DateTime.fromISO(announcement.start_at) < DateTime.now()\n ? `${t('announcementsPage.card.occurred')} `\n : `${t('announcementsPage.card.scheduled')} `}\n {DateTime.fromISO(announcement.start_at).toRelative()}\n </small>\n </Typography>\n </>\n );\n const { loading: loadingDeletePermission, allowed: canDelete } =\n usePermission({ permission: announcementDeletePermission });\n const { loading: loadingUpdatePermission, allowed: canUpdate } =\n usePermission({ permission: announcementUpdatePermission });\n\n const AnnouncementEditMenu = () => {\n const [open, setOpen] = React.useState(false);\n const [anchorEl, setAnchorEl] = React.useState<undefined | HTMLElement>(\n undefined,\n );\n\n const handleOpenEditMenu = (event: React.MouseEvent<HTMLButtonElement>) => {\n setAnchorEl(event.currentTarget);\n setOpen(true);\n };\n\n const handleCloseEditClose = () => {\n setAnchorEl(undefined);\n setOpen(false);\n };\n\n const canShowMenu =\n (!loadingUpdatePermission && canUpdate) ||\n (!loadingDeletePermission && canDelete);\n\n return (\n <>\n {canShowMenu && (\n <IconButton\n data-testid=\"announcement-edit-menu\"\n aria-label=\"more\"\n onClick={handleOpenEditMenu}\n >\n <MoreVertIcon />\n </IconButton>\n )}\n <Menu anchorEl={anchorEl} open={open} onClose={handleCloseEditClose}>\n {!loadingUpdatePermission && canUpdate && (\n <MenuItem\n data-testid=\"edit-announcement\"\n component={LinkButton}\n to={editAnnouncementLink({ id: announcement.id })}\n >\n <ListItemIcon>\n <EditIcon />\n </ListItemIcon>\n {t('announcementsPage.card.edit')}\n </MenuItem>\n )}\n {!loadingDeletePermission && canDelete && (\n <MenuItem onClick={onDelete}>\n <ListItemIcon>\n <DeleteIcon />\n </ListItemIcon>\n {t('announcementsPage.card.delete')}\n </MenuItem>\n )}\n </Menu>\n </>\n );\n };\n\n return (\n <Card>\n <CardHeader\n action={<AnnouncementEditMenu />}\n title={title}\n subheader={subTitle}\n />\n <CardContent>{announcement.excerpt}</CardContent>\n </Card>\n );\n};\n\nconst AnnouncementsGrid = ({\n maxPerPage,\n category,\n cardTitleLength,\n active,\n sortBy,\n order,\n}: {\n maxPerPage: number;\n category?: string;\n cardTitleLength?: number;\n active?: boolean;\n sortBy?: 'created_at' | 'start_at';\n order?: 'asc' | 'desc';\n}) => {\n const classes = useStyles();\n const announcementsApi = useApi(announcementsApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [page, setPage] = React.useState(1);\n const handleChange = (_event: any, value: number) => {\n setPage(value);\n };\n\n const {\n announcements,\n loading,\n error,\n retry: refresh,\n } = useAnnouncements(\n {\n max: maxPerPage,\n page: page,\n category,\n active,\n sortBy,\n order,\n },\n { dependencies: [maxPerPage, page, category] },\n );\n\n const { t } = useAnnouncementsTranslation();\n\n const {\n isOpen: isDeleteDialogOpen,\n open: openDeleteDialog,\n close: closeDeleteDialog,\n announcement: announcementToDelete,\n } = useDeleteAnnouncementDialogState();\n\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\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({\n message: t('announcementsPage.grid.announcementDeleted'),\n severity: 'success',\n });\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n\n refresh();\n };\n\n return (\n <>\n <ItemCardGrid>\n {announcements.results.map(announcement => (\n <AnnouncementCard\n key={announcement.id}\n announcement={announcement}\n onDelete={() => openDeleteDialog(announcement)}\n options={{ titleLength: cardTitleLength }}\n />\n ))}\n </ItemCardGrid>\n\n {announcements && announcements.count !== 0 && (\n <div className={classes.pagination}>\n <Pagination\n count={Math.ceil(announcements.count / maxPerPage)}\n page={page}\n onChange={handleChange}\n />\n </div>\n )}\n\n <DeleteAnnouncementDialog\n open={isDeleteDialogOpen}\n onCancel={onCancelDelete}\n onConfirm={onConfirmDelete}\n />\n </>\n );\n};\n\ntype AnnouncementCardProps = {\n titleLength?: number;\n};\n\ntype AnnouncementCreateButtonProps = {\n name?: string;\n};\n\nexport type AnnouncementsPageProps = {\n themeId: string;\n title: string;\n subtitle?: ReactNode;\n maxPerPage?: number;\n category?: string;\n buttonOptions?: AnnouncementCreateButtonProps;\n cardOptions?: AnnouncementCardProps;\n hideContextMenu?: boolean;\n hideInactive?: boolean;\n sortby?: 'created_at' | 'start_at';\n order?: 'asc' | 'desc';\n};\n\nexport const AnnouncementsPage = (props: AnnouncementsPageProps) => {\n const location = useLocation();\n const queryParams = new URLSearchParams(location.search);\n const newAnnouncementLink = useRouteRef(announcementCreateRouteRef);\n const { loading: loadingCreatePermission, allowed: canCreate } =\n usePermission({ permission: announcementCreatePermission });\n const { t } = useAnnouncementsTranslation();\n\n const {\n hideContextMenu,\n hideInactive,\n themeId,\n title,\n subtitle,\n buttonOptions,\n maxPerPage,\n category,\n cardOptions,\n sortby,\n order,\n } = props;\n\n return (\n <Page themeId={themeId}>\n <Header title={title} subtitle={subtitle}>\n {!hideContextMenu && <ContextMenu />}\n </Header>\n\n <Content>\n <ContentHeader title=\"\">\n {!loadingCreatePermission && (\n <LinkButton\n disabled={!canCreate}\n to={newAnnouncementLink()}\n color=\"primary\"\n variant=\"contained\"\n >\n {buttonOptions\n ? `${t('announcementsPage.genericNew')} ${buttonOptions.name}`\n : t('announcementsPage.newAnnouncement')}\n </LinkButton>\n )}\n </ContentHeader>\n\n <AnnouncementsGrid\n maxPerPage={maxPerPage ?? 10}\n category={category ?? queryParams.get('category') ?? undefined}\n cardTitleLength={cardOptions?.titleLength}\n active={hideInactive ? true : false}\n sortBy={sortby ?? 'created_at'}\n order={order ?? 'desc'}\n />\n </Content>\n </Page>\n );\n};\n"],"names":["React","MoreVertIcon"],"mappings":"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"}
|
|
@@ -13,16 +13,22 @@ const DEFAULT_TIMELINE_ALIGNMENT = "alternate";
|
|
|
13
13
|
const DEFAULT_TIMELINE_WIDTH = "425px";
|
|
14
14
|
const DEFAULT_RESULTS_MAX = 10;
|
|
15
15
|
const DEFAULT_INACTIVE = false;
|
|
16
|
+
const DEFAULT_SORTBY = "created_at";
|
|
17
|
+
const DEFAULT_ORDER = "desc";
|
|
16
18
|
const AnnouncementsTimeline = ({
|
|
17
19
|
maxResults = DEFAULT_RESULTS_MAX,
|
|
18
20
|
timelineAlignment = DEFAULT_TIMELINE_ALIGNMENT,
|
|
19
21
|
timelineMinWidth = DEFAULT_TIMELINE_WIDTH,
|
|
20
|
-
hideInactive = DEFAULT_INACTIVE
|
|
22
|
+
hideInactive = DEFAULT_INACTIVE,
|
|
23
|
+
sortBy = DEFAULT_SORTBY,
|
|
24
|
+
order = DEFAULT_ORDER
|
|
21
25
|
}) => {
|
|
22
26
|
const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);
|
|
23
27
|
const { announcements, loading, error } = useAnnouncements({
|
|
24
28
|
max: maxResults,
|
|
25
|
-
active: hideInactive
|
|
29
|
+
active: hideInactive,
|
|
30
|
+
sortBy,
|
|
31
|
+
order
|
|
26
32
|
});
|
|
27
33
|
const { t } = useAnnouncementsTranslation();
|
|
28
34
|
if (loading) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnnouncementsTimeline.esm.js","sources":["../../../src/components/AnnouncementsTimeline/AnnouncementsTimeline.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 { useRouteRef } from '@backstage/core-plugin-api';\nimport React from 'react';\nimport { Link } from 'react-router-dom';\nimport { DateTime } from 'luxon';\nimport { announcementViewRouteRef } from '../../routes';\nimport {\n useAnnouncements,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport { Progress } from '@backstage/core-components';\nimport {\n Timeline,\n TimelineItem,\n TimelineConnector,\n TimelineDot,\n TimelineSeparator,\n TimelineOppositeContent,\n TimelineContent,\n} from '@material-ui/lab';\nimport { Box, Typography } from '@material-ui/core';\nimport Stack from '@mui/material/Stack';\n\n/**\n * Props for the AnnouncementsTimeline component.\n *\n * @public\n */\nexport type AnnouncementsTimelineProps = {\n /**\n * The maximum number of results to display.\n * Default: 10\n */\n maxResults?: number;\n /**\n * The alignment of the timeline items. Can be 'left', 'right', or 'alternate'.\n * Default: 'alternate'\n */\n timelineAlignment?: 'left' | 'right' | 'alternate';\n /**\n * The minimum width of the timeline.\n * Default: '425px'\n */\n timelineMinWidth?: string;\n /**\n * Whether to only show active announcements.\n * Default: false\n */\n hideInactive?: boolean;\n};\n\n/**\n * Default alignment for the timeline.\n */\nconst DEFAULT_TIMELINE_ALIGNMENT = 'alternate';\n\n/**\n * Default width for the timeline.\n */\nconst DEFAULT_TIMELINE_WIDTH = '425px';\n\n/**\n * Default maximum number of results to display.\n */\nconst DEFAULT_RESULTS_MAX = 10;\n\n/**\n * Default setting for only displaying active annoucenments.\n */\nconst DEFAULT_INACTIVE = false;\n\n/**\n * Timeline of most recent announcements.\n *\n * @param options - The options for the announcements timeline.\n * @returns The rendered announcements timeline.\n */\nexport const AnnouncementsTimeline = ({\n maxResults = DEFAULT_RESULTS_MAX,\n timelineAlignment = DEFAULT_TIMELINE_ALIGNMENT,\n timelineMinWidth = DEFAULT_TIMELINE_WIDTH,\n hideInactive = DEFAULT_INACTIVE,\n}: AnnouncementsTimelineProps) => {\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n\n const { announcements, loading, error } = useAnnouncements({\n max: maxResults,\n active: hideInactive,\n });\n const { t } = useAnnouncementsTranslation();\n\n if (loading) {\n return <Progress />;\n }\n\n if (!announcements || announcements.count === 0)\n return <>{t('announcementsTimeline.noAnnouncements')}</>;\n\n if (error)\n return <>{`${t('announcementsTimeline.error')}: ${error.message}`}</>;\n\n return (\n <Stack\n direction=\"column\"\n justifyContent=\"center\"\n alignItems=\"center\"\n spacing={0}\n >\n <Box sx={{ minWidth: timelineMinWidth }}>\n <Timeline align={timelineAlignment}>\n {announcements.results.map(a => (\n <TimelineItem key={`ti-${a.id}`}>\n <TimelineOppositeContent\n key={`toc-${a.id}`}\n style={{ margin: 'auto 0' }}\n >\n {DateTime.fromISO(a.created_at).toRelative()}\n </TimelineOppositeContent>\n\n <TimelineSeparator>\n <TimelineConnector />\n <TimelineDot color=\"primary\" />\n <TimelineConnector />\n </TimelineSeparator>\n\n <TimelineContent key={`tc-${a.id}`}>\n <Link to={viewAnnouncementLink({ id: a.id })}>\n <Typography key={`th6-${a.id}`} variant=\"h6\" component=\"span\">\n {a.title}\n </Typography>\n </Link>\n <Typography key={`te-${a.id}`} variant=\"body2\">\n {a.excerpt}\n </Typography>\n </TimelineContent>\n </TimelineItem>\n ))}\n </Timeline>\n </Box>\n </Stack>\n );\n};\n"],"names":["React"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"AnnouncementsTimeline.esm.js","sources":["../../../src/components/AnnouncementsTimeline/AnnouncementsTimeline.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 { useRouteRef } from '@backstage/core-plugin-api';\nimport React from 'react';\nimport { Link } from 'react-router-dom';\nimport { DateTime } from 'luxon';\nimport { announcementViewRouteRef } from '../../routes';\nimport {\n useAnnouncements,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport { Progress } from '@backstage/core-components';\nimport {\n Timeline,\n TimelineItem,\n TimelineConnector,\n TimelineDot,\n TimelineSeparator,\n TimelineOppositeContent,\n TimelineContent,\n} from '@material-ui/lab';\nimport { Box, Typography } from '@material-ui/core';\nimport Stack from '@mui/material/Stack';\n\n/**\n * Props for the AnnouncementsTimeline component.\n *\n * @public\n */\nexport type AnnouncementsTimelineProps = {\n /**\n * The maximum number of results to display.\n * Default: 10\n */\n maxResults?: number;\n /**\n * The alignment of the timeline items. Can be 'left', 'right', or 'alternate'.\n * Default: 'alternate'\n */\n timelineAlignment?: 'left' | 'right' | 'alternate';\n /**\n * The minimum width of the timeline.\n * Default: '425px'\n */\n timelineMinWidth?: string;\n /**\n * Whether to only show active announcements.\n * Default: false\n */\n hideInactive?: boolean;\n /**\n * The field by which date time to sort the announcements.\n * Can be 'created_at' or 'start_at'.\n * Default: 'created_at'\n */\n sortBy?: 'created_at' | 'start_at';\n /**\n * The order in which to sort the announcements.\n * Can be 'asc' for ascending (older first) or 'desc' for descending (new first).\n * Default: 'desc'\n */\n order?: 'asc' | 'desc';\n};\n\n/**\n * Default alignment for the timeline.\n */\nconst DEFAULT_TIMELINE_ALIGNMENT = 'alternate';\n\n/**\n * Default width for the timeline.\n */\nconst DEFAULT_TIMELINE_WIDTH = '425px';\n\n/**\n * Default maximum number of results to display.\n */\nconst DEFAULT_RESULTS_MAX = 10;\n\n/**\n * Default setting for only displaying active annoucenments.\n */\nconst DEFAULT_INACTIVE = false;\n\n/**\n * Default sort by filter\n */\nconst DEFAULT_SORTBY = 'created_at';\n\n/**\n * Default order to display announcments. Newer announcements are display by default\n */\nconst DEFAULT_ORDER = 'desc';\n\n/**\n * Timeline of most recent announcements.\n *\n * @param options - The options for the announcements timeline.\n * @returns The rendered announcements timeline.\n */\nexport const AnnouncementsTimeline = ({\n maxResults = DEFAULT_RESULTS_MAX,\n timelineAlignment = DEFAULT_TIMELINE_ALIGNMENT,\n timelineMinWidth = DEFAULT_TIMELINE_WIDTH,\n hideInactive = DEFAULT_INACTIVE,\n sortBy = DEFAULT_SORTBY,\n order = DEFAULT_ORDER,\n}: AnnouncementsTimelineProps) => {\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n\n const { announcements, loading, error } = useAnnouncements({\n max: maxResults,\n active: hideInactive,\n sortBy,\n order,\n });\n const { t } = useAnnouncementsTranslation();\n\n if (loading) {\n return <Progress />;\n }\n\n if (!announcements || announcements.count === 0)\n return <>{t('announcementsTimeline.noAnnouncements')}</>;\n\n if (error)\n return <>{`${t('announcementsTimeline.error')}: ${error.message}`}</>;\n\n return (\n <Stack\n direction=\"column\"\n justifyContent=\"center\"\n alignItems=\"center\"\n spacing={0}\n >\n <Box sx={{ minWidth: timelineMinWidth }}>\n <Timeline align={timelineAlignment}>\n {announcements.results.map(a => (\n <TimelineItem key={`ti-${a.id}`}>\n <TimelineOppositeContent\n key={`toc-${a.id}`}\n style={{ margin: 'auto 0' }}\n >\n {DateTime.fromISO(a.created_at).toRelative()}\n </TimelineOppositeContent>\n\n <TimelineSeparator>\n <TimelineConnector />\n <TimelineDot color=\"primary\" />\n <TimelineConnector />\n </TimelineSeparator>\n\n <TimelineContent key={`tc-${a.id}`}>\n <Link to={viewAnnouncementLink({ id: a.id })}>\n <Typography key={`th6-${a.id}`} variant=\"h6\" component=\"span\">\n {a.title}\n </Typography>\n </Link>\n <Typography key={`te-${a.id}`} variant=\"body2\">\n {a.excerpt}\n </Typography>\n </TimelineContent>\n </TimelineItem>\n ))}\n </Timeline>\n </Box>\n </Stack>\n );\n};\n"],"names":["React"],"mappings":"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"}
|
|
@@ -14,7 +14,10 @@ import '@backstage/core-plugin-api';
|
|
|
14
14
|
import '@backstage-community/plugin-announcements-react';
|
|
15
15
|
import 'react-use/esm/useAsyncRetry';
|
|
16
16
|
import '@material-ui/core';
|
|
17
|
-
import '
|
|
17
|
+
import '@uiw/react-md-editor';
|
|
18
|
+
import './AnnouncementForm/CategoryInput.esm.js';
|
|
19
|
+
import '@material-ui/icons/SaveAlt';
|
|
20
|
+
import 'luxon';
|
|
18
21
|
import 'slugify';
|
|
19
22
|
import '@material-ui/icons/Delete';
|
|
20
23
|
import '@material-ui/icons/Edit';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.esm.js","sources":["../../src/components/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 React from 'react';\nimport { Routes, Route } from 'react-router-dom';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport {\n announcementCreatePermission,\n announcementUpdatePermission,\n} from '@backstage-community/plugin-announcements-common';\nimport {\n announcementAdminRouteRef,\n announcementCreateRouteRef,\n announcementEditRouteRef,\n announcementViewRouteRef,\n categoriesListRouteRef,\n} from '../routes';\nimport { AnnouncementsPage, AnnouncementsPageProps } from './AnnouncementsPage';\nimport { AnnouncementPage } from './AnnouncementPage';\nimport { CreateAnnouncementPage } from './CreateAnnouncementPage';\nimport { EditAnnouncementPage } from './EditAnnouncementPage';\nimport { CategoriesPage } from './CategoriesPage';\nimport { AdminPortal } from './Admin';\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};\n\nexport const Router = (props: RouterProps) => {\n const propsWithDefaults: AnnouncementsPageProps = {\n themeId: 'home',\n title: 'Announcements',\n hideInactive: false,\n ...props,\n };\n\n return (\n <Routes>\n <Route path=\"/\" element={<AnnouncementsPage {...propsWithDefaults} />} />\n <Route\n path={`${announcementViewRouteRef.path}`}\n element={<AnnouncementPage {...propsWithDefaults} />}\n />\n <Route\n path={`${announcementCreateRouteRef.path}`}\n element={\n <RequirePermission permission={announcementCreatePermission}>\n <CreateAnnouncementPage {...propsWithDefaults} />\n </RequirePermission>\n }\n />\n <Route\n path={`${announcementEditRouteRef.path}`}\n element={\n <RequirePermission permission={announcementUpdatePermission}>\n <EditAnnouncementPage {...propsWithDefaults} />\n </RequirePermission>\n }\n />\n <Route\n path={`${announcementAdminRouteRef.path}`}\n element={\n <RequirePermission permission={announcementCreatePermission}>\n <AdminPortal />\n </RequirePermission>\n }\n />\n\n <Route\n path={`${categoriesListRouteRef.path}`}\n element={<CategoriesPage themeId={propsWithDefaults.themeId} />}\n />\n </Routes>\n );\n};\n"],"names":["React"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Router.esm.js","sources":["../../src/components/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 React from 'react';\nimport { Routes, Route } from 'react-router-dom';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport {\n announcementCreatePermission,\n announcementUpdatePermission,\n} from '@backstage-community/plugin-announcements-common';\nimport {\n announcementAdminRouteRef,\n announcementCreateRouteRef,\n announcementEditRouteRef,\n announcementViewRouteRef,\n categoriesListRouteRef,\n} from '../routes';\nimport { AnnouncementsPage, AnnouncementsPageProps } from './AnnouncementsPage';\nimport { AnnouncementPage } from './AnnouncementPage';\nimport { CreateAnnouncementPage } from './CreateAnnouncementPage';\nimport { EditAnnouncementPage } from './EditAnnouncementPage';\nimport { CategoriesPage } from './CategoriesPage';\nimport { AdminPortal } from './Admin';\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};\n\nexport const Router = (props: RouterProps) => {\n const propsWithDefaults: AnnouncementsPageProps = {\n themeId: 'home',\n title: 'Announcements',\n hideInactive: false,\n ...props,\n };\n\n return (\n <Routes>\n <Route path=\"/\" element={<AnnouncementsPage {...propsWithDefaults} />} />\n <Route\n path={`${announcementViewRouteRef.path}`}\n element={<AnnouncementPage {...propsWithDefaults} />}\n />\n <Route\n path={`${announcementCreateRouteRef.path}`}\n element={\n <RequirePermission permission={announcementCreatePermission}>\n <CreateAnnouncementPage {...propsWithDefaults} />\n </RequirePermission>\n }\n />\n <Route\n path={`${announcementEditRouteRef.path}`}\n element={\n <RequirePermission permission={announcementUpdatePermission}>\n <EditAnnouncementPage {...propsWithDefaults} />\n </RequirePermission>\n }\n />\n <Route\n path={`${announcementAdminRouteRef.path}`}\n element={\n <RequirePermission permission={announcementCreatePermission}>\n <AdminPortal />\n </RequirePermission>\n }\n />\n\n <Route\n path={`${categoriesListRouteRef.path}`}\n element={<CategoriesPage themeId={propsWithDefaults.themeId} />}\n />\n </Routes>\n );\n};\n"],"names":["React"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAmDa,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,GAAG;AAAA,GACL;AAEA,EAAA,uBACGA,cAAA,CAAA,aAAA,CAAA,MAAA,EAAA,IAAA,kBACEA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAM,IAAK,EAAA,GAAA,EAAI,OAAS,kBAAAA,cAAA,CAAA,aAAA,CAAC,iBAAmB,EAAA,EAAA,GAAG,iBAAmB,EAAA,CAAA,EAAI,CACvE,kBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,CAAG,EAAA,wBAAA,CAAyB,IAAI,CAAA,CAAA;AAAA,MACtC,OAAS,kBAAAA,cAAA,CAAA,aAAA,CAAC,gBAAkB,EAAA,EAAA,GAAG,iBAAmB,EAAA;AAAA;AAAA,GAEpD,kBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,CAAG,EAAA,0BAAA,CAA2B,IAAI,CAAA,CAAA;AAAA,MACxC,OAAA,+CACG,iBAAkB,EAAA,EAAA,UAAA,EAAY,gDAC5BA,cAAA,CAAA,aAAA,CAAA,sBAAA,EAAA,EAAwB,GAAG,iBAAA,EAAmB,CACjD;AAAA;AAAA,GAGJ,kBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,CAAG,EAAA,wBAAA,CAAyB,IAAI,CAAA,CAAA;AAAA,MACtC,OAAA,+CACG,iBAAkB,EAAA,EAAA,UAAA,EAAY,gDAC5BA,cAAA,CAAA,aAAA,CAAA,oBAAA,EAAA,EAAsB,GAAG,iBAAA,EAAmB,CAC/C;AAAA;AAAA,GAGJ,kBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,CAAG,EAAA,yBAAA,CAA0B,IAAI,CAAA,CAAA;AAAA,MACvC,yBACGA,cAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,EAAkB,YAAY,4BAC7B,EAAA,kBAAAA,cAAA,CAAA,aAAA,CAAC,iBAAY,CACf;AAAA;AAAA,GAIJ,kBAAAA,cAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,CAAG,EAAA,sBAAA,CAAuB,IAAI,CAAA,CAAA;AAAA,MACpC,OAAS,kBAAAA,cAAA,CAAA,aAAA,CAAC,cAAe,EAAA,EAAA,OAAA,EAAS,kBAAkB,OAAS,EAAA;AAAA;AAAA,GAEjE,CAAA;AAEJ;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,18 @@ type AnnouncementsTimelineProps = {
|
|
|
31
31
|
* Default: false
|
|
32
32
|
*/
|
|
33
33
|
hideInactive?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* The field by which date time to sort the announcements.
|
|
36
|
+
* Can be 'created_at' or 'start_at'.
|
|
37
|
+
* Default: 'created_at'
|
|
38
|
+
*/
|
|
39
|
+
sortBy?: 'created_at' | 'start_at';
|
|
40
|
+
/**
|
|
41
|
+
* The order in which to sort the announcements.
|
|
42
|
+
* Can be 'asc' for ascending (older first) or 'desc' for descending (new first).
|
|
43
|
+
* Default: 'desc'
|
|
44
|
+
*/
|
|
45
|
+
order?: 'asc' | 'desc';
|
|
34
46
|
};
|
|
35
47
|
|
|
36
48
|
/** @public */
|
|
@@ -74,16 +86,18 @@ declare const AnnouncementsAdminPortal: (props?: {
|
|
|
74
86
|
/**
|
|
75
87
|
* @public
|
|
76
88
|
*/
|
|
77
|
-
declare const AnnouncementsTimeline: ({ maxResults, timelineAlignment, timelineMinWidth, hideInactive, }: AnnouncementsTimelineProps) => react.JSX.Element;
|
|
89
|
+
declare const AnnouncementsTimeline: ({ maxResults, timelineAlignment, timelineMinWidth, hideInactive, sortBy, order, }: AnnouncementsTimelineProps) => react.JSX.Element;
|
|
78
90
|
/**
|
|
79
91
|
* @public
|
|
80
92
|
*/
|
|
81
|
-
declare const AnnouncementsCard: ({ title, max, category, active, variant, }: {
|
|
93
|
+
declare const AnnouncementsCard: ({ title, max, category, active, variant, sortBy, order, }: {
|
|
82
94
|
title?: string | undefined;
|
|
83
95
|
max?: number | undefined;
|
|
84
96
|
category?: string | undefined;
|
|
85
97
|
active?: boolean | undefined;
|
|
86
98
|
variant?: _backstage_core_components_index.InfoCardVariants | undefined;
|
|
99
|
+
sortBy?: "created_at" | "start_at" | undefined;
|
|
100
|
+
order?: "desc" | "asc" | undefined;
|
|
87
101
|
}) => react.JSX.Element;
|
|
88
102
|
/**
|
|
89
103
|
* @public
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-announcements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"main": "./dist/index.esm.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"postpack": "backstage-cli package postpack"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@backstage-community/plugin-announcements-common": "^0.
|
|
62
|
-
"@backstage-community/plugin-announcements-react": "^0.
|
|
61
|
+
"@backstage-community/plugin-announcements-common": "^0.3.0",
|
|
62
|
+
"@backstage-community/plugin-announcements-react": "^0.4.0",
|
|
63
63
|
"@backstage/catalog-model": "^1.7.3",
|
|
64
64
|
"@backstage/core-app-api": "^1.15.4",
|
|
65
65
|
"@backstage/core-compat-api": "^0.3.5",
|