Projekt

Obecné

Profil

Stáhnout (15.8 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, 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
                        <Button type="primary" onClick={addChild(record)}>
102
                            <PlusOutlined />
103
                        </Button>
104
                    )}
105
                    <Button type="text" onClick={editRecord(record)}>
106
                        <EditOutlined />
107
                    </Button>
108
                    <Popconfirm
109
                        title="Opravdu chcete smazat?"
110
                        onConfirm={deleteRecord(record)}
111
                    >
112
                        <Button type="primary" danger>
113
                            <DeleteOutlined />
114
                        </Button>
115
                    </Popconfirm>
116
                </Stack>
117
            ),
118
        },
119
    ];
120

    
121
    // ------------------------------------ ADD CATEGORY MODAL -------------------------------------
122

    
123
    const openAddCategoryModal = () => {
124
        setShowAddCategoryModal(true);
125
    };
126

    
127
    const submitAddCategoryModal = (val: CategoryModalValues) => {
128
        tagController
129
            .categoriesPost({
130
                name: val.name,
131
                description: val.description,
132
                color: val.color,
133
                disabledForAnnotators: val.disabledForAnnotators,
134
            })
135
            .then(
136
                () => loadData(),
137
                (reason) => console.log(reason)
138
            );
139

    
140
        setShowAddCategoryModal(false);
141
    };
142

    
143
    const cancelAddCategoryModal = () => {
144
        setShowAddCategoryModal(false);
145
    };
146

    
147
    // --------------------------------------------------------------------------------------------
148

    
149
    // ------------------------------------ EDIT CATEGORY MODAL -----------------------------------
150

    
151
    const openEditCategoryModal = () => {
152
        setShowEditCategoryModal(true);
153
    };
154

    
155
    const submitEditCategoryModel = (val: CategoryModalValues) => {
156
        tagController
157
            .categoryCategoryIdPut(selectedRecord.key, {
158
                name: val.name,
159
                description: val.description,
160
                color: val.color,
161
                disabledForAnnotators: val.disabledForAnnotators,
162
            })
163
            .then(() => loadData());
164

    
165
        setShowEditCategoryModal(false);
166
    };
167

    
168
    const cancelEditCategoryModal = () => {
169
        setShowEditCategoryModal(false);
170
    };
171

    
172
    // --------------------------------------------------------------------------------------------
173

    
174
    // ------------------------------------ ADD TAG MODAL -------------------------------------
175

    
176
    const openAddTagModal = () => {
177
        setShowAddTagModal(true);
178
    };
179

    
180
    const submitAddTagModal = (val: TagModalValues) => {
181
        tagController
182
            .tagsPost({
183
                categoryId: selectedRecord.key,
184
                name: val.name,
185
                description: val.description,
186
                color: val.color,
187
            })
188
            .then(() => loadData());
189

    
190
        setShowAddTagModal(false);
191
    };
192

    
193
    const cancelAddTagModal = () => {
194
        setShowAddTagModal(false);
195
    };
196

    
197
    // --------------------------------------------------------------------------------------------
198

    
199
    // ------------------------------------ EDIT TAG MODAL -------------------------------------
200

    
201
    const openEditTagModal = () => {
202
        setShowEditTagModal(true);
203
    };
204

    
205
    const submitEditTagModal = (val: TagModalValues) => {
206
        tagController
207
            .tagTagIdPut(selectedRecord.key, {
208
                name: val.name,
209
                description: val.description,
210
                color: val.color,
211
            })
212
            .then(() => loadData());
213

    
214
        setShowEditTagModal(false);
215
    };
216

    
217
    const cancelEditTagModal = () => {
218
        setShowEditTagModal(false);
219
    };
220

    
221
    // --------------------------------------------------------------------------------------------
222

    
223
    // ------------------------------------ ADD SUB TAG MODAL -------------------------------------
224

    
225
    const openAddSubTagModal = () => {
226
        setShowAddSubTagModal(true);
227
    };
228

    
229
    const submitAddSubTagModal = (val: SubTagModalValues) => {
230
        tagController
231
            .subtagsPost({
232
                tagId: selectedRecord.key,
233
                name: val.name,
234
                description: val.description,
235
            })
236
            .then(() => loadData());
237

    
238
        setShowAddSubTagModal(false);
239
    };
240

    
241
    const cancelAddSubTagModal = () => {
242
        setShowAddSubTagModal(false);
243
    };
244

    
245
    // --------------------------------------------------------------------------------------------
246

    
247
    // ------------------------------------ EDIT SUB TAG MODAL -------------------------------------
248

    
249
    const openEditSubTagModal = () => {
250
        setShowEditSubTagModal(true);
251
    };
