Projekt

Obecné

Profil

Stáhnout (12.7 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
}) => {
208 7652cf88 Lukáš Vlček
    const [annotation, setAnnotation] = useState<AnnotationInfo | null>(null);
209
210 acb8a961 Dominik Poch
    /**
211
     * Tags managed by the context.
212
     */
213 c057279b Lukáš Vlček
    const [tags, setTags] = useState<TagInstanceInfo[] | null>(null);
214
215 9a41c02f Dominik Poch
    const [mappedTags, setMappedTags] = useState<Tag[] | null>(null);
216 6973d036 Lukáš Vlček
    const [selectedInstanceId, setSelectedInstanceId] = useState<string | null>(null);
217
    const [selectedOccurrenceId, setSelectedOccurrenceId] = useState<string | null>(null);
218 9a41c02f Dominik Poch
219 dee53692 Jaroslav Hrubý
    const [submitting, setSubmitting] = useState(false);
220
221 b51488cd Jaroslav Hrubý
    const router = useRouter();
222
223 4bc99591 Lukáš Vlček
    async function markSelectedText(
224
        tagId: string,
225
        subtagId: string | null,
226
        instanceId: string | null
227
    ) {
228 dee53692 Jaroslav Hrubý
        setSubmitting(true);
229 4bc99591 Lukáš Vlček
        if (!annotation) {
230
            console.log('annotation not found');
231
            return;
232
        }
233
234
        const selectionInfo = GetSelectionInfo(annotation);
235
        if (!selectionInfo) {
236
            console.log(
237
                'not able to continue, selection processing not completed successfully'
238
            );
239 eb2b4573 Jaroslav Hrubý
            ShowToast('Není označen žádný text pro přidělení značky', 'warning');
240
            setSubmitting(false);
241 4bc99591 Lukáš Vlček
            return;
242
        }
243
244
        const id = subtagId ?? tagId;
245
        const type: ETagType = subtagId == null ? ETagType.Tag : ETagType.Subtag;
246 dee53692 Jaroslav Hrubý
        const res = await annotationController
247
            .annotationAnnotationIdPost(props.annotationId, {
248 4bc99591 Lukáš Vlček
                id: id,
249
                instanceId,
250
                type,
251
                position: selectionInfo.startPositionOriginalDocument,
252
                length: selectionInfo.selectionLengthOriginalDocument,
253 ba94b8c1 Lukáš Vlček
                selectedText: selectionInfo.selectedText,
254 dee53692 Jaroslav Hrubý
            })
255 5ef75299 Lukáš Vlček
            .catch((e) =>
256
                ShowToast('Tato část textu je již touto značkou anotována', 'warning')
257
            );
258 4bc99591 Lukáš Vlček
259
        await refreshAnnotation();
260
    }
261
262 acb8a961 Dominik Poch
    /**
263
     * Default implementation of addOccurrence method.
264
     * @param tag The tag with new occurrence.
265
     */
266 4bc99591 Lukáš Vlček
    const addOccurrence = async (tag: Tag) => {
267
        await markSelectedText(tag.tagId, tag.subtagId ?? null, tag.instanceId);
268 acb8a961 Dominik Poch
    };
269
270
    /**
271
     * Deletes an occurrence of an annotation.
272
     * @param occurrence Occurrence that should be deleted.
273
     */
274 9fdb7d55 Lukáš Vlček
    const deleteOccurrence = async (occurrence: TagInstanceInfo) => {
275
        if (!occurrence.occurenceId) {
276
            console.log('invalid occurrence');
277
            return;
278
        }
279
280 dee53692 Jaroslav Hrubý
        ShowConfirmDelete(() => {
281
            annotationController
282
                .annotationAnnotationIdOccurenceIdDelete(
283
                    props.annotationId,
284
                    occurrence.occurenceId ?? ''
285
                )
286
                .then(() => refreshAnnotation());
287
        }, 'značku');
288 acb8a961 Dominik Poch
    };
289
290 b51488cd Jaroslav Hrubý
    /**
291
     * Finishes annotation of document (marked as DONE).
292
     */
293
    const finishAnnotation = () => {
294
        const req: MarkAnnotationDoneRequest = { done: true };
295
        ShowConfirm(
296
            () =>
297
                annotationController
298
                    .annotationAnnotationIdDonePut(props.annotationId, req)
299
                    .then(() => {
300
                        router.push('/documents/annotator');
301
                        ShowToast('Anotování bylo úspěšně dokončeno');
302
                    }),
303
            'dokončit anotování'
304
        );
305
    };
306
307 acb8a961 Dominik Poch
    /**
308
     * Changes a position of an occurrence of an annotation.
309
     * @param occurrence Occurrence whose position should be changed.
310
     * @param newValue New value of the position.
311
     */
312 9a41c02f Dominik Poch
    const changePosition = (occurrence: TagInstanceInfo, newValue: number) => {
313 acb8a961 Dominik Poch
        //TODO: Implement method (should use objects from server API)
314
    };
315
316
    /**
317
     * Changes a length of an occurrence of an annotation.
318
     * @param occurrence Occurrence whose length should be changed.
319
     * @param newValue New value of the length.
320
     */
321 9a41c02f Dominik Poch
    const changeLength = (occurrence: TagInstanceInfo, newValue: number) => {
322 acb8a961 Dominik Poch
        //TODO: Implement method (should use objects from server API)
323
    };
324
325 812ee966 Dominik Poch
    /**
326
     * Changes a note of an occurrence of an annotation.
327
     * @param occurrence Occurrence whose note should be changed.
328
     * @param newValue New value of the note.
329
     */
330
    const changeNote = async (occurrence: TagInstanceInfo, newValue: string) => {
331
        if (!occurrence.occurenceId) {
332
            console.log('invalid occurrence');
333
            return;
334
        }
335
336
        const postRes =
337
            await annotationController.annotationAnnotationIdTagOccurenceIdNotePost(
338
                props.annotationId,
339
                occurrence.occurenceId,
340
                { note: newValue }
341
            );
342
343 89154cb1 Dominik Poch
        occurrence.note = newValue;
344 812ee966 Dominik Poch
    };
345
346 bcbaa7d3 Dominik Poch
    /**
347
     * Changes sentiment of an annotation.
348
     * @param occurrence Occurrence whose sentiment should be changed.
349
     * @param newValue New value of the sentiment.
350
     */
351
    const changeSentiment = async (
352
        occurrence: TagInstanceInfo,
353
        newValue: ETagSentiment
354
    ) => {
355
        if (!occurrence.instance) {
356
            console.log('invalid instance');
357
            return;
358
        }
359
360
        const putRes =
361
            await annotationController.annotationAnnotationIdInstanceIdSentimentPut(
362
                props.annotationId,
363
                occurrence.instance,
364
                { sentiment: newValue }
365
            );
366
367 89154cb1 Dominik Poch
        occurrence.sentiment = newValue;
368 bcbaa7d3 Dominik Poch
    };
369
370 9a41c02f Dominik Poch
    const remapAnnotations = (data: AnnotationInfo) => {
371 4bc99591 Lukáš Vlček
        let map = new Map<string, Tag>();
372 9a41c02f Dominik Poch
        data.tagInstances?.forEach((tagInstance) => {
373 4bc99591 Lukáš Vlček
            if (map.has(tagInstance.instance ?? '-')) {
374
                let tag = map.get(tagInstance.instance ?? '-');
375 9a41c02f Dominik Poch
                tag!.occurrences = [...tag!.occurrences, tagInstance];
376
            } else {
377 4bc99591 Lukáš Vlček
                map.set(tagInstance.instance ?? '-', {
378
                    tagName: tagInstance.tagName ?? '',
379
                    subtagName: tagInstance.subTagName ?? null,
380 9a41c02f Dominik Poch
                    category: tagInstance.tagCategoryName ?? '',
381
                    occurrences: [tagInstance],
382 4bc99591 Lukáš Vlček
                    tagId: tagInstance.tagId ?? '',
383
                    instanceId: tagInstance.instance ?? '',
384
                    subtagId: tagInstance.subTagId ?? null,
385 9a41c02f Dominik Poch
                });
386
            }
387
        });
388
389
        setMappedTags(Array.from(map.values()));
390
    };
391
392 7652cf88 Lukáš Vlček
    async function refreshAnnotation() {
393
        const data = await annotationController.annotationAnnotationIdGet(
394
            props.annotationId
395
        );
396
397 9a41c02f Dominik Poch
        remapAnnotations(data.data);
398 7652cf88 Lukáš Vlček
        setAnnotation(data.data ?? null);
399 dee53692 Jaroslav Hrubý
        setSubmitting(false);
400 7652cf88 Lukáš Vlček
    }
401
402 acb8a961 Dominik Poch
    /**
403
     * Initializes the context.
404
     */
405 c057279b Lukáš Vlček
    useEffect(() => {
406 7652cf88 Lukáš Vlček
        refreshAnnotation();
407 7595035c Lukáš Vlček
    }, [props.annotationId]);
408 c057279b Lukáš Vlček
409
    return (
410
        <AnnotationContext.Provider
411
            value={{
412
                tags,
413 dee53692 Jaroslav Hrubý
                submitting,
414 c057279b Lukáš Vlček
                setTags,
415
                addOccurrence,
416
                deleteOccurrence,
417 b51488cd Jaroslav Hrubý
                finishAnnotation,
418 c057279b Lukáš Vlček
                changeLength,
419
                changePosition,
420 812ee966 Dominik Poch
                changeNote,
421 bcbaa7d3 Dominik Poch
                changeSentiment,
422 7652cf88 Lukáš Vlček
                refreshAnnotation,
423
                annotation,
424 9a41c02f Dominik Poch
                mappedTags,
425 4bc99591 Lukáš Vlček
                markSelectedText,
426 6973d036 Lukáš Vlček
                selectedInstanceId,
427
                setSelectedInstanceId,
428
                selectedOccurrenceId,
429
                setSelectedOccurrenceId,
430 c057279b Lukáš Vlček
            }}
431
        >
432
            {props.children}
433
        </AnnotationContext.Provider>
434
    );
435
};
436
437
export default AnnotationProvider;