Projekt

Obecné

Profil

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