252

    
253
    const submitEditSubTagModal = (val: SubTagModalValues) => {
254
        tagController
255
            .subtagSubtagIdPut(selectedRecord.key, {
256
                name: val.name,
257
                description: val.description,
258
            })
259
            .then(() => loadData());
260

    
261
        setShowEditSubTagModal(false);
262
    };
263

    
264
    const cancelEditSubTagModal = () => {
265
        setShowEditSubTagModal(false);
266
    };
267

    
268
    // --------------------------------------------------------------------------------------------
269

    
270
    // ------------------------------------ RECORD OPERATIONS -------------------------------------
271

    
272
    const addChild = (record: any) => (e: any) => {
273
        setSelectedRecord(record);
274

    
275
        if (record.depth === 0) {
276
            openAddTagModal();
277
        } else if (record.depth === 1) {
278
            openAddSubTagModal();
279
        }
280
    };
281

    
282
    const editRecord = (record: any) => (e: any) => {
283
        setSelectedRecord(record);
284

    
285
        if (record.depth === 0) {
286
            openEditCategoryModal();
287
        } else if (record.depth === 1) {
288
            openEditTagModal();
289
        } else if (record.depth === 2) {
290
            openEditSubTagModal();
291
        }
292
    };
293

    
294
    const deleteRecord = (record: any) => (e: any) => {
295
        if (record.depth === 0) {
296
            tagController.categoryCategoryIdDelete(record.key).then(() => loadData());
297
        } else if (record.depth === 1) {
298
            tagController.tagTagIdDelete(record.key).then(() => loadData());
299
        } else if (record.depth === 2) {
300
            tagController.subtagSubtagIdDelete(record.key).then(() => loadData());
301
        }
302
    };
303

    
304
    // --------------------------------------------------------------------------------------------
305

    
306
    /**
307
     * Loads data from a server.
308
     */
309
    const loadData = () => {
310
        tagController.tagsGet().then((tagTree) => {
311
            if (typeof tagTree.data.tagCategories != 'undefined') {
312
                setTagData(tagTree.data.tagCategories);
313
                setShownData(mapData(tagTree.data.tagCategories));
314
            }
315
        });
316
    };
317

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

    
352
    /**
353
     * Searches given value in 'name' column in a table.
354
     * If the provided value is empty the method loads all data from a server.
355
     * @param value Value that is searched.
356
     */
357
    const searchTag = (value: string) => {
358
        let data = mapData(tagData);
359

    
360
        if (value) {
361
            data = data?.filter((category) => {
362
                category.children = category.children?.filter((tag: any) => {
363
                    tag.children = tag.children?.filter((subTag: any) =>
364
                        subTag.name.toLowerCase().includes(value.toLowerCase())
365
                    );
366

    
367
                    return (
368
                        tag.children?.length > 0 ||
369
                        tag.name.toLowerCase().includes(value.toLowerCase())
370
                    );
371
                });
372

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

    
380
        setShownData(data);
381
    };
382

    
383
    return redirecting || role !== 'ADMINISTRATOR' ? null : (
384
        <MainLayout>
385
            {showAddCategoryModal && (
386
                <CategoryModal
387
                    title="Vytvořit kategorii"
388
                    submitText="Přidat"
389
                    onCancel={cancelAddCategoryModal}
390
                    onSubmit={submitAddCategoryModal}
391
                />
392
            )}
393

    
394
            {showEditCategoryModal && (
395
                <CategoryModal
396
                    title="Editovat kategorii"
397
                    submitText="Změnit"
398
                    onCancel={cancelEditCategoryModal}
399
                    onSubmit={submitEditCategoryModel}
400
                    defaultValues={selectedRecord}
401
                />
402
            )}
403

    
404
            {showAddTagModal && (
405
                <TagModal
406
                    title="Vytvořit tag"
407
                    submitText="Přidat"
408
                    onCancel={cancelAddTagModal}
409
                    onSubmit={submitAddTagModal}
410
                    defaultValues={{ color: selectedRecord.color }}
411
                />
412
            )}
413

    
414
            {showEditTagModal && (
415
                <TagModal
416
                    title="Editovat tag"
417
                    submitText="Změnit"
418
                    onCancel={cancelEditTagModal}
419
                    onSubmit={submitEditTagModal}
420
                    defaultValues={selectedRecord}
421
                />
422
            )}
423

    
424
            {showAddSubTagModal && (
425
                <SubTagModal
426
                    title="Vytvořit sub tag"
427
                    submitText="Přidat"
428
                    onCancel={cancelAddSubTagModal}
429
                    onSubmit={submitAddSubTagModal}
430
                />
431
            )}
432

    
433
            {showEditSubTagModal && (
434
                <SubTagModal
435
                    title="Editovat sub tag"
436
                    submitText="Změnit"
437
                    onCancel={cancelEditSubTagModal}
438
                    onSubmit={submitEditSubTagModal}
439
                    defaultValues={selectedRecord}
440
                />
441
            )}
442

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

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