Projekt

Obecné

Profil

« Předchozí | Další » 

Revize b80a6919

Přidáno uživatelem Lukáš Vlček před asi 2 roky(ů)

Document finalization

Zobrazit rozdíly:

webapp/components/annotation/AnnotationItem.tsx
1 1
import { Col, Container, Row, Stack } from 'react-bootstrap';
2 2
import { Tag } from '../types/tag';
3
import { ChangeEvent, useContext, useState } from 'react';
3
import { useContext, useState } from 'react';
4 4
import 'antd/dist/antd.css';
5
import { Button, Input, Select } from 'antd';
6
import {
7
    PlusOutlined,
8
    DownOutlined,
9
    DeleteOutlined,
10
    TagOutlined,
11
    EyeOutlined,
12
} from '@ant-design/icons';
5
import { Button, Select } from 'antd';
6
import { DownOutlined, PlusOutlined, TagOutlined } from '@ant-design/icons';
13 7
import { AnnotationContext } from '../../contexts/AnnotationContext';
14
import { ETagSentiment, TagInstanceInfo } from '../../api';
15
import { getTextMaxLength } from '../../utils/strings';
8
import { AnnotationOccurrenceItem } from './AnnotationOccurrenceItem';
9
import { COLOR_ALL_OCCURRENCES_ACCEPTED, COLOR_HIGHLIGHTED_TAG } from '../../constants';
10
import { ABadge, BadgeStyle } from '../common/ABadge';
11
import { getNameTruncated } from '../../utils/strings';
12
import { ShowConfirm } from '../../utils/alerts';
16 13

  
17 14
const { Option } = Select;
18 15

  
......
25 22
    /**
26 23
     * Should properties of this annotation be visible?
27 24
     */
28
    const [visibleProperties, setVisibleProperties] = useState(false);
25
    const [detailsVisible, setDetailsVisible] = useState(false);
29 26

  
30 27
    /**
31 28
     * Context that manages annotations.
32 29
     */
33 30
    const {
34 31
        addOccurrence,
35
        deleteOccurrence,
36
        changePosition,
37
        changeNote,
38
        changeSentiment,
39
        changeLength,
40
        selectedOccurrenceId,
41 32
        selectedInstanceId,
42 33
        setSelectedOccurrenceId,
43 34
        setSelectedInstanceId,
35
        isFinal,
36
        makeOccurrenceFinal,
44 37
    } = useContext(AnnotationContext);
45 38

  
46 39
    /**
......
50 43
        addOccurrence(props.tag);
51 44
    };
52 45

  
53
    /**
54
     * Removes an occurrence of this annotation from the context.
55
     * @param occurrence The occurrence that should be removed.
56
     */
57
    const onDeleteOccurrence = (occurrence: TagInstanceInfo) => (e: any) => {
58
        deleteOccurrence(occurrence);
59
    };
60

  
61
    /**
62
     * Changes a position of an occurrence of this annotation in the context.
63
     * @param occurrence The occurrence that should be changed.
64
     */
65
    const onChangePosition =
66
        (occurrence: TagInstanceInfo) => (e: ChangeEvent<HTMLInputElement>) => {
67
            changePosition(occurrence, Number(e.currentTarget.value));
68
        };
69

  
70
    /**
71
     * Changes a length of an occurrence of this annotation in the context.
72
     * @param occurrence The occurrence that should be changed.
73
     */
74
    const onChangeLength =
75
        (occurrence: TagInstanceInfo) => (e: ChangeEvent<HTMLInputElement>) => {
76
            changeLength(occurrence, Number(e.currentTarget.value));
77
        };
78

  
79
    const onChangeSentiment = (occurrence: TagInstanceInfo) => (val: ETagSentiment) => {
80
        changeSentiment(occurrence, val);
81
    };
82

  
83
    const onChangeNote =
84
        (occurrence: TagInstanceInfo) => (e: ChangeEvent<HTMLTextAreaElement>) => {
85
            changeNote(occurrence, e.currentTarget.value);
86
        };
87

  
88 46
    /**
89 47
     * Changes visibility of properties of this annotation.
90 48
     */
91 49
    const changePropertiesVisibility = () => {
92
        setVisibleProperties(!visibleProperties);
50
        setDetailsVisible(!detailsVisible);
93 51
    };
