Projekt

Obecné

Profil

Stáhnout (13 KB) Statistiky
| Větev: | Tag: | Revize:
1 acb8a961 Dominik Poch
import React, { createContext, useEffect, useState } from 'react';
2 bcbaa7d3 Dominik Poch
import {
3
    AnnotationInfo,
4
    ETagSentiment,
5
    ETagType,
6 b51488cd Jaroslav Hrubý
    MarkAnnotationDoneRequest,
7 bcbaa7d3 Dominik Poch
    TagInstanceInfo,
8
} from '../api';
9 9a41c02f Dominik Poch
import { Tag } from '../components/types/tag';
10 b51488cd Jaroslav Hrubý
import { annotationController } from '../controllers';
11 4bc99591 Lukáš Vlček
import { GetSelectionInfo } from '../utils/selectionUtils';
12 b51488cd Jaroslav Hrubý
import { ShowConfirm, ShowConfirmDelete, ShowToast } from '../utils/alerts';
13
import { useRouter } from 'next/router';
14 c057279b Lukáš Vlček
15 acb8a961 Dominik Poch
/**
16
 * Interface of an annotation context provider.
17
 */
18 c057279b Lukáš Vlček
interface IAnnotationContextProvider {
19 acb8a961 Dominik Poch
    /**
20
     * Tags managed by the context.
21
     */
22 c057279b Lukáš Vlček
    tags: TagInstanceInfo[] | null;
23 acb8a961 Dominik Poch
24 dee53692 Jaroslav Hrubý
    /**
25
     * Submitting boolean
26
     */
27
    submitting: boolean;
28
29 acb8a961 Dominik Poch
    /**
30
     * Sets new tags.
31
     * @param newTags An array of new tags.
32
     */
33 c057279b Lukáš Vlček
    setTags: (newTags: TagInstanceInfo[] | null) => void;
34 acb8a961 Dominik Poch
35
    /**
36
     * Adds occurrence to an annotation.
37
     * @param tag Tag whose occurrence should be added.
38
     */
39 c73aecde Dominik Poch
    addOccurrence: (tag: Tag) => void;
40 acb8a961 Dominik Poch
41
    /**
42
     * Deletes an occurrence of an annotation.
43
     * @param occurrence Occurrence that should be deleted.
44
     */
45 9a41c02f Dominik Poch
    deleteOccurrence: (occurrence: TagInstanceInfo) => void;
46 acb8a961 Dominik Poch
47 b51488cd Jaroslav Hrubý
    /**
48
     * Finishes annotation of document (marked as DONE).
49
     */
50
    finishAnnotation: () => void;
51
52 acb8a961 Dominik Poch
    /**
53
     * Changes a position of an occurrence of an annotation.
54
     * @param occurrence Occurrence whose position should be changed.
55
     * @param newValue New value of the position.
56
     */
57 9a41c02f Dominik Poch
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => void;
58 acb8a961 Dominik Poch
59
    /**
60
     * Changes a length of an occurrence of an annotation.
61
     * @param occurrence Occurrence whose length should be changed.
62
     * @param newValue New value of the length.
63
     */
64 9a41c02f Dominik Poch
    changeLength: (occurrence: TagInstanceInfo, newValue: number) => void;
65 7652cf88 Lukáš Vlček
66 812ee966 Dominik Poch
    /**
67
     * Changes a note of an occurrence of an annotation.
68
     * @param occurrence Occurrence whose note should be changed.
69
     * @param newValue New value of the note.
70
     */
71
    changeNote: (occurrence: TagInstanceInfo, newValue: string) => void;
72
73 bcbaa7d3 Dominik Poch
    /**
74
     * Changes sentiment of an annotation.
75
     * @param occurrence Occurrence whose sentiment should be changed.
76
     * @param newValue New value of the sentiment.
77
     */
78
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => void;
79
80 7652cf88 Lukáš Vlček
    annotation: AnnotationInfo | null;
81 9a41c02f Dominik Poch
    mappedTags: Tag[] | null;
82 7652cf88 Lukáš Vlček
    refreshAnnotation: () => void;
83 4bc99591 Lukáš Vlček
84
    markSelectedText: (
85
        tagId: string,
86
        subtagId: string | null,
87
        instanceID: string | null
88
    ) => void;
89 6973d036 Lukáš Vlček
90
    selectedInstanceId: string | null;
91
    setSelectedInstanceId: (newId: string | null) => void;
92
93
    selectedOccurrenceId: string | null;
94
    setSelectedOccurrenceId: (newId: string | null) => void;
95 c057279b Lukáš Vlček
}
96
97 acb8a961 Dominik Poch
/**
98
 * The annotation context that manages active annotations.
99
 */
