Projekt

Obecné

Profil

Stáhnout (11 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
    /**
62
     * Changes a note of an occurrence of an annotation.
63
     * @param occurrence Occurrence whose note should be changed.
64
     * @param newValue New value of the note.
65
     */
66
    changeNote: (occurrence: TagInstanceInfo, newValue: string) => void;
67

    
68
    /**
69
     * Changes sentiment of an annotation.
70
     * @param occurrence Occurrence whose sentiment should be changed.
71
     * @param newValue New value of the sentiment.
72
     */
73
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => void;
74

    
75
    annotation: AnnotationInfo | null;
76
    mappedTags: Tag[] | null;
77
    refreshAnnotation: () => void;
78

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

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

    
95
    /**
96
     * Submitting boolean
97
     */
98
    submitting: false,
99

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

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

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

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

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

    
142
    /**
143
     * Changes a note of an occurrence of an annotation.
144
     * @param occurrence Occurrence whose note should be changed.
145
     * @param newValue New value of the note.
146
     */
147
    changeNote: (occurrence: TagInstanceInfo, newValue: string) => {
148
        return;
149
    },
150

    
151
    /**
152
     * Changes sentiment of an annotation.
153
     * @param occurrence Occurrence whose sentiment should be changed.
154
     * @param newValue New value of the sentiment.
155
     */
156
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => {
157
        return;
158
    },
159

    
160
    annotation: null,
161
    mappedTags: null,
162
    refreshAnnotation: () => {
163
        return;
164
    },
165

    
166
    markSelectedText: () => {
167
        return;
168
    },
169
});
170

    
171
/**
172
 * Provider of the annotation context.
173
 * @param props Children that should have access to the annotation context.
174
 * @returns Prepared html of the provider.
175
 */
