Projekt

Obecné

Profil

Stáhnout (16 KB) Statistiky
| Větev: | Tag: | Revize:
1 8c45ccb0 hrubyjar
import 'antd/dist/antd.css';
2 c6109e2d Lukáš Vlček
import React, { useContext, useEffect, useState } from 'react';
3 8c45ccb0 hrubyjar
4
import { useUnauthRedirect } from '../../../hooks';
5
import { useRouter } from 'next/router';
6 c4f198c3 Jaroslav Hrubý
import { Button, Row, Space, Table, Tag, Typography } from 'antd';
7 c6109e2d Lukáš Vlček
import { faFileLines, faUser } from '@fortawesome/free-solid-svg-icons';
8 8c45ccb0 hrubyjar
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
9
import { LoggedUserContext } from '../../../contexts/LoggedUserContext';
10 bae9fbba Jaroslav Hrubý
import { MainLayout } from '../../../layouts/MainLayout';
11 4a7bae81 Jaroslav Hrubý
import AddDocumentModal from '../../../components/modals/AddDocumentModal';
12 ff61085f Lukáš Vlček
import {
13
    DocumentListInfo,
14 87a3d8d1 Lukáš Vlček
    DocumentListResponse,
15 ff61085f Lukáš Vlček
    DocumentUserInfo,
16
    EState,
17
} from '../../../api';
18 c6109e2d Lukáš Vlček
import { documentController, userController } from '../../../controllers';
19 9bfa1e39 Jaroslav Hrubý
import AssignDocumentModal from '../../../components/modals/AssignDocumentModal';
20 c4f198c3 Jaroslav Hrubý
import { ShowConfirm, ShowToast } from '../../../utils/alerts';
21 43d49a98 Jaroslav Hrubý
import { TableDocInfo } from '../../../components/types/TableDocInfo';
22 ff61085f Lukáš Vlček
import {
23
    getAnnotationStateColor,
24 c4f198c3 Jaroslav Hrubý
    getAnnotationStateString,
25 ff61085f Lukáš Vlček
    getNameTruncated,
26
    getUserInfoAlt,
27
} from '../../../utils/strings';
28 87a3d8d1 Lukáš Vlček
import { ABadge, BadgeStyle } from '../../../components/common/ABadge';
29 e7eca311 Lukáš Vlček
import SetRequiredAnnotationsCountModal from '../../../components/modals/SetRequiredAnnotationsCountModal';
30 d7167305 Jaroslav Hrubý
import DocPreviewModal from '../../../components/modals/DocPreviewModal';
31 0db53e25 Jaroslav Hrubý
import { UserFilter } from '../../../components/types/UserFilter';
32 669ffe38 Jaroslav Hrubý
import { getColumnSearchProps, getLocaleProps } from '../../../utils/tableUtils';
33 c4f198c3 Jaroslav Hrubý
import {
34
    CheckCircleOutlined,
35
    ClockCircleOutlined,
36
    SyncOutlined,
37
} from '@ant-design/icons';
38
import { SweetAlertIcon } from 'sweetalert2';
39 8c45ccb0 hrubyjar
40
function AdminDocumentPage() {
41
    const redirecting = useUnauthRedirect('/login');
42
    const { logout, role } = useContext(LoggedUserContext);
43 c4f198c3 Jaroslav Hrubý
    const [finalizing, setFinalizing] = React.useState(false);
44 9bfa1e39 Jaroslav Hrubý
    const [visibleAdd, setVisibleAdd] = React.useState(false);
45
    const [visibleAssign, setVisibleAssign] = React.useState(false);
46 d7167305 Jaroslav Hrubý
    const [visiblePreview, setVisiblePreview] = React.useState(false);
47 e7eca311 Lukáš Vlček
    const [visibleSetCount, setVisibleSetCount] = React.useState(false);
48
49 8c45ccb0 hrubyjar
    const router = useRouter();
50
51 43d49a98 Jaroslav Hrubý
    const [documents, setDocuments] = useState<TableDocInfo[]>([]);
52 0db53e25 Jaroslav Hrubý
    const [userFilters, setUserFilters] = useState<UserFilter[]>([]);
53 cca0bfa0 Lukáš Vlček
    const [selectedDocs, setSelectedDocs] = useState<string[]>([]);
54 d7167305 Jaroslav Hrubý
    const [previewDocContent, setPreviewDocContent] = useState<string>();
55
    const [previewDocName, setPreviewDocName] = useState<string>();
56 c6109e2d Lukáš Vlček
57 43d49a98 Jaroslav Hrubý
    async function fetchData() {
58
        const docs = (await documentController.documentsGet(0, 1000)).data.documents;
59
        // @ts-ignore
60
        const tableDocs: TableDocInfo[] = docs?.map((doc, index) => {
61
            return { key: index, ...doc };
62
        });
63 9bfa1e39 Jaroslav Hrubý
64 0db53e25 Jaroslav Hrubý
        const users = (await userController.usersGet()).data.users;
65
        // @ts-ignore
66
        const filters: UserFilter[] = users?.map((user) => {
67
            return {
68
                text: user.name + ' ' + user.surname,
69
                value: user.username,
70
            };
71
        });
72
        setUserFilters(filters);
73
74 43d49a98 Jaroslav Hrubý
        if (!docs) {
75
            setDocuments([]);
76
        } else {
77
            setDocuments(tableDocs);
78 c6109e2d Lukáš Vlček
        }
79 43d49a98 Jaroslav Hrubý
    }
80 c6109e2d Lukáš Vlček
81 43d49a98 Jaroslav Hrubý
    useEffect(() => {
82 06d1aa21 Jaroslav Hrubý
        if (!redirecting && role === 'ADMINISTRATOR') {
83 c6109e2d Lukáš Vlček
            fetchData();
84 8c45ccb0 hrubyjar
        }
85
    }, [logout, redirecting, role, router]);
86
87 c4f198c3 Jaroslav Hrubý
    const finalizeDocumentConfirm = async (
88
        document: DocumentListInfo,
89
        recreate: boolean
90
    ) => {
91
        let desc = recreate ? 'Dosavadní změny finální verze budou smazány' : '';
92
        let icon: SweetAlertIcon = recreate ? 'warning' : 'question';
93
94
        const doneAnnotations = document.annotatingUsers?.filter(
95
            (usr) => usr.state === EState.Done
96
        ).length;
97
98
        if (
99
            doneAnnotations !== undefined &&
100
            document.requiredAnnotations !== undefined &&
101
            doneAnnotations < document.requiredAnnotations
102
        ) {
103
            icon = 'warning';
104
            desc =
105
                'Není dokončen požadovaný počet anotací <br /> (dokončeno ' +
106
                doneAnnotations +
107
                ' z ' +
108
                document.requiredAnnotations +
109
                ')';
110
        }
111
        recreate
112
            ? ShowConfirm(
113
                  () => finalizeDocument(document.id),
114
                  'vytvořit novou finální verzi dokumentu',
115
                  desc,
116
                  icon
117
              )
118
            : ShowConfirm(
119
                  () => finalizeDocument(document.id),
120
                  'vytvořit finální verzi dokumentu',
121
                  desc,
122
                  icon
123
              );
124
    };
125
126
    const finalizeDocument = async (documentId: string | undefined) => {
127
        setFinalizing(true);
128
        const finalAnnotationId = (
129
            await documentController.documentDocumentIdFinalPost(
130
                documentId ? documentId : ''
131
            )
132
        ).data.finalAnnotationId;
133
        if (!finalAnnotationId) {
134
            ShowToast('Finální verzi se nepovedlo vytvořit', 'error');
135
        } else {
136
            router.push({
137
                pathname: '/annotation/[annotationId]',
138
                query: { annotationId: finalAnnotationId, final: true },
139
            });
140
        }
141
        setFinalizing(false);
142
    };
143
144
    const editFinalizedDocument = async (finalAnnotationId: string) => {
145
        setFinalizing(true);
146
        if (!finalAnnotationId) {
147
            ShowToast('Finální verze dosud neexistuje', 'warning');
148
        } else {
149
            router.push({
150
                pathname: '/annotation/[annotationId]',
151
                query: { annotationId: finalAnnotationId, final: true },
152
            });
153
        }
154
        setFinalizing(false);
155
    };
156
157
    const getFinalizationStateIcon = (state: EState) => {
158
        const color = getAnnotationStateColor(state);
159
        const label = getAnnotationStateString(state);
160
        let icon = <CheckCircleOutlined />;
161
        if (state === 'NEW') {
162
            icon = <ClockCircleOutlined />;
163
        }
164
        if (state === 'IN_PROGRESS') {
165
            icon = <SyncOutlined />;
166
        }
167
168
        return (
169
            <Tag icon={icon} color={color} key={label}>
170
                {label.toUpperCase()}
171
            </Tag>
172
        );
173
    };
174
175 9bfa1e39 Jaroslav Hrubý
    const showAssignModal = () => {
176
        if (selectedDocs.length == 0) {
177
            ShowToast('Vyberte dokument pro přiřazení', 'warning', 3000, 'top-end');
178
        } else {
179
            setVisibleAssign(true);
180
        }
181
    };
182 e7eca311 Lukáš Vlček
    const showRequiredAnnotationsCountModal = () => {
183
        if (selectedDocs.length == 0) {
184
            ShowToast(
185
                'Vyberte dokument, pro které chcete nastavit požadovaný počet anotací',
186
                'warning',
187
                3000,
188
                'top-end'
189
            );
190
        } else {
191
            setVisibleSetCount(true);
192
        }
193
    };
194 9bfa1e39 Jaroslav Hrubý
    const showAddModal = () => {
195
        setVisibleAdd(true);
196 4a7bae81 Jaroslav Hrubý
    };
197
198 d7167305 Jaroslav Hrubý
    const showPreviewModal = async (id: string, name: string) => {
199
        const documentContent = (await documentController.documentDocumentIdGet(id)).data
200
            .content;
201 e97b42bc Jaroslav Hrubý
        if (documentContent) {
202
            setPreviewDocName(name);
203
            setPreviewDocContent(documentContent);
204
            setVisiblePreview(true);
205
        }
206 d7167305 Jaroslav Hrubý
    };
207
208 4a7bae81 Jaroslav Hrubý
    const hideModal = () => {
209 43d49a98 Jaroslav Hrubý
        fetchData();
210 9bfa1e39 Jaroslav Hrubý
        setVisibleAdd(false);
211
        setVisibleAssign(false);
212 e7eca311 Lukáš Vlček
        setVisibleSetCount(false);
213 d7167305 Jaroslav Hrubý
        setVisiblePreview(false);
214 8c45ccb0 hrubyjar
    };
215
216 c6109e2d Lukáš Vlček
    const columns = [
217
        {
218
            title: 'Název dokumentu',
219
            dataIndex: 'name',
220
            key: 'name',
221 c4f198c3 Jaroslav Hrubý
            width: '15%',
222 0db53e25 Jaroslav Hrubý
            ...getColumnSearchProps('name', 'název'),
223 669ffe38 Jaroslav Hrubý
            sorter: {
224
                // @ts-ignore
225
                compare: (a, b) => a.name.localeCompare(b.name),
226
                multiple: 2,
227
            },
228 c6109e2d Lukáš Vlček
        },
229
        {
230
            title: 'Délka',
231
            dataIndex: 'length',
232
            key: 'length',
233 c4f198c3 Jaroslav Hrubý
            width: '6%',
234
            align: 'center' as 'center',
235 0db53e25 Jaroslav Hrubý
            sorter: {
236
                // @ts-ignore
237
                compare: (a, b) => a.length - b.length,
238
                multiple: 1,
239
            },
240 c6109e2d Lukáš Vlček
        },
241 87a3d8d1 Lukáš Vlček
        {
242
            title: 'Dokončeno | přiřazeno | vyžadováno',
243
            key: 'annotationCounts',
244 c4f198c3 Jaroslav Hrubý
            width: '15%',
245
            align: 'center' as 'center',
246 87a3d8d1 Lukáš Vlček
            render: (
247
                columnData: DocumentListResponse,
248
                record: DocumentListInfo,
249
                index: number
250
            ) => {
251
                const finished =
252
                    record.annotatingUsers?.filter((d) => d.state === EState.Done)
253
                        .length ?? 0;
254
255
                return (
256
                    <div>
257
                        <ABadge
258
                            style={
259
                                finished === record.annotatingUsers?.length
260
                                    ? BadgeStyle.SUCCESS
261
                                    : BadgeStyle.WARNING
262
                            }
263
                        >
264
                            {finished}
265
                        </ABadge>
266
                        {' | '}
267
                        <ABadge
268
                            style={
269 ef2143b8 Lukáš Vlček
                                (record.annotatingUsers?.length ?? 0) >=
270
                                (record.requiredAnnotations ?? 0)
271 87a3d8d1 Lukáš Vlček
                                    ? BadgeStyle.SUCCESS
272
                                    : BadgeStyle.WARNING
273
                            }
274
                        >
275
                            {record.annotatingUsers?.length}
276
                        </ABadge>
277
                        {' | '}
278
                        <ABadge style={BadgeStyle.GENERAL}>
279
                            {record.requiredAnnotations}
280
                        </ABadge>
281
                    </div>
282
                );
283
            },
284
        },
285 c6109e2d Lukáš Vlček
        {
286
            title: 'Anotátoři',
287
            dataIndex: 'annotatingUsers',
288
            key: 'annotatingUsers',
289 c4f198c3 Jaroslav Hrubý
            width: '20%',
290 ff61085f Lukáš Vlček
            render: (
291
                columnData: DocumentUserInfo[],
292
                record: DocumentListInfo,
293
                index: number
294
            ) => {
295 c6109e2d Lukáš Vlček
                return (
296
                    <div>
297
                        {columnData.map((e) => (
298
                            <span
299
                                key={e.username + '.' + record.id}
300 ff61085f Lukáš Vlček
                                title={getUserInfoAlt(e) + '\nStav: ' + e.state}
301
                                style={{
302
                                    color: getAnnotationStateColor(e.state),
303
                                    padding: 3,
304
                                }}
305
                                className={'me-3'}
306 c6109e2d Lukáš Vlček
                            >
307
                                <FontAwesomeIcon
308
                                    icon={faUser}
309 ff61085f Lukáš Vlček
                                    title={getUserInfoAlt(e)}
310 c6109e2d Lukáš Vlček
                                    className={'me-2'}
311
                                />
312 c4f198c3 Jaroslav Hrubý
                                {record.finalAnnotations?.some(
313
                                    (annot) => annot.userId === e.id
314
                                ) ? (
315
                                    <u>{getNameTruncated(e)}</u>
316
                                ) : (
317
                                    getNameTruncated(e)
318
                                )}
319 c6109e2d Lukáš Vlček
                            </span>
320
                        ))}
321
                    </div>
322
                );
323
            },
324 0db53e25 Jaroslav Hrubý
            filters: userFilters,
325
            filterSearch: true,
326
            // @ts-ignore
327
            onFilter: (value, record) =>
328
                // @ts-ignore
329
                record.annotatingUsers.find((user) => user['username'] === value),
330
            sorter: {
331
                // @ts-ignore
332
                compare: (a, b) => a.annotatingUsers.length - b.annotatingUsers.length,
333 669ffe38 Jaroslav Hrubý
                multiple: 3,
334 0db53e25 Jaroslav Hrubý
            },
335 c6109e2d Lukáš Vlček
        },
336 d7167305 Jaroslav Hrubý
        {
337
            title: '',
338
            key: 'action',
339
            dataIndex: ['id', 'name'],
340 c4f198c3 Jaroslav Hrubý
            width: '10%',
341
            align: 'center' as 'center',
342 d7167305 Jaroslav Hrubý
            // @ts-ignore
343
            render: (text, row) => (
344
                <Button key={row.id} onClick={() => showPreviewModal(row.id, row.name)}>
345
                    Náhled
346
                </Button>
347
            ),
348
        },
349 c4f198c3 Jaroslav Hrubý
        {
350
            title: 'Finální verze dokumentu',
351
            key: 'final',
352
            dataIndex: ['id', 'finalizedExists'],
353
            // @ts-ignore
354
            render: (text, row) =>
355
                row.finalizedExists ? (
356
                    <Row>
357
                        <Space>
358
                            <Button
359
                                disabled={finalizing}
360
                                onClick={() => finalizeDocumentConfirm(row.id, true)}
361
                            >
362
                                Znovu vytvořit
363
                            </Button>
364
                            <Button
365
                                disabled={finalizing}
366
                                onClick={() =>
367
                                    editFinalizedDocument(row.finalizedAnnotationId)
368
                                }
369
                            >
370
                                Upravit
371
                            </Button>
372
                            {getFinalizationStateIcon(row.finalizedState)}
373
                        </Space>
374
                    </Row>
375
                ) : (
376
                    <Button
377
                        disabled={finalizing}
378
                        onClick={() => finalizeDocumentConfirm(row, false)}
379
                    >
380
                        Finalizovat
381
                    </Button>
382
                ),
383
            filters: [
384
                {
385
                    text: 'Nefinalizováno',
386
                    value: null,
387
                },
388
                {
389
                    text: 'Nový',
390
                    value: 'NEW',
391
                },
392
                {
393
                    text: 'Rozpracováno',
394
                    value: 'IN_PROGRESS',
395
                },
396
                {
397
                    text: 'Hotovo',
398
                    value: 'DONE',
399
                },
400
            ],
401
            // @ts-ignore
402
            onFilter: (value, record) => record.finalizedState === value,
403
        },
404 c6109e2d Lukáš Vlček
    ];
405
406 9bfa1e39 Jaroslav Hrubý
    const rowSelection = {
407
        onChange: (selectedRowKeys: React.Key[], selectedRows: DocumentListInfo[]) => {
408 43d49a98 Jaroslav Hrubý
            // @ts-ignore
409 9bfa1e39 Jaroslav Hrubý
            setSelectedDocs(selectedRows.map((row) => row.id));
410
        },
411
    };
412
413 8c45ccb0 hrubyjar
    return redirecting || role !== 'ADMINISTRATOR' ? null : (
414
        <MainLayout>
415
            <Typography.Title level={2}>
416
                <FontAwesomeIcon icon={faFileLines} /> Dokumenty
417
            </Typography.Title>
418 9bfa1e39 Jaroslav Hrubý
            <Button type={'primary'} onClick={showAddModal}>
419 8c45ccb0 hrubyjar
                Nahrát dokument
420
            </Button>
421 9bfa1e39 Jaroslav Hrubý
            <Button onClick={showAssignModal}>Přiřadit dokumenty</Button>
422 e7eca311 Lukáš Vlček
            <Button onClick={showRequiredAnnotationsCountModal}>
423
                Nastavit požadovaný počet anotací
424
            </Button>
425 9bfa1e39 Jaroslav Hrubý
            {visibleAdd && <AddDocumentModal onCancel={hideModal} />}
426
            {visibleAssign && (
427
                <AssignDocumentModal documentsIds={selectedDocs} onCancel={hideModal} />
428
            )}
429 d7167305 Jaroslav Hrubý
            {visiblePreview && (
430
                <DocPreviewModal
431
                    onCancel={hideModal}
432 329a602d Jaroslav Hrubý
                    documentName={previewDocName ?? ''}
433
                    content={
434
                        previewDocContent ?? 'Nastala chyba při načítání obsahu dokumentu'
435 cca0bfa0 Lukáš Vlček
                    }
436
                />
437 d8873409 Vojtěch Bartička
            )}
438 e7eca311 Lukáš Vlček
            {visibleSetCount && (
439
                <SetRequiredAnnotationsCountModal
440
                    documentsIds={selectedDocs}
441
                    onCancel={hideModal}
442 d7167305 Jaroslav Hrubý
                />
443
            )}
444 c6109e2d Lukáš Vlček
445
            <Table
446 669ffe38 Jaroslav Hrubý
                locale={{ ...getLocaleProps() }}
447 9bfa1e39 Jaroslav Hrubý
                rowSelection={{
448
                    type: 'checkbox',
449
                    ...rowSelection,
450
                }}
451 0db53e25 Jaroslav Hrubý
                // @ts-ignore
452 c6109e2d Lukáš Vlček
                columns={columns}
453
                dataSource={documents}
454 9bfa1e39 Jaroslav Hrubý
                size="middle"
455
                scroll={{ y: 600 }}
456 c6109e2d Lukáš Vlček
            />
457 8c45ccb0 hrubyjar
        </MainLayout>
458
    );
459
}
460
461
export default AdminDocumentPage;