Projekt

Obecné

Profil

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

    
4
import { useUnauthRedirect } from '../../hooks';
5
import { useRouter } from 'next/router';
6
import { Button, Checkbox, Popconfirm, Tooltip, Typography } from 'antd';
7
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
8
import { faTags } from '@fortawesome/free-solid-svg-icons';
9
import { LoggedUserContext } from '../../contexts/LoggedUserContext';
10
import { MainLayout } from '../../layouts/MainLayout';
11
import { Container, Row, Stack } from 'react-bootstrap';
12
import { Table } from 'antd';
13
import { tagController } from '../../controllers';
14
import Search from 'antd/lib/input/Search';
15
import { DeleteOutlined, PlusOutlined, EditOutlined } from '@ant-design/icons';
16
import CategoryModal, {
17
    CategoryModalValues,
18
} from '../../components/modals/CategoryModal';
19
import TagModal, { TagModalValues } from '../../components/modals/TagModal';
20
import SubTagModal, { SubTagModalValues } from '../../components/modals/SubTagModal';
21

    
22
/**
23
 * Creates a tag management page.
24
 * @returns The tag management page.
25
 */
26
function TagsPage() {
27
    const redirecting = useUnauthRedirect('/login');
28
    const { logout, role } = useContext(LoggedUserContext);
29
    const router = useRouter();
30

    
31
    const [tagData, setTagData] = useState<any[] | null>([]);
32

    
33
    /**
34
     * Data in a table.
35
     */
36
    const [shownData, setShownData] = useState<any[] | undefined>([]);
37

    
38
    // States that says if modal windows should be shown.
39
    const [showAddCategoryModal, setShowAddCategoryModal] = useState(false);
40
    const [showEditCategoryModal, setShowEditCategoryModal] = useState(false);
41
    const [showAddTagModal, setShowAddTagModal] = useState(false);
42
    const [showEditTagModal, setShowEditTagModal] = useState(false);
43
    const [showAddSubTagModal, setShowAddSubTagModal] = useState(false);
44
    const [showEditSubTagModal, setShowEditSubTagModal] = useState(false);
45

    
46
    /**
47
     * Currently selected record in a table.
48
     */
49
    const [selectedRecord, setSelectedRecord] = useState({
50
        key: '',
51
        name: '',
52
        description: '',
53
        color: '',
54
        disabledForAnnotators: false,
55
    });
56

    
57
    /**
58
     * Loads data on start.
59
     */
60
    useEffect(() => {
61
        if (!redirecting && role === 'ADMINISTRATOR') {
62
            loadData();
63
        }
64
    }, [logout, redirecting, role, router]);
65

    
66
    /**
67
     * Definition of columns of a table.
68
     */
69
    const columns = [
70
        { title: 'Název', dataIndex: 'name', key: 'name' },
71
        {
72
            title: 'Barva',
73
            dataIndex: 'color',
74
            key: 'color',
75
            width: 75,
76
            render: (
77
                columnData: string | null | undefined,
78
                record: any,
79
                index: number
80
            ) => {
81
                if (columnData) return <input type="color" value={columnData} disabled />;
82
            },
83
        },
84
        {
85
            title: 'Skrýt pro anotátory',
86
            dataIndex: 'disabledForAnnotators',
87
            key: 'disabledForAnnotators',
88
            width: 150,
89
            render: (columnData: boolean | undefined, record: any, index: number) =>
90
                columnData !== undefined && <Checkbox checked={columnData} disabled />,
91
        },
92
        { title: 'Popis', dataIndex: 'description', key: 'description' },
93
        {
94
            title: '',
95
            dataIndex: 'operations',
96
            key: 'operations',
97
            width: 200,
98
            render: (text: any, record: any, index: number) => (
99
                <Stack direction="horizontal">
100
                    {record.depth < 2 && (
101
                        <Tooltip title="Přidat potomka">
102
                            <Button type="primary" onClick={addChild(record)}>
103
                                <PlusOutlined />
104
                            </Button>
105
                        </Tooltip>
106
                    )}
107
                    <Tooltip title="Upravit">
108
                        <Button type="text" onClick={editRecord(record)}>
109
                            <EditOutlined />
110
                        </Button>
111
                    </Tooltip>
112
                    <Popconfirm
113
                        title="Opravdu chcete smazat?"
114
                        onConfirm={deleteRecord(record)}
115
                    >
116
                        <Tooltip title="Odstranit">
117
                            <Button type="primary" danger>
118
                                <DeleteOutlined />
119
                            </Button>
120
                        </Tooltip>
121
                    </Popconfirm>
122
                </Stack>
123
            ),
124
        },
125
    ];
126

    
127
    // ------------------------------------ ADD CATEGORY MODAL -------------------------------------
128

    
129
    const openAddCategoryModal = () => {
130
        setShowAddCategoryModal(true);
131
    };
132

    
133
    const submitAddCategoryModal = (val: CategoryModalValues) => {
134
        tagController
135
            .categoriesPost({
136
                name: val.name,
137
                description: val.description,
138
                color: val.color,
139
                disabledForAnnotators: val.disabledForAnnotators,
140
            })
141
            .then(
142
                () => loadData(),
143
                (reason) => console.log(reason)
144
            );
145

    
146
        setShowAddCategoryModal(false);
147
    };
148

    
149
    const cancelAddCategoryModal = () => {
150
        setShowAddCategoryModal(false);
151
    };
152

    
153
    // --------------------------------------------------------------------------------------------
154

    
155
    // ------------------------------------ EDIT CATEGORY MODAL -----------------------------------
156

    
157
    const openEditCategoryModal = () => {
158
        setShowEditCategoryModal(true);
159
    };
160

    
161
    const submitEditCategoryModel = (val: CategoryModalValues) => {
162
        tagController
163
            .categoryCategoryIdPut(selectedRecord.key, {
164
                name: val.name,
165
                description: val.description,
166
                color: val.color,
167
                disabledForAnnotators: val.disabledForAnnotators,
168
            })
169
            .then(() => loadData());
170

    
171
        setShowEditCategoryModal(false);
172
    };
173

    
174
    const cancelEditCategoryModal = () => {
175
        setShowEditCategoryModal(false);
176
    };
177

    
178
    // --------------------------------------------------------------------------------------------
179

    
180
    // ------------------------------------ ADD TAG MODAL -------------------------------------
181

    
182
    const openAddTagModal = () => {
183
        setShowAddTagModal(true);
184
    };
185

    
186
    const submitAddTagModal = (val: TagModalValues) => {
187
        tagController
188
            .tagsPost({
189
                categoryId: selectedRecord.key,
190
                name: val.name,
191
                description: val.description,
192
                color: val.color,
193
            })
194
            .then(() => loadData());
195

    
196
        setShowAddTagModal(false);
197
    };
198

    
199
    const cancelAddTagModal = () => {
200
        setShowAddTagModal(false);
201
    };
202

    
203
    // --------------------------------------------------------------------------------------------
204

    
205
    // ------------------------------------ EDIT TAG MODAL -------------------------------------
206

    
207
    const openEditTagModal = () => {
208
        setShowEditTagModal(true);
209
    };
210

    
211
    const submitEditTagModal = (val: TagModalValues) => {
212
        tagController
213
            .tagTagIdPut(selectedRecord.key, {
214
                name: val.name,
215
                description: val.description,
216
                color: val.color,
217
            })
218
            .then(() => loadData());
219

    
220
        setShowEditTagModal(false);
221
    };
222

    
223
    const cancelEditTagModal = () => {
224
        setShowEditTagModal(false);
225
    };
226

    
227
    // --------------------------------------------------------------------------------------------
228

    
229
    // ------------------------------------ ADD SUB TAG MODAL -------------------------------------
230

    
231
    const openAddSubTagModal = () => {
232
        setShowAddSubTagModal(true);
233
    };
234

    
235
    const submitAddSubTagModal = (val: SubTagModalValues) => {
236
        tagController
237
            .subtagsPost({
238
                tagId: selectedRecord.key,
239
                name: val.name,
240
                description: val.description,
241
            })
242
            .then(() => loadData());
243

    
244
        setShowAddSubTagModal(false);
245
    };
246

    
247
    const cancelAddSubTagModal = () => {
248
        setShowAddSubTagModal(false);
249
    };
250

    
251
    // --------------------------------------------------------------------------------------------
252

    
253
    // ------------------------------------ EDIT SUB TAG MODAL -------------------------------------
254

    
255
    const openEditSubTagModal = () => {
256
        setShowEditSubTagModal(true);
257
    };
258

    
259
    const submitEditSubTagModal = (val: SubTagModalValues) => {
260
        tagController
261
            .subtagSubtagIdPut(selectedRecord.key, {
262
                name: val.name,
263
                description: val.description,
264
            })
265
            .then(() => loadData());
266

    
267
        setShowEditSubTagModal(false);
268
    };
269

    
270
    const cancelEditSubTagModal = () => {
271
        setShowEditSubTagModal(false);
272
    };
273

    
274
    // --------------------------------------------------------------------------------------------
275

    
276
    // ------------------------------------ RECORD OPERATIONS -------------------------------------
277

    
278
    const addChild = (record: any) => (e: any) => {
279
        setSelectedRecord(record);
280

    
281
        if (record.depth === 0) {
282
            openAddTagModal();
283
        } else if (record.depth === 1) {
284
            openAddSubTagModal();
285
        }
286
    };
287

    
288
    const editRecord = (record: any) => (e: any) => {
289
        setSelectedRecord(record);
290

    
291
        if (record.depth === 0) {
292
            openEditCategoryModal();
293
        } else if (record.depth === 1) {
294
            openEditTagModal();
295
        } else if (record.depth === 2) {
296
            openEditSubTagModal();
297
        }
298
    };
299

    
300
    const deleteRecord = (record: any) => (e: any) => {
301
        if (record.depth === 0) {
302
            tagController.categoryCategoryIdDelete(record.key).then(() => loadData());
303
        } else if (record.depth === 1) {
304
            tagController.tagTagIdDelete(record.key).then(() => loadData());
305
        } else if (record.depth === 2) {
306
            tagController.subtagSubtagIdDelete(record.key).then(() => loadData());
307
        }
308
    };
309

    
310
    // --------------------------------------------------------------------------------------------
311

    
312
    /**
313
     * Loads data from a server.
314
     */
315
    const loadData = () => {
316
        tagController.tagsGet().then((tagTree) => {
317
            if (typeof tagTree.data.tagCategories != 'undefined') {
318
                setTagData(tagTree.data.tagCategories);
319
                setShownData(mapData(tagTree.data.tagCategories));
320
            }
321
        });
322
    };
323

    
324
    const mapData = (data: any[] | null) => {
325
        return data?.map((catInfo) => {
326
            return {
327
                key: catInfo.id,
328
                name: catInfo.name,
329
                description: catInfo.description,
330
                color: catInfo.color,
331
                depth: 0,
332
                disabledForAnnotators: catInfo.disabledForAnnotators,
333
                ...(catInfo.tags?.length && {
334
                    children: catInfo.tags?.map((tagInfo: any) => {
335
                        return {
336
                            key: tagInfo.id,
337
                            name: tagInfo.name,
338
                            description: tagInfo.description,
339
                            color: tagInfo.color,
340
                            depth: 1,
341
                            ...(tagInfo.subTags?.length && {
342
                                children: tagInfo.subTags?.map((subInfo: any) => {
343
                                    return {
344
                                        key: subInfo.id,
345
                                        name: subInfo.name,
346
                                        description: subInfo.description,
347
                                        depth: 2,
348
                                    };
349
                                }),
350
                            }),
351
                        };
352
                    }),
353
                }),
354
            };
355
        });
356
    };
357

    
358
    /**
359
     * Searches given value in 'name' column in a table.
360
     * If the provided value is empty the method loads all data from a server.
361
     * @param value Value that is searched.
362
     */
363
    const searchTag = (value: string) => {
364
        let data = mapData(tagData);
365

    
366
        if (value) {
367
            data = data?.filter((category) => {
368
                category.children = category.children?.filter((tag: any) => {
369
                    tag.children = tag.children?.filter((subTag: any) =>
370
                        subTag.name.toLowerCase().includes(value.toLowerCase())
371
                    );
372

    
373
                    return (
374
                        tag.children?.length > 0 ||
375
                        tag.name.toLowerCase().includes(value.toLowerCase())
376
                    );
377
                });
378

    
379
                return (
380
                    category.children?.length > 0 ||
381
                    category.name.toLowerCase().includes(value.toLowerCase())
382
                );
383
            });
384
        }
385

    
386
        setShownData(data);
387
    };
388

    
389
    return redirecting || role !== 'ADMINISTRATOR' ? null : (
390
        <MainLayout>
391
            {showAddCategoryModal && (
392
                <CategoryModal
393
                    title="Vytvořit kategorii"
394
                    submitText="Přidat"
395
                    onCancel={cancelAddCategoryModal}
396
                    onSubmit={submitAddCategoryModal}
397
                />
398
            )}
399

    
400
            {showEditCategoryModal && (
401
                <CategoryModal
402
                    title="Editovat kategorii"
403
                    submitText="Změnit"
404
                    onCancel={cancelEditCategoryModal}
405
                    onSubmit={submitEditCategoryModel}
406
                    defaultValues={selectedRecord}
407
                />
408
            )}
409

    
410
            {showAddTagModal && (
411
                <TagModal
412
                    title="Vytvořit tag"
413
                    submitText="Přidat"
414
                    onCancel={cancelAddTagModal}
415
                    onSubmit={submitAddTagModal}
416
                    defaultValues={{ color: selectedRecord.color }}
417
                />
418
            )}
419

    
420
            {showEditTagModal && (
421
                <TagModal
422
                    title="Editovat tag"
423
                    submitText="Změnit"
424
                    onCancel={cancelEditTagModal}
425
                    onSubmit={submitEditTagModal}
426
                    defaultValues={selectedRecord}
427
                />
428
            )}
429

    
430
            {showAddSubTagModal && (
431
                <SubTagModal
432
                    title="Vytvořit sub tag"
433
                    submitText="Přidat"
434
                    onCancel={cancelAddSubTagModal}
435
                    onSubmit={submitAddSubTagModal}
436
                />
437
            )}
438

    
439
            {showEditSubTagModal && (
440
                <SubTagModal
441
                    title="Editovat sub tag"
442
                    submitText="Změnit"
443
                    onCancel={cancelEditSubTagModal}
444
                    onSubmit={submitEditSubTagModal}
445
                    defaultValues={selectedRecord}
446
                />
447
            )}
448

    
449
            <Container>
450
                <Row>
451
                    <Typography.Title level={2}>
452
                        <FontAwesomeIcon icon={faTags} /> Značky
453
                    </Typography.Title>
454
                </Row>
455
                <Row>
456
                    <Table
457
                        columns={columns}
458
                        dataSource={shownData}
459
                        scroll={{ y: 'calc(100vh - 300px)' }}
460
                        size="small"
461
                        title={() => (
462
                            <Stack direction="horizontal" gap={3}>
463
                                <Button type="primary" onClick={openAddCategoryModal}>
464
                                    Přidat kategorii
465
                                </Button>
466
                                <Search
467
                                    placeholder="Vyhledání tagu"
468
                                    onSearch={searchTag}
469
                                    style={{ width: 200 }}
470
                                    className="ms-auto"
471
                                />
472
                            </Stack>
473
                        )}
474
                    />
475
                </Row>
476
            </Container>
477
        </MainLayout>
478
    );
479
}
480

    
481
export default TagsPage;
    (1-1/1)