176
const AnnotationProvider = (props: {
177
    children: React.ReactNode;
178
    annotationId: string;
179
}) => {
180
    const [annotation, setAnnotation] = useState<AnnotationInfo | null>(null);
181

    
182
    /**
183
     * Tags managed by the context.
184
     */
185
    const [tags, setTags] = useState<TagInstanceInfo[] | null>(null);
186

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

    
189
    const [submitting, setSubmitting] = useState(false);
190

    
191
    async function markSelectedText(
192
        tagId: string,
193
        subtagId: string | null,
194
        instanceId: string | null
195
    ) {
196
        setSubmitting(true);
197
        if (!annotation) {
198
            console.log('annotation not found');
199
            return;
200
        }
201

    
202
        const selectionInfo = GetSelectionInfo(annotation);
203
        if (!selectionInfo) {
204
            console.log(
205
                'not able to continue, selection processing not completed successfully'
206
            );
207
            ShowToast('Není označen žádný text pro přidělení značky', 'warning');
208
            setSubmitting(false);
209
            return;
210
        }
211

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

    
226
        await refreshAnnotation();
227
    }
228

    
229
    /**
230
     * Default implementation of addOccurrence method.
231
     * @param tag The tag with new occurrence.
232
     */
233
    const addOccurrence = async (tag: Tag) => {
234
        await markSelectedText(tag.tagId, tag.subtagId ?? null, tag.instanceId);
235
    };
236

    
237
    /**
238
     * Deletes an occurrence of an annotation.
239
     * @param occurrence Occurrence that should be deleted.
240
     */
241
    const deleteOccurrence = async (occurrence: TagInstanceInfo) => {
242
        if (!occurrence.occurenceId) {
243
            console.log('invalid occurrence');
244
            return;
245
        }
246

    
247
        ShowConfirmDelete(() => {
248
            annotationController
249
                .annotationAnnotationIdOccurenceIdDelete(
250
                    props.annotationId,
251
                    occurrence.occurenceId ?? ''
252
                )
253
                .then(() => refreshAnnotation());
254
        }, 'značku');
255
    };
256

    
257
    /**
258
     * Changes a position of an occurrence of an annotation.
259
     * @param occurrence Occurrence whose position should be changed.
260
     * @param newValue New value of the position.
261
     */
262
    const changePosition = (occurrence: TagInstanceInfo, newValue: number) => {
263
        //TODO: Implement method (should use objects from server API)
264
    };
265

    
266
    /**
267
     * Changes a length of an occurrence of an annotation.
268
     * @param occurrence Occurrence whose length should be changed.
269
     * @param newValue New value of the length.
270
     */
271
    const changeLength = (occurrence: TagInstanceInfo, newValue: number) => {
272
        //TODO: Implement method (should use objects from server API)
273
    };
274

    
275
    /**
276
     * Changes a note of an occurrence of an annotation.
277
     * @param occurrence Occurrence whose note should be changed.
278
     * @param newValue New value of the note.
279
     */
280
    const changeNote = async (occurrence: TagInstanceInfo, newValue: string) => {
281
        if (!occurrence.occurenceId) {
282
            console.log('invalid occurrence');
283
            return;
284
        }
285

    
286
        const postRes =
287
            await annotationController.annotationAnnotationIdTagOccurenceIdNotePost(
288
                props.annotationId,
289
                occurrence.occurenceId,
290
                { note: newValue }
291
            );
292

    
293
        occurrence.note = newValue;
294
    };
295

    
296
    /**
297
     * Changes sentiment of an annotation.
298
     * @param occurrence Occurrence whose sentiment should be changed.
299
     * @param newValue New value of the sentiment.
300
     */
301
    const changeSentiment = async (
302
        occurrence: TagInstanceInfo,
303
        newValue: ETagSentiment
304
    ) => {
305
        if (!occurrence.instance) {
306
            console.log('invalid instance');
307
            return;
308
        }
309

    
310
        const putRes =
311
            await annotationController.annotationAnnotationIdInstanceIdSentimentPut(
312
                props.annotationId,
313
                occurrence.instance,
314
                { sentiment: newValue }
315
            );
316

    
317
        occurrence.sentiment = newValue;
318
    };
319

    
320
    const remapAnnotations = (data: AnnotationInfo) => {
321
        let map = new Map<string, Tag>();
322
        data.tagInstances?.forEach((tagInstance) => {
323
            if (map.has(tagInstance.instance ?? '-')) {
324
                let tag = map.get(tagInstance.instance ?? '-');
325
                tag!.occurrences = [...tag!.occurrences, tagInstance];
326
            } else {
327
                map.set(tagInstance.instance ?? '-', {
328
                    tagName: tagInstance.tagName ?? '',
329
                    subtagName: tagInstance.subTagName ?? null,
330
                    category: tagInstance.tagCategoryName ?? '',
331
                    occurrences: [tagInstance],
332
                    tagId: tagInstance.tagId ?? '',
333
                    instanceId: tagInstance.instance ?? '',
334
                    subtagId: tagInstance.subTagId ?? null,
335
                });
336
            }
337
        });
338

    
339
        setMappedTags(Array.from(map.values()));
340
    };
341

    
342
    async function refreshAnnotation() {
343
        const data = await annotationController.annotationAnnotationIdGet(
344
            props.annotationId
345
        );
346

    
347
        remapAnnotations(data.data);
348
        setAnnotation(data.data ?? null);
349
        setSubmitting(false);
350
    }
351

    
352
    /**
353
     * Initializes the context.
354
     */
355
    useEffect(() => {
356
        refreshAnnotation();
357
    }, [props.annotationId]);
358

    
359
    return (
360
        <AnnotationContext.Provider
361
            value={{
362
                tags,
363
                submitting,
364
                setTags,
365
                addOccurrence,
366
                deleteOccurrence,
367
                changeLength,
368
                changePosition,
369
                changeNote,
370
                changeSentiment,
371
                refreshAnnotation,
372
                annotation,
373
                mappedTags,
374
                markSelectedText,
375
            }}
376
        >
377
            {props.children}
378
        </AnnotationContext.Provider>
379
    );
380
};
381

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