Projekt

Obecné

Profil

Stáhnout (11.4 KB) Statistiky
| Větev: | Tag: | Revize:
1
import 'antd/dist/antd.css';
2
import React, { FocusEvent, useContext, useEffect, useState } from 'react';
3

    
4
import { useUnauthRedirect } from '../../../hooks';
5
import { useRouter } from 'next/router';
6
import { Button, Input, Space, Table, Typography } from 'antd';
7
import { faFileLines, faUser } from '@fortawesome/free-solid-svg-icons';
8
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
9
import { LoggedUserContext } from '../../../contexts/LoggedUserContext';
10
import { MainLayout } from '../../../layouts/MainLayout';
11
import AddDocumentModal from '../../../components/modals/AddDocumentModal';
12
import {
13
    DocumentListInfo,
14
    DocumentListResponse,
15
    DocumentUserInfo,
16
    EState,
17
} from '../../../api';
18
import { documentController, userController } from '../../../controllers';
19
import AssignDocumentModal from '../../../components/modals/AssignDocumentModal';
20
import { ShowConfirmDelete, ShowToast } from '../../../utils/alerts';
21
import { TableDocInfo } from '../../../components/types/TableDocInfo';
22
import {
23
    getAnnotationStateColor,
24
    getNameTruncated,
25
    getUserInfoAlt,
26
} from '../../../utils/strings';
27
import { ABadge, BadgeStyle } from '../../../components/common/ABadge';
28
import SetRequiredAnnotationsCountModal from '../../../components/modals/SetRequiredAnnotationsCountModal';
29
import DocPreviewModal from '../../../components/modals/DocPreviewModal';
30
import { UserFilter } from '../../../components/types/UserFilter';
31
import { getColumnSearchProps, getLocaleProps } from '../../../utils/tableUtils';
32
import { UserOutlined } from '@ant-design/icons';
33
import Swal from 'sweetalert2';
34
import { Stack } from 'react-bootstrap';
35

    
36
function AdminDocumentPage() {
37
    const redirecting = useUnauthRedirect('/login');
38
    const { logout, role } = useContext(LoggedUserContext);
39
    const [visibleAdd, setVisibleAdd] = React.useState(false);
40
    const [visibleAssign, setVisibleAssign] = React.useState(false);
41
    const [visiblePreview, setVisiblePreview] = React.useState(false);
42
    const [visibleSetCount, setVisibleSetCount] = React.useState(false);
43

    
44
    const router = useRouter();
45

    
46
    const [documents, setDocuments] = useState<TableDocInfo[]>([]);
47
    const [userFilters, setUserFilters] = useState<UserFilter[]>([]);
48
    const [selectedDocs, setSelectedDocs] = useState<string[]>([]);
49
    const [previewDocContent, setPreviewDocContent] = useState<string>();
50
    const [previewDocName, setPreviewDocName] = useState<string>();
51
    const [annotationCount, setAnnotationCount] = useState<number>();
52

    
53
    async function fetchData() {
54
        const docs = (await documentController.documentsGet(0, 1000)).data.documents;
55
        // @ts-ignore
56
        const tableDocs: TableDocInfo[] = docs?.map((doc, index) => {
57
            return { key: index, ...doc };
58
        });
59

    
60
        const users = (await userController.usersGet()).data.users;
61
        // @ts-ignore
62
        const filters: UserFilter[] = users?.map((user) => {
63
            return {
64
                text: user.name + ' ' + user.surname,
65
                value: user.username,
66
            };
67
        });
68
        setUserFilters(filters);
69

    
70
        let annotationCountRes =
71
            await documentController.documentsRequiredAnnotationsGlobalGet();
72
        setAnnotationCount(annotationCountRes.data.requiredAnnotationsGlobal);
73

    
74
        if (!docs) {
75
            setDocuments([]);
76
        } else {
77
            setDocuments(tableDocs);
78
        }
79
    }
80

    
81
    useEffect(() => {
82
        if (!redirecting && role === 'ADMINISTRATOR') {
83
            fetchData();
84
        }
85
    }, [logout, redirecting, role, router]);
86

    
87
    const showAssignModal = () => {
88
        if (selectedDocs.length == 0) {
89
            ShowToast('Vyberte dokument pro přiřazení', 'warning', 3000, 'top-end');
90
        } else {
91
            setVisibleAssign(true);
92
        }
93
    };
94
    const showRequiredAnnotationsCountModal = () => {
95
        if (selectedDocs.length == 0) {
96
            ShowToast(
97
                'Vyberte dokument, pro které chcete nastavit požadovaný počet anotací',
98
                'warning',
99
                3000,
100
                'top-end'
101
            );
102
        } else {
103
            setVisibleSetCount(true);
104
        }
105
    };
106
    const showAddModal = () => {
107
        setVisibleAdd(true);
108
    };
109

    
110
    const showPreviewModal = async (id: string, name: string) => {
111
        const documentContent = (await documentController.documentDocumentIdGet(id)).data
112
            .content;
113
        if (documentContent) {
114
            setPreviewDocName(name);
115
            setPreviewDocContent(documentContent);
116
            setVisiblePreview(true);
117
        }
118
    };
119

    
120
    const changeDefaultAnotationCount = (e: FocusEvent<HTMLInputElement>) => {
121
        documentController.documentsRequiredAnnotationsGlobalPost({
122
            requiredAnnotations: parseInt(e.currentTarget.value),
123
        });
124
    };
125

    
126
    const hideModal = () => {
127
        fetchData();
128
        setVisibleAdd(false);
129
        setVisibleAssign(false);
130
        setVisibleSetCount(false);
131
        setVisiblePreview(false);
132
    };
133

    
134
    const columns = [
135
        {
136
            title: 'Název dokumentu',
137
            dataIndex: 'name',
138
            key: 'name',
139
            ...getColumnSearchProps('name', 'název'),
140
            sorter: {
141
                // @ts-ignore
142
                compare: (a, b) => a.name.localeCompare(b.name),
143
                multiple: 2,
144
            },
145
        },
146
        {
147
            title: 'Délka',
148
            dataIndex: 'length',
149
            key: 'length',
150
            sorter: {
151
                // @ts-ignore
152
                compare: (a, b) => a.length - b.length,
153
                multiple: 1,
154
            },
155
        },
156
        {
157
            title: 'Dokončeno | přiřazeno | vyžadováno',
158
            key: 'annotationCounts',
159
            render: (
160
                columnData: DocumentListResponse,
161
                record: DocumentListInfo,
162
                index: number
163
            ) => {
164
                const finished =
165
                    record.annotatingUsers?.filter((d) => d.state === EState.Done)
166
                        .length ?? 0;
167

    
168
                return (
169
                    <div>
170
                        <ABadge
171
                            style={
172
                                finished === record.annotatingUsers?.length
173
                                    ? BadgeStyle.SUCCESS
174
                                    : BadgeStyle.WARNING
175
                            }
176
                        >
177
                            {finished}
178
                        </ABadge>
179
                        {' | '}
180
                        <ABadge
181
                            style={
182
                                (record.annotatingUsers?.length ?? 0) >=
183
                                (record.requiredAnnotations ?? 0)
184
                                    ? BadgeStyle.SUCCESS
185
                                    : BadgeStyle.WARNING
186
                            }
187
                        >
188
                            {record.annotatingUsers?.length}
189
                        </ABadge>
190
                        {' | '}
191
                        <ABadge style={BadgeStyle.GENERAL}>
192
                            {record.requiredAnnotations}
193
                        </ABadge>
194
                    </div>
195
                );
196
            },
197
        },
198
        {
199
            title: 'Anotátoři',
200
            dataIndex: 'annotatingUsers',
201
            key: 'annotatingUsers',
202
            render: (
203
                columnData: DocumentUserInfo[],
204
                record: DocumentListInfo,
205
                index: number
206
            ) => {
207
                return (
208
                    <div>
209
                        {columnData.map((e) => (
210
                            <span
211
                                key={e.username + '.' + record.id}
212
                                title={getUserInfoAlt(e) + '\nStav: ' + e.state}
213
                                style={{
214
                                    color: getAnnotationStateColor(e.state),
215
                                    padding: 3,
216
                                }}
217
                                className={'me-3'}
218
                            >
219
                                <FontAwesomeIcon
220
                                    icon={faUser}
221
                                    title={getUserInfoAlt(e)}
222
                                    className={'me-2'}
223
                                />
224
                                {getNameTruncated(e)}
225
                            </span>
226
                        ))}
227
                    </div>
228
                );
229
            },
230
            filters: userFilters,
231
            filterSearch: true,
232
            // @ts-ignore
233
            onFilter: (value, record) =>
234
                // @ts-ignore
235
                record.annotatingUsers.find((user) => user['username'] === value),
236
            sorter: {
237
                // @ts-ignore
238
                compare: (a, b) => a.annotatingUsers.length - b.annotatingUsers.length,
239
                multiple: 3,
240
            },
241
        },
242
        {
243
            title: '',
244
            key: 'action',
245
            dataIndex: ['id', 'name'],
246
            // @ts-ignore
247
            render: (text, row) => (
248
                <Button key={row.id} onClick={() => showPreviewModal(row.id, row.name)}>
249
                    Náhled
250
                </Button>
251
            ),
252
        },
253
    ];
254

    
255
    const rowSelection = {
256
        onChange: (selectedRowKeys: React.Key[], selectedRows: DocumentListInfo[]) => {
257
            // @ts-ignore
258
            setSelectedDocs(selectedRows.map((row) => row.id));
259
        },
260
    };
261

    
262
    return redirecting || role !== 'ADMINISTRATOR' ? null : (
263
        <MainLayout>
264
            <Typography.Title level={2}>
265
                <FontAwesomeIcon icon={faFileLines} /> Dokumenty
266
            </Typography.Title>
267
            <Stack style={{ width: '30%' }} direction="horizontal" key={annotationCount}>
268
                <span style={{ width: '70%' }}>Výchozí počet anotací:</span>
269
                <Input
270
                    defaultValue={annotationCount}
271
                    onBlur={changeDefaultAnotationCount}
272
                />
273
            </Stack>
274

    
275
            <Button type={'primary'} onClick={showAddModal}>
276
                Nahrát dokument
277
            </Button>
278
            <Button onClick={showAssignModal}>Přiřadit dokumenty</Button>
279
            <Button onClick={showRequiredAnnotationsCountModal}>
280
                Nastavit požadovaný počet anotací
281
            </Button>
282
            {visibleAdd && <AddDocumentModal onCancel={hideModal} />}
283
            {visibleAssign && (
284
                <AssignDocumentModal documentsIds={selectedDocs} onCancel={hideModal} />
285
            )}
286
            {visiblePreview && (
287
                <DocPreviewModal
288
                    onCancel={hideModal}
289
                    documentName={previewDocName ?? ''}
290
                    content={
291
                        previewDocContent ?? 'Nastala chyba při načítání obsahu dokumentu'
292
                    }
293
                />
294
            )}
295
            {visibleSetCount && (
296
                <SetRequiredAnnotationsCountModal
297
                    documentsIds={selectedDocs}
298
                    onCancel={hideModal}
299
                />
300
            )}
301

    
302
            <Table
303
                locale={{ ...getLocaleProps() }}
304
                rowSelection={{
305
                    type: 'checkbox',
306
                    ...rowSelection,
307
                }}
308
                // @ts-ignore
309
                columns={columns}
310
                dataSource={documents}
311
                size="middle"
312
                scroll={{ y: 600 }}
313
            />
314
        </MainLayout>
315
    );
316
}
317

    
318
export default AdminDocumentPage;
    (1-1/1)