100 c057279b Lukáš Vlček
export const AnnotationContext = createContext<IAnnotationContextProvider>({
101 acb8a961 Dominik Poch
    /**
102
     * Default tags.
103
     */
104 c057279b Lukáš Vlček
    tags: null,
105 acb8a961 Dominik Poch
106 dee53692 Jaroslav Hrubý
    /**
107
     * Submitting boolean
108
     */
109
    submitting: false,
110
111 acb8a961 Dominik Poch
    /**
112
     * Default implementation of setTags method.
113
     * @param v Array of new tags.
114
     */
115 c057279b Lukáš Vlček
    setTags: (v) => {
116
        return;
117
    },
118 acb8a961 Dominik Poch
119
    /**
120
     * Default implementation of addOccurrence method.
121
     * @param tag The tag with new occurrence.
122
     */
123 c73aecde Dominik Poch
    addOccurrence: (tag: Tag) => {
124 c057279b Lukáš Vlček
        return;
125
    },
126 acb8a961 Dominik Poch
127
    /**
128
     * Default implementation of deleteOccurrence method.
129
     * @param occurrence Occurrence that should be deleted.
130
     */
131 9a41c02f Dominik Poch
    deleteOccurrence: (occurrence: TagInstanceInfo) => {
132 c057279b Lukáš Vlček
        return;
133
    },
134 acb8a961 Dominik Poch
135 b51488cd Jaroslav Hrubý
    /**
136
     * Finishes annotation of document (marked as DONE).
137
     */
138
    finishAnnotation: () => {
139
        return;
140
    },
141
142 acb8a961 Dominik Poch
    /**
143
     * Default implementation of changePosition method.
144
     * @param occurrence Occurrence whose position should be changed.
145
     * @param newValue A new position.
146
     */
147 9a41c02f Dominik Poch
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => {
148 c057279b Lukáš Vlček
        return;
149
    },
150 acb8a961 Dominik Poch
151
    /**
152
     * Default implementation of changeLength method.
153
     * @param occurrence Occurrence whose length should be changed.
154
     * @param newValue A new length.
155
     */
156 9a41c02f Dominik Poch
    changeLength: (occurrence: TagInstanceInfo, newValue: number) => {
157 c057279b Lukáš Vlček
        return;
158
    },
159 7652cf88 Lukáš Vlček
160 812ee966 Dominik Poch
    /**
161
     * Changes a note of an occurrence of an annotation.
162
     * @param occurrence Occurrence whose note should be changed.
163
     * @param newValue New value of the note.
164
     */
165
    changeNote: (occurrence: TagInstanceInfo, newValue: string) => {
166
        return;
167
    },
168
169 bcbaa7d3 Dominik Poch
    /**
170
     * Changes sentiment of an annotation.
171
     * @param occurrence Occurrence whose sentiment should be changed.
172
     * @param newValue New value of the sentiment.
173
     */
174
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => {
175
        return;
176
    },
177
178 7652cf88 Lukáš Vlček
    annotation: null,
179 9a41c02f Dominik Poch
    mappedTags: null,
180 7652cf88 Lukáš Vlček
    refreshAnnotation: () => {
181
        return;
182
    },
183 4bc99591 Lukáš Vlček
184
    markSelectedText: () => {
185
        return;
186
    },
187 6973d036 Lukáš Vlček
188
    selectedInstanceId: null,
189
    setSelectedInstanceId: (newId: string | null) => {
190
        return;
191
    },
192
193
    selectedOccurrenceId: null,
194
    setSelectedOccurrenceId: (newId: string | null) => {
195
        return;
196
    },
197 c057279b Lukáš Vlček
});
198
199 acb8a961 Dominik Poch
/**
200
 * Provider of the annotation context.
201
 * @param props Children that should have access to the annotation context.
202
 * @returns Prepared html of the provider.
203
 */
