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 b80a6919 Lukáš Vlček
    makeOccurrenceFinal: (occurrence: TagInstanceInfo) => void;
83
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
    makeOccurrenceFinal: (occurrence: TagInstanceInfo) => {
210
        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 b80a6919 Lukáš Vlček
    async function makeOccurrenceFinal(occurrence: TagInstanceInfo) {
429
        if (!occurrence?.occurenceId) {
430
            return;
431
        }
432
433
        await annotationController.annotationAnnotationIdOccurenceIdFinalPut(
434
            props.annotationId,
435
            occurrence.occurenceId,
436
            { isFinal: true }
437
        );
438
439
        await refreshAnnotation();
440
    }
441
442 7652cf88 Lukáš Vlček
    async function refreshAnnotation() {
443
        const data = await annotationController.annotationAnnotationIdGet(
444 048b4bc0 Lukáš Vlček
            props.annotationId,
445
            props.isFinal
446 7652cf88 Lukáš Vlček
        );
447
448 9a41c02f Dominik Poch
        remapAnnotations(data.data);
449 7652cf88 Lukáš Vlček
        setAnnotation(data.data ?? null);
450 dee53692 Jaroslav Hrubý
        setSubmitting(false);
451 7652cf88 Lukáš Vlček
    }
452
453 acb8a961 Dominik Poch
    /**
454
     * Initializes the context.
455
     */
456 c057279b Lukáš Vlček
    useEffect(() => {
457 7652cf88 Lukáš Vlček
        refreshAnnotation();
458 7595035c Lukáš Vlček
    }, [props.annotationId]);
459 c057279b Lukáš Vlček
460
    return (
461
        <AnnotationContext.Provider
462
            value={{
463
                tags,
464 dee53692 Jaroslav Hrubý
                submitting,
465 c057279b Lukáš Vlček
                setTags,
466
                addOccurrence,
467
                deleteOccurrence,
468 b51488cd Jaroslav Hrubý
                finishAnnotation,
469 c057279b Lukáš Vlček
                changeLength,
470
                changePosition,
471 61acc160 Dominik Poch
                changeDocumentNote,
472 812ee966 Dominik Poch
                changeNote,
473 bcbaa7d3 Dominik Poch
                changeSentiment,
474 7652cf88 Lukáš Vlček
                refreshAnnotation,
475
                annotation,
476 9a41c02f Dominik Poch
                mappedTags,
477 4bc99591 Lukáš Vlček
                markSelectedText,
478 6973d036 Lukáš Vlček
                selectedInstanceId,
479
                setSelectedInstanceId,
480
                selectedOccurrenceId,
481
                setSelectedOccurrenceId,
482 b80a6919 Lukáš Vlček
                isFinal: props.isFinal,
483
                makeOccurrenceFinal,
484 c057279b Lukáš Vlček
            }}
485
        >
486
            {props.children}
487
        </AnnotationContext.Provider>
488
    );
489
};
490
491
export default AnnotationProvider;