Projekt

Obecné

Profil

Stáhnout (10.4 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 } from '../controllers';
12
import { GetSelectionInfo } from '../utils/selectionUtils';
13

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

    
23
    /**
24
     * Sets new tags.
25
     * @param newTags An array of new tags.
26
     */
27
    setTags: (newTags: TagInstanceInfo[] | null) => void;
28

    
29
    /**
30
     * Adds occurrence to an annotation.
31
     * @param tag Tag whose occurrence should be added.
32
     */
33
    addOccurrence: (tag: Tag) => void;
34

    
35
    /**
36
     * Deletes an occurrence of an annotation.
37
     * @param occurrence Occurrence that should be deleted.
38
     */
39
    deleteOccurrence: (occurrence: TagInstanceInfo) => void;
40

    
41
    /**
42
     * Changes a position of an occurrence of an annotation.
43
     * @param occurrence Occurrence whose position should be changed.
44
     * @param newValue New value of the position.
45
     */
46
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => void;
47

    
48
    /**
49
     * Changes a length of an occurrence of an annotation.
50
     * @param occurrence Occurrence whose length should be changed.
51
     * @param newValue New value of the length.
52
     */
53
    changeLength: (occurrence: TagInstanceInfo, newValue: number) => void;
54

    
55
    /**
56
     * Changes a note of an occurrence of an annotation.
57
     * @param occurrence Occurrence whose note should be changed.
58
     * @param newValue New value of the note.
59
     */
60
    changeNote: (occurrence: TagInstanceInfo, newValue: string) => void;
61

    
62
    /**
63
     * Changes sentiment of an annotation.
64
     * @param occurrence Occurrence whose sentiment should be changed.
65
     * @param newValue New value of the sentiment.
66
     */
67
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => void;
68

    
69
    annotation: AnnotationInfo | null;
70
    mappedTags: Tag[] | null;
71
    refreshAnnotation: () => void;
72

    
73
    markSelectedText: (
74
        tagId: string,
75
        subtagId: string | null,
76
        instanceID: string | null
77
    ) => void;
78
}
79

    
80
/**
81
 * The annotation context that manages active annotations.
82
 */
83
export const AnnotationContext = createContext<IAnnotationContextProvider>({
84
    /**
85
     * Default tags.
86
     */
87
    tags: null,
88

    
89
    /**
90
     * Default implementation of setTags method.
91
     * @param v Array of new tags.
92
     */
93
    setTags: (v) => {
94
        return;
95
    },
96

    
97
    /**
98
     * Default implementation of addOccurrence method.
99
     * @param tag The tag with new occurrence.
100
     */
101
    addOccurrence: (tag: Tag) => {
102
        return;
103
    },
104

    
105
    /**
106
     * Default implementation of deleteOccurrence method.
107
     * @param occurrence Occurrence that should be deleted.
108
     */
109
    deleteOccurrence: (occurrence: TagInstanceInfo) => {
110
        return;
111
    },
112

    
113
    /**
114
     * Default implementation of changePosition method.
115
     * @param occurrence Occurrence whose position should be changed.
116
     * @param newValue A new position.
117
     */
118
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => {
119
        return;
120
    },
121

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

    
131
    /**
132
     * Changes a note of an occurrence of an annotation.
133
     * @param occurrence Occurrence whose note should be changed.
134
     * @param newValue New value of the note.
135
     */
136
    changeNote: (occurrence: TagInstanceInfo, newValue: string) => {
137
        return;
138
    },
139

    
140
    /**
141
     * Changes sentiment of an annotation.
142
     * @param occurrence Occurrence whose sentiment should be changed.
143
     * @param newValue New value of the sentiment.
144
     */
145
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => {
146
        return;
147
    },
148

    
149
    annotation: null,
150
    mappedTags: null,
151
    refreshAnnotation: () => {
152
        return;
153
    },
154

    
155
    markSelectedText: () => {
156
        return;
157
    },
158
});
159

    
160
/**
161
 * Provider of the annotation context.
162
 * @param props Children that should have access to the annotation context.
163
 * @returns Prepared html of the provider.
164
 */
