Projekt

Obecné

Profil

Stáhnout (9.17 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 sentiment of an annotation.
57
     * @param occurrence Occurrence whose sentiment should be changed.
58
     * @param newValue New value of the sentiment.
59
     */
60
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => void;
61

    
62
    annotation: AnnotationInfo | null;
63
    mappedTags: Tag[] | null;
64
    refreshAnnotation: () => void;
65

    
66
    markSelectedText: (
67
        tagId: string,
68
        subtagId: string | null,
69
        instanceID: string | null
70
    ) => void;
71
}
72

    
73
/**
74
 * The annotation context that manages active annotations.
75
 */
76
export const AnnotationContext = createContext<IAnnotationContextProvider>({
77
    /**
78
     * Default tags.
79
     */
80
    tags: null,
81

    
82
    /**
83
     * Default implementation of setTags method.
84
     * @param v Array of new tags.
85
     */
86
    setTags: (v) => {
87
        return;
88
    },
89

    
90
    /**
91
     * Default implementation of addOccurrence method.
92
     * @param tag The tag with new occurrence.
93
     */
94
    addOccurrence: (tag: Tag) => {
95
        return;
96
    },
97

    
98
    /**
99
     * Default implementation of deleteOccurrence method.
100
     * @param occurrence Occurrence that should be deleted.
101
     */
102
    deleteOccurrence: (occurrence: TagInstanceInfo) => {
103
        return;
104
    },
105

    
106
    /**
107
     * Default implementation of changePosition method.
108
     * @param occurrence Occurrence whose position should be changed.
109
     * @param newValue A new position.
110
     */
111
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => {
112
        return;
113
    },
114

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

    
124
    /**
125
     * Changes sentiment of an annotation.
126
     * @param occurrence Occurrence whose sentiment should be changed.
127
     * @param newValue New value of the sentiment.
128
     */
129
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => {
130
        return;
131
    },
132

    
133
    annotation: null,
134
    mappedTags: null,
135
    refreshAnnotation: () => {
136
        return;
137
    },
138

    
139
    markSelectedText: () => {
140
        return;
141
    },
142
});
143

    
144
/**
145
 * Provider of the annotation context.
146
 * @param props Children that should have access to the annotation context.
147
 * @returns Prepared html of the provider.
148
 */
