Projekt

Obecné

Profil

Stáhnout (15.5 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
    /**
32
     * Data in a table.
33
     */
34
    const [tagData, setTagData] = useState<any[] | undefined>([]);
35

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

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

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

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

    
119
    // ------------------------------------ ADD CATEGORY MODAL -------------------------------------
120

    
121
    const openAddCategoryModal = () => {
122
        setShowAddCategoryModal(true);
123
    };
124

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

    
138
        setShowAddCategoryModal(false);
139
    };
140

    
141
    const cancelAddCategoryModal = () => {
142
        setShowAddCategoryModal(false);
143
    };
144

    
145
    // --------------------------------------------------------------------------------------------
146

    
147
    // ------------------------------------ EDIT CATEGORY MODAL -----------------------------------
148

    
149
    const openEditCategoryModal = () => {
150
        setShowEditCategoryModal(true);
151
    };
152

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

    
163
        setShowEditCategoryModal(false);
164
    };
165

    
166
    const cancelEditCategoryModal = () => {
167
        setShowEditCategoryModal(false);
168
    };
169

    
170
    // --------------------------------------------------------------------------------------------
171

    
172
    // ------------------------------------ ADD TAG MODAL -------------------------------------
173

    
174
    const openAddTagModal = () => {
175
        setShowAddTagModal(true);
176
    };
177

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

    
188
        setShowAddTagModal(false);
189
    };
190

    
191
    const cancelAddTagModal = () => {
192
        setShowAddTagModal(false);
193
    };
194

    
195
    // --------------------------------------------------------------------------------------------
196

    
197
    // ------------------------------------ EDIT TAG MODAL -------------------------------------
198

    
199
    const openEditTagModal = () => {
200
        setShowEditTagModal(true);
201
    };
202

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

    
212
        setShowEditTagModal(false);
213
    };
214

    
215
    const cancelEditTagModal = () => {
216
        setShowEditTagModal(false);
217
    };
218

    
219
    // --------------------------------------------------------------------------------------------
220

    
221
    // ------------------------------------ ADD SUB TAG MODAL -------------------------------------
222

    
223
    const openAddSubTagModal = () => {
224
        setShowAddSubTagModal(true);
225
    };
226

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

    
236
        setShowAddSubTagModal(false);
237
    };
238

    
239
    const cancelAddSubTagModal = () => {
240
        setShowAddSubTagModal(false);
241
    };
242

    
243
    // --------------------------------------------------------------------------------------------
244

    
245
    // ------------------------------------ EDIT SUB TAG MODAL -------------------------------------
246

    
247
    const openEditSubTagModal = () => {
248
        setShowEditSubTagModal(true);
249
    };
250

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

    
259
        setShowEditSubTagModal(false);
260
    };
261

    
262
    const cancelEditSubTagModal = () => {
263
        setShowEditSubTagModal(false);
264
    };
265

    
266
    // --------------------------------------------------------------------------------------------
267

    
268
    // ------------------------------------ RECORD OPERATIONS -------------------------------------
