@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 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function safetyRun<T>(promise?: Promise<T>): void;
|
|
2
|
+
export default safetyRun;
|
package/dist/tools/safetyRun.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.safetyRun = safetyRun;
|
|
4
4
|
function safetyRun(promise) {
|
|
5
5
|
promise?.catch((e) => {
|
|
6
6
|
console.error(e);
|
|
7
7
|
});
|
|
8
8
|
}
|
|
9
|
+
exports.default = safetyRun;
|
|
9
10
|
//# sourceMappingURL=safetyRun.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safetyRun.js","sourceRoot":"","sources":["../../src/tools/safetyRun.ts"],"names":[],"mappings":";;AAAA,
|
|
1
|
+
{"version":3,"file":"safetyRun.js","sourceRoot":"","sources":["../../src/tools/safetyRun.ts"],"names":[],"mappings":";;AAAA,8BAIC;AAJD,SAAgB,SAAS,CAAI,OAAoB;IAC/C,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QACnB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,kBAAe,SAAS,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boarteam/boar-pack-common-frontend",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Common frontend package for Boar Pack",
|
|
5
5
|
"repository": "git@github.com:boarteam/boar-pack.git",
|
|
6
6
|
"author": "Andrew Balakirev <balakirev.andrey@gmail.com>",
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"main": "dist/index",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
10
|
"files": [
|
|
11
|
-
"src",
|
|
12
11
|
"dist"
|
|
13
12
|
],
|
|
14
13
|
"publishConfig": {
|
|
@@ -53,5 +52,5 @@
|
|
|
53
52
|
"build": "rm -rf dist && tsc --project tsconfig.build.json",
|
|
54
53
|
"yalc:push": "yalc push"
|
|
55
54
|
},
|
|
56
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "db759a35be3528d9970b7d2408d3b90d19bd7741"
|
|
57
56
|
}
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import { Badge, Button, message, Modal, Tabs } from "antd";
|
|
2
|
-
import { ProColumns } from "@ant-design/pro-components";
|
|
3
|
-
import { createStyles } from "antd-style";
|
|
4
|
-
import { useEffect, useState } from "react";
|
|
5
|
-
import ConflictsTab from "./ConflictsTab";
|
|
6
|
-
import ErrorsTab from "./ErrorsTab";
|
|
7
|
-
import ResultsTab from "./ResultsTab";
|
|
8
|
-
import NewRecordsTab, { TCreatedRecordsColumnsConfig } from "./NewRecordsTab";
|
|
9
|
-
import ChangesTab from "./ChangesTab";
|
|
10
|
-
import { TDiffResult } from "../Table/useImportExport";
|
|
11
|
-
enum ModalTabs {
|
|
12
|
-
changes = "changes",
|
|
13
|
-
newRecords = "newRecords",
|
|
14
|
-
errors = "errors",
|
|
15
|
-
results = "results",
|
|
16
|
-
conflicts = "conflicts",
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export type TServerErrorItem = { field: string; message: string };
|
|
20
|
-
|
|
21
|
-
export type TRelationalFields = Map<string, {
|
|
22
|
-
key: string,
|
|
23
|
-
data: {
|
|
24
|
-
[key: string]: any,
|
|
25
|
-
}
|
|
26
|
-
}>
|
|
27
|
-
|
|
28
|
-
export type TImportConflict = {
|
|
29
|
-
id: number;
|
|
30
|
-
version: number;
|
|
31
|
-
fields: Array<{
|
|
32
|
-
field: string;
|
|
33
|
-
current_value: any;
|
|
34
|
-
imported_value: any;
|
|
35
|
-
}>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export type TImportResponse = {
|
|
39
|
-
errors?: Array<TServerErrorItem>,
|
|
40
|
-
conflicts?: Array<TImportConflict>,
|
|
41
|
-
created_count: number,
|
|
42
|
-
updated_count: number
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const useStyles = createStyles(() => {
|
|
46
|
-
return {
|
|
47
|
-
changesModal: {
|
|
48
|
-
".ant-modal-content": {
|
|
49
|
-
width: 800,
|
|
50
|
-
},
|
|
51
|
-
".ant-table-content": {
|
|
52
|
-
overflowX: "auto",
|
|
53
|
-
},
|
|
54
|
-
"ul": {
|
|
55
|
-
maxHeight: 500,
|
|
56
|
-
overflowY: "auto",
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
export function ChangesModal<
|
|
63
|
-
Entity,
|
|
64
|
-
ImportRequestParams,
|
|
65
|
-
>({
|
|
66
|
-
onClose,
|
|
67
|
-
onCommit,
|
|
68
|
-
changes,
|
|
69
|
-
relationalFields,
|
|
70
|
-
originRecordsColumnsConfig,
|
|
71
|
-
changedRecordsColumnsConfig,
|
|
72
|
-
createdRecordsColumnsConfig,
|
|
73
|
-
}: {
|
|
74
|
-
onCommit: (params: ImportRequestParams) => Promise<TImportResponse>,
|
|
75
|
-
onClose: () => void;
|
|
76
|
-
changes?: TDiffResult<Entity>,
|
|
77
|
-
relationalFields?: TRelationalFields,
|
|
78
|
-
originRecordsColumnsConfig: ProColumns<Entity>[],
|
|
79
|
-
changedRecordsColumnsConfig: ProColumns<Entity>[];
|
|
80
|
-
createdRecordsColumnsConfig: TCreatedRecordsColumnsConfig<Entity>;
|
|
81
|
-
}) {
|
|
82
|
-
const { styles } = useStyles();
|
|
83
|
-
const [activeTab, setActiveTab] = useState<string>(ModalTabs.changes);
|
|
84
|
-
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
85
|
-
const [importResponse, setImportResponse] = useState<TImportResponse>();
|
|
86
|
-
const [serverErrors, setServerErrors] = useState<TServerErrorItem[]>([]);
|
|
87
|
-
const [resolvedData, setResolvedData] = useState<Entity[]>();
|
|
88
|
-
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
if (serverErrors.length > 0) {
|
|
91
|
-
setActiveTab(ModalTabs.errors);
|
|
92
|
-
}
|
|
93
|
-
}, [serverErrors.length]);
|
|
94
|
-
|
|
95
|
-
if (!changes) return null;
|
|
96
|
-
|
|
97
|
-
const { created, updated, tableData } = changes;
|
|
98
|
-
|
|
99
|
-
const onCancel = () => {
|
|
100
|
-
setActiveTab(ModalTabs.changes);
|
|
101
|
-
setImportResponse(undefined);
|
|
102
|
-
setServerErrors([]);
|
|
103
|
-
setResolvedData([])
|
|
104
|
-
onClose();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const handleCommitClick = async () => {
|
|
108
|
-
// TODO: Client validation
|
|
109
|
-
// ...
|
|
110
|
-
setServerErrors([]);
|
|
111
|
-
setIsLoading(true);
|
|
112
|
-
|
|
113
|
-
const modifiedSource = (resolvedData && resolvedData.length > 0)
|
|
114
|
-
? resolvedData
|
|
115
|
-
: updated;
|
|
116
|
-
|
|
117
|
-
const payload: any = {
|
|
118
|
-
new: created,
|
|
119
|
-
modified: modifiedSource,
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
onCommit(payload).then((res) => {
|
|
123
|
-
setImportResponse(res);
|
|
124
|
-
|
|
125
|
-
// Check conflicts
|
|
126
|
-
if (res.conflicts?.length) {
|
|
127
|
-
setActiveTab(ModalTabs.conflicts);
|
|
128
|
-
message.error("There are conflicts in the import. Please resolve them.");
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
setActiveTab(ModalTabs.results);
|
|
133
|
-
}).catch((err) => {
|
|
134
|
-
// TODO: Simplify
|
|
135
|
-
const status = err?.status || err?.statusCode || err?.response?.status;
|
|
136
|
-
const payload = err?.body || err?.response?.data || err?.data || err;
|
|
137
|
-
|
|
138
|
-
if ((status === 400 || payload?.statusCode === 400) && Array.isArray(payload?.errors)) {
|
|
139
|
-
setServerErrors(payload.errors);
|
|
140
|
-
message.error(payload.message || "Validation error");
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
console.error("Commit failed:", err);
|
|
145
|
-
message.error("Unexpected error while committing changes");
|
|
146
|
-
}).finally(() => {
|
|
147
|
-
setIsLoading(false);
|
|
148
|
-
});
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const tabList = [
|
|
152
|
-
{
|
|
153
|
-
key: ModalTabs.changes,
|
|
154
|
-
tab: "Changed values",
|
|
155
|
-
disabled: tableData.length === 0,
|
|
156
|
-
label: tableData.length ? (
|
|
157
|
-
<Badge
|
|
158
|
-
size="small"
|
|
159
|
-
color="blue"
|
|
160
|
-
count={tableData.length}
|
|
161
|
-
>
|
|
162
|
-
Changed Values
|
|
163
|
-
</Badge>
|
|
164
|
-
) : "Changed Values",
|
|
165
|
-
children: <ChangesTab
|
|
166
|
-
changedRecordsColumnsConfig={changedRecordsColumnsConfig}
|
|
167
|
-
updated={tableData}
|
|
168
|
-
/>,
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
key: ModalTabs.newRecords,
|
|
172
|
-
tab: "New records",
|
|
173
|
-
disabled: created.length === 0,
|
|
174
|
-
label: created.length ? (
|
|
175
|
-
<Badge
|
|
176
|
-
size="small"
|
|
177
|
-
color="blue"
|
|
178
|
-
count={created.length}
|
|
179
|
-
>
|
|
180
|
-
New Records
|
|
181
|
-
</Badge>
|
|
182
|
-
) : "New Records",
|
|
183
|
-
children: <NewRecordsTab
|
|
184
|
-
createdRecordsColumnsConfig={createdRecordsColumnsConfig}
|
|
185
|
-
created={created}
|
|
186
|
-
/>,
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
key: ModalTabs.errors,
|
|
190
|
-
tab: "Import errors",
|
|
191
|
-
disabled: serverErrors.length === 0,
|
|
192
|
-
label: serverErrors.length ? (
|
|
193
|
-
<Badge size="small" count={serverErrors.length}>
|
|
194
|
-
Errors
|
|
195
|
-
</Badge>
|
|
196
|
-
) : "Errors",
|
|
197
|
-
children: <ErrorsTab serverErrors={serverErrors} />,
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
key: ModalTabs.conflicts,
|
|
201
|
-
tab: "Import conflicts",
|
|
202
|
-
disabled: !importResponse || importResponse.conflicts?.length === 0,
|
|
203
|
-
label: importResponse?.conflicts?.length ? (
|
|
204
|
-
<Badge size="small" count={importResponse.conflicts.length}>
|
|
205
|
-
Conflicts
|
|
206
|
-
</Badge>
|
|
207
|
-
) : "Conflicts",
|
|
208
|
-
children: <ConflictsTab<Entity>
|
|
209
|
-
conflicts={importResponse?.conflicts}
|
|
210
|
-
setResolvedData={setResolvedData}
|
|
211
|
-
relationalFields={relationalFields}
|
|
212
|
-
originColumns={originRecordsColumnsConfig}
|
|
213
|
-
/>,
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
key: ModalTabs.results,
|
|
217
|
-
tab: "Import results",
|
|
218
|
-
disabled: !importResponse || !!importResponse.conflicts?.length,
|
|
219
|
-
label: "Results",
|
|
220
|
-
children: <ResultsTab importStatistic={
|
|
221
|
-
{
|
|
222
|
-
created: importResponse?.created_count || 0,
|
|
223
|
-
updated: importResponse?.updated_count || 0,
|
|
224
|
-
}
|
|
225
|
-
} />,
|
|
226
|
-
},
|
|
227
|
-
];
|
|
228
|
-
|
|
229
|
-
return (
|
|
230
|
-
<Modal
|
|
231
|
-
title="Preview changes"
|
|
232
|
-
open={true}
|
|
233
|
-
onCancel={onCancel}
|
|
234
|
-
footer={[
|
|
235
|
-
<Button key="close" onClick={onCancel}>Close</Button>,
|
|
236
|
-
<Button
|
|
237
|
-
loading={isLoading}
|
|
238
|
-
type="primary"
|
|
239
|
-
key="approve"
|
|
240
|
-
onClick={handleCommitClick}
|
|
241
|
-
disabled={
|
|
242
|
-
importResponse?.conflicts?.length === 0
|
|
243
|
-
|| serverErrors.length > 0
|
|
244
|
-
|| updated.length === 0 && created.length === 0
|
|
245
|
-
}
|
|
246
|
-
>
|
|
247
|
-
Commit
|
|
248
|
-
</Button>,
|
|
249
|
-
]}
|
|
250
|
-
className={styles.changesModal}
|
|
251
|
-
>
|
|
252
|
-
<Tabs
|
|
253
|
-
activeKey={activeTab}
|
|
254
|
-
onChange={setActiveTab}
|
|
255
|
-
defaultActiveKey="1"
|
|
256
|
-
items={tabList}
|
|
257
|
-
/>
|
|
258
|
-
</Modal>
|
|
259
|
-
)
|
|
260
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { Tag } from "antd";
|
|
2
|
-
import { ProColumns } from "@ant-design/pro-components";
|
|
3
|
-
import { TDiffResult, TUpdatedDiffResult } from "../Table/useImportExport";
|
|
4
|
-
import ProTable from "@ant-design/pro-table";
|
|
5
|
-
|
|
6
|
-
function ChangesTab<Entity> ({ updated, changedRecordsColumnsConfig }: {
|
|
7
|
-
updated: TDiffResult<Entity>['tableData'],
|
|
8
|
-
changedRecordsColumnsConfig: ProColumns<Entity>[]
|
|
9
|
-
}) {
|
|
10
|
-
if (!updated.length) {
|
|
11
|
-
return <>
|
|
12
|
-
No changes found.
|
|
13
|
-
</>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const updateColumns: ProColumns<TUpdatedDiffResult>[] = [
|
|
17
|
-
...(changedRecordsColumnsConfig as unknown as ProColumns<TUpdatedDiffResult>[]),
|
|
18
|
-
{
|
|
19
|
-
title: "Changes",
|
|
20
|
-
dataIndex: "diff",
|
|
21
|
-
key: "diff",
|
|
22
|
-
render: (_dom, entity) => (
|
|
23
|
-
<div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
|
|
24
|
-
{entity.diff.map((change, index) => {
|
|
25
|
-
const c = change as { path?: any[]; lhs?: any; rhs?: any };
|
|
26
|
-
return (
|
|
27
|
-
<div key={index} style={{ display: "flex", alignItems: "center" }}>
|
|
28
|
-
<Tag color="blue">{c.path?.join(".")}</Tag>
|
|
29
|
-
{c.lhs ? `${c.lhs.toString()} →` : "- →"} {c.rhs ? c.rhs : c.rhs === false ? 'false' : '-'}
|
|
30
|
-
</div>
|
|
31
|
-
);
|
|
32
|
-
})}
|
|
33
|
-
</div>
|
|
34
|
-
),
|
|
35
|
-
},
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
return [
|
|
39
|
-
<h3 key='changes-header'>Changed Values (Local Comparing)</h3>,
|
|
40
|
-
<ProTable<TUpdatedDiffResult>
|
|
41
|
-
key='changes-data'
|
|
42
|
-
dataSource={updated}
|
|
43
|
-
columns={updateColumns}
|
|
44
|
-
rowKey='id'
|
|
45
|
-
search={false}
|
|
46
|
-
toolBarRender={false}
|
|
47
|
-
/>
|
|
48
|
-
]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export default ChangesTab;
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { Descriptions, TImportConflict } from "../../index";
|
|
2
|
-
import { Tag, Tooltip, Button } from "antd";
|
|
3
|
-
import { Dispatch, SetStateAction, useEffect, useState } from "react";
|
|
4
|
-
import { TImportResponse, TRelationalFields } from "./ChangesModal";
|
|
5
|
-
import { keyBy } from "lodash";
|
|
6
|
-
import { createStyles } from "antd-style";
|
|
7
|
-
import { SwapOutlined } from "@ant-design/icons";
|
|
8
|
-
import { ProColumns } from "@ant-design/pro-components";
|
|
9
|
-
|
|
10
|
-
const useStyles = createStyles(() => {
|
|
11
|
-
return {
|
|
12
|
-
conflictsStyle: {
|
|
13
|
-
".ant-descriptions-row > *:nth-child(1), .ant-descriptions-row > *:nth-child(2)": {
|
|
14
|
-
|
|
15
|
-
},
|
|
16
|
-
".ant-descriptions-row > *:nth-child(3)": {
|
|
17
|
-
|
|
18
|
-
},
|
|
19
|
-
".ant-descriptions-row > *:nth-child(4)": {
|
|
20
|
-
backgroundColor: "#f0fff0 !important",
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const getCurrentKey = (field: string) => {
|
|
27
|
-
return `${field}-current`;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const getNormalizedKey = (field: string) => {
|
|
31
|
-
return field.replace('_id', '');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function ConflictsTab<Entity>({
|
|
35
|
-
conflicts,
|
|
36
|
-
relationalFields,
|
|
37
|
-
setResolvedData,
|
|
38
|
-
originColumns,
|
|
39
|
-
}: {
|
|
40
|
-
conflicts?: TImportResponse['conflicts'],
|
|
41
|
-
relationalFields?: TRelationalFields;
|
|
42
|
-
setResolvedData?: Dispatch<SetStateAction<Entity[]>>;
|
|
43
|
-
originColumns: ProColumns<Entity>[];
|
|
44
|
-
}) {
|
|
45
|
-
|
|
46
|
-
if (!conflicts || conflicts.length === 0) {
|
|
47
|
-
return <p>No conflicts found.</p>;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const getRelationalData = (key: string, value: string) => {
|
|
51
|
-
if (relationalFields?.has(key)) {
|
|
52
|
-
const relation = relationalFields.get(key);
|
|
53
|
-
return relation?.data[value] ?? null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return value;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/*Initial value based on received conflicts
|
|
60
|
-
{
|
|
61
|
-
field: 'importing field value',
|
|
62
|
-
field-current: 'current field name from server',
|
|
63
|
-
...
|
|
64
|
-
}*/
|
|
65
|
-
const [resolvedData, setLocalResolvedData] = useState<Record<string, any>[]>(conflicts.map(conflict => (
|
|
66
|
-
conflict.fields.reduce((acc: Record<string, any>, currentValue) => {
|
|
67
|
-
const key = getNormalizedKey(currentValue.field);
|
|
68
|
-
acc[key] = getRelationalData(key, currentValue.imported_value);
|
|
69
|
-
acc[getCurrentKey(key)] = getRelationalData(key, currentValue.current_value);
|
|
70
|
-
|
|
71
|
-
return acc;
|
|
72
|
-
}, {})
|
|
73
|
-
)));
|
|
74
|
-
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
if (!setResolvedData) return;
|
|
77
|
-
|
|
78
|
-
const payload = resolvedData.map((obj, i) => {
|
|
79
|
-
const data = { ...obj };
|
|
80
|
-
// Remove "current" postfix key from the resolved data
|
|
81
|
-
Object.keys(obj).forEach(key => {
|
|
82
|
-
if (key.endsWith('-current')) {
|
|
83
|
-
delete data[key];
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
id: conflicts[i].id,
|
|
89
|
-
...data,
|
|
90
|
-
version: conflicts[i].version,
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
setResolvedData(payload as Entity[]);
|
|
95
|
-
}, [resolvedData, conflicts, setResolvedData]);
|
|
96
|
-
|
|
97
|
-
const { styles } = useStyles();
|
|
98
|
-
|
|
99
|
-
const useCurrentValue = (conflict: TImportConflict, field: string) => {
|
|
100
|
-
const key = getNormalizedKey(field);
|
|
101
|
-
|
|
102
|
-
// Update the resolved data for this conflict
|
|
103
|
-
setLocalResolvedData(prev => {
|
|
104
|
-
const newData = [...prev];
|
|
105
|
-
const index = conflicts.indexOf(conflict);
|
|
106
|
-
newData[index] = {
|
|
107
|
-
...newData[index],
|
|
108
|
-
[key]: newData[index][getCurrentKey(key)],
|
|
109
|
-
};
|
|
110
|
-
return newData;
|
|
111
|
-
});
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const keyedOriginColumns = keyBy(originColumns, "dataIndex");
|
|
115
|
-
|
|
116
|
-
return conflicts.map((conflict, idx) => {
|
|
117
|
-
const conflictColumns: ProColumns[] = [];
|
|
118
|
-
|
|
119
|
-
conflict.fields.forEach(field => {
|
|
120
|
-
const key = getNormalizedKey(field.field);
|
|
121
|
-
const originColumn = keyedOriginColumns[key];
|
|
122
|
-
conflictColumns.push({
|
|
123
|
-
...originColumn,
|
|
124
|
-
dataIndex: getCurrentKey(key),
|
|
125
|
-
editable: false,
|
|
126
|
-
// Should override render to keep -current value
|
|
127
|
-
render: (node) => node
|
|
128
|
-
});
|
|
129
|
-
conflictColumns.push({
|
|
130
|
-
...originColumn,
|
|
131
|
-
title: (
|
|
132
|
-
<div style={{ textAlign: 'center' }}>
|
|
133
|
-
<Tooltip title="Use value from server">
|
|
134
|
-
<Button
|
|
135
|
-
size="small"
|
|
136
|
-
type="link"
|
|
137
|
-
icon={<SwapOutlined />}
|
|
138
|
-
onClick={() => useCurrentValue(conflict, field.field)}
|
|
139
|
-
/>
|
|
140
|
-
</Tooltip>
|
|
141
|
-
</div>
|
|
142
|
-
),
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
return (
|
|
147
|
-
<div key={idx} style={{ display: "flex", flexDirection: "column", gap: 15, width: "100%" }}>
|
|
148
|
-
<div>
|
|
149
|
-
<Tag color="error">ID {conflict.id}</Tag>
|
|
150
|
-
<Tag color="blue">Server version: v{conflict.version}</Tag>
|
|
151
|
-
</div>
|
|
152
|
-
<table>
|
|
153
|
-
<thead>
|
|
154
|
-
<tr>
|
|
155
|
-
<th style={{ width: '50%' }}>Current (From Server)</th>
|
|
156
|
-
<th style={{ width: '50%' }}>New (Importing)</th>
|
|
157
|
-
</tr>
|
|
158
|
-
</thead>
|
|
159
|
-
</table>
|
|
160
|
-
<Descriptions
|
|
161
|
-
size="small"
|
|
162
|
-
bordered
|
|
163
|
-
entity={resolvedData[idx]}
|
|
164
|
-
columns={conflictColumns}
|
|
165
|
-
column={2}
|
|
166
|
-
canEdit={true}
|
|
167
|
-
mainTitle={null}
|
|
168
|
-
className={styles.conflictsStyle}
|
|
169
|
-
>
|
|
170
|
-
</Descriptions>
|
|
171
|
-
</div>
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
export default ConflictsTab;
|
|
@@ -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';
|