165
const AnnotationProvider = (props: {
166
    children: React.ReactNode;
167
    annotationId: string;
168
}) => {
169
    const [annotation, setAnnotation] = useState<AnnotationInfo | null>(null);
170

    
171
    /**
172
     * Tags managed by the context.
173
     */
174
    const [tags, setTags] = useState<TagInstanceInfo[] | null>(null);
175

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

    
178
    async function markSelectedText(
179
        tagId: string,
180
        subtagId: string | null,
181
        instanceId: string | null
182
    ) {
183
        if (!annotation) {
184
            console.log('annotation not found');
185
            return;
186
        }
187

    
188
        const selectionInfo = GetSelectionInfo(annotation);
189
        if (!selectionInfo) {
190
            console.log(
191
                'not able to continue, selection processing not completed successfully'
192
            );
193
            return;
194
        }
195

    
196
        const id = subtagId ?? tagId;
197
        const type: ETagType = subtagId == null ? ETagType.Tag : ETagType.Subtag;
198

    
199
        const res = await annotationController.annotationAnnotationIdPost(
200
            props.annotationId,
201
            {
202
                id: id,
203
                instanceId,
204
                type,
205
                position: selectionInfo.startPositionOriginalDocument,
206
                length: selectionInfo.selectionLengthOriginalDocument,
207
            }
208
        );
209

    
210
        await refreshAnnotation();
211
    }
212

    
213
    /**
214
     * Default implementation of addOccurrence method.
215
     * @param tag The tag with new occurrence.
216
     */
217
    const addOccurrence = async (tag: Tag) => {
218
        await markSelectedText(tag.tagId, tag.subtagId ?? null, tag.instanceId);
219
    };
220

    
221
    /**
222
     * Deletes an occurrence of an annotation.
223
     * @param occurrence Occurrence that should be deleted.
224
     */
225
    const deleteOccurrence = async (occurrence: TagInstanceInfo) => {
226
        if (!occurrence.occurenceId) {
227
            console.log('invalid occurrence');
228
            return;
229
        }
230

    
231
        const deleteRes =
232
            await annotationController.annotationAnnotationIdOccurenceIdDelete(
233
                props.annotationId,
234
                occurrence.occurenceId
235
            );
236

    
237
        await refreshAnnotation();
238
    };
239

    
240
    /**
241
     * Changes a position of an occurrence of an annotation.
242
     * @param occurrence Occurrence whose position should be changed.
243
     * @param newValue New value of the position.
244
     */
245
    const changePosition = (occurrence: TagInstanceInfo, newValue: number) => {
246
        //TODO: Implement method (should use objects from server API)
247
    };
248

    
249
    /**
250
     * Changes a length of an occurrence of an annotation.
251
     * @param occurrence Occurrence whose length should be changed.
252
     * @param newValue New value of the length.
253
     */
254
    const changeLength = (occurrence: TagInstanceInfo, newValue: number) => {
255
        //TODO: Implement method (should use objects from server API)
256
    };
257

    
258
    /**
259
     * Changes a note of an occurrence of an annotation.
260
     * @param occurrence Occurrence whose note should be changed.
261
     * @param newValue New value of the note.
262
     */
263
    const changeNote = async (occurrence: TagInstanceInfo, newValue: string) => {
264
        if (!occurrence.occurenceId) {
265
            console.log('invalid occurrence');
266
            return;
267
        }
268

    
269
        const postRes =
270
            await annotationController.annotationAnnotationIdTagOccurenceIdNotePost(
271
                props.annotationId,
272
                occurrence.occurenceId,
273
                { note: newValue }
274
            );
275

    
276
        await refreshAnnotation();
277
    };
278

    
279
    /**
280
     * Changes sentiment of an annotation.
281
     * @param occurrence Occurrence whose sentiment should be changed.
282
     * @param newValue New value of the sentiment.
283
     */
284
    const changeSentiment = async (
285
        occurrence: TagInstanceInfo,
286
        newValue: ETagSentiment
287
    ) => {
288
        if (!occurrence.instance) {
289
            console.log('invalid instance');
290
            return;
291
        }
292

    
293
        const putRes =
294
            await annotationController.annotationAnnotationIdInstanceIdSentimentPut(
295
                props.annotationId,
296
                occurrence.instance,
297
                { sentiment: newValue }
298
            );
299

    
300
        await refreshAnnotation();
301
    };
302

    
303
    const remapAnnotations = (data: AnnotationInfo) => {
304
        let map = new Map<string, Tag>();
305
        data.tagInstances?.forEach((tagInstance) => {
306
            if (map.has(tagInstance.instance ?? '-')) {
307
                let tag = map.get(tagInstance.instance ?? '-');
308
                tag!.occurrences = [...tag!.occurrences, tagInstance];
309
            } else {
310
                map.set(tagInstance.instance ?? '-', {
311
                    tagName: tagInstance.tagName ?? '',
312
                    subtagName: tagInstance.subTagName ?? null,
313
                    category: tagInstance.tagCategoryName ?? '',
314
                    occurrences: [tagInstance],
315
                    tagId: tagInstance.tagId ?? '',
316
                    instanceId: tagInstance.instance ?? '',
317
                    subtagId: tagInstance.subTagId ?? null,
318
                });
319
            }
320
        });
321

    
322
        setMappedTags(Array.from(map.values()));
323
    };
324

    
325
    async function refreshAnnotation() {
326
        const data = await annotationController.annotationAnnotationIdGet(
327
            props.annotationId
328
        );
329

    
330
        remapAnnotations(data.data);
331
        setAnnotation(data.data ?? null);
332
    }
333

    
334
    /**
335
     * Initializes the context.
336
     */
337
    useEffect(() => {
338
        refreshAnnotation();
339
    }, [props.annotationId]);
340

    
341
    return (
342
        <AnnotationContext.Provider
343
            value={{
344
                tags,
345
                setTags,
346
                addOccurrence,
347
                deleteOccurrence,
348
                changeLength,
349
                changePosition,
350
                changeNote,
351
                changeSentiment,
352
                refreshAnnotation,
353
                annotation,
354
                mappedTags,
355
                markSelectedText,
356
            }}
357
        >
358
            {props.children}
359
        </AnnotationContext.Provider>
360
    );
361
};
362

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