@boarteam/boar-pack-common-frontend 4.0.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/tools/safetyRun.d.ts +2 -1
- package/dist/tools/safetyRun.js +2 -1
- package/dist/tools/safetyRun.js.map +1 -1
- package/package.json +2 -3
- package/src/components/ChangesModal/ChangesModal.tsx +0 -260
- 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/Comment/index.ts +0 -5
- package/src/components/Descriptions/Descriptions.tsx +0 -328
- package/src/components/Descriptions/DescriptionsCreateModal.tsx +0 -65
- package/src/components/Descriptions/descriptionTypes.ts +0 -73
- package/src/components/Descriptions/index.ts +0 -5
- 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 -144
- package/src/components/Inputs/index.ts +0 -9
- package/src/components/Inputs/useCheckConnection.tsx +0 -79
- package/src/components/List/List.tsx +0 -266
- package/src/components/List/index.ts +0 -3
- package/src/components/List/listTypes.ts +0 -31
- package/src/components/QuestionMarkHint/QuestionMarkHint.tsx +0 -33
- package/src/components/QuestionMarkHint/index.ts +0 -1
- 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 -294
- package/src/components/Table/getTableDataQueryParams.ts +0 -79
- package/src/components/Table/index.ts +0 -7
- package/src/components/Table/tableTools.ts +0 -244
- package/src/components/Table/tableTypes.ts +0 -148
- 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 -315
- package/src/components/index.ts +0 -6
- package/src/index.ts +0 -2
- package/src/tools/ApiError.ts +0 -18
- package/src/tools/WebsocketClient.ts +0 -146
- package/src/tools/index.ts +0 -6
- 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
|
@@ -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,328 +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 columnDataIndexToSection = sections.reduce((acc, section) => {
|
|
93
|
-
section.columns.forEach(column => {
|
|
94
|
-
if (Array.isArray(column.dataIndex)) {
|
|
95
|
-
throw new Error('We only support simple dataIndex for now');
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
acc.set(column.dataIndex, section);
|
|
99
|
-
})
|
|
100
|
-
return acc;
|
|
101
|
-
}, new Map<Key, TDescriptionSection<Entity>>());
|
|
102
|
-
|
|
103
|
-
const {
|
|
104
|
-
contentViewModeButton,
|
|
105
|
-
contentViewMode
|
|
106
|
-
} = useContentViewMode({
|
|
107
|
-
mode: contentViewModeProp || (sections.length > 1 ? VIEW_MODE_TYPE.TABS : VIEW_MODE_TYPE.GENERAL)
|
|
108
|
-
});
|
|
109
|
-
const [errorsPerSection, setErrorsPerSection] = useState<Map<TDescriptionSection<Entity>['key'], number>>(
|
|
110
|
-
new Map(sections.map(section => [section.key, 0]))
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
const handleSubmit = async () => {
|
|
114
|
-
try {
|
|
115
|
-
// Validate all fields in the form
|
|
116
|
-
const data = await form.validateFields();
|
|
117
|
-
// Let the parent component handle the submit logic
|
|
118
|
-
await onCreate(data);
|
|
119
|
-
} catch (error) {
|
|
120
|
-
console.error('Validation or submission failed:', error);
|
|
121
|
-
} finally {
|
|
122
|
-
// Recalculate the error count per section (tab) after validation
|
|
123
|
-
const newErrorsPerSection = new Map<string, number>();
|
|
124
|
-
sections.forEach((section) => {
|
|
125
|
-
let errorCount = 0;
|
|
126
|
-
section.columns.forEach((column) => {
|
|
127
|
-
if (form.getFieldError(column.dataIndex as NamePath<Entity>)?.length > 0) {
|
|
128
|
-
errorCount++;
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
newErrorsPerSection.set(section.key, errorCount);
|
|
132
|
-
});
|
|
133
|
-
setErrorsPerSection(newErrorsPerSection);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
useImperativeHandle(ref, () => ({
|
|
138
|
-
reset: () => {
|
|
139
|
-
setErrorsPerSection(new Map(sections.map(section => [section.key, 0])));
|
|
140
|
-
form.resetFields();
|
|
141
|
-
},
|
|
142
|
-
submit: () => handleSubmit(),
|
|
143
|
-
setFieldErrors: (fields: FieldData<Entity>[]) => {
|
|
144
|
-
form.setFields(fields)
|
|
145
|
-
}
|
|
146
|
-
}));
|
|
147
|
-
|
|
148
|
-
const onValuesChange = debounce((changedValues, allValues) => {
|
|
149
|
-
let key = Object.keys(changedValues)[0];
|
|
150
|
-
|
|
151
|
-
// changedValues = {} if we clear select value
|
|
152
|
-
if (!key) {
|
|
153
|
-
const previousValues = form.getFieldsValue(true);
|
|
154
|
-
key = Object.keys(previousValues).find((field) => !(field in allValues));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
form.validateFields([key])
|
|
158
|
-
.finally(() => {
|
|
159
|
-
const section = columnDataIndexToSection.get(key);
|
|
160
|
-
const dataIndexes = section.columns.map(column => {
|
|
161
|
-
return Array.isArray(column.dataIndex) ? column.dataIndex.join('.') : column.dataIndex;
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
const errorsNumber = form.getFieldsError(dataIndexes as NamePath<Entity>[]).reduce((acc, field) => acc + field.errors.length, 0);
|
|
165
|
-
setErrorsPerSection((prev) => {
|
|
166
|
-
const updated = new Map(prev);
|
|
167
|
-
updated.set(section.key, errorsNumber);
|
|
168
|
-
return updated;
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
}, 500);
|
|
172
|
-
|
|
173
|
-
const queryParams = useMemo(() => {
|
|
174
|
-
const join = params?.join;
|
|
175
|
-
const queryParams: TGetOneParams & TPathParams = {
|
|
176
|
-
...(pathParams ?? {} as TPathParams),
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const { joinSelect, joinFields } = buildJoinFields(join);
|
|
180
|
-
queryParams.join = joinSelect;
|
|
181
|
-
queryParams.fields = collectFieldsFromColumns(
|
|
182
|
-
columns,
|
|
183
|
-
idColumnName,
|
|
184
|
-
joinFields,
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
return queryParams;
|
|
188
|
-
}, [params, pathParams]);
|
|
189
|
-
|
|
190
|
-
const getKey = (index: number) =>
|
|
191
|
-
index + String(pathParams?.[idColumnName as keyof TPathParams])
|
|
192
|
-
|
|
193
|
-
const requestData = async () => {
|
|
194
|
-
if (!getOne) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
setLoading(true);
|
|
199
|
-
|
|
200
|
-
try {
|
|
201
|
-
const record = await getOne(queryParams);
|
|
202
|
-
onEntityChange?.(record);
|
|
203
|
-
setData(record ?? undefined);
|
|
204
|
-
} catch (e) {
|
|
205
|
-
console.error(e);
|
|
206
|
-
setData(undefined);
|
|
207
|
-
} finally {
|
|
208
|
-
setLoading(false);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const onSave: RowEditableConfig<Entity>['onSave'] = async (propName, record) => {
|
|
213
|
-
try {
|
|
214
|
-
await form.validateFields();
|
|
215
|
-
if (onUpdate && entityToUpdateDto) {
|
|
216
|
-
await onUpdate({
|
|
217
|
-
...queryParams,
|
|
218
|
-
...{} as Partial<Entity>,
|
|
219
|
-
requestBody: entityToUpdateDto(pick(record, [propName as keyof Entity])),
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
setData(record);
|
|
224
|
-
if (typeof afterSave === 'function') {
|
|
225
|
-
await afterSave(record);
|
|
226
|
-
}
|
|
227
|
-
} catch (e) {
|
|
228
|
-
console.error(e);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
useEffect(() => {
|
|
233
|
-
safetyRun(requestData());
|
|
234
|
-
}, [])
|
|
235
|
-
|
|
236
|
-
useEffect(() => {
|
|
237
|
-
setData(entity);
|
|
238
|
-
form.setFieldsValue(entity);
|
|
239
|
-
}, [entity])
|
|
240
|
-
|
|
241
|
-
if (loading) {
|
|
242
|
-
return <PageLoading />;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (!data) {
|
|
246
|
-
return (
|
|
247
|
-
<Result
|
|
248
|
-
status="404"
|
|
249
|
-
title="404"
|
|
250
|
-
subTitle="The entity is not found."
|
|
251
|
-
/>
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const formProps = contentViewMode === VIEW_MODE_TYPE.TABS ? {
|
|
256
|
-
onValuesChange,
|
|
257
|
-
} : undefined;
|
|
258
|
-
|
|
259
|
-
const contentViewSwitcher = sections.length > 1 ? contentViewModeButton : undefined;
|
|
260
|
-
const descriptions = sections.map((section, index) => {
|
|
261
|
-
return <ProDescriptions<Entity>
|
|
262
|
-
key={getKey(index)}
|
|
263
|
-
title={section.title as React.ReactNode}
|
|
264
|
-
actionRef={actionRef}
|
|
265
|
-
size={"small"}
|
|
266
|
-
bordered
|
|
267
|
-
loading={loading}
|
|
268
|
-
style={{ marginBottom: 20 }}
|
|
269
|
-
labelStyle={{ width: '15%' }}
|
|
270
|
-
dataSource={data as Entity}
|
|
271
|
-
className={styles.antDescriptionsStyles}
|
|
272
|
-
editable={canEdit ? {
|
|
273
|
-
type: 'multiple',
|
|
274
|
-
onSave,
|
|
275
|
-
deletePopconfirmMessage: intl.formatMessage({ id: 'table.deletePopconfirmMessage' }),
|
|
276
|
-
onlyAddOneLineAlertMessage: intl.formatMessage({ id: 'table.onlyAddOneLineAlertMessage' }),
|
|
277
|
-
cancelText: <Tooltip title={intl.formatMessage({ id: 'table.cancelText' })}><StopOutlined /></Tooltip>,
|
|
278
|
-
deleteText: <Tooltip title={intl.formatMessage({ id: 'table.deleteText' })}><DeleteOutlined /></Tooltip>,
|
|
279
|
-
saveText: <Button size={"small"} type={"primary"}><FormattedMessage id={'table.saveText'} /></Button>,
|
|
280
|
-
...(fieldsEditType === FieldsEdit.All && {
|
|
281
|
-
editableKeys: [...buildFieldsFromColumnsForDescriptionsDisplay(columns, idColumnName)],
|
|
282
|
-
actionRender: () => [],
|
|
283
|
-
}),
|
|
284
|
-
...editable,
|
|
285
|
-
} : undefined}
|
|
286
|
-
columns={section.columns}
|
|
287
|
-
extra={contentViewMode === VIEW_MODE_TYPE.GENERAL && index === 0 ? contentViewSwitcher : undefined}
|
|
288
|
-
formProps={formProps}
|
|
289
|
-
{...rest}
|
|
290
|
-
/>;
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
if (contentViewMode === VIEW_MODE_TYPE.GENERAL) {
|
|
294
|
-
return descriptions;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const tabsItems: TabsProps['items'] = sections.map((section, index) => {
|
|
298
|
-
return {
|
|
299
|
-
key: getKey(index),
|
|
300
|
-
label: (
|
|
301
|
-
<Badge
|
|
302
|
-
size='small'
|
|
303
|
-
overflowCount={5}
|
|
304
|
-
count={errorsPerSection.get(section.key)}
|
|
305
|
-
>
|
|
306
|
-
{section.title as React.ReactNode}
|
|
307
|
-
</Badge>
|
|
308
|
-
),
|
|
309
|
-
forceRender: true,
|
|
310
|
-
children: descriptions[index],
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
return <Tabs
|
|
315
|
-
defaultActiveKey="0"
|
|
316
|
-
items={tabsItems}
|
|
317
|
-
tabBarExtraContent={contentViewModeButton}
|
|
318
|
-
/>;
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
const Descriptions = React.forwardRef(DescriptionsComponent) as <Entity extends Record<string | symbol, any>,
|
|
322
|
-
CreateDto = Entity,
|
|
323
|
-
UpdateDto = Entity,
|
|
324
|
-
TPathParams = object>(
|
|
325
|
-
props: TDescriptionsProps<Entity, CreateDto, UpdateDto, TPathParams>
|
|
326
|
-
) => React.ReactElement;
|
|
327
|
-
|
|
328
|
-
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;
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import React, { MutableRefObject } from "react";
|
|
2
|
-
import { ActionType } from "@ant-design/pro-table";
|
|
3
|
-
import { RowEditableConfig } from "@ant-design/pro-utils";
|
|
4
|
-
import { QueryJoin } from "@nestjsx/crud-request";
|
|
5
|
-
import { ProColumns } from "@ant-design/pro-components";
|
|
6
|
-
import { ProDescriptionsProps } from "@ant-design/pro-descriptions";
|
|
7
|
-
import { FieldData } from "rc-field-form/lib/interface";
|
|
8
|
-
import { VIEW_MODE_TYPE } from "./useContentViewMode";
|
|
9
|
-
|
|
10
|
-
export type TGetOneParams = {
|
|
11
|
-
/**
|
|
12
|
-
* Selects resource fields. <a href="https://github.com/nestjsx/crud/wiki/Requests#select" target="_blank">Docs</a>
|
|
13
|
-
*/
|
|
14
|
-
fields?: Array<string>,
|
|
15
|
-
/**
|
|
16
|
-
* Adds relational resources. <a href="https://github.com/nestjsx/crud/wiki/Requests#join" target="_blank">Docs</a>
|
|
17
|
-
*/
|
|
18
|
-
join?: Array<string>,
|
|
19
|
-
/**
|
|
20
|
-
* Reset cache (if was enabled). <a href="https://github.com/nestjsx/crud/wiki/Requests#cache" target="_blank">Docs</a>
|
|
21
|
-
*/
|
|
22
|
-
cache?: number,
|
|
23
|
-
}
|
|
24
|
-
export type TDescriptionGetRequestParams = {
|
|
25
|
-
join?: QueryJoin | QueryJoin[];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export type DescriptionsRefType<Entity> = {
|
|
29
|
-
reset: () => void;
|
|
30
|
-
submit: () => void;
|
|
31
|
-
setFieldErrors: (fields: FieldData<Entity>[]) => void;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export enum FieldsEdit {
|
|
35
|
-
Single = 'single',
|
|
36
|
-
All = 'all'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type TDescriptionsProps<Entity, CreateDto, UpdateDto, TPathParams = object> = {
|
|
40
|
-
mainTitle?: ProColumns<Entity>['title'] | null,
|
|
41
|
-
entity?: Partial<Entity>,
|
|
42
|
-
getOne?: ({}: TGetOneParams & TPathParams) => Promise<Entity | null>,
|
|
43
|
-
onUpdate?: ({}: Partial<Entity> & {
|
|
44
|
-
requestBody: UpdateDto,
|
|
45
|
-
index?: number,
|
|
46
|
-
} & TPathParams) => Promise<Entity>,
|
|
47
|
-
onCreate?: (data: Partial<Entity>) => Promise<void>;
|
|
48
|
-
onDelete?: ({}: Partial<Entity> & TPathParams) => Promise<void>,
|
|
49
|
-
pathParams?: TPathParams,
|
|
50
|
-
idColumnName?: string & keyof Entity,
|
|
51
|
-
entityToUpdateDto?: (entity: Entity) => UpdateDto,
|
|
52
|
-
createNewDefaultParams?: Partial<Entity>,
|
|
53
|
-
afterSave?: (record: Entity) => Promise<void>,
|
|
54
|
-
actionRef?: MutableRefObject<ActionType | undefined>,
|
|
55
|
-
editable?: RowEditableConfig<Entity>,
|
|
56
|
-
canEdit?: boolean,
|
|
57
|
-
fieldsEditType?: FieldsEdit,
|
|
58
|
-
params?: TDescriptionGetRequestParams,
|
|
59
|
-
columns: ProColumns<Entity>[],
|
|
60
|
-
onEntityChange?: (entity: Entity | null) => void;
|
|
61
|
-
contentViewMode?: VIEW_MODE_TYPE,
|
|
62
|
-
ref?: React.Ref<DescriptionsRefType<Entity>>,
|
|
63
|
-
} & Omit<ProDescriptionsProps<Entity>, 'columns'>;
|
|
64
|
-
|
|
65
|
-
export type TDescriptionsCreateModalProps<Entity> = Omit<ProDescriptionsProps<Entity>, 'columns'> & {
|
|
66
|
-
modalTitle?: string,
|
|
67
|
-
mainTitle?: ProColumns<Entity>['title'] | null,
|
|
68
|
-
idColumnName: string & keyof Entity | (string & keyof Entity)[],
|
|
69
|
-
columns: ProColumns<Entity>[],
|
|
70
|
-
data: Partial<Entity> | undefined,
|
|
71
|
-
onSubmit: (data: Entity) => Promise<void>,
|
|
72
|
-
onClose: () => void,
|
|
73
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Button, Tooltip } from "antd";
|
|
2
|
-
import { AppstoreOutlined, MenuOutlined } from "@ant-design/icons";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
|
|
5
|
-
export enum VIEW_MODE_TYPE {
|
|
6
|
-
TABS = 'tabs',
|
|
7
|
-
GENERAL = 'general'
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default function useContentViewMode({
|
|
11
|
-
mode,
|
|
12
|
-
}: {
|
|
13
|
-
mode?: VIEW_MODE_TYPE;
|
|
14
|
-
} = {}) {
|
|
15
|
-
const [contentViewMode, setContentViewMode] = useState<VIEW_MODE_TYPE>(mode || VIEW_MODE_TYPE.GENERAL);
|
|
16
|
-
|
|
17
|
-
const contentViewModeButton = <Tooltip
|
|
18
|
-
title={contentViewMode === VIEW_MODE_TYPE.TABS ? 'Switch to general view' : 'Switch to tabs view'}
|
|
19
|
-
key="viewModeToggle">
|
|
20
|
-
<Button
|
|
21
|
-
type="text"
|
|
22
|
-
icon={contentViewMode === VIEW_MODE_TYPE.TABS ? <MenuOutlined /> : <AppstoreOutlined />}
|
|
23
|
-
onClick={() => setContentViewMode(contentViewMode === VIEW_MODE_TYPE.TABS ? VIEW_MODE_TYPE.GENERAL : VIEW_MODE_TYPE.TABS)}
|
|
24
|
-
/>
|
|
25
|
-
</Tooltip>;
|
|
26
|
-
|
|
27
|
-
return { contentViewMode, contentViewModeButton };
|
|
28
|
-
}
|