269

    
270
    const addChild = (record: any) => (e: any) => {
271
        setSelectedRecord(record);
272

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

    
280
    const editRecord = (record: any) => (e: any) => {
281
        setSelectedRecord(record);
282

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

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

    
302
    // --------------------------------------------------------------------------------------------
303

    
304
    /**
305
     * Loads data from a server.
306
     */
307
    const loadData = () => {
308
        tagController.tagsGet().then((tagTree) => {
309
            if (typeof tagTree.data.tagCategories != 'undefined') {
310
                let data = tagTree.data.tagCategories?.map((catInfo) => {
311
                    return {
312
                        key: catInfo.id,
313
                        name: catInfo.name,
314
                        description: catInfo.description,
315
                        color: catInfo.color,
316
                        depth: 0,
317
                        disabledForAnnotators: catInfo.disabledForAnnotators,
318
                        ...(catInfo.tags?.length && {
319
                            children: catInfo.tags?.map((tagInfo) => {
320
                                return {
321
                                    key: tagInfo.id,
322
                                    name: tagInfo.name,
323
                                    description: tagInfo.description,
324
                                    color: tagInfo.color,
325
                                    depth: 1,
326
                                    ...(tagInfo.subTags?.length && {
327
                                        children: tagInfo.subTags?.map((subInfo) => {
328
                                            return {
329
                                                key: subInfo.id,
330
                                                name: subInfo.name,
331
                                                description: subInfo.description,
332
                                                depth: 2,
333
                                            };
334
                                        }),
335
                                    }),
336
                                };
337
                            }),
338
                        }),
339
                    };
340
                });
341

    
342
                setTagData(data);
343
            }
344
        });
345
    };
346

    
347
    /**
348
     * Searches given value in 'name' column in a table.
349
     * If the provided value is empty the method loads all data from a server.
350
     * @param value Value that is searched.
351
     */
352
    const searchTag = (value: string) => {
353
        if (!value) loadData();
354

    
355
        let data = tagData?.filter((category) => {
356
            category.children = category.children?.filter((tag: any) => {
357
                tag.children = tag.children?.filter((subTag: any) =>
358
                    subTag.name.startsWith(value)
359
                );
360

    
361
                return tag.children?.length > 0 || tag.name.startsWith(value);
362
            });
363

    
364
            return category.children?.length > 0 || category.name.startsWith(value);
365
        });
366

    
367
        setTagData(data);
368
    };
369

    
370
    return redirecting || role !== 'ADMINISTRATOR' ? null : (
371
        <MainLayout>
372
            {showAddCategoryModal && (
373
                <CategoryModal
374
                    title="Vytvořit kategorii"
375
                    submitText="Přidat"
376
                    onCancel={cancelAddCategoryModal}
377
                    onSubmit={submitAddCategoryModal}
378
                />
379
            )}
380

    
381
            {showEditCategoryModal && (
382
                <CategoryModal
383
                    title="Editovat kategorii"
384
                    submitText="Změnit"
385
                    onCancel={cancelEditCategoryModal}
386
                    onSubmit={submitEditCategoryModel}
387
                    defaultValues={selectedRecord}
388
                />
389
            )}
390

    
391
            {showAddTagModal && (
392
                <TagModal
393
                    title="Vytvořit tag"
394
                    submitText="Přidat"
395
                    onCancel={cancelAddTagModal}
396
                    onSubmit={submitAddTagModal}
397
                    defaultValues={{ color: selectedRecord.color }}
398
                />
399
            )}
400

    
401
            {showEditTagModal && (
402
                <TagModal
403
                    title="Editovat tag"
404
                    submitText="Změnit"
405
                    onCancel={cancelEditTagModal}
406
                    onSubmit={submitEditTagModal}
407
                    defaultValues={selectedRecord}
408
                />
409
            )}
410

    
411
            {showAddSubTagModal && (
412
                <SubTagModal
413
                    title="Vytvořit sub tag"
414
                    submitText="Přidat"
415
                    onCancel={cancelAddSubTagModal}
416
                    onSubmit={submitAddSubTagModal}
417
                />
418
            )}
419

    
420
            {showEditSubTagModal && (
421
                <SubTagModal
422
                    title="Editovat sub tag"
423
                    submitText="Změnit"
424
                    onCancel={cancelEditSubTagModal}
425
                    onSubmit={submitEditSubTagModal}
426
                    defaultValues={selectedRecord}
427
                />
428
            )}
429

    
430
            <Container>
431
                <Row>
432
                    <Typography.Title level={2}>
433
                        <FontAwesomeIcon icon={faTags} /> Značky
434
                    </Typography.Title>
435
                </Row>
436
                <Row>
437
                    <Table
438
                        columns={columns}
439
                        dataSource={tagData}
440
                        scroll={{ y: 'calc(100vh - 300px)' }}
441
                        size="small"
442
                        title={() => (
443
                            <Stack direction="horizontal" gap={3}>
444
                                <Button type="primary" onClick={openAddCategoryModal}>
445
                                    Přidat kategorii
446
                                </Button>
447
                                <Search
448
                                    placeholder="Vyhledání tagu"
449
                                    onSearch={searchTag}
450
                                    style={{ width: 200 }}
451
                                    className="ms-auto"
452
                                />
453
                            </Stack>
454
                        )}
455
                    />
456
                </Row>
457
            </Container>
458
        </MainLayout>
459
    );
460
}
461

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