@boarteam/boar-pack-common-frontend 3.4.0 → 4.1.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/dist/components/ChangesModal/ChangesModal.d.ts +37 -0
- package/dist/components/ChangesModal/ChangesModal.js +143 -0
- package/dist/components/ChangesModal/ChangesModal.js.map +1 -0
- package/dist/components/ChangesModal/ChangesTab.d.ts +7 -0
- package/dist/components/ChangesModal/ChangesTab.js +29 -0
- package/dist/components/ChangesModal/ChangesTab.js.map +1 -0
- package/dist/components/ChangesModal/ConflictsTab.d.ts +10 -0
- package/dist/components/ChangesModal/ConflictsTab.js +105 -0
- package/dist/components/ChangesModal/ConflictsTab.js.map +1 -0
- package/dist/components/ChangesModal/ErrorsTab.d.ts +5 -0
- package/dist/components/ChangesModal/ErrorsTab.js +27 -0
- package/dist/components/ChangesModal/ErrorsTab.js.map +1 -0
- package/dist/components/ChangesModal/NewRecordsTab.d.ts +12 -0
- package/dist/components/ChangesModal/NewRecordsTab.js +24 -0
- package/dist/components/ChangesModal/NewRecordsTab.js.map +1 -0
- package/dist/components/ChangesModal/ResultsTab.d.ts +8 -0
- package/dist/components/ChangesModal/ResultsTab.js +12 -0
- package/dist/components/ChangesModal/ResultsTab.js.map +1 -0
- package/dist/components/ChangesModal/index.d.ts +1 -0
- package/dist/components/ChangesModal/index.js +5 -0
- package/dist/components/ChangesModal/index.js.map +1 -0
- package/dist/components/Comment/Comment.d.ts +12 -0
- package/dist/components/Comment/Comment.js +25 -0
- package/dist/components/Comment/Comment.js.map +1 -0
- package/dist/components/Comment/CommentAvatar.d.ts +7 -0
- package/dist/components/Comment/CommentAvatar.js +22 -0
- package/dist/components/Comment/CommentAvatar.js.map +1 -0
- package/dist/components/Comment/CommentForm.d.ts +6 -0
- package/dist/components/Comment/CommentForm.js +17 -0
- package/dist/components/Comment/CommentForm.js.map +1 -0
- package/dist/components/Comment/CommentFormModal.d.ts +10 -0
- package/dist/components/Comment/CommentFormModal.js +13 -0
- package/dist/components/Comment/CommentFormModal.js.map +1 -0
- package/dist/components/Comment/index.js +11 -0
- package/dist/components/Comment/index.js.map +1 -0
- package/dist/components/Descriptions/Descriptions.d.ts +4 -0
- package/dist/components/Descriptions/Descriptions.js +218 -0
- package/dist/components/Descriptions/Descriptions.js.map +1 -0
- package/dist/components/Descriptions/DescriptionsCreateModal.d.ts +3 -0
- package/dist/components/Descriptions/DescriptionsCreateModal.js +30 -0
- package/dist/components/Descriptions/DescriptionsCreateModal.js.map +1 -0
- package/dist/components/Descriptions/descriptionTypes.d.ts +68 -0
- package/dist/components/Descriptions/descriptionTypes.js +9 -0
- package/dist/components/Descriptions/descriptionTypes.js.map +1 -0
- package/dist/components/Descriptions/index.js +11 -0
- package/dist/components/Descriptions/index.js.map +1 -0
- package/dist/components/Descriptions/useContentViewMode.d.ts +10 -0
- package/dist/components/Descriptions/useContentViewMode.js +19 -0
- package/dist/components/Descriptions/useContentViewMode.js.map +1 -0
- package/dist/components/Descriptions/useDescriptionColumns.d.ts +8 -0
- package/dist/components/Descriptions/useDescriptionColumns.js +27 -0
- package/dist/components/Descriptions/useDescriptionColumns.js.map +1 -0
- package/dist/components/Inputs/DateRange.d.ts +8 -0
- package/dist/components/Inputs/DateRange.js +61 -0
- package/dist/components/Inputs/DateRange.js.map +1 -0
- package/dist/components/Inputs/MultiStringSelect.d.ts +5 -0
- package/dist/components/Inputs/MultiStringSelect.js +10 -0
- package/dist/components/Inputs/MultiStringSelect.js.map +1 -0
- package/dist/components/Inputs/NumberInputHandlingNewRecord.d.ts +3 -0
- package/dist/components/Inputs/NumberInputHandlingNewRecord.js +11 -0
- package/dist/components/Inputs/NumberInputHandlingNewRecord.js.map +1 -0
- package/dist/components/Inputs/NumberSwitcher.d.ts +8 -0
- package/dist/components/Inputs/NumberSwitcher.js +13 -0
- package/dist/components/Inputs/NumberSwitcher.js.map +1 -0
- package/dist/components/Inputs/Password.d.ts +3 -0
- package/dist/components/Inputs/Password.js +18 -0
- package/dist/components/Inputs/Password.js.map +1 -0
- package/dist/components/Inputs/RelationSelect.d.ts +21 -0
- package/dist/components/Inputs/RelationSelect.js +58 -0
- package/dist/components/Inputs/RelationSelect.js.map +1 -0
- package/dist/components/Inputs/SearchSelect.d.ts +12 -0
- package/dist/components/Inputs/SearchSelect.js +40 -0
- package/dist/components/Inputs/SearchSelect.js.map +1 -0
- package/dist/components/Inputs/filterDropdowns.d.ts +11 -0
- package/dist/components/Inputs/filterDropdowns.js +56 -0
- package/dist/components/Inputs/filterDropdowns.js.map +1 -0
- package/dist/components/Inputs/index.js +13 -0
- package/dist/components/Inputs/index.js.map +1 -0
- package/dist/components/Inputs/useCheckConnection.d.ts +13 -0
- package/dist/components/Inputs/useCheckConnection.js +53 -0
- package/dist/components/Inputs/useCheckConnection.js.map +1 -0
- package/dist/components/List/List.d.ts +3 -0
- package/dist/components/List/List.js +144 -0
- package/dist/components/List/List.js.map +1 -0
- package/dist/components/List/index.js +9 -0
- package/dist/components/List/index.js.map +1 -0
- package/dist/components/List/listTypes.d.ts +30 -0
- package/dist/components/List/listTypes.js +3 -0
- package/dist/components/List/listTypes.js.map +1 -0
- package/dist/components/QuestionMarkHint/QuestionMarkHint.d.ts +7 -0
- package/dist/components/QuestionMarkHint/QuestionMarkHint.js +16 -0
- package/dist/components/QuestionMarkHint/QuestionMarkHint.js.map +1 -0
- package/dist/components/QuestionMarkHint/index.js +5 -0
- package/dist/components/QuestionMarkHint/index.js.map +1 -0
- package/dist/components/Table/BulkDeleteButton.d.ts +8 -0
- package/dist/components/Table/BulkDeleteButton.js +27 -0
- package/dist/components/Table/BulkDeleteButton.js.map +1 -0
- package/dist/components/Table/BulkEditButton.d.ts +11 -0
- package/dist/components/Table/BulkEditButton.js +66 -0
- package/dist/components/Table/BulkEditButton.js.map +1 -0
- package/dist/components/Table/CreateEntityModal.d.ts +25 -0
- package/dist/components/Table/CreateEntityModal.js +23 -0
- package/dist/components/Table/CreateEntityModal.js.map +1 -0
- package/dist/components/Table/DeleteButton.d.ts +4 -0
- package/dist/components/Table/DeleteButton.js +28 -0
- package/dist/components/Table/DeleteButton.js.map +1 -0
- package/dist/components/Table/Table.d.ts +6 -0
- package/dist/components/Table/Table.js +154 -0
- package/dist/components/Table/Table.js.map +1 -0
- package/dist/components/Table/getTableDataQueryParams.d.ts +15 -0
- package/dist/components/Table/getTableDataQueryParams.js +37 -0
- package/dist/components/Table/getTableDataQueryParams.js.map +1 -0
- package/{src/components/Table/index.ts → dist/components/Table/index.d.ts} +1 -1
- package/dist/components/Table/index.js +14 -0
- package/dist/components/Table/index.js.map +1 -0
- package/dist/components/Table/tableTools.d.ts +38 -0
- package/dist/components/Table/tableTools.js +185 -0
- package/dist/components/Table/tableTools.js.map +1 -0
- package/dist/components/Table/tableTypes.d.ts +145 -0
- package/dist/components/Table/tableTypes.js +3 -0
- package/dist/components/Table/tableTypes.js.map +1 -0
- package/dist/components/Table/useBulkEditing.d.ts +30 -0
- package/dist/components/Table/useBulkEditing.js +79 -0
- package/dist/components/Table/useBulkEditing.js.map +1 -0
- package/dist/components/Table/useColumnsSets.d.ts +22 -0
- package/dist/components/Table/useColumnsSets.js +82 -0
- package/dist/components/Table/useColumnsSets.js.map +1 -0
- package/dist/components/Table/useCreation.d.ts +21 -0
- package/dist/components/Table/useCreation.js +75 -0
- package/dist/components/Table/useCreation.js.map +1 -0
- package/dist/components/Table/useEditableTable.d.ts +7 -0
- package/dist/components/Table/useEditableTable.js +63 -0
- package/dist/components/Table/useEditableTable.js.map +1 -0
- package/dist/components/Table/useImportExport.d.ts +35 -0
- package/dist/components/Table/useImportExport.js +207 -0
- package/dist/components/Table/useImportExport.js.map +1 -0
- package/dist/components/index.js +10 -0
- package/dist/components/index.js.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/ApiError.d.ts +16 -0
- package/dist/tools/ApiError.js +13 -0
- package/dist/tools/ApiError.js.map +1 -0
- package/dist/tools/WebsocketClient.d.ts +38 -0
- package/dist/tools/WebsocketClient.js +114 -0
- package/dist/tools/WebsocketClient.js.map +1 -0
- package/{src/tools/index.ts → dist/tools/index.d.ts} +1 -1
- package/dist/tools/index.js +10 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/numberTools.d.ts +1 -0
- package/dist/tools/numberTools.js +10 -0
- package/dist/tools/numberTools.js.map +1 -0
- package/dist/tools/safetyRun.d.ts +2 -0
- package/dist/tools/safetyRun.js +10 -0
- package/dist/tools/safetyRun.js.map +1 -0
- package/dist/tools/useFullscreen.d.ts +6 -0
- package/dist/tools/useFullscreen.js +56 -0
- package/dist/tools/useFullscreen.js.map +1 -0
- package/dist/tools/useTabs.d.ts +2 -0
- package/dist/tools/useTabs.js +18 -0
- package/dist/tools/useTabs.js.map +1 -0
- package/package.json +6 -4
- package/src/components/ChangesModal/ChangesModal.tsx +0 -262
- package/src/components/ChangesModal/ChangesTab.tsx +0 -51
- package/src/components/ChangesModal/ConflictsTab.tsx +0 -176
- package/src/components/ChangesModal/ErrorsTab.tsx +0 -49
- package/src/components/ChangesModal/NewRecordsTab.tsx +0 -48
- package/src/components/ChangesModal/ResultsTab.tsx +0 -28
- package/src/components/ChangesModal/index.ts +0 -1
- package/src/components/Comment/Comment.tsx +0 -53
- package/src/components/Comment/CommentAvatar.tsx +0 -34
- package/src/components/Comment/CommentForm.tsx +0 -36
- package/src/components/Comment/CommentFormModal.tsx +0 -31
- package/src/components/Descriptions/Descriptions.tsx +0 -351
- package/src/components/Descriptions/DescriptionsCreateModal.tsx +0 -65
- package/src/components/Descriptions/descriptionTypes.ts +0 -74
- package/src/components/Descriptions/useContentViewMode.tsx +0 -28
- package/src/components/Descriptions/useDescriptionColumns.ts +0 -42
- package/src/components/Inputs/DateRange.tsx +0 -75
- package/src/components/Inputs/MultiStringSelect.tsx +0 -20
- package/src/components/Inputs/NumberInputHandlingNewRecord.tsx +0 -11
- package/src/components/Inputs/NumberSwitcher.tsx +0 -27
- package/src/components/Inputs/Password.tsx +0 -33
- package/src/components/Inputs/RelationSelect.tsx +0 -108
- package/src/components/Inputs/SearchSelect.tsx +0 -93
- package/src/components/Inputs/filterDropdowns.tsx +0 -141
- package/src/components/Inputs/useCheckConnection.tsx +0 -79
- package/src/components/List/List.tsx +0 -266
- package/src/components/List/listTypes.ts +0 -31
- package/src/components/QuestionMarkHint/QuestionMarkHint.tsx +0 -33
- package/src/components/Table/BulkDeleteButton.tsx +0 -55
- package/src/components/Table/BulkEditButton.tsx +0 -160
- package/src/components/Table/CreateEntityModal.tsx +0 -85
- package/src/components/Table/DeleteButton.tsx +0 -44
- package/src/components/Table/Table.tsx +0 -316
- package/src/components/Table/getTableDataQueryParams.ts +0 -79
- package/src/components/Table/tableTools.ts +0 -244
- package/src/components/Table/tableTypes.ts +0 -152
- package/src/components/Table/useBulkEditing.tsx +0 -128
- package/src/components/Table/useColumnsSets.tsx +0 -142
- package/src/components/Table/useCreation.tsx +0 -114
- package/src/components/Table/useEditableTable.tsx +0 -86
- package/src/components/Table/useImportExport.tsx +0 -312
- package/src/tools/ApiError.ts +0 -18
- package/src/tools/WebsocketClient.ts +0 -138
- package/src/tools/numberTools.ts +0 -6
- package/src/tools/safetyRun.ts +0 -5
- package/src/tools/useFullscreen.tsx +0 -62
- package/src/tools/useTabs.ts +0 -17
- /package/{src/components/Comment/index.ts → dist/components/Comment/index.d.ts} +0 -0
- /package/{src/components/Descriptions/index.ts → dist/components/Descriptions/index.d.ts} +0 -0
- /package/{src/components/Inputs/index.ts → dist/components/Inputs/index.d.ts} +0 -0
- /package/{src/components/List/index.ts → dist/components/List/index.d.ts} +0 -0
- /package/{src/components/QuestionMarkHint/index.ts → dist/components/QuestionMarkHint/index.d.ts} +0 -0
- /package/{src/components/index.ts → dist/components/index.d.ts} +0 -0
- /package/{src/index.ts → dist/index.d.ts} +0 -0
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { List, Tag } from "antd";
|
|
2
|
-
import { TServerErrorItem } from "./ChangesModal";
|
|
3
|
-
|
|
4
|
-
const formatField = (field: string) => {
|
|
5
|
-
const parts = field.split(".");
|
|
6
|
-
if (parts[0] === "new" && parts.length >= 3) {
|
|
7
|
-
const idx = Number(parts[1]);
|
|
8
|
-
return `New #${isNaN(idx) ? parts[1] : idx + 1}: ${parts.slice(2).join(".")}`;
|
|
9
|
-
}
|
|
10
|
-
if (parts[0] === "updated" && parts.length >= 3) {
|
|
11
|
-
const id = parts[1];
|
|
12
|
-
return `Updated ${id}: ${parts.slice(2).join(".")}`;
|
|
13
|
-
}
|
|
14
|
-
return field;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const ErrorsTab = ({
|
|
18
|
-
serverErrors,
|
|
19
|
-
}: {
|
|
20
|
-
serverErrors: TServerErrorItem[],
|
|
21
|
-
}) => {
|
|
22
|
-
if (serverErrors.length === 0) {
|
|
23
|
-
return <div>No errors</div>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
[
|
|
28
|
-
<p key='errors-header'>Please fix the following errors and repeat import</p>,
|
|
29
|
-
<List
|
|
30
|
-
key='errors-list'
|
|
31
|
-
size="small"
|
|
32
|
-
dataSource={serverErrors}
|
|
33
|
-
renderItem={(err, idx) => (
|
|
34
|
-
<List.Item key={idx}>
|
|
35
|
-
<div style={{ display: "flex", flexDirection: "column", gap: 4, width: "100%" }}>
|
|
36
|
-
{err.field && <div>
|
|
37
|
-
<Tag color="error">{formatField(err.field)}</Tag>
|
|
38
|
-
</div>}
|
|
39
|
-
<div>{err.message}</div>
|
|
40
|
-
{err.field && <div style={{ color: "#999" }}>({err.field})</div>}
|
|
41
|
-
</div>
|
|
42
|
-
</List.Item>
|
|
43
|
-
)}
|
|
44
|
-
/>,
|
|
45
|
-
]
|
|
46
|
-
);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export default ErrorsTab;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { ProColumns } from "@ant-design/pro-components";
|
|
2
|
-
import { TDiffResult } from "../Table/useImportExport";
|
|
3
|
-
import ProTable from "@ant-design/pro-table";
|
|
4
|
-
import useColumnsSets, { TColumnsSet } from "../Table/useColumnsSets";
|
|
5
|
-
|
|
6
|
-
export type TCreatedRecordsColumnsConfig<Entity> = {
|
|
7
|
-
columnsSets?: TColumnsSet<Entity>[],
|
|
8
|
-
columns: ProColumns<Entity>[],
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function NewRecordsTab<Entity>({
|
|
12
|
-
created,
|
|
13
|
-
createdRecordsColumnsConfig,
|
|
14
|
-
}: {
|
|
15
|
-
created: TDiffResult<Entity>['created'],
|
|
16
|
-
createdRecordsColumnsConfig: TCreatedRecordsColumnsConfig<Entity>,
|
|
17
|
-
}) {
|
|
18
|
-
const { columns, columnsSets } = createdRecordsColumnsConfig;
|
|
19
|
-
|
|
20
|
-
const {
|
|
21
|
-
columnsSetSelect,
|
|
22
|
-
columnsState,
|
|
23
|
-
} = useColumnsSets<Entity>({
|
|
24
|
-
columns,
|
|
25
|
-
columnsSets,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
if (!created.length) {
|
|
29
|
-
return <p>No new records found.</p>
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return [
|
|
33
|
-
<h3 key='new-records-header'>New Records (Local Comparing)</h3>,
|
|
34
|
-
<ProTable<Entity>
|
|
35
|
-
key='new-records-data'
|
|
36
|
-
dataSource={created}
|
|
37
|
-
columns={columns}
|
|
38
|
-
columnsState={columnsState}
|
|
39
|
-
toolBarRender={(...args) => [
|
|
40
|
-
columnsSetSelect?.() || null,
|
|
41
|
-
]}
|
|
42
|
-
rowKey={(record, index) => index}
|
|
43
|
-
search={false}
|
|
44
|
-
/>,
|
|
45
|
-
];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export default NewRecordsTab;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { CheckCircleOutlined, SyncOutlined } from "@ant-design/icons";
|
|
2
|
-
|
|
3
|
-
type TImportStatistic = {
|
|
4
|
-
created: number;
|
|
5
|
-
updated: number;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const ResultsTab = ({
|
|
9
|
-
importStatistic
|
|
10
|
-
}: {
|
|
11
|
-
importStatistic: TImportStatistic
|
|
12
|
-
}) => {
|
|
13
|
-
return [
|
|
14
|
-
<h3 key='results-header'>Import Results</h3>,
|
|
15
|
-
<div key='results-data' style={{ display: "flex", gap: "16px", alignItems: "center" }}>
|
|
16
|
-
<div style={{ display: "flex", alignItems: "center" }}>
|
|
17
|
-
<CheckCircleOutlined style={{ color: "#52c41a", marginRight: "8px" }} />
|
|
18
|
-
<span>Created: {importStatistic.created}</span>
|
|
19
|
-
</div>
|
|
20
|
-
<div style={{ display: "flex", alignItems: "center" }}>
|
|
21
|
-
<SyncOutlined style={{ color: "#1890ff", marginRight: "8px" }} />
|
|
22
|
-
<span>Updated: {importStatistic.updated}</span>
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
]
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export default ResultsTab;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './ChangesModal';
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import dayjs from "dayjs";
|
|
2
|
-
import { createStyles } from "antd-style";
|
|
3
|
-
import CommentAvatar from "./CommentAvatar";
|
|
4
|
-
|
|
5
|
-
export interface AuthorProps {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface CommentProps {
|
|
11
|
-
key: string;
|
|
12
|
-
content: string;
|
|
13
|
-
author: AuthorProps;
|
|
14
|
-
date: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const useStyles = createStyles(() => {
|
|
18
|
-
return {
|
|
19
|
-
/**
|
|
20
|
-
* Styles for the ant-descriptions component to show edit icon on hover
|
|
21
|
-
*/
|
|
22
|
-
commentStyles: {
|
|
23
|
-
display: 'flex',
|
|
24
|
-
alignItems: 'flex-start',
|
|
25
|
-
gap: '10px'
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const Comment: React.FC<CommentProps> = ({
|
|
31
|
-
content,
|
|
32
|
-
author,
|
|
33
|
-
date,
|
|
34
|
-
...rest
|
|
35
|
-
}) => {
|
|
36
|
-
const { styles } = useStyles();
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<div
|
|
40
|
-
className={styles.commentStyles}
|
|
41
|
-
{...rest}
|
|
42
|
-
>
|
|
43
|
-
<CommentAvatar author={author} />
|
|
44
|
-
<div>
|
|
45
|
-
<strong>{author.name}</strong>
|
|
46
|
-
<p>{content}</p>
|
|
47
|
-
<small style={{ color: '#888' }}>{dayjs(date).format('DD.MM.YYYY HH:mm')}</small>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
export default Comment;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Avatar } from "antd";
|
|
2
|
-
import { AuthorProps } from "./Comment";
|
|
3
|
-
import React from "react";
|
|
4
|
-
|
|
5
|
-
interface CommentProps {
|
|
6
|
-
author: AuthorProps;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const ColorList = [
|
|
10
|
-
'#f56a00',
|
|
11
|
-
'#7265e6',
|
|
12
|
-
'#ffbf00',
|
|
13
|
-
'#00a2ae',
|
|
14
|
-
'#b45d7e',
|
|
15
|
-
'#ace665',
|
|
16
|
-
'#6e3aaf',
|
|
17
|
-
'#54ae00'
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
const getColorByAuthor = (authorId: string) => {
|
|
21
|
-
return ColorList[parseInt(authorId, 36) % ColorList.length]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const CommentAvatar: React.FC<CommentProps> = ({
|
|
25
|
-
author,
|
|
26
|
-
}) => {
|
|
27
|
-
return (
|
|
28
|
-
<Avatar style={{ backgroundColor: getColorByAuthor(author.id), verticalAlign: 'middle', flexShrink: 0 }} size="large">
|
|
29
|
-
{author.name.slice(0, 1)}
|
|
30
|
-
</Avatar>
|
|
31
|
-
);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export default CommentAvatar;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Form, Input, Button } from 'antd';
|
|
3
|
-
|
|
4
|
-
interface CommentFormProps {
|
|
5
|
-
onSubmit: (content: string) => void;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const CommentForm: React.FC<CommentFormProps> = ({ onSubmit }) => {
|
|
9
|
-
const [content, setContent] = useState('');
|
|
10
|
-
|
|
11
|
-
const handleSubmit = () => {
|
|
12
|
-
if (content.trim()) {
|
|
13
|
-
onSubmit(content);
|
|
14
|
-
setContent('');
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<Form layout="vertical" onFinish={handleSubmit}>
|
|
20
|
-
<div>
|
|
21
|
-
<Form.Item label="Leave a comment:">
|
|
22
|
-
<Input.TextArea
|
|
23
|
-
value={content}
|
|
24
|
-
onChange={(e) => setContent(e.target.value)}
|
|
25
|
-
autoSize={{ minRows: 3, maxRows: 6 }}
|
|
26
|
-
/>
|
|
27
|
-
</Form.Item>
|
|
28
|
-
</div>
|
|
29
|
-
<Button type="primary" htmlType="submit" style={{ width: 100 }}>
|
|
30
|
-
Send
|
|
31
|
-
</Button>
|
|
32
|
-
</Form>
|
|
33
|
-
);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export default CommentForm;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Modal } from 'antd';
|
|
3
|
-
import CommentForm from "./CommentForm";
|
|
4
|
-
|
|
5
|
-
interface CommentFormProps {
|
|
6
|
-
isOpen: boolean;
|
|
7
|
-
setIsOpen: (open: boolean) => void;
|
|
8
|
-
onSubmit: (content: string) => void;
|
|
9
|
-
children?: React.ReactNode;
|
|
10
|
-
title?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const CommentFormModal: React.FC<CommentFormProps> = ({ setIsOpen, isOpen, onSubmit, children, title = 'Add comment' }) => {
|
|
14
|
-
return (
|
|
15
|
-
<Modal
|
|
16
|
-
title={title}
|
|
17
|
-
open={isOpen}
|
|
18
|
-
width={800}
|
|
19
|
-
closeIcon={true}
|
|
20
|
-
footer={null}
|
|
21
|
-
onCancel={() => {
|
|
22
|
-
setIsOpen(false);
|
|
23
|
-
}}
|
|
24
|
-
>
|
|
25
|
-
{children}
|
|
26
|
-
<CommentForm onSubmit={onSubmit} />
|
|
27
|
-
</Modal>
|
|
28
|
-
);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export default CommentFormModal;
|
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
import { ActionType } from "@ant-design/pro-table";
|
|
2
|
-
import React, { Key, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
3
|
-
import { Badge, Button, Result, Tabs, TabsProps, Tooltip } from "antd";
|
|
4
|
-
import { DeleteOutlined, StopOutlined } from "@ant-design/icons";
|
|
5
|
-
import { FormattedMessage, useIntl } from "react-intl";
|
|
6
|
-
import { DescriptionsRefType, FieldsEdit, TDescriptionsProps, TGetOneParams } from "./descriptionTypes";
|
|
7
|
-
import { PageLoading, ProDescriptions } from "@ant-design/pro-components";
|
|
8
|
-
import { columnsToDescriptionItemProps, TDescriptionSection } from "./useDescriptionColumns";
|
|
9
|
-
import pick from "lodash/pick";
|
|
10
|
-
import safetyRun from "../../tools/safetyRun";
|
|
11
|
-
import {
|
|
12
|
-
buildFieldsFromColumnsForDescriptionsDisplay,
|
|
13
|
-
buildJoinFields,
|
|
14
|
-
collectFieldsFromColumns,
|
|
15
|
-
} from "../Table";
|
|
16
|
-
import { RowEditableConfig } from "@ant-design/pro-utils";
|
|
17
|
-
import { useForm } from "antd/es/form/Form";
|
|
18
|
-
import useContentViewMode, { VIEW_MODE_TYPE } from "./useContentViewMode";
|
|
19
|
-
import { createStyles } from "antd-style";
|
|
20
|
-
import { debounce } from "lodash";
|
|
21
|
-
import { NamePath } from "antd/lib/form/interface";
|
|
22
|
-
import { FieldData } from "rc-field-form/lib/interface";
|
|
23
|
-
|
|
24
|
-
const useStyles = createStyles(({css}) => {
|
|
25
|
-
return {
|
|
26
|
-
antDescriptionsStyles: css`
|
|
27
|
-
.ant-descriptions-item-content {
|
|
28
|
-
.anticon-edit {
|
|
29
|
-
opacity: 0;
|
|
30
|
-
transition: opacity 200ms;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
&:hover {
|
|
34
|
-
.anticon-edit {
|
|
35
|
-
opacity: 1;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
`
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const DescriptionsComponent = <Entity extends Record<string | symbol, any>,
|
|
44
|
-
CreateDto = Entity,
|
|
45
|
-
UpdateDto = Entity,
|
|
46
|
-
TPathParams = object,
|
|
47
|
-
>(
|
|
48
|
-
{
|
|
49
|
-
mainTitle = 'General',
|
|
50
|
-
entity,
|
|
51
|
-
getOne,
|
|
52
|
-
onUpdate,
|
|
53
|
-
onCreate,
|
|
54
|
-
pathParams,
|
|
55
|
-
idColumnName = 'id',
|
|
56
|
-
entityToUpdateDto,
|
|
57
|
-
afterSave,
|
|
58
|
-
actionRef: actionRefProp,
|
|
59
|
-
editable,
|
|
60
|
-
canEdit = false,
|
|
61
|
-
fieldsEditType = FieldsEdit.Single,
|
|
62
|
-
columns,
|
|
63
|
-
params,
|
|
64
|
-
onEntityChange,
|
|
65
|
-
contentViewMode: contentViewModeProp,
|
|
66
|
-
...rest
|
|
67
|
-
}: TDescriptionsProps<Entity,
|
|
68
|
-
CreateDto,
|
|
69
|
-
UpdateDto,
|
|
70
|
-
TPathParams>,
|
|
71
|
-
ref: React.Ref<DescriptionsRefType<Entity>>,
|
|
72
|
-
) => {
|
|
73
|
-
const { styles } = useStyles();
|
|
74
|
-
|
|
75
|
-
let [form] = useForm<Entity>();
|
|
76
|
-
if (!editable?.form) {
|
|
77
|
-
editable = {
|
|
78
|
-
...editable,
|
|
79
|
-
form,
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
form = editable.form;
|
|
83
|
-
|
|
84
|
-
const actionRefComponent = useRef<ActionType>();
|
|
85
|
-
const actionRef = actionRefProp || actionRefComponent;
|
|
86
|
-
const intl = useIntl();
|
|
87
|
-
const [data, setData] = useState<Partial<Entity> | undefined>(entity);
|
|
88
|
-
const [loading, setLoading] = useState(false);
|
|
89
|
-
|
|
90
|
-
const sections = columnsToDescriptionItemProps(columns, mainTitle);
|
|
91
|
-
|
|
92
|
-
const recalculateErrors = () => {
|
|
93
|
-
// Recalculate the error count per section (tab) after validation
|
|
94
|
-
const newErrorsPerSection = new Map<string, number>();
|
|
95
|
-
sections.forEach((section) => {
|
|
96
|
-
let errorCount = 0;
|
|
97
|
-
section.columns.forEach((column) => {
|
|
98
|
-
if (form.getFieldError(column.dataIndex as NamePath<Entity>)?.length > 0) {
|
|
99
|
-
errorCount++;
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
newErrorsPerSection.set(section.key, errorCount);
|
|
103
|
-
});
|
|
104
|
-
setErrorsPerSection(newErrorsPerSection);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const columnDataIndexToSection = sections.reduce((acc, section) => {
|
|
108
|
-
section.columns.forEach(column => {
|
|
109
|
-
if (Array.isArray(column.dataIndex)) {
|
|
110
|
-
throw new Error('We only support simple dataIndex for now');
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
acc.set(column.dataIndex, section);
|
|
114
|
-
})
|
|
115
|
-
return acc;
|
|
116
|
-
}, new Map<Key, TDescriptionSection<Entity>>());
|
|
117
|
-
|
|
118
|
-
const {
|
|
119
|
-
contentViewModeButton,
|
|
120
|
-
contentViewMode
|
|
121
|
-
} = useContentViewMode({
|
|
122
|
-
mode: contentViewModeProp || (sections.length > 1 ? VIEW_MODE_TYPE.TABS : VIEW_MODE_TYPE.GENERAL)
|
|
123
|
-
});
|
|
124
|
-
const [errorsPerSection, setErrorsPerSection] = useState<Map<TDescriptionSection<Entity>['key'], number>>(
|
|
125
|
-
new Map(sections.map(section => [section.key, 0]))
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
const handleSubmit = async () => {
|
|
129
|
-
try {
|
|
130
|
-
// Validate all fields in the form
|
|
131
|
-
const data = await form.validateFields();
|
|
132
|
-
// Let the parent component handle the submit logic
|
|
133
|
-
await onCreate(data);
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error('Validation or submission failed:', error);
|
|
136
|
-
} finally {
|
|
137
|
-
recalculateErrors();
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const handleUpdate = async () => {
|
|
142
|
-
try {
|
|
143
|
-
// Validate all fields in the form
|
|
144
|
-
const data = await form.validateFields();
|
|
145
|
-
// Let the parent component handle the update logic
|
|
146
|
-
return onSave(null, data, null);
|
|
147
|
-
} catch (error) {
|
|
148
|
-
console.error('Validation or submission failed:', error);
|
|
149
|
-
throw error;
|
|
150
|
-
} finally {
|
|
151
|
-
recalculateErrors();
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
useImperativeHandle(ref, () => ({
|
|
156
|
-
reset: () => {
|
|
157
|
-
setErrorsPerSection(new Map(sections.map(section => [section.key, 0])));
|
|
158
|
-
form.resetFields();
|
|
159
|
-
},
|
|
160
|
-
submit: () => handleSubmit(),
|
|
161
|
-
update: () => handleUpdate(),
|
|
162
|
-
setFieldErrors: (fields: FieldData<Entity>[]) => {
|
|
163
|
-
form.setFields(fields)
|
|
164
|
-
}
|
|
165
|
-
}));
|
|
166
|
-
|
|
167
|
-
const onValuesChange = debounce((changedValues, allValues) => {
|
|
168
|
-
let key = Object.keys(changedValues)[0];
|
|
169
|
-
|
|
170
|
-
// changedValues = {} if we clear select value
|
|
171
|
-
if (!key) {
|
|
172
|
-
const previousValues = form.getFieldsValue(true);
|
|
173
|
-
key = Object.keys(previousValues).find((field) => !(field in allValues));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
form.validateFields([key])
|
|
177
|
-
.finally(() => {
|
|
178
|
-
const section = columnDataIndexToSection.get(key);
|
|
179
|
-
const dataIndexes = section.columns.map(column => {
|
|
180
|
-
return Array.isArray(column.dataIndex) ? column.dataIndex.join('.') : column.dataIndex;
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
const errorsNumber = form.getFieldsError(dataIndexes as NamePath<Entity>[]).reduce((acc, field) => acc + field.errors.length, 0);
|
|
184
|
-
setErrorsPerSection((prev) => {
|
|
185
|
-
const updated = new Map(prev);
|
|
186
|
-
updated.set(section.key, errorsNumber);
|
|
187
|
-
return updated;
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
}, 500);
|
|
191
|
-
|
|
192
|
-
const queryParams = useMemo(() => {
|
|
193
|
-
const join = params?.join;
|
|
194
|
-
const queryParams: TGetOneParams & TPathParams = {
|
|
195
|
-
...(pathParams ?? {} as TPathParams),
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const { joinSelect, joinFields } = buildJoinFields(join);
|
|
199
|
-
queryParams.join = joinSelect;
|
|
200
|
-
queryParams.fields = collectFieldsFromColumns(
|
|
201
|
-
columns,
|
|
202
|
-
idColumnName,
|
|
203
|
-
joinFields,
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
return queryParams;
|
|
207
|
-
}, [params, pathParams]);
|
|
208
|
-
|
|
209
|
-
const getKey = (index: number) =>
|
|
210
|
-
index + String(pathParams?.[idColumnName as keyof TPathParams])
|
|
211
|
-
|
|
212
|
-
const requestData = async () => {
|
|
213
|
-
if (!getOne) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
setLoading(true);
|
|
218
|
-
|
|
219
|
-
try {
|
|
220
|
-
const record = await getOne(queryParams);
|
|
221
|
-
onEntityChange?.(record);
|
|
222
|
-
setData(record ?? undefined);
|
|
223
|
-
} catch (e) {
|
|
224
|
-
console.error(e);
|
|
225
|
-
setData(undefined);
|
|
226
|
-
} finally {
|
|
227
|
-
setLoading(false);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const onSave: RowEditableConfig<Entity>['onSave'] = async (propName, record) => {
|
|
232
|
-
try {
|
|
233
|
-
await form.validateFields();
|
|
234
|
-
if (onUpdate && entityToUpdateDto) {
|
|
235
|
-
await onUpdate({
|
|
236
|
-
...queryParams,
|
|
237
|
-
...{} as Partial<Entity>,
|
|
238
|
-
requestBody: entityToUpdateDto(
|
|
239
|
-
propName === null
|
|
240
|
-
? record
|
|
241
|
-
: pick(record, [propName as keyof Entity])
|
|
242
|
-
),
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
setData(record);
|
|
247
|
-
if (typeof afterSave === 'function') {
|
|
248
|
-
await afterSave(record);
|
|
249
|
-
}
|
|
250
|
-
} catch (e) {
|
|
251
|
-
console.error(e);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
useEffect(() => {
|
|
256
|
-
safetyRun(requestData());
|
|
257
|
-
}, [])
|
|
258
|
-
|
|
259
|
-
useEffect(() => {
|
|
260
|
-
setData(entity);
|
|
261
|
-
form.setFieldsValue(entity);
|
|
262
|
-
}, [entity])
|
|
263
|
-
|
|
264
|
-
if (loading) {
|
|
265
|
-
return <PageLoading />;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (!data) {
|
|
269
|
-
return (
|
|
270
|
-
<Result
|
|
271
|
-
status="404"
|
|
272
|
-
title="404"
|
|
273
|
-
subTitle="The entity is not found."
|
|
274
|
-
/>
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const formProps = contentViewMode === VIEW_MODE_TYPE.TABS ? {
|
|
279
|
-
onValuesChange,
|
|
280
|
-
} : undefined;
|
|
281
|
-
|
|
282
|
-
const contentViewSwitcher = sections.length > 1 ? contentViewModeButton : undefined;
|
|
283
|
-
const descriptions = sections.map((section, index) => {
|
|
284
|
-
return <ProDescriptions<Entity>
|
|
285
|
-
key={getKey(index)}
|
|
286
|
-
title={section.title as React.ReactNode}
|
|
287
|
-
actionRef={actionRef}
|
|
288
|
-
size={"small"}
|
|
289
|
-
bordered
|
|
290
|
-
loading={loading}
|
|
291
|
-
style={{ marginBottom: 20 }}
|
|
292
|
-
labelStyle={{ width: '15%' }}
|
|
293
|
-
dataSource={data as Entity}
|
|
294
|
-
className={styles.antDescriptionsStyles}
|
|
295
|
-
editable={canEdit ? {
|
|
296
|
-
type: 'multiple',
|
|
297
|
-
onSave,
|
|
298
|
-
deletePopconfirmMessage: intl.formatMessage({ id: 'table.deletePopconfirmMessage' }),
|
|
299
|
-
onlyAddOneLineAlertMessage: intl.formatMessage({ id: 'table.onlyAddOneLineAlertMessage' }),
|
|
300
|
-
cancelText: <Tooltip title={intl.formatMessage({ id: 'table.cancelText' })}><StopOutlined /></Tooltip>,
|
|
301
|
-
deleteText: <Tooltip title={intl.formatMessage({ id: 'table.deleteText' })}><DeleteOutlined /></Tooltip>,
|
|
302
|
-
saveText: <Button size={"small"} type={"primary"}><FormattedMessage id={'table.saveText'} /></Button>,
|
|
303
|
-
...(fieldsEditType === FieldsEdit.All && {
|
|
304
|
-
editableKeys: [...buildFieldsFromColumnsForDescriptionsDisplay(columns, idColumnName)],
|
|
305
|
-
actionRender: () => [],
|
|
306
|
-
}),
|
|
307
|
-
...editable,
|
|
308
|
-
} : undefined}
|
|
309
|
-
columns={section.columns}
|
|
310
|
-
extra={contentViewMode === VIEW_MODE_TYPE.GENERAL && index === 0 ? contentViewSwitcher : undefined}
|
|
311
|
-
formProps={formProps}
|
|
312
|
-
{...rest}
|
|
313
|
-
/>;
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
if (contentViewMode === VIEW_MODE_TYPE.GENERAL) {
|
|
317
|
-
return descriptions;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const tabsItems: TabsProps['items'] = sections.map((section, index) => {
|
|
321
|
-
return {
|
|
322
|
-
key: getKey(index),
|
|
323
|
-
label: (
|
|
324
|
-
<Badge
|
|
325
|
-
size='small'
|
|
326
|
-
overflowCount={5}
|
|
327
|
-
count={errorsPerSection.get(section.key)}
|
|
328
|
-
>
|
|
329
|
-
{section.title as React.ReactNode}
|
|
330
|
-
</Badge>
|
|
331
|
-
),
|
|
332
|
-
forceRender: true,
|
|
333
|
-
children: descriptions[index],
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
return <Tabs
|
|
338
|
-
defaultActiveKey="0"
|
|
339
|
-
items={tabsItems}
|
|
340
|
-
tabBarExtraContent={contentViewModeButton}
|
|
341
|
-
/>;
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
const Descriptions = React.forwardRef(DescriptionsComponent) as <Entity extends Record<string | symbol, any>,
|
|
345
|
-
CreateDto = Entity,
|
|
346
|
-
UpdateDto = Entity,
|
|
347
|
-
TPathParams = object>(
|
|
348
|
-
props: TDescriptionsProps<Entity, CreateDto, UpdateDto, TPathParams>
|
|
349
|
-
) => React.ReactElement;
|
|
350
|
-
|
|
351
|
-
export default Descriptions;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { useEffect, useMemo } from "react";
|
|
2
|
-
import { Button, Modal } from "antd";
|
|
3
|
-
import { TDescriptionsCreateModalProps } from "./descriptionTypes";
|
|
4
|
-
import { ProDescriptions } from "@ant-design/pro-components";
|
|
5
|
-
import { columnsToDescriptionItemProps } from "./useDescriptionColumns";
|
|
6
|
-
import { useForm } from "antd/es/form/Form";
|
|
7
|
-
import { buildFieldsFromColumnsForDescriptionsDisplay } from "../Table";
|
|
8
|
-
|
|
9
|
-
const DescriptionsCreateModal = <Entity extends Record<string | symbol, any>>({
|
|
10
|
-
idColumnName,
|
|
11
|
-
columns,
|
|
12
|
-
data,
|
|
13
|
-
onClose,
|
|
14
|
-
onSubmit,
|
|
15
|
-
...rest
|
|
16
|
-
}: TDescriptionsCreateModalProps<Entity>) => {
|
|
17
|
-
const sections = columnsToDescriptionItemProps(columns, 'General');
|
|
18
|
-
const [form] = useForm();
|
|
19
|
-
|
|
20
|
-
const editableKeys = useMemo(() => {
|
|
21
|
-
return [
|
|
22
|
-
...buildFieldsFromColumnsForDescriptionsDisplay(
|
|
23
|
-
columns,
|
|
24
|
-
idColumnName,
|
|
25
|
-
),
|
|
26
|
-
];
|
|
27
|
-
}, [columns, idColumnName]);
|
|
28
|
-
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
data ? form.setFieldsValue(data) : form.resetFields();
|
|
31
|
-
}, [data]);
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<Modal
|
|
35
|
-
open={data !== undefined}
|
|
36
|
-
onCancel={onClose}
|
|
37
|
-
width='80%'
|
|
38
|
-
footer={[
|
|
39
|
-
<Button key='submit' type="primary" onClick={async () => form.validateFields().then(onSubmit)}>Create</Button>
|
|
40
|
-
]}
|
|
41
|
-
>
|
|
42
|
-
{sections.map((section, index) => (
|
|
43
|
-
<ProDescriptions<Entity>
|
|
44
|
-
key={index + (Array.isArray(idColumnName) ? idColumnName.join('-') : idColumnName)}
|
|
45
|
-
title={section.title as React.ReactNode}
|
|
46
|
-
size={"small"}
|
|
47
|
-
bordered
|
|
48
|
-
column={2}
|
|
49
|
-
style={{ marginBottom: 20 }}
|
|
50
|
-
labelStyle={{ width: '15%' }}
|
|
51
|
-
contentStyle={{ width: '25%' }}
|
|
52
|
-
editable={{
|
|
53
|
-
form,
|
|
54
|
-
editableKeys,
|
|
55
|
-
actionRender: () => [],
|
|
56
|
-
}}
|
|
57
|
-
columns={section.columns}
|
|
58
|
-
{...rest}
|
|
59
|
-
/>
|
|
60
|
-
))}
|
|
61
|
-
</Modal>
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export default DescriptionsCreateModal;
|