Projekt

Obecné

Profil

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