94 52

  
53
    function isAllAccepted() {
54
        return props.tag.occurrences.filter((o) => !o.isFinal).length === 0;
55
    }
56
    function getBackgroundColor(): string {
57
        if (selectedInstanceId === props.tag.instanceId) {
58
            // highlighted tag
59
            return COLOR_HIGHLIGHTED_TAG;
60
        }
61

  
62
        if (isFinal) {
63
            if (isAllAccepted()) {
64
                return COLOR_ALL_OCCURRENCES_ACCEPTED;
65
            } else {
66
                return '#E4C8CC';
67
            }
68
        }
69

  
70
        return 'white';
71
    }
95 72
    return (
96
        <Container>
97
            <Row
98
                className="border rounded"
99
                style={{
100
                    backgroundColor:
101
                        selectedInstanceId === props.tag.instanceId ? '#FCF3CF' : 'white',
102
                }}
103
            >
73
        <Container
74
            className="border rounded"
75
            style={{
76
                backgroundColor: getBackgroundColor(),
77
            }}
78
        >
79
            <Row className="">
104 80
                <Col sm="auto" className="d-flex align-items-center">
105 81
                    <Button
106 82
                        icon={<TagOutlined style={{ marginLeft: 0 }} />}
......
111 87
                        style={{
112 88
                            border: 'none',
113 89
                            paddingLeft: 0,
114
                            backgroundColor:
115
                                selectedInstanceId === props.tag.instanceId
116
                                    ? '#FCF3CF'
117
                                    : 'white',
90
                            backgroundColor: getBackgroundColor(),
118 91
                        }}
119 92
                        title={'Zvýraznit značky'}
120 93
                    />
......
124 97
                    {props.tag.subtagName ? ' (' + props.tag.subtagName + ')' : ''}
125 98
                </Col>
126 99
                <Col sm="auto">
100
                    {props.tag.occurrences.length > 1 && (
101
                        <ABadge style={BadgeStyle.GENERAL}>
102
                            {props.tag.occurrences.length}
103
                        </ABadge>
104
                    )}
105

  
127 106
                    <Button
128 107
                        type="text"
129 108
                        shape="circle"
......
138 117
                    />
139 118
                </Col>
140 119
            </Row>
141
            {visibleProperties && (
142
                <Stack gap={1} className="mb-2">
143
                    <div>Kategorie: {props.tag.category}</div>
144
                    <div>Výskyty:</div>
145
                    {props.tag.occurrences.map((occurrence, index) => {
146
                        return (
147
                            <Container
148
                                key={index}
149
                                className="shadow-sm"
150
                                style={{
151
                                    backgroundColor:
152
                                        selectedOccurrenceId === occurrence.occurenceId
153
                                            ? '#D8E1E9'
154
                                            : 'white',
155
                                }}
156
                            >
157
                                <Row className="mb-1 mt-1">
158
                                    <Col>
159
                                        <Row>
160
                                            <Col>Pozice: {occurrence.position}</Col>
161
                                            <Col>Délka: {occurrence.length}</Col>
162
                                        </Row>
163
                                        <Row>
164
                                            <i title={occurrence.selectedText ?? ''}>
165
                                                {getTextMaxLength(
166
                                                    occurrence.selectedText ?? '',
167
                                                    35
168
                                                )}
169
                                            </i>
170
                                        </Row>
171
                                        <Row>
172
                                            <Col
173
                                                className="d-flex align-items-center"
174
                                                sm="4"
120
            {isFinal && !isAllAccepted() && (
121
                <>
122
                    <Row
123
                        style={{
124
                            backgroundColor: getBackgroundColor(),
125
                        }}
126
                    >
127
                        <Col sm="12" className="d-flex align-items-center">
128
                            {props.tag.occurrences.length === 1 && (
129
                                <div
130
                                    style={{
131
                                        display: 'flex',
132
                                        flexDirection: 'row',
133
                                        width: '100%',
134
                                        justifyContent: 'space-between',
135
                                    }}
136
                                >
137
                                    <div style={{ width: '60%' }}>
138
                                        Anotovali:{' '}
139
                                        {props.tag.occurrences[0].users?.map((u) => (
140
                                            <span
141
                                                title={
142
                                                    u.name +
143
                                                    ' ' +
144
                                                    u.surname +
145
                                                    ' (' +
146
                                                    u.username +
147
                                                    ')'
148
                                                }
149
                                                key={
150
                                                    props.tag.occurrences[0].occurenceId +
151
                                                    '.' +
152
                                                    u.id
153
                                                }
154
                                                style={{ marginRight: 10 }}
175 155
                                            >
176
                                                Poznámka:
177
                                            </Col>
178
                                            <Col>
179
                                                <Input.TextArea
180
                                                    defaultValue={occurrence.note ?? ''}
181
                                                    onBlur={onChangeNote(occurrence)}
182
                                                    rows={1}
183
                                                />
184
                                            </Col>
185
                                        </Row>
186
                                        {occurrence.sentiment && (
187
                                            <Row>
188
                                                <Col
189
                                                    className="d-flex align-items-center"
190
                                                    sm="4"
191
                                                >
192
                                                    Sentiment:
193
                                                </Col>
194
                                                <Col>
195
                                                    <Select
196
                                                        defaultValue={
197
                                                            occurrence.sentiment
198
                                                        }
199
                                                        style={{ width: '100%' }}
200
                                                        onChange={onChangeSentiment(
201
                                                            occurrence
202
                                                        )}
203
                                                    >
204
                                                        <Option
205
                                                            value={ETagSentiment.Positive}
206
                                                        >
207
                                                            <span
208
                                                                style={{ color: 'green' }}
209
                                                            >
210
                                                                Pozitivní
211
                                                            </span>
212
                                                        </Option>
213
                                                        <Option
214
                                                            value={ETagSentiment.Neutral}
215
                                                        >
216
                                                            Neutrální
217
                                                        </Option>
218
                                                        <Option
219
                                                            value={ETagSentiment.Negative}
220
                                                        >
221
                                                            <span
222
                                                                style={{
223
                                                                    color: '#ff4d4f',
224
                                                                }}
225
                                                            >
226
                                                                Negativní
227
                                                            </span>
228
                                                        </Option>
229
                                                    </Select>
230
                                                </Col>
231
                                            </Row>
232
                                        )}
233
                                    </Col>
234
                                    <Col
235
                                        sm="auto"
236
                                        className="d-flex align-items-center flex-column justify-content-sm-evenly"
237
                                    >
156
                                                {getNameTruncated(u)}
157
                                            </span>
158
                                        ))}
159
                                    </div>
160
                                    <div>
238 161
                                        <Button
239
                                            icon={<EyeOutlined />}
240 162
                                            onClick={() => {
241
                                                setSelectedOccurrenceId(
242
                                                    occurrence.occurenceId ?? null
243
                                                );
244
                                                setSelectedInstanceId(
245
                                                    props.tag.instanceId
246
                                                );
163
                                                ShowConfirm(() => {
164
                                                    makeOccurrenceFinal(
165
                                                        props.tag.occurrences[0]
166
                                                    );
167
                                                }, 'označit toto řešení jako správné');
247 168
                                            }}
248
                                            title={'Zvýraznit výskyt'}
249
                                        />
250
                                        <Button
251
                                            icon={<DeleteOutlined />}
252
                                            onClick={onDeleteOccurrence(occurrence)}
253
                                            danger
254
                                        />
255
                                    </Col>
256
                                </Row>
257
                            </Container>
169
                                        >
170
                                            Přijmout toto řešení
171
                                        </Button>
172
                                    </div>
173
                                </div>
174
                            )}
175
                        </Col>
176
                    </Row>
177
                </>
178
            )}
179

  
180
            {detailsVisible && (
181
                <Stack gap={1} className="mb-2">
182
                    <div>Kategorie: {props.tag.category}</div>
183
                    <div>Výskyty (části):</div>
184
                    {props.tag.occurrences.map((occurrence, index) => {
185
                        return (
186
                            <AnnotationOccurrenceItem
187
                                occurrence={occurrence}
188
                                tag={props.tag}
189
                                key={'occ-' + occurrence.occurenceId}
190
                            />
258 191
                        );
259 192
                    })}
260 193
                </Stack>

Také k dispozici: Unified diff