@backstage-community/plugin-announcements 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/dist/Router.esm.js +3 -0
- package/dist/Router.esm.js.map +1 -1
- package/dist/alpha/components/admin/announcements/AnnouncementForm/AnnouncementForm.esm.js +194 -126
- package/dist/alpha/components/admin/announcements/AnnouncementForm/AnnouncementForm.esm.js.map +1 -1
- package/dist/alpha/components/admin/announcements/AnnouncementForm/OnBehalfTeamDropdown.esm.js +35 -44
- package/dist/alpha/components/admin/announcements/AnnouncementForm/OnBehalfTeamDropdown.esm.js.map +1 -1
- package/dist/alpha/components/admin/announcements/AnnouncementsContent.esm.js +10 -43
- package/dist/alpha/components/admin/announcements/AnnouncementsContent.esm.js.map +1 -1
- package/dist/alpha/components/admin/announcements/AnnouncementsTable.esm.js +15 -1
- package/dist/alpha/components/admin/announcements/AnnouncementsTable.esm.js.map +1 -1
- package/dist/alpha/components/admin/categories/CategoriesContent.esm.js +2 -2
- package/dist/alpha/components/admin/categories/CategoriesContent.esm.js.map +1 -1
- package/dist/alpha/components/admin/categories/{CreateCatagoryDialog.esm.js → CreateCategoryDialog.esm.js} +3 -3
- package/dist/alpha/components/admin/categories/{CreateCatagoryDialog.esm.js.map → CreateCategoryDialog.esm.js.map} +1 -1
- package/dist/alpha/components/announcements/AnnouncementsFilterBar.esm.js +6 -2
- package/dist/alpha/components/announcements/AnnouncementsFilterBar.esm.js.map +1 -1
- package/dist/alpha/components/announcements/AnnouncementsGrid.esm.js +9 -12
- package/dist/alpha/components/announcements/AnnouncementsGrid.esm.js.map +1 -1
- package/dist/alpha/components/shared/CategorySelectInput/CategorySelectInput.esm.js +4 -3
- package/dist/alpha/components/shared/CategorySelectInput/CategorySelectInput.esm.js.map +1 -1
- package/dist/alpha/components/shared/TagsSelectInput/TagsSelectInput.esm.js +4 -3
- package/dist/alpha/components/shared/TagsSelectInput/TagsSelectInput.esm.js.map +1 -1
- package/package.json +12 -12
- package/dist/alpha/components/admin/announcements/AnnouncementForm/CategoryInput.esm.js +0 -82
- package/dist/alpha/components/admin/announcements/AnnouncementForm/CategoryInput.esm.js.map +0 -1
- package/dist/alpha/components/admin/announcements/AnnouncementForm/TagsInput.esm.js +0 -100
- package/dist/alpha/components/admin/announcements/AnnouncementForm/TagsInput.esm.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# @backstage-community/plugin-announcements
|
|
2
2
|
|
|
3
|
+
## 2.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 57c349e: `AnnouncementsOptions` has been dropped as an optional arg for the `useAnnouncements` hook in favor of handling state and dependencies internally.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [57c349e]
|
|
12
|
+
- @backstage-community/plugin-announcements-react@0.21.0
|
|
13
|
+
|
|
14
|
+
## 2.1.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- 99b4b52: Backstage version bump to v1.47.2
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- 1a71b9a: The On Behalf Of form component is now rewritten with `@backstage/ui`. The announcements table will now display the on behalf of group alongside publisher if present.
|
|
23
|
+
- 3e53912: The tags select component in the announcements form has been swapped with our new `@backstage/ui` select implementation
|
|
24
|
+
- 44a0337: The category selection in the announcements form has been refactored to use the new `CategorySelectInput` and `CreateCategoryDialog` components written with `@backstage/ui`. Category creation is now handled through the same mechanism as the categories table.
|
|
25
|
+
- 64a82b0: Updates all non-date related text inputs to use the `TextField` from `@backstage/ui`.
|
|
26
|
+
- 6f6d4c8: Switch components in the announcements form have been migrated to use `@backstage/ui`. The "Send notifications" label now includes support for translations.
|
|
27
|
+
- 41f738e: Updates the announcements form to use `@backstage/ui` for the following components:
|
|
28
|
+
|
|
29
|
+
- Box
|
|
30
|
+
- Button
|
|
31
|
+
- InfoCard -> Card, CardBody, CardHeader
|
|
32
|
+
- Grid
|
|
33
|
+
- Typography -> Text
|
|
34
|
+
- Paper -> _removed_
|
|
35
|
+
- Divider -> _removed_
|
|
36
|
+
|
|
37
|
+
These are minor changes that do not affect the functionality of the announcements form.
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [44a0337]
|
|
40
|
+
- Updated dependencies [6f6d4c8]
|
|
41
|
+
- Updated dependencies [99b4b52]
|
|
42
|
+
- @backstage-community/plugin-announcements-react@0.20.0
|
|
43
|
+
- @backstage-community/plugin-announcements-common@0.17.0
|
|
44
|
+
|
|
3
45
|
## 2.0.0
|
|
4
46
|
|
|
5
47
|
### Major Changes
|
package/dist/Router.esm.js
CHANGED
|
@@ -5,6 +5,9 @@ import { announcementCreatePermission } from '@backstage-community/plugin-announ
|
|
|
5
5
|
import { AnnouncementsAdminPage } from './alpha/components/admin/AnnouncementsAdminPage.esm.js';
|
|
6
6
|
import { AnnouncementsContent } from './alpha/components/admin/announcements/AnnouncementsContent.esm.js';
|
|
7
7
|
import { CategoriesContent } from './alpha/components/admin/categories/CategoriesContent.esm.js';
|
|
8
|
+
import '@backstage-community/plugin-announcements-react';
|
|
9
|
+
import 'react';
|
|
10
|
+
import '@backstage/ui';
|
|
8
11
|
import { TagsContent } from './alpha/components/admin/tags/TagsContent.esm.js';
|
|
9
12
|
import { AnnouncementsPage } from './alpha/components/announcements/AnnouncementsPage.esm.js';
|
|
10
13
|
import { ViewAnnouncementPage } from './alpha/components/announcements/ViewAnnouncementPage.esm.js';
|
package/dist/Router.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.esm.js","sources":["../src/Router.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Routes, Route } from 'react-router-dom';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';\nimport {\n AnnouncementsAdminPage,\n AnnouncementsContent,\n CategoriesContent,\n TagsContent,\n AnnouncementsPage,\n AnnouncementsPageProps,\n ViewAnnouncementPage,\n} from './alpha/components';\nimport { MarkdownRendererTypeProps } from './components';\n\nimport { compatWrapper } from '@backstage/core-compat-api';\n\ntype RouterProps = {\n title?: string;\n category?: string;\n hideStartAt?: boolean;\n markdownRenderer?: MarkdownRendererTypeProps;\n defaultInactive?: boolean;\n};\n\nexport const Router = (props: RouterProps) => {\n const propsWithDefaults: AnnouncementsPageProps = {\n title: 'Announcements',\n hideStartAt: false,\n markdownRenderer: 'backstage',\n ...props,\n };\n\n return (\n <Routes>\n <Route path=\"/\" element={<AnnouncementsPage {...propsWithDefaults} />} />\n <Route\n path=\"/view/:id\"\n element={\n <ViewAnnouncementPage\n markdownRenderer={propsWithDefaults.markdownRenderer}\n title={propsWithDefaults.title}\n />\n }\n />\n <Route\n path=\"/admin\"\n element={\n <RequirePermission permission={announcementCreatePermission}>\n <AnnouncementsAdminPage\n title={props.title}\n defaultInactive={props.defaultInactive}\n />\n </RequirePermission>\n }\n >\n <Route\n path=\"\"\n element={\n <AnnouncementsContent\n formDefaults={{ defaultInactive: props.defaultInactive }}\n />\n }\n />\n <Route path=\"categories\" element={<CategoriesContent />} />\n <Route path=\"tags\" element={<TagsContent />} />\n </Route>\n </Routes>\n );\n};\n\nexport const OldFrontendSystemCompatibleRouter = (props: RouterProps) => {\n return compatWrapper(<Router {...props} />);\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Router.esm.js","sources":["../src/Router.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Routes, Route } from 'react-router-dom';\nimport { RequirePermission } from '@backstage/plugin-permission-react';\nimport { announcementCreatePermission } from '@backstage-community/plugin-announcements-common';\nimport {\n AnnouncementsAdminPage,\n AnnouncementsContent,\n CategoriesContent,\n TagsContent,\n AnnouncementsPage,\n AnnouncementsPageProps,\n ViewAnnouncementPage,\n} from './alpha/components';\nimport { MarkdownRendererTypeProps } from './components';\n\nimport { compatWrapper } from '@backstage/core-compat-api';\n\ntype RouterProps = {\n title?: string;\n category?: string;\n hideStartAt?: boolean;\n markdownRenderer?: MarkdownRendererTypeProps;\n defaultInactive?: boolean;\n};\n\nexport const Router = (props: RouterProps) => {\n const propsWithDefaults: AnnouncementsPageProps = {\n title: 'Announcements',\n hideStartAt: false,\n markdownRenderer: 'backstage',\n ...props,\n };\n\n return (\n <Routes>\n <Route path=\"/\" element={<AnnouncementsPage {...propsWithDefaults} />} />\n <Route\n path=\"/view/:id\"\n element={\n <ViewAnnouncementPage\n markdownRenderer={propsWithDefaults.markdownRenderer}\n title={propsWithDefaults.title}\n />\n }\n />\n <Route\n path=\"/admin\"\n element={\n <RequirePermission permission={announcementCreatePermission}>\n <AnnouncementsAdminPage\n title={props.title}\n defaultInactive={props.defaultInactive}\n />\n </RequirePermission>\n }\n >\n <Route\n path=\"\"\n element={\n <AnnouncementsContent\n formDefaults={{ defaultInactive: props.defaultInactive }}\n />\n }\n />\n <Route path=\"categories\" element={<CategoriesContent />} />\n <Route path=\"tags\" element={<TagsContent />} />\n </Route>\n </Routes>\n );\n};\n\nexport const OldFrontendSystemCompatibleRouter = (props: RouterProps) => {\n return compatWrapper(<Router {...props} />);\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAuCa,MAAA,MAAA,GAAS,CAAC,KAAuB,KAAA;AAC5C,EAAA,MAAM,iBAA4C,GAAA;AAAA,IAChD,KAAO,EAAA,eAAA;AAAA,IACP,WAAa,EAAA,KAAA;AAAA,IACb,gBAAkB,EAAA,WAAA;AAAA,IAClB,GAAG;AAAA,GACL;AAEA,EAAA,4BACG,MACC,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,KAAA,EAAA,EAAM,MAAK,GAAI,EAAA,OAAA,sBAAU,iBAAmB,EAAA,EAAA,GAAG,mBAAmB,CAAI,EAAA,CAAA;AAAA,oBACvE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAK,EAAA,WAAA;AAAA,QACL,OACE,kBAAA,GAAA;AAAA,UAAC,oBAAA;AAAA,UAAA;AAAA,YACC,kBAAkB,iBAAkB,CAAA,gBAAA;AAAA,YACpC,OAAO,iBAAkB,CAAA;AAAA;AAAA;AAC3B;AAAA,KAEJ;AAAA,oBACA,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAK,EAAA,QAAA;AAAA,QACL,OACE,kBAAA,GAAA,CAAC,iBAAkB,EAAA,EAAA,UAAA,EAAY,4BAC7B,EAAA,QAAA,kBAAA,GAAA;AAAA,UAAC,sBAAA;AAAA,UAAA;AAAA,YACC,OAAO,KAAM,CAAA,KAAA;AAAA,YACb,iBAAiB,KAAM,CAAA;AAAA;AAAA,SAE3B,EAAA,CAAA;AAAA,QAGF,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,IAAK,EAAA,EAAA;AAAA,cACL,OACE,kBAAA,GAAA;AAAA,gBAAC,oBAAA;AAAA,gBAAA;AAAA,kBACC,YAAc,EAAA,EAAE,eAAiB,EAAA,KAAA,CAAM,eAAgB;AAAA;AAAA;AACzD;AAAA,WAEJ;AAAA,8BACC,KAAM,EAAA,EAAA,IAAA,EAAK,cAAa,OAAS,kBAAA,GAAA,CAAC,qBAAkB,CAAI,EAAA,CAAA;AAAA,8BACxD,KAAM,EAAA,EAAA,IAAA,EAAK,QAAO,OAAS,kBAAA,GAAA,CAAC,eAAY,CAAI,EAAA;AAAA;AAAA;AAAA;AAC/C,GACF,EAAA,CAAA;AAEJ;AAEa,MAAA,iCAAA,GAAoC,CAAC,KAAuB,KAAA;AACvE,EAAA,OAAO,aAAc,iBAAA,GAAA,CAAC,MAAQ,EAAA,EAAA,GAAG,OAAO,CAAE,CAAA;AAC5C;;;;"}
|
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import MDEditor from '@uiw/react-md-editor';
|
|
4
4
|
import { DateTime } from 'luxon';
|
|
5
5
|
import slugify from 'slugify';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
6
|
+
import { useApi, identityApiRef, alertApiRef } from '@backstage/core-plugin-api';
|
|
7
|
+
import { Card, CardHeader, Text, CardBody, Box, Grid, TextField, Flex, Button, Switch } from '@backstage/ui';
|
|
8
|
+
import { RiAddLine, RiSave2Line } from '@remixicon/react';
|
|
9
|
+
import { announcementsApiRef, useAnnouncementsTranslation, useCategories, useTags } from '@backstage-community/plugin-announcements-react';
|
|
10
|
+
import '@backstage/frontend-plugin-api';
|
|
11
|
+
import '../../../../../routes.esm.js';
|
|
12
|
+
import '@backstage/plugin-catalog-react';
|
|
13
|
+
import 'react-router-dom';
|
|
14
|
+
import { CategorySelectInput } from '../../../shared/CategorySelectInput/CategorySelectInput.esm.js';
|
|
15
|
+
import { TagsSelectInput } from '../../../shared/TagsSelectInput/TagsSelectInput.esm.js';
|
|
16
|
+
import { CreateCategoryDialog } from '../../categories/CreateCategoryDialog.esm.js';
|
|
17
|
+
import { CreateTagDialog } from '../../tags/CreateTagDialog.esm.js';
|
|
10
18
|
import OnBehalfTeamDropdown from './OnBehalfTeamDropdown.esm.js';
|
|
11
|
-
import
|
|
12
|
-
import Box from '@mui/material/Box';
|
|
13
|
-
import Button from '@mui/material/Button';
|
|
14
|
-
import Divider from '@mui/material/Divider';
|
|
15
|
-
import FormControlLabel from '@mui/material/FormControlLabel';
|
|
16
|
-
import FormGroup from '@mui/material/FormGroup';
|
|
17
|
-
import Grid from '@mui/material/Grid';
|
|
18
|
-
import Paper from '@mui/material/Paper';
|
|
19
|
-
import SaveAltIcon from '@mui/icons-material/SaveAlt';
|
|
20
|
-
import Switch from '@mui/material/Switch';
|
|
21
|
-
import TextField from '@mui/material/TextField';
|
|
22
|
-
import Typography from '@mui/material/Typography';
|
|
19
|
+
import MuiTextField from '@mui/material/TextField';
|
|
23
20
|
|
|
24
21
|
const AnnouncementForm = ({
|
|
25
22
|
initialData,
|
|
@@ -27,63 +24,114 @@ const AnnouncementForm = ({
|
|
|
27
24
|
}) => {
|
|
28
25
|
const identityApi = useApi(identityApiRef);
|
|
29
26
|
const announcementsApi = useApi(announcementsApiRef);
|
|
27
|
+
const alertApi = useApi(alertApiRef);
|
|
30
28
|
const { t } = useAnnouncementsTranslation();
|
|
29
|
+
const {
|
|
30
|
+
categories,
|
|
31
|
+
loading: categoriesLoading,
|
|
32
|
+
retry: refreshCategories
|
|
33
|
+
} = useCategories();
|
|
34
|
+
const { tags, loading: tagsLoading, retry: refreshTags } = useTags();
|
|
31
35
|
const formattedStartAt = initialData.start_at ? DateTime.fromISO(initialData.start_at).toISODate() : DateTime.now().toISODate();
|
|
32
36
|
const formattedUntilDate = initialData.until_date ? DateTime.fromISO(initialData.until_date).toISODate() : DateTime.now().endOf("day").plus({ days: 7 }).toISODate();
|
|
33
37
|
const [form, setForm] = useState({
|
|
34
38
|
...initialData,
|
|
35
39
|
active: initialData.active ?? true,
|
|
36
|
-
category: initialData.category
|
|
40
|
+
category: initialData.category ?? null,
|
|
37
41
|
start_at: formattedStartAt || "",
|
|
38
42
|
until_date: formattedUntilDate || "",
|
|
39
|
-
tags: initialData.tags
|
|
43
|
+
tags: initialData.tags ?? null,
|
|
40
44
|
sendNotification: initialData.sendNotification ?? false
|
|
41
45
|
});
|
|
42
46
|
const [loading, setLoading] = useState(false);
|
|
43
47
|
const [onBehalfOfSelectedTeam, setOnBehalfOfSelectedTeam] = useState(
|
|
44
48
|
initialData.on_behalf_of || ""
|
|
45
49
|
);
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
const [showCreateCategoryDialog, setShowCreateCategoryDialog] = useState(false);
|
|
51
|
+
const [showCreateTagDialog, setShowCreateTagDialog] = useState(false);
|
|
52
|
+
const handleCreateCategory = async (request) => {
|
|
53
|
+
const slugifiedTitle = slugify(request.title.trim(), { lower: true });
|
|
54
|
+
const existingCategory = categories.find(
|
|
55
|
+
(cat) => cat.slug === slugifiedTitle
|
|
56
|
+
);
|
|
57
|
+
if (existingCategory) {
|
|
58
|
+
alertApi.post({
|
|
59
|
+
message: t("categoriesForm.errors.alreadyExists"),
|
|
60
|
+
severity: "warning"
|
|
61
|
+
});
|
|
62
|
+
setForm((prevForm) => ({
|
|
63
|
+
...prevForm,
|
|
64
|
+
category: existingCategory
|
|
65
|
+
}));
|
|
66
|
+
setShowCreateCategoryDialog(false);
|
|
67
|
+
} else {
|
|
68
|
+
try {
|
|
69
|
+
await announcementsApi.createCategory(request);
|
|
70
|
+
alertApi.post({
|
|
71
|
+
message: t("newCategoryDialog.createdMessage"),
|
|
72
|
+
severity: "success"
|
|
73
|
+
});
|
|
74
|
+
setShowCreateCategoryDialog(false);
|
|
75
|
+
refreshCategories();
|
|
76
|
+
setForm((prevForm) => ({
|
|
77
|
+
...prevForm,
|
|
78
|
+
category: {
|
|
79
|
+
title: request.title,
|
|
80
|
+
slug: slugifiedTitle
|
|
81
|
+
}
|
|
82
|
+
}));
|
|
83
|
+
} catch (err) {
|
|
84
|
+
alertApi.post({ message: err.message, severity: "error" });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
51
87
|
};
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
88
|
+
const handleCreateTag = async (request) => {
|
|
89
|
+
const slugifiedTitle = slugify(request.title.trim(), { lower: true });
|
|
90
|
+
const existingTag = tags?.find((tag) => tag.slug === slugifiedTitle);
|
|
91
|
+
if (existingTag) {
|
|
92
|
+
alertApi.post({
|
|
93
|
+
message: t("tagsForm.errors.alreadyExists"),
|
|
94
|
+
severity: "warning"
|
|
95
|
+
});
|
|
96
|
+
setForm((prevForm) => ({
|
|
97
|
+
...prevForm,
|
|
98
|
+
tags: [...prevForm.tags ?? [], existingTag]
|
|
99
|
+
}));
|
|
100
|
+
setShowCreateTagDialog(false);
|
|
101
|
+
} else {
|
|
102
|
+
try {
|
|
103
|
+
await announcementsApi.createTag(request);
|
|
104
|
+
alertApi.post({
|
|
105
|
+
message: t("newTagDialog.createdMessage"),
|
|
106
|
+
severity: "success"
|
|
107
|
+
});
|
|
108
|
+
setShowCreateTagDialog(false);
|
|
109
|
+
refreshTags();
|
|
110
|
+
const newTag = { title: request.title, slug: slugifiedTitle };
|
|
111
|
+
setForm((prevForm) => ({
|
|
112
|
+
...prevForm,
|
|
113
|
+
tags: [...prevForm.tags ?? [], newTag]
|
|
114
|
+
}));
|
|
115
|
+
} catch (err) {
|
|
116
|
+
alertApi.post({ message: err.message, severity: "error" });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
57
119
|
};
|
|
58
120
|
const handleSubmit = async (event) => {
|
|
59
121
|
setLoading(true);
|
|
60
122
|
event.preventDefault();
|
|
61
123
|
const userIdentity = await identityApi.getBackstageIdentity();
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
} else {
|
|
70
|
-
try {
|
|
71
|
-
await announcementsApi.createTag({ title: tagValue });
|
|
72
|
-
processedTags.push(slugifiedTag);
|
|
73
|
-
} catch (error) {
|
|
74
|
-
if (error.status === 409) {
|
|
75
|
-
processedTags.push(slugifiedTag);
|
|
76
|
-
} else {
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
form.tags = processedTags;
|
|
83
|
-
}
|
|
84
|
-
const { id, created_at, ...announcementData } = form;
|
|
124
|
+
const {
|
|
125
|
+
id,
|
|
126
|
+
created_at,
|
|
127
|
+
category,
|
|
128
|
+
tags: formTags,
|
|
129
|
+
...announcementData
|
|
130
|
+
} = form;
|
|
85
131
|
const createRequest = {
|
|
86
132
|
...announcementData,
|
|
133
|
+
category: category?.slug,
|
|
134
|
+
tags: formTags?.map((tag) => tag.slug),
|
|
87
135
|
publisher: userIdentity.userEntityRef,
|
|
88
136
|
on_behalf_of: onBehalfOfSelectedTeam
|
|
89
137
|
};
|
|
@@ -95,68 +143,88 @@ const AnnouncementForm = ({
|
|
|
95
143
|
setLoading(false);
|
|
96
144
|
}
|
|
97
145
|
};
|
|
98
|
-
return /* @__PURE__ */
|
|
99
|
-
/* @__PURE__ */ jsx(
|
|
100
|
-
/* @__PURE__ */ jsx(
|
|
101
|
-
|
|
102
|
-
/* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
|
|
146
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
147
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(Text, { variant: "title-small", children: initialData.title ? t("announcementForm.editAnnouncement") : t("announcementForm.newAnnouncement") }) }),
|
|
148
|
+
/* @__PURE__ */ jsx(CardBody, { children: /* @__PURE__ */ jsx(Box, { p: "3", children: /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs(Grid.Root, { columns: "12", children: [
|
|
149
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: "12", children: /* @__PURE__ */ jsx(
|
|
103
150
|
TextField,
|
|
104
151
|
{
|
|
105
|
-
id: "title",
|
|
106
152
|
label: t("announcementForm.title"),
|
|
107
153
|
value: form.title,
|
|
108
|
-
onChange:
|
|
109
|
-
|
|
110
|
-
fullWidth: true,
|
|
111
|
-
required: true
|
|
154
|
+
onChange: (title) => setForm({ ...form, title }),
|
|
155
|
+
isRequired: true
|
|
112
156
|
}
|
|
113
157
|
) }),
|
|
114
|
-
/* @__PURE__ */ jsx(Grid, {
|
|
158
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: "12", children: /* @__PURE__ */ jsx(
|
|
115
159
|
TextField,
|
|
116
160
|
{
|
|
117
|
-
id: "excerpt",
|
|
118
161
|
label: t("announcementForm.excerpt"),
|
|
119
162
|
value: form.excerpt,
|
|
120
|
-
onChange:
|
|
121
|
-
|
|
122
|
-
fullWidth: true,
|
|
123
|
-
required: true,
|
|
124
|
-
multiline: true
|
|
125
|
-
}
|
|
126
|
-
) }),
|
|
127
|
-
/* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsx(
|
|
128
|
-
Paper,
|
|
129
|
-
{
|
|
130
|
-
variant: "outlined",
|
|
131
|
-
sx: { borderRadius: 2, borderColor: "divider", p: 2 },
|
|
132
|
-
children: /* @__PURE__ */ jsx(
|
|
133
|
-
MDEditor,
|
|
134
|
-
{
|
|
135
|
-
value: form.body,
|
|
136
|
-
style: { minHeight: "30rem" },
|
|
137
|
-
onChange: (value) => setForm({ ...form, ...{ body: value || "" } })
|
|
138
|
-
}
|
|
139
|
-
)
|
|
163
|
+
onChange: (excerpt) => setForm({ ...form, excerpt }),
|
|
164
|
+
isRequired: true
|
|
140
165
|
}
|
|
141
166
|
) }),
|
|
142
|
-
/* @__PURE__ */ jsx(Grid, {
|
|
143
|
-
|
|
167
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: "12", children: /* @__PURE__ */ jsx(
|
|
168
|
+
MDEditor,
|
|
144
169
|
{
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
170
|
+
value: form.body,
|
|
171
|
+
style: { minHeight: "30rem" },
|
|
172
|
+
onChange: (value) => setForm({ ...form, ...{ body: value || "" } })
|
|
148
173
|
}
|
|
149
174
|
) }),
|
|
150
|
-
/* @__PURE__ */ jsx(Grid, {
|
|
175
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: { xs: "12", md: "4" }, children: /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "end", children: [
|
|
176
|
+
/* @__PURE__ */ jsx(Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
|
|
177
|
+
CategorySelectInput,
|
|
178
|
+
{
|
|
179
|
+
initialCategory: form.category ?? void 0,
|
|
180
|
+
categories,
|
|
181
|
+
isLoading: categoriesLoading,
|
|
182
|
+
setCategory: (category) => setForm((prev) => ({ ...prev, category }))
|
|
183
|
+
}
|
|
184
|
+
) }),
|
|
185
|
+
/* @__PURE__ */ jsx(
|
|
186
|
+
Button,
|
|
187
|
+
{
|
|
188
|
+
"data-testid": "create-category-icon-button",
|
|
189
|
+
variant: "secondary",
|
|
190
|
+
size: "small",
|
|
191
|
+
iconStart: /* @__PURE__ */ jsx(RiAddLine, {}),
|
|
192
|
+
onClick: () => setShowCreateCategoryDialog(true),
|
|
193
|
+
"aria-label": t("admin.categoriesContent.createButton")
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
] }) }),
|
|
197
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: { xs: "12", md: "4" }, children: /* @__PURE__ */ jsx(
|
|
151
198
|
OnBehalfTeamDropdown,
|
|
152
199
|
{
|
|
153
200
|
selectedTeam: onBehalfOfSelectedTeam,
|
|
154
201
|
onChange: setOnBehalfOfSelectedTeam
|
|
155
202
|
}
|
|
156
203
|
) }),
|
|
157
|
-
/* @__PURE__ */ jsx(Grid, {
|
|
158
|
-
|
|
159
|
-
|
|
204
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: { xs: "12", md: "4" }, children: /* @__PURE__ */ jsxs(Flex, { gap: "2", align: "end", children: [
|
|
205
|
+
/* @__PURE__ */ jsx(Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
|
|
206
|
+
TagsSelectInput,
|
|
207
|
+
{
|
|
208
|
+
initialTags: form.tags ?? void 0,
|
|
209
|
+
tags,
|
|
210
|
+
isLoading: tagsLoading,
|
|
211
|
+
setTags: (selectedTags) => setForm((prev) => ({ ...prev, tags: selectedTags }))
|
|
212
|
+
}
|
|
213
|
+
) }),
|
|
214
|
+
/* @__PURE__ */ jsx(
|
|
215
|
+
Button,
|
|
216
|
+
{
|
|
217
|
+
"data-testid": "create-tag-icon-button",
|
|
218
|
+
variant: "secondary",
|
|
219
|
+
size: "small",
|
|
220
|
+
iconStart: /* @__PURE__ */ jsx(RiAddLine, {}),
|
|
221
|
+
onClick: () => setShowCreateTagDialog(true),
|
|
222
|
+
"aria-label": t("admin.tagsContent.createButton")
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
] }) }),
|
|
226
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: { xs: "12", md: "4" }, children: /* @__PURE__ */ jsx(
|
|
227
|
+
MuiTextField,
|
|
160
228
|
{
|
|
161
229
|
variant: "outlined",
|
|
162
230
|
label: t("announcementForm.startAt"),
|
|
@@ -172,8 +240,8 @@ const AnnouncementForm = ({
|
|
|
172
240
|
})
|
|
173
241
|
}
|
|
174
242
|
) }),
|
|
175
|
-
/* @__PURE__ */ jsx(Grid, {
|
|
176
|
-
|
|
243
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: { xs: "12", md: "4" }, children: /* @__PURE__ */ jsx(
|
|
244
|
+
MuiTextField,
|
|
177
245
|
{
|
|
178
246
|
variant: "outlined",
|
|
179
247
|
label: t("announcementForm.untilDate"),
|
|
@@ -191,53 +259,53 @@ const AnnouncementForm = ({
|
|
|
191
259
|
}
|
|
192
260
|
}
|
|
193
261
|
) }),
|
|
194
|
-
/* @__PURE__ */ jsx(Grid, {
|
|
195
|
-
/* @__PURE__ */ jsx(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs(FormGroup, { row: true, style: { justifyContent: "flex-end" }, children: [
|
|
262
|
+
/* @__PURE__ */ jsx(Grid.Item, { colSpan: "12", children: /* @__PURE__ */ jsxs(Flex, { justify: "end", children: [
|
|
196
263
|
/* @__PURE__ */ jsx(
|
|
197
|
-
|
|
264
|
+
Switch,
|
|
198
265
|
{
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
checked: form.active,
|
|
204
|
-
onChange: handleChangeActive,
|
|
205
|
-
color: "primary"
|
|
206
|
-
}
|
|
207
|
-
),
|
|
208
|
-
label: t("announcementForm.active")
|
|
266
|
+
name: "active",
|
|
267
|
+
label: t("announcementForm.active"),
|
|
268
|
+
isSelected: form.active,
|
|
269
|
+
onChange: (isSelected) => setForm({ ...form, active: isSelected })
|
|
209
270
|
}
|
|
210
271
|
),
|
|
211
272
|
/* @__PURE__ */ jsx(
|
|
212
|
-
|
|
273
|
+
Switch,
|
|
213
274
|
{
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
checked: form.sendNotification,
|
|
219
|
-
onChange: handleChangeActive,
|
|
220
|
-
color: "primary"
|
|
221
|
-
}
|
|
222
|
-
),
|
|
223
|
-
label: "Send Notification"
|
|
275
|
+
name: "sendNotification",
|
|
276
|
+
label: t("announcementForm.sendNotification"),
|
|
277
|
+
isSelected: form.sendNotification,
|
|
278
|
+
onChange: (isSelected) => setForm({ ...form, sendNotification: isSelected })
|
|
224
279
|
}
|
|
225
280
|
),
|
|
226
281
|
/* @__PURE__ */ jsx(
|
|
227
282
|
Button,
|
|
228
283
|
{
|
|
229
|
-
variant: "contained",
|
|
230
|
-
color: "primary",
|
|
231
284
|
type: "submit",
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
startIcon: /* @__PURE__ */ jsx(SaveAltIcon, {}),
|
|
285
|
+
isDisabled: loading || !form.body,
|
|
286
|
+
iconStart: /* @__PURE__ */ jsx(RiSave2Line, {}),
|
|
235
287
|
children: t("announcementForm.submit")
|
|
236
288
|
}
|
|
237
289
|
)
|
|
238
290
|
] }) })
|
|
239
|
-
] }) })
|
|
240
|
-
|
|
291
|
+
] }) }) }) }),
|
|
292
|
+
/* @__PURE__ */ jsx(
|
|
293
|
+
CreateCategoryDialog,
|
|
294
|
+
{
|
|
295
|
+
open: showCreateCategoryDialog,
|
|
296
|
+
onConfirm: handleCreateCategory,
|
|
297
|
+
onCancel: () => setShowCreateCategoryDialog(false)
|
|
298
|
+
}
|
|
299
|
+
),
|
|
300
|
+
/* @__PURE__ */ jsx(
|
|
301
|
+
CreateTagDialog,
|
|
302
|
+
{
|
|
303
|
+
open: showCreateTagDialog,
|
|
304
|
+
onConfirm: handleCreateTag,
|
|
305
|
+
onCancel: () => setShowCreateTagDialog(false)
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
] });
|
|
241
309
|
};
|
|
242
310
|
|
|
243
311
|
export { AnnouncementForm };
|
package/dist/alpha/components/admin/announcements/AnnouncementForm/AnnouncementForm.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnnouncementForm.esm.js","sources":["../../../../../../src/alpha/components/admin/announcements/AnnouncementForm/AnnouncementForm.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useState, type ChangeEvent, type FormEvent } from 'react';\nimport MDEditor from '@uiw/react-md-editor';\nimport { DateTime } from 'luxon';\nimport slugify from 'slugify';\nimport { InfoCard } from '@backstage/core-components';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport {\n CreateAnnouncementRequest,\n useAnnouncementsTranslation,\n announcementsApiRef,\n} from '@backstage-community/plugin-announcements-react';\nimport { Announcement } from '@backstage-community/plugin-announcements-common';\n\nimport CategoryInput from './CategoryInput';\nimport OnBehalfTeamDropdown from './OnBehalfTeamDropdown';\nimport TagsInput from './TagsInput';\n\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Divider from '@mui/material/Divider';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport FormGroup from '@mui/material/FormGroup';\nimport Grid from '@mui/material/Grid';\nimport Paper from '@mui/material/Paper';\nimport SaveAltIcon from '@mui/icons-material/SaveAlt';\nimport Switch from '@mui/material/Switch';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\ntype AnnouncementFormProps = {\n initialData: Announcement;\n onSubmit: (data: CreateAnnouncementRequest) => Promise<void>;\n};\n\nexport const AnnouncementForm = ({\n initialData,\n onSubmit,\n}: AnnouncementFormProps) => {\n const identityApi = useApi(identityApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const { t } = useAnnouncementsTranslation();\n\n const formattedStartAt = initialData.start_at\n ? DateTime.fromISO(initialData.start_at).toISODate()\n : DateTime.now().toISODate();\n\n const formattedUntilDate = initialData.until_date\n ? DateTime.fromISO(initialData.until_date).toISODate()\n : DateTime.now().endOf('day').plus({ days: 7 }).toISODate();\n\n const [form, setForm] = useState({\n ...initialData,\n active: initialData.active ?? true,\n category: initialData.category?.slug,\n start_at: formattedStartAt || '',\n until_date: formattedUntilDate || '',\n tags: initialData.tags?.map(tag => tag.slug) || undefined,\n sendNotification: initialData.sendNotification ?? false,\n });\n const [loading, setLoading] = useState(false);\n const [onBehalfOfSelectedTeam, setOnBehalfOfSelectedTeam] = useState(\n initialData.on_behalf_of || '',\n );\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.id]: event.target.value,\n });\n };\n\n const handleChangeActive = (event: ChangeEvent<HTMLInputElement>) => {\n setForm({\n ...form,\n [event.target.name]: event.target.checked,\n });\n };\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n setLoading(true);\n event.preventDefault();\n\n const userIdentity = await identityApi.getBackstageIdentity();\n\n if (form.tags && form.tags.length > 0) {\n const existingTags = await announcementsApi.tags();\n\n const processedTags = [];\n\n for (const tagValue of form.tags) {\n const slugifiedTag = slugify(tagValue.trim(), { lower: true });\n\n if (existingTags.some(tag => tag.slug === slugifiedTag)) {\n processedTags.push(slugifiedTag);\n } else {\n try {\n await announcementsApi.createTag({ title: tagValue });\n processedTags.push(slugifiedTag);\n } catch (error) {\n if (error.status === 409) {\n processedTags.push(slugifiedTag);\n } else {\n throw error;\n }\n }\n }\n }\n\n form.tags = processedTags;\n }\n\n const { id, created_at, ...announcementData } = form;\n\n const createRequest: CreateAnnouncementRequest = {\n ...announcementData,\n publisher: userIdentity.userEntityRef,\n on_behalf_of: onBehalfOfSelectedTeam,\n };\n\n try {\n await onSubmit(createRequest);\n } catch (error) {\n throw error;\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <InfoCard>\n <Box p={3}>\n <Typography variant=\"h5\" gutterBottom>\n {initialData.title\n ? t('announcementForm.editAnnouncement')\n : t('announcementForm.newAnnouncement')}\n </Typography>\n <Divider sx={{ mb: 3 }} />\n <form onSubmit={handleSubmit}>\n <Grid container spacing={3}>\n <Grid item xs={12}>\n <TextField\n id=\"title\"\n label={t('announcementForm.title')}\n value={form.title}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n />\n </Grid>\n\n <Grid item xs={12}>\n <TextField\n id=\"excerpt\"\n label={t('announcementForm.excerpt')}\n value={form.excerpt}\n onChange={handleChange}\n variant=\"outlined\"\n fullWidth\n required\n multiline\n />\n </Grid>\n\n <Grid item xs={12}>\n <Paper\n variant=\"outlined\"\n sx={{ borderRadius: 2, borderColor: 'divider', p: 2 }}\n >\n <MDEditor\n value={form.body}\n style={{ minHeight: '30rem' }}\n onChange={value =>\n setForm({ ...form, ...{ body: value || '' } })\n }\n />\n </Paper>\n </Grid>\n\n <Grid item xs={12} sm={6}>\n <CategoryInput\n setForm={setForm}\n form={form}\n initialValue={initialData.category?.title ?? ''}\n />\n </Grid>\n\n <Grid item xs={12} sm={6}>\n <OnBehalfTeamDropdown\n selectedTeam={onBehalfOfSelectedTeam}\n onChange={setOnBehalfOfSelectedTeam}\n />\n </Grid>\n\n <Grid item xs={12} sm={6}>\n <TagsInput setForm={setForm} form={form} />\n </Grid>\n\n <Grid item xs={12} sm={3}>\n <TextField\n variant=\"outlined\"\n label={t('announcementForm.startAt')}\n id=\"start-at-date\"\n type=\"date\"\n value={form.start_at}\n InputLabelProps={{ shrink: true }}\n required\n fullWidth\n onChange={e =>\n setForm({\n ...form,\n start_at: e.target.value,\n })\n }\n />\n </Grid>\n\n <Grid item xs={12} sm={3}>\n <TextField\n variant=\"outlined\"\n label={t('announcementForm.untilDate')}\n id=\"until-date\"\n type=\"date\"\n value={form.until_date}\n InputLabelProps={{ shrink: true }}\n fullWidth\n onChange={e =>\n setForm({\n ...form,\n until_date: e.target.value,\n })\n }\n inputProps={{\n min: DateTime.fromISO(form.start_at)\n .endOf('day')\n .plus({ days: 1 })\n .toISODate(),\n }}\n />\n </Grid>\n\n <Grid item xs={12}>\n <Divider />\n </Grid>\n\n <Grid item xs={12}>\n <FormGroup row style={{ justifyContent: 'flex-end' }}>\n <FormControlLabel\n control={\n <Switch\n name=\"active\"\n checked={form.active}\n onChange={handleChangeActive}\n color=\"primary\"\n />\n }\n label={t('announcementForm.active')}\n />\n <FormControlLabel\n control={\n <Switch\n name=\"sendNotification\"\n checked={form.sendNotification}\n onChange={handleChangeActive}\n color=\"primary\"\n />\n }\n label=\"Send Notification\"\n />\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={loading || !form.body}\n size=\"large\"\n startIcon={<SaveAltIcon />}\n >\n {t('announcementForm.submit')}\n </Button>\n </FormGroup>\n </Grid>\n </Grid>\n </form>\n </Box>\n </InfoCard>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnnouncementForm.esm.js","sources":["../../../../../../src/alpha/components/admin/announcements/AnnouncementForm/AnnouncementForm.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useState, type FormEvent } from 'react';\nimport MDEditor from '@uiw/react-md-editor';\nimport { DateTime } from 'luxon';\nimport slugify from 'slugify';\nimport {\n identityApiRef,\n useApi,\n alertApiRef,\n} from '@backstage/core-plugin-api';\nimport {\n Box,\n Button,\n Card,\n CardBody,\n CardHeader,\n Flex,\n Grid,\n Text,\n TextField,\n Switch,\n} from '@backstage/ui';\nimport { RiSave2Line, RiAddLine } from '@remixicon/react';\nimport {\n CreateAnnouncementRequest,\n CreateCategoryRequest,\n CreateTagRequest,\n useAnnouncementsTranslation,\n announcementsApiRef,\n useCategories,\n useTags,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n Category,\n Tag,\n} from '@backstage-community/plugin-announcements-common';\n\nimport { CategorySelectInput, TagsSelectInput } from '../../../shared';\nimport { CreateCategoryDialog } from '../../categories';\nimport { CreateTagDialog } from '../../tags';\nimport OnBehalfTeamDropdown from './OnBehalfTeamDropdown';\n\nimport MuiTextField from '@mui/material/TextField';\n\ntype AnnouncementFormProps = {\n initialData: Announcement;\n onSubmit: (data: CreateAnnouncementRequest) => Promise<void>;\n};\n\nexport const AnnouncementForm = ({\n initialData,\n onSubmit,\n}: AnnouncementFormProps) => {\n const identityApi = useApi(identityApiRef);\n const announcementsApi = useApi(announcementsApiRef);\n const alertApi = useApi(alertApiRef);\n const { t } = useAnnouncementsTranslation();\n const {\n categories,\n loading: categoriesLoading,\n retry: refreshCategories,\n } = useCategories();\n const { tags, loading: tagsLoading, retry: refreshTags } = useTags();\n\n const formattedStartAt = initialData.start_at\n ? DateTime.fromISO(initialData.start_at).toISODate()\n : DateTime.now().toISODate();\n\n const formattedUntilDate = initialData.until_date\n ? DateTime.fromISO(initialData.until_date).toISODate()\n : DateTime.now().endOf('day').plus({ days: 7 }).toISODate();\n\n const [form, setForm] = useState({\n ...initialData,\n active: initialData.active ?? true,\n category: initialData.category ?? null,\n start_at: formattedStartAt || '',\n until_date: formattedUntilDate || '',\n tags: initialData.tags ?? null,\n sendNotification: initialData.sendNotification ?? false,\n });\n const [loading, setLoading] = useState(false);\n const [onBehalfOfSelectedTeam, setOnBehalfOfSelectedTeam] = useState(\n initialData.on_behalf_of || '',\n );\n const [showCreateCategoryDialog, setShowCreateCategoryDialog] =\n useState(false);\n const [showCreateTagDialog, setShowCreateTagDialog] = useState(false);\n\n const handleCreateCategory = async (request: CreateCategoryRequest) => {\n const slugifiedTitle = slugify(request.title.trim(), { lower: true });\n const existingCategory = categories.find(\n cat => cat.slug === slugifiedTitle,\n );\n\n if (existingCategory) {\n alertApi.post({\n message: t('categoriesForm.errors.alreadyExists'),\n severity: 'warning',\n });\n\n // Select the existing category in the form\n setForm(prevForm => ({\n ...prevForm,\n category: existingCategory,\n }));\n\n setShowCreateCategoryDialog(false);\n } else {\n try {\n await announcementsApi.createCategory(request);\n\n alertApi.post({\n message: t('newCategoryDialog.createdMessage'),\n severity: 'success',\n });\n\n setShowCreateCategoryDialog(false);\n refreshCategories();\n\n // Select the new category in the form\n setForm(prevForm => ({\n ...prevForm,\n category: {\n title: request.title,\n slug: slugifiedTitle,\n },\n }));\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n }\n };\n\n const handleCreateTag = async (request: CreateTagRequest) => {\n const slugifiedTitle = slugify(request.title.trim(), { lower: true });\n const existingTag = tags?.find(tag => tag.slug === slugifiedTitle);\n\n if (existingTag) {\n alertApi.post({\n message: t('tagsForm.errors.alreadyExists'),\n severity: 'warning',\n });\n\n setForm(prevForm => ({\n ...prevForm,\n tags: [...(prevForm.tags ?? []), existingTag],\n }));\n\n setShowCreateTagDialog(false);\n } else {\n try {\n await announcementsApi.createTag(request);\n\n alertApi.post({\n message: t('newTagDialog.createdMessage'),\n severity: 'success',\n });\n\n setShowCreateTagDialog(false);\n refreshTags();\n\n const newTag = { title: request.title, slug: slugifiedTitle };\n\n setForm(prevForm => ({\n ...prevForm,\n tags: [...(prevForm.tags ?? []), newTag],\n }));\n } catch (err) {\n alertApi.post({ message: (err as Error).message, severity: 'error' });\n }\n }\n };\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {\n setLoading(true);\n event.preventDefault();\n\n const userIdentity = await identityApi.getBackstageIdentity();\n\n const {\n id,\n created_at,\n category,\n tags: formTags,\n ...announcementData\n } = form;\n\n const createRequest: CreateAnnouncementRequest = {\n ...announcementData,\n category: category?.slug,\n tags: formTags?.map(tag => tag.slug),\n publisher: userIdentity.userEntityRef,\n on_behalf_of: onBehalfOfSelectedTeam,\n };\n\n try {\n await onSubmit(createRequest);\n } catch (error) {\n throw error;\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <Card>\n <CardHeader>\n <Text variant=\"title-small\">\n {initialData.title\n ? t('announcementForm.editAnnouncement')\n : t('announcementForm.newAnnouncement')}\n </Text>\n </CardHeader>\n\n <CardBody>\n <Box p=\"3\">\n <form onSubmit={handleSubmit}>\n <Grid.Root columns=\"12\">\n <Grid.Item colSpan=\"12\">\n <TextField\n label={t('announcementForm.title')}\n value={form.title}\n onChange={title => setForm({ ...form, title })}\n isRequired\n />\n </Grid.Item>\n\n <Grid.Item colSpan=\"12\">\n <TextField\n label={t('announcementForm.excerpt')}\n value={form.excerpt}\n onChange={excerpt => setForm({ ...form, excerpt })}\n isRequired\n />\n </Grid.Item>\n\n <Grid.Item colSpan=\"12\">\n <MDEditor\n value={form.body}\n style={{ minHeight: '30rem' }}\n onChange={value =>\n setForm({ ...form, ...{ body: value || '' } })\n }\n />\n </Grid.Item>\n\n <Grid.Item colSpan={{ xs: '12', md: '4' }}>\n <Flex gap=\"2\" align=\"end\">\n <Box style={{ flex: 1 }}>\n <CategorySelectInput\n initialCategory={form.category ?? undefined}\n categories={categories}\n isLoading={categoriesLoading}\n setCategory={(category: Category | null) =>\n setForm(prev => ({ ...prev, category }))\n }\n />\n </Box>\n\n <Button\n data-testid=\"create-category-icon-button\"\n variant=\"secondary\"\n size=\"small\"\n iconStart={<RiAddLine />}\n onClick={() => setShowCreateCategoryDialog(true)}\n aria-label={t('admin.categoriesContent.createButton')}\n />\n </Flex>\n </Grid.Item>\n\n <Grid.Item colSpan={{ xs: '12', md: '4' }}>\n <OnBehalfTeamDropdown\n selectedTeam={onBehalfOfSelectedTeam}\n onChange={setOnBehalfOfSelectedTeam}\n />\n </Grid.Item>\n\n <Grid.Item colSpan={{ xs: '12', md: '4' }}>\n <Flex gap=\"2\" align=\"end\">\n <Box style={{ flex: 1 }}>\n <TagsSelectInput\n initialTags={form.tags ?? undefined}\n tags={tags}\n isLoading={tagsLoading}\n setTags={(selectedTags: Tag[] | null) =>\n setForm(prev => ({ ...prev, tags: selectedTags }))\n }\n />\n </Box>\n\n <Button\n data-testid=\"create-tag-icon-button\"\n variant=\"secondary\"\n size=\"small\"\n iconStart={<RiAddLine />}\n onClick={() => setShowCreateTagDialog(true)}\n aria-label={t('admin.tagsContent.createButton')}\n />\n </Flex>\n </Grid.Item>\n\n <Grid.Item colSpan={{ xs: '12', md: '4' }}>\n <MuiTextField\n variant=\"outlined\"\n label={t('announcementForm.startAt')}\n id=\"start-at-date\"\n type=\"date\"\n value={form.start_at}\n InputLabelProps={{ shrink: true }}\n required\n fullWidth\n onChange={e =>\n setForm({\n ...form,\n start_at: e.target.value,\n })\n }\n />\n </Grid.Item>\n\n <Grid.Item colSpan={{ xs: '12', md: '4' }}>\n <MuiTextField\n variant=\"outlined\"\n label={t('announcementForm.untilDate')}\n id=\"until-date\"\n type=\"date\"\n value={form.until_date}\n InputLabelProps={{ shrink: true }}\n fullWidth\n onChange={e =>\n setForm({\n ...form,\n until_date: e.target.value,\n })\n }\n inputProps={{\n min: DateTime.fromISO(form.start_at)\n .endOf('day')\n .plus({ days: 1 })\n .toISODate(),\n }}\n />\n </Grid.Item>\n\n <Grid.Item colSpan=\"12\">\n <Flex justify=\"end\">\n <Switch\n name=\"active\"\n label={t('announcementForm.active')}\n isSelected={form.active}\n onChange={isSelected =>\n setForm({ ...form, active: isSelected })\n }\n />\n <Switch\n name=\"sendNotification\"\n label={t('announcementForm.sendNotification')}\n isSelected={form.sendNotification}\n onChange={isSelected =>\n setForm({ ...form, sendNotification: isSelected })\n }\n />\n <Button\n type=\"submit\"\n isDisabled={loading || !form.body}\n iconStart={<RiSave2Line />}\n >\n {t('announcementForm.submit')}\n </Button>\n </Flex>\n </Grid.Item>\n </Grid.Root>\n </form>\n </Box>\n </CardBody>\n\n <CreateCategoryDialog\n open={showCreateCategoryDialog}\n onConfirm={handleCreateCategory}\n onCancel={() => setShowCreateCategoryDialog(false)}\n />\n\n <CreateTagDialog\n open={showCreateTagDialog}\n onConfirm={handleCreateTag}\n onCancel={() => setShowCreateTagDialog(false)}\n />\n </Card>\n );\n};\n"],"names":[],"mappings":"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"}
|