204 7595035c Lukáš Vlček
const AnnotationProvider = (props: {
205
    children: React.ReactNode;
206
    annotationId: string;
207 048b4bc0 Lukáš Vlček
    isFinal: boolean;
208 7595035c Lukáš Vlček
}) => {
209 7652cf88 Lukáš Vlček
    const [annotation, setAnnotation] = useState<AnnotationInfo | null>(null);
210
211 acb8a961 Dominik Poch
    /**
212
     * Tags managed by the context.
213
     */
214 c057279b Lukáš Vlček
    const [tags, setTags] = useState<TagInstanceInfo[] | null>(null);
215
216 9a41c02f Dominik Poch
    const [mappedTags, setMappedTags] = useState<Tag[] | null>(null);
217 6973d036 Lukáš Vlček
    const [selectedInstanceId, setSelectedInstanceId] = useState<string | null>(null);
218
    const [selectedOccurrenceId, setSelectedOccurrenceId] = useState<string | null>(null);
219 9a41c02f Dominik Poch
220 dee53692 Jaroslav Hrubý
    const [submitting, setSubmitting] = useState(false);
221
222 b51488cd Jaroslav Hrubý
    const router = useRouter();
223
224 4bc99591 Lukáš Vlček
    async function markSelectedText(
225
        tagId: string,
226
        subtagId: string | null,
227
        instanceId: string | null
228
    ) {
229 dee53692 Jaroslav Hrubý
        setSubmitting(true);
230 4bc99591 Lukáš Vlček
        if (!annotation) {
231
            console.log('annotation not found');
232
            return;
233
        }
234
235
        const selectionInfo = GetSelectionInfo(annotation);
236
        if (!selectionInfo) {
237
            console.log(
238
                'not able to continue, selection processing not completed successfully'
239
            );
240 eb2b4573 Jaroslav Hrubý
            ShowToast('Není označen žádný text pro přidělení značky', 'warning');
241
            setSubmitting(false);
242 4bc99591 Lukáš Vlček
            return;
243
        }
244
245
        const id = subtagId ?? tagId;
246
        const type: ETagType = subtagId == null ? ETagType.Tag : ETagType.Subtag;
247 dee53692 Jaroslav Hrubý
        const res = await annotationController
248 048b4bc0 Lukáš Vlček
            .annotationAnnotationIdPost(props.annotationId, props.isFinal, {
249 4bc99591 Lukáš Vlček
                id: id,
250
                instanceId,
251
                type,
252
                position: selectionInfo.startPositionOriginalDocument,
253
                length: selectionInfo.selectionLengthOriginalDocument,
254 ba94b8c1 Lukáš Vlček
                selectedText: selectionInfo.selectedText,
255 dee53692 Jaroslav Hrubý
            })
256 5ef75299 Lukáš Vlček
            .catch((e) =>
257
                ShowToast('Tato část textu je již touto značkou anotována', 'warning')
258
            );
259 4bc99591 Lukáš Vlček
260
        await refreshAnnotation();
261
    }
262
263 acb8a961 Dominik Poch
    /**
264
     * Default implementation of addOccurrence method.
265
     * @param tag The tag with new occurrence.
266
     */
267 4bc99591 Lukáš Vlček
    const addOccurrence = async (tag: Tag) => {
268
        await markSelectedText(tag.tagId, tag.subtagId ?? null, tag.instanceId);
269 acb8a961 Dominik Poch
    };
270
271
    /**
272
     * Deletes an occurrence of an annotation.
273
     * @param occurrence Occurrence that should be deleted.
274
     */
275 9fdb7d55 Lukáš Vlček
    const deleteOccurrence = async (occurrence: TagInstanceInfo) => {
276
        if (!occurrence.occurenceId) {
277
            console.log('invalid occurrence');
278
            return;
279
        }
280
281 dee53692 Jaroslav Hrubý
        ShowConfirmDelete(() => {
282
            annotationController
283
                .annotationAnnotationIdOccurenceIdDelete(
284
                    props.annotationId,
285
                    occurrence.occurenceId ?? ''
286
                )
287
                .then(() => refreshAnnotation());
288
        }, 'značku');
289 acb8a961 Dominik Poch
    };
290
291 b51488cd Jaroslav Hrubý
    /**
292
     * Finishes annotation of document (marked as DONE).
293
     */
294
    const finishAnnotation = () => {
295
        const req: MarkAnnotationDoneRequest = { done: true };
296
        ShowConfirm(
297
            () =>
298
                annotationController
299 048b4bc0 Lukáš Vlček
                    .annotationAnnotationIdDonePut(props.annotationId, props.isFinal, req)
300 b51488cd Jaroslav Hrubý
                    .then(() => {
301 048b4bc0 Lukáš Vlček
                        if (props.isFinal) {
302
                            router.push('/documents/admin');
303
                        } else {
304
                            router.push('/documents/annotator');
305
                        }
306
307 b51488cd Jaroslav Hrubý
                        ShowToast('Anotování bylo úspěšně dokončeno');
308
                    }),
309
            'dokončit anotování'
310
        );
311
    };
312
313 acb8a961 Dominik Poch
    /**
314
     * Changes a position of an occurrence of an annotation.
315
     * @param occurrence Occurrence whose position should be changed.
316
     * @param newValue New value of the position.
317
     */
318 9a41c02f Dominik Poch
    const changePosition = (occurrence: TagInstanceInfo, newValue: number) => {
319 acb8a961 Dominik Poch
        //TODO: Implement method (should use objects from server API)
320
    };
321
322
    /**
323
     * Changes a length of an occurrence of an annotation.
324
     * @param occurrence Occurrence whose length should be changed.
325
     * @param newValue New value of the length.
326
     */
327 9a41c02f Dominik Poch
    const changeLength = (occurrence: TagInstanceInfo, newValue: number) => {
328 acb8a961 Dominik Poch
        //TODO: Implement method (should use objects from server API)
329
    };
330
331 812ee966 Dominik Poch
    /**
332
     * Changes a note of an occurrence of an annotation.
333
     * @param occurrence Occurrence whose note should be changed.
334
     * @param newValue New value of the note.
335
     */
336
    const changeNote = async (occurrence: TagInstanceInfo, newValue: string) => {
337
        if (!occurrence.occurenceId) {
338
            console.log('invalid occurrence');
339
            return;
340
        }
341
342
        const postRes =
343
            await annotationController.annotationAnnotationIdTagOccurenceIdNotePost(
344
                props.annotationId,
345
                occurrence.occurenceId,
346 048b4bc0 Lukáš Vlček
                props.isFinal,
347 812ee966 Dominik Poch
                { note: newValue }
348
            );
349
350 89154cb1 Dominik Poch
        occurrence.note = newValue;
351 812ee966 Dominik Poch
    };
352
353 bcbaa7d3 Dominik Poch
    /**
354
     * Changes sentiment of an annotation.
355
     * @param occurrence Occurrence whose sentiment should be changed.
356
     * @param newValue New value of the sentiment.
357
     */
358
    const changeSentiment = async (
359
        occurrence: TagInstanceInfo,
360
        newValue: ETagSentiment
361
    ) => {
362
        if (!occurrence.instance) {
363
            console.log('invalid instance');
364
            return;
365
        }
366
367
        const putRes =
368
            await annotationController.annotationAnnotationIdInstanceIdSentimentPut(
369
                props.annotationId,
370
                occurrence.instance,
371 048b4bc0 Lukáš Vlček
                props.isFinal,
372 bcbaa7d3 Dominik Poch
                { sentiment: newValue }
373
            );
374
375 89154cb1 Dominik Poch
        occurrence.sentiment = newValue;
376 bcbaa7d3 Dominik Poch
    };
377
378 9a41c02f Dominik Poch
    const remapAnnotations = (data: AnnotationInfo) => {
379 4bc99591 Lukáš Vlček
        let map = new Map<string, Tag>();
380 9a41c02f Dominik Poch
        data.tagInstances?.forEach((tagInstance) => {
381 4bc99591 Lukáš Vlček
            if (map.has(tagInstance.instance ?? '-')) {
382
                let tag = map.get(tagInstance.instance ?? '-');
383 9a41c02f Dominik Poch
                tag!.occurrences = [...tag!.occurrences, tagInstance];
384
            } else {
385 4bc99591 Lukáš Vlček
                map.set(tagInstance.instance ?? '-', {
386
                    tagName: tagInstance.tagName ?? '',
387
                    subtagName: tagInstance.subTagName ?? null,
388 9a41c02f Dominik Poch
                    category: tagInstance.tagCategoryName ?? '',
389
                    occurrences: [tagInstance],
390 4bc99591 Lukáš Vlček
                    tagId: tagInstance.tagId ?? '',
391
                    instanceId: tagInstance.instance ?? '',
392
                    subtagId: tagInstance.subTagId ?? null,
393 9a41c02f Dominik Poch
                });
394
            }
395
        });
396
397
        setMappedTags(Array.from(map.values()));
398
    };
399
400 7652cf88 Lukáš Vlček
    async function refreshAnnotation() {
401
        const data = await annotationController.annotationAnnotationIdGet(
402 048b4bc0 Lukáš Vlček
            props.annotationId,
403
            props.isFinal
404 7652cf88 Lukáš Vlček
        );
405
406 9a41c02f Dominik Poch
        remapAnnotations(data.data);
407 7652cf88 Lukáš Vlček
        setAnnotation(data.data ?? null);
408 dee53692 Jaroslav Hrubý
        setSubmitting(false);
409 7652cf88 Lukáš Vlček
    }
410
411 acb8a961 Dominik Poch
    /**
412
     * Initializes the context.
413
     */
414 c057279b Lukáš Vlček
    useEffect(() => {
415 7652cf88 Lukáš Vlček
        refreshAnnotation();
416 7595035c Lukáš Vlček
    }, [props.annotationId]);
417 c057279b Lukáš Vlček
418
    return (
419
        <AnnotationContext.Provider
420
            value={{
421
                tags,
422 dee53692 Jaroslav Hrubý
                submitting,
423 c057279b Lukáš Vlček
                setTags,
424
                addOccurrence,
425
                deleteOccurrence,
426 b51488cd Jaroslav Hrubý
                finishAnnotation,
427 c057279b Lukáš Vlček
                changeLength,
428
                changePosition,
429 812ee966 Dominik Poch
                changeNote,
430 bcbaa7d3 Dominik Poch
                changeSentiment,
431 7652cf88 Lukáš Vlček
                refreshAnnotation,
432
                annotation,
433 9a41c02f Dominik Poch
                mappedTags,
434 4bc99591 Lukáš Vlček
                markSelectedText,
435 6973d036 Lukáš Vlček
                selectedInstanceId,
436
                setSelectedInstanceId,
437
                selectedOccurrenceId,
438
                setSelectedOccurrenceId,
439 c057279b Lukáš Vlček
            }}
440
        >
441
            {props.children}
442
        </AnnotationContext.Provider>
443
    );
444
};
445
446
export default AnnotationProvider;