Projekt

Obecné

Profil

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