149
const AnnotationProvider = (props: {
150
    children: React.ReactNode;
151
    annotationId: string;
152
}) => {
153
    const [annotation, setAnnotation] = useState<AnnotationInfo | null>(null);
154

    
155
    /**
156
     * Tags managed by the context.
157
     */
158
    const [tags, setTags] = useState<TagInstanceInfo[] | null>(null);
159

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

    
162
    async function markSelectedText(
163
        tagId: string,
164
        subtagId: string | null,
165
        instanceId: string | null
166
    ) {
167
        if (!annotation) {
168
            console.log('annotation not found');
169
            return;
170
        }
171

    
172
        const selectionInfo = GetSelectionInfo(annotation);
173
        if (!selectionInfo) {
174
            console.log(
175
                'not able to continue, selection processing not completed successfully'
176
            );
177
            return;
178
        }
179

    
180
        const id = subtagId ?? tagId;
181
        const type: ETagType = subtagId == null ? ETagType.Tag : ETagType.Subtag;
182

    
183
        const res = await annotationController.annotationAnnotationIdPost(
184
            props.annotationId,
185
            {
186
                id: id,
187
                instanceId,
188
                type,
189
                position: selectionInfo.startPositionOriginalDocument,
190
                length: selectionInfo.selectionLengthOriginalDocument,
191
            }
192
        );
193

    
194
        await refreshAnnotation();
195
    }
196

    
197
    /**
198
     * Default implementation of addOccurrence method.
199
     * @param tag The tag with new occurrence.
200
     */
201
    const addOccurrence = async (tag: Tag) => {
202
        await markSelectedText(tag.tagId, tag.subtagId ?? null, tag.instanceId);
203
    };
204

    
205
    /**
206
     * Deletes an occurrence of an annotation.
207
     * @param occurrence Occurrence that should be deleted.
208
     */
209
    const deleteOccurrence = async (occurrence: TagInstanceInfo) => {
210
        if (!occurrence.occurenceId) {
211
            console.log('invalid occurrence');
212
            return;
213
        }
214

    
215
        const deleteRes =
216
            await annotationController.annotationAnnotationIdOccurenceIdDelete(
217
                props.annotationId,
218
                occurrence.occurenceId
219
            );
220

    
221
        await refreshAnnotation();
222
    };
223

    
224
    /**
225
     * Changes a position of an occurrence of an annotation.
226
     * @param occurrence Occurrence whose position should be changed.
227
     * @param newValue New value of the position.
228
     */
229
    const changePosition = (occurrence: TagInstanceInfo, newValue: number) => {
230
        //TODO: Implement method (should use objects from server API)
231
    };
232

    
233
    /**
234
     * Changes a length of an occurrence of an annotation.
235
     * @param occurrence Occurrence whose length should be changed.
236
     * @param newValue New value of the length.
237
     */
238
    const changeLength = (occurrence: TagInstanceInfo, newValue: number) => {
239
        //TODO: Implement method (should use objects from server API)
240
    };
241

    
242
    /**
243
     * Changes sentiment of an annotation.
244
     * @param occurrence Occurrence whose sentiment should be changed.
245
     * @param newValue New value of the sentiment.
246
     */
247
    const changeSentiment = async (
248
        occurrence: TagInstanceInfo,
249
        newValue: ETagSentiment
250
    ) => {
251
        if (!occurrence.instance) {
252
            console.log('invalid instance');
253
            return;
254
        }
255

    
256
        const putRes =
257
            await annotationController.annotationAnnotationIdInstanceIdSentimentPut(
258
                props.annotationId,
259
                occurrence.instance,
260
                { sentiment: newValue }
261
            );
262

    
263
        await refreshAnnotation();
264
    };
265

    
266
    const remapAnnotations = (data: AnnotationInfo) => {
267
        let map = new Map<string, Tag>();
268
        data.tagInstances?.forEach((tagInstance) => {
269
            if (map.has(tagInstance.instance ?? '-')) {
270
                let tag = map.get(tagInstance.instance ?? '-');
271
                tag!.occurrences = [...tag!.occurrences, tagInstance];
272
            } else {
273
                map.set(tagInstance.instance ?? '-', {
274
                    tagName: tagInstance.tagName ?? '',
275
                    subtagName: tagInstance.subTagName ?? null,
276
                    category: tagInstance.tagCategoryName ?? '',
277
                    occurrences: [tagInstance],
278
                    tagId: tagInstance.tagId ?? '',
279
                    instanceId: tagInstance.instance ?? '',
280
                    subtagId: tagInstance.subTagId ?? null,
281
                });
282
            }
283
        });
284

    
285
        setMappedTags(Array.from(map.values()));
286
    };
287

    
288
    async function refreshAnnotation() {
289
        const data = await annotationController.annotationAnnotationIdGet(
290
            props.annotationId
291
        );
292

    
293
        remapAnnotations(data.data);
294
        setAnnotation(data.data ?? null);
295
    }
296

    
297
    /**
298
     * Initializes the context.
299
     */
300
    useEffect(() => {
301
        refreshAnnotation();
302
    }, [props.annotationId]);
303

    
304
    return (
305
        <AnnotationContext.Provider
306
            value={{
307
                tags,
308
                setTags,
309
                addOccurrence,
310
                deleteOccurrence,
311
                changeLength,
312
                changePosition,
313
                changeSentiment,
314
                refreshAnnotation,
315
                annotation,
316
                mappedTags,
317
                markSelectedText,
318
            }}
319
        >
320
            {props.children}
321
        </AnnotationContext.Provider>
322
    );
323
};
324

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