Projekt

Obecné

Profil

Stáhnout (11.5 KB) Statistiky
| Větev: | Tag: | Revize:
1
import React, { createContext, useEffect, useState } from 'react';
2
import {
3
    AnnotationInfo,
4
    ETagSentiment,
5
    ETagType,
6
    SubTagInfo,
7
    TagInfo,
8
    TagInstanceInfo,
9
} from '../api';
10
import { Tag } from '../components/types/tag';
11
import { annotationController, userController } from '../controllers';
12
import { GetSelectionInfo } from '../utils/selectionUtils';
13
import { ShowConfirmDelete, ShowToast } from '../utils/alerts';
14

    
15
/**
16
 * Interface of an annotation context provider.
17
 */
18
interface IAnnotationContextProvider {
19
    /**
20
     * Tags managed by the context.
21
     */
22
    tags: TagInstanceInfo[] | null;
23

    
24
    /**
25
     * Submitting boolean
26
     */
27
    submitting: boolean;
28

    
29
    /**
30
     * Sets new tags.
31
     * @param newTags An array of new tags.
32
     */
33
    setTags: (newTags: TagInstanceInfo[] | null) => void;
34

    
35
    /**
36
     * Adds occurrence to an annotation.
37
     * @param tag Tag whose occurrence should be added.
38
     */
39
    addOccurrence: (tag: Tag) => void;
40

    
41
    /**
42
     * Deletes an occurrence of an annotation.
43
     * @param occurrence Occurrence that should be deleted.
44
     */
45
    deleteOccurrence: (occurrence: TagInstanceInfo) => void;
46

    
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
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => void;
53

    
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
    changeLength: (occurrence: TagInstanceInfo, newValue: number) => void;
60

    
61
    changeDocumentNote: (newValue: string) => void;
62

    
63
    /**
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
    /**
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
    annotation: AnnotationInfo | null;
78
    mappedTags: Tag[] | null;
79
    refreshAnnotation: () => void;
80

    
81
    markSelectedText: (
82
        tagId: string,
83
        subtagId: string | null,
84
        instanceID: string | null
85
    ) => void;
86
}
87

    
88
/**
89
 * The annotation context that manages active annotations.
90
 */
91
export const AnnotationContext = createContext<IAnnotationContextProvider>({
92
    /**
93
     * Default tags.
94
     */
95
    tags: null,
96

    
97
    /**
98
     * Submitting boolean
99
     */
100
    submitting: false,
101

    
102
    /**
103
     * Default implementation of setTags method.
104
     * @param v Array of new tags.
105
     */
106
    setTags: (v) => {
107
        return;
108
    },
109

    
110
    /**
111
     * Default implementation of addOccurrence method.
112
     * @param tag The tag with new occurrence.
113
     */
114
    addOccurrence: (tag: Tag) => {
115
        return;
116
    },
117

    
118
    /**
119
     * Default implementation of deleteOccurrence method.
120
     * @param occurrence Occurrence that should be deleted.
121
     */
122
    deleteOccurrence: (occurrence: TagInstanceInfo) => {
123
        return;
124
    },
125

    
126
    /**
127
     * Default implementation of changePosition method.
128
     * @param occurrence Occurrence whose position should be changed.
129
     * @param newValue A new position.
130
     */
131
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => {
132
        return;
133
    },
134

    
135
    /**
136
     * Default implementation of changeLength method.
137
     * @param occurrence Occurrence whose length should be changed.
138
     * @param newValue A new length.
139
     */
140
    changeLength: (occurrence: TagInstanceInfo, newValue: number) => {
141
        return;
142
    },
143

    
144
    changeDocumentNote: (newValue: string) => {
145
        return;
146
    },
147

    
148
    /**
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
    /**
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
    annotation: null,
167
    mappedTags: null,
168
    refreshAnnotation: () => {
169
        return;
170
    },
171

    
172
    markSelectedText: () => {
173
        return;
174
    },
175
});
176

    
177
/**
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
const AnnotationProvider = (props: {
183
    children: React.ReactNode;
184
    annotationId: string;
185
}) => {
186
    const [annotation, setAnnotation] = useState<AnnotationInfo | null>(null);
187

    
188
    /**
189
     * Tags managed by the context.
190
     */
191
    const [tags, setTags] = useState<TagInstanceInfo[] | null>(null);
192

    
193
    const [mappedTags, setMappedTags] = useState<Tag[] | null>(null);
194

    
195
    const [submitting, setSubmitting] = useState(false);
196

    
197
    async function markSelectedText(
198
        tagId: string,
199
        subtagId: string | null,
200
        instanceId: string | null
201
    ) {
202
        setSubmitting(true);
203
        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
            ShowToast('Není označen žádný text pro přidělení značky', 'warning');
214
            setSubmitting(false);
215
            return;
216
        }
217

    
218
        const id = subtagId ?? tagId;
219
        const type: ETagType = subtagId == null ? ETagType.Tag : ETagType.Subtag;
220
        const res = await annotationController
221
            .annotationAnnotationIdPost(props.annotationId, {
222
                id: id,
223
                instanceId,
224
                type,
225
                position: selectionInfo.startPositionOriginalDocument,
226
                length: selectionInfo.selectionLengthOriginalDocument,
227
            })
228
            .catch((e) =>
229
                ShowToast('Tato část textu je již touto značkou anotována', 'warning')
230
            );
231

    
232
        await refreshAnnotation();
233
    }
234

    
235
    /**
236
     * Default implementation of addOccurrence method.
237
     * @param tag The tag with new occurrence.
238
     */
239
    const addOccurrence = async (tag: Tag) => {
240
        await markSelectedText(tag.tagId, tag.subtagId ?? null, tag.instanceId);
241
    };
242

    
243
    /**
244
     * Deletes an occurrence of an annotation.
245
     * @param occurrence Occurrence that should be deleted.
246
     */
247
    const deleteOccurrence = async (occurrence: TagInstanceInfo) => {
248
        if (!occurrence.occurenceId) {
249
            console.log('invalid occurrence');
250
            return;
251
        }
252

    
253
        ShowConfirmDelete(() => {
254
            annotationController
255
                .annotationAnnotationIdOccurenceIdDelete(
256
                    props.annotationId,
257
                    occurrence.occurenceId ?? ''
258
                )
259
                .then(() => refreshAnnotation());
260
        }, 'značku');
261
    };
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
    const changePosition = (occurrence: TagInstanceInfo, newValue: number) => {
269
        //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
    const changeLength = (occurrence: TagInstanceInfo, newValue: number) => {
278
        //TODO: Implement method (should use objects from server API)
279
    };
280

    
281
    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
    /**
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
        occurrence.note = newValue;
311
    };
312

    
313
    /**
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
        occurrence.sentiment = newValue;
335
    };
336

    
337
    const remapAnnotations = (data: AnnotationInfo) => {
338
        let map = new Map<string, Tag>();
339
        data.tagInstances?.forEach((tagInstance) => {
340
            if (map.has(tagInstance.instance ?? '-')) {
341
                let tag = map.get(tagInstance.instance ?? '-');
342
                tag!.occurrences = [...tag!.occurrences, tagInstance];
343
            } else {
344
                map.set(tagInstance.instance ?? '-', {
345
                    tagName: tagInstance.tagName ?? '',
346
                    subtagName: tagInstance.subTagName ?? null,
347
                    category: tagInstance.tagCategoryName ?? '',
348
                    occurrences: [tagInstance],
349
                    tagId: tagInstance.tagId ?? '',
350
                    instanceId: tagInstance.instance ?? '',
351
                    subtagId: tagInstance.subTagId ?? null,
352
                });
353
            }
354
        });
355

    
356
        setMappedTags(Array.from(map.values()));
357
    };
358

    
359
    async function refreshAnnotation() {
360
        const data = await annotationController.annotationAnnotationIdGet(
361
            props.annotationId
362
        );
363

    
364
        remapAnnotations(data.data);
365
        setAnnotation(data.data ?? null);
366
        setSubmitting(false);
367
    }
368

    
369
    /**
370
     * Initializes the context.
371
     */
372
    useEffect(() => {
373
        refreshAnnotation();
374
    }, [props.annotationId]);
375

    
376
    return (
377
        <AnnotationContext.Provider
378
            value={{
379
                tags,
380
                submitting,
381
                setTags,
382
                addOccurrence,
383
                deleteOccurrence,
384
                changeLength,
385
                changePosition,
386
                changeDocumentNote,
387
                changeNote,
388
                changeSentiment,
389
                refreshAnnotation,
390
                annotation,
391
                mappedTags,
392
                markSelectedText,
393
            }}
394
        >
395
            {props.children}
396
        </AnnotationContext.Provider>
397
    );
398
};
399

    
400
export default AnnotationProvider;
(1-1/3)