Projekt

Obecné

Profil

« Předchozí | Další » 

Revize b80a6919

Přidáno uživatelem Lukáš Vlček před asi 2 roky(ů)

Document finalization

Zobrazit rozdíly:

webapp/api/api.ts
47 47
     */
48 48
    'note'?: string | null;
49 49
}
50
/**
51
 * 
52
 * @export
53
 * @interface Annotation
54
 */
55
export interface Annotation {
56
    /**
57
     * 
58
     * @type {string}
59
     * @memberof Annotation
60
     */
61
    'id'?: string;
62
    /**
63
     * 
64
     * @type {Document}
65
     * @memberof Annotation
66
     */
67
    'document'?: Document;
68
    /**
69
     * 
70
     * @type {User}
71
     * @memberof Annotation
72
     */
73
    'user'?: User;
74
    /**
75
     * 
76
     * @type {User}
77
     * @memberof Annotation
78
     */
79
    'userAssigned'?: User;
80
    /**
81
     * 
82
     * @type {string}
83
     * @memberof Annotation
84
     */
85
    'dateAssigned'?: string;
86
    /**
87
     * 
88
     * @type {EState}
89
     * @memberof Annotation
90
     */
91
    'state'?: EState;
92
    /**
93
     * 
94
     * @type {string}
95
     * @memberof Annotation
96
     */
97
    'dateLastChanged'?: string;
98
    /**
99
     * 
100
     * @type {string}
101
     * @memberof Annotation
102
     */
103
    'note'?: string | null;
104
    /**
105
     * 
106
     * @type {string}
107
     * @memberof Annotation
108
     */
109
    'cachedDocumentHTML'?: string | null;
110
    /**
111
     * 
112
     * @type {string}
113
     * @memberof Annotation
114
     */
115
    'cachedStartPositions'?: string | null;
116
    /**
117
     * 
118
     * @type {string}
119
     * @memberof Annotation
120
     */
121
    'cachedLengths'?: string | null;
122
    /**
123
     * 
124
     * @type {string}
125
     * @memberof Annotation
126
     */
127
    'cachedClosingPositions'?: string | null;
128
    /**
129
     * 
130
     * @type {string}
131
     * @memberof Annotation
132
     */
133
    'cachedClosingLengths'?: string | null;
134
    /**
135
     * 
136
     * @type {string}
137
     * @memberof Annotation
138
     */
139
    'cachedCSS'?: string | null;
140
    /**
141
     * 
142
     * @type {string}
143
     * @memberof Annotation
144
     */
145
    'lastModifiedTagId'?: string | null;
146
    /**
147
     * 
148
     * @type {EModified}
149
     * @memberof Annotation
150
     */
151
    'modifiedType'?: EModified;
152
    /**
153
     * 
154
     * @type {Array<Class>}
155
     * @memberof Annotation
156
     */
157
    'classes'?: Array<Class> | null;
158
    /**
159
     * 
160
     * @type {Array<FinalAnnotation>}
161
     * @memberof Annotation
162
     */
163
    'finalAnnotations'?: Array<FinalAnnotation> | null;
164
}
50 165
/**
51 166
 * 
52 167
 * @export
......
245 360
     */
246 361
    'role'?: ERole;
247 362
}
363
/**
364
 * 
365
 * @export
366
 * @interface Class
367
 */
368
export interface Class {
369
    /**
370
     * 
371
     * @type {string}
372
     * @memberof Class
373
     */
374
    'id'?: string;
375
    /**
376
     * 
377
     * @type {string}
378
     * @memberof Class
379
     */
380
    'name'?: string | null;
381
    /**
382
     * 
383
     * @type {string}
384
     * @memberof Class
385
     */
386
    'description'?: string | null;
387
    /**
388
     * 
389
     * @type {string}
390
     * @memberof Class
391
     */
392
    'color'?: string | null;
393
    /**
394
     * 
395
     * @type {Array<Annotation>}
396
     * @memberof Class
397
     */
398
    'annotations'?: Array<Annotation> | null;
399
}
248 400
/**
249 401
 * 
250 402
 * @export
......
419 571
     */
420 572
    'role'?: ERole;
421 573
}
574
/**
575
 * 
576
 * @export
577
 * @interface Document
578
 */
579
export interface Document {
580
    /**
581
     * 
582
     * @type {string}
583
     * @memberof Document
584
     */
585
    'id'?: string;
586
    /**
587
     * 
588
     * @type {string}
589
     * @memberof Document
590
     */
591
    'name'?: string | null;
592
    /**
593
     * 
594
     * @type {number}
595
     * @memberof Document
596
     */
597
    'length'?: number;
598
    /**
599
     * 
600
     * @type {DocumentContent}
601
     * @memberof Document
602
     */
603
    'content'?: DocumentContent;
604
    /**
605
     * 
606
     * @type {string}
607
     * @memberof Document
608
     */
609
    'dateAdded'?: string;
610
    /**
611
     * 
612
     * @type {User}
613
     * @memberof Document
614
     */
615
    'userAdded'?: User;
616
    /**
617
     * 
618
     * @type {number}
619
     * @memberof Document
620
     */
621
    'requiredAnnotations'?: number;
622
}
422 623
/**
423 624
 * 
424 625
 * @export
......
494 695
     */
495 696
    'username'?: string | null;
496 697
}
698
/**
699
 * 
700
 * @export
701
 * @interface DocumentContent
702
 */
703
export interface DocumentContent {
704
    /**
705
     * 
706
     * @type {string}
707
     * @memberof DocumentContent
708
     */
709
    'id'?: string;
710
    /**
711
     * 
712
     * @type {string}
713
     * @memberof DocumentContent
714
     */
715
    'content'?: string | null;
716
}
497 717
/**
498 718
 * 
499 719
 * @export
......
664 884
export type EDocumentType = typeof EDocumentType[keyof typeof EDocumentType];
665 885

  
666 886

  
887
/**
888
 * 
889
 * @export
890
 * @enum {string}
891
 */
892

  
893
export const EModified = {
894
    Added: 'ADDED',
895
    Removed: 'REMOVED',
896
    None: 'NONE'
897
} as const;
898

  
899
export type EModified = typeof EModified[keyof typeof EModified];
900

  
901

  
667 902
/**
668 903
 * 
669 904
 * @export
......
722 957
export type ETagType = typeof ETagType[keyof typeof ETagType];
723 958

  
724 959

  
960
/**
961
 * 
962
 * @export
963
 * @interface FinalAnnotation
964
 */
965
export interface FinalAnnotation {
966
    /**
967
     * 
968
     * @type {string}
969
     * @memberof FinalAnnotation
970
     */
971
    'id'?: string;
972
    /**
973
     * 
974
     * @type {Document}
975
     * @memberof FinalAnnotation
976
     */
977
    'document'?: Document;
978
    /**
979
     * 
980
     * @type {User}
981
     * @memberof FinalAnnotation
982
     */
983
    'user'?: User;
984
    /**
985
     * 
986
     * @type {User}
987
     * @memberof FinalAnnotation
988
     */
989
    'userAssigned'?: User;
990
    /**
991
     * 
992
     * @type {string}
993
     * @memberof FinalAnnotation
994
     */
995
    'dateAssigned'?: string;
996
    /**
997
     * 
998
     * @type {EState}
999
     * @memberof FinalAnnotation
1000
     */
1001
    'state'?: EState;
1002
    /**
1003
     * 
1004
     * @type {string}
1005
     * @memberof FinalAnnotation
1006
     */
1007
    'dateLastChanged'?: string;
1008
    /**
1009
     * 
1010
     * @type {string}
1011
     * @memberof FinalAnnotation
1012
     */
1013
    'note'?: string | null;
1014
    /**
1015
     * 
1016
     * @type {string}
1017
     * @memberof FinalAnnotation
1018
     */
1019
    'cachedDocumentHTML'?: string | null;
1020
    /**
1021
     * 
1022
     * @type {string}
1023
     * @memberof FinalAnnotation
1024
     */
1025
    'cachedStartPositions'?: string | null;
1026
    /**
1027
     * 
1028
     * @type {string}
1029
     * @memberof FinalAnnotation
1030
     */
1031
    'cachedLengths'?: string | null;
1032
    /**
1033
     * 
1034
     * @type {string}
1035
     * @memberof FinalAnnotation
1036
     */
1037
    'cachedClosingPositions'?: string | null;
1038
    /**
1039
     * 
1040
     * @type {string}
1041
     * @memberof FinalAnnotation
1042
     */
1043
    'cachedClosingLengths'?: string | null;
1044
    /**
1045
     * 
1046
     * @type {string}
1047
     * @memberof FinalAnnotation
1048
     */
1049
    'cachedCSS'?: string | null;
1050
    /**
1051
     * 
1052
     * @type {string}
1053
     * @memberof FinalAnnotation
1054
     */
1055
    'lastModifiedTagId'?: string | null;
1056
    /**
1057
     * 
1058
     * @type {EModified}
1059
     * @memberof FinalAnnotation
1060
     */
1061
    'modifiedType'?: EModified;
1062
    /**
1063
     * 
1064
     * @type {Array<Class>}
1065
     * @memberof FinalAnnotation
1066
     */
1067
    'classes'?: Array<Class> | null;
1068
    /**
1069
     * 
1070
     * @type {Array<FinalAnnotation>}
1071
     * @memberof FinalAnnotation
1072
     */
1073
    'finalAnnotations'?: Array<FinalAnnotation> | null;
1074
    /**
1075
     * 
1076
     * @type {Array<Annotation>}
1077
     * @memberof FinalAnnotation
1078
     */
1079
    'annotations'?: Array<Annotation> | null;
1080
}
1081
/**
1082
 * 
1083
 * @export
1084
 * @interface FinalAnnotationTag
1085
 */
1086
export interface FinalAnnotationTag {
1087
    /**
1088
     * 
1089
     * @type {string}
1090
     * @memberof FinalAnnotationTag
1091
     */
1092
    'id'?: string;
1093
    /**
1094
     * 
1095
     * @type {Tag}
1096
     * @memberof FinalAnnotationTag
1097
     */
1098
    'tag'?: Tag;
1099
    /**
1100
     * 
1101
     * @type {SubTag}
1102
     * @memberof FinalAnnotationTag
1103
     */
1104
    'subTag'?: SubTag;
1105
    /**
1106
     * 
1107
     * @type {string}
1108
     * @memberof FinalAnnotationTag
1109
     */
1110
    'instance'?: string;
1111
    /**
1112
     * 
1113
     * @type {string}
1114
     * @memberof FinalAnnotationTag
1115
     */
1116
    'note'?: string | null;
1117
    /**
1118
     * 
1119
     * @type {number}
1120
     * @memberof FinalAnnotationTag
1121
     */
1122
    'position'?: number;
1123
    /**
1124
     * 
1125
     * @type {number}
1126
     * @memberof FinalAnnotationTag
1127
     */
1128
    'length'?: number;
1129
    /**
1130
     * 
1131
     * @type {ETagSentiment}
1132
     * @memberof FinalAnnotationTag
1133
     */
1134
    'sentiment'?: ETagSentiment;
1135
    /**
1136
     * 
1137
     * @type {string}
1138
     * @memberof FinalAnnotationTag
1139
     */
1140
    'selectedText'?: string | null;
1141
    /**
1142
     * 
1143
     * @type {FinalAnnotation}
1144
     * @memberof FinalAnnotationTag
1145
     */
1146
    'annotation'?: FinalAnnotation;
1147
    /**
1148
     * 
1149
     * @type {boolean}
1150
     * @memberof FinalAnnotationTag
1151
     */
1152
    'isFinal'?: boolean;
1153
    /**
1154
     * 
1155
     * @type {Array<User>}
1156
     * @memberof FinalAnnotationTag
1157
     */
1158
    'users'?: Array<User> | null;
1159
}
725 1160
/**
726 1161
 * 
727 1162
 * @export
......
924 1359
     */
925 1360
    'instance'?: string | null;
926 1361
}
1362
/**
1363
 * 
1364
 * @export
1365
 * @interface SetInstanceIsFinalRequest
1366
 */
1367
export interface SetInstanceIsFinalRequest {
1368
    /**
1369
     * 
1370
     * @type {boolean}
1371
     * @memberof SetInstanceIsFinalRequest
1372
     */
1373
    'isFinal'?: boolean;
1374
}
927 1375
/**
928 1376
 * 
929 1377
 * @export
......
969 1417
     */
970 1418
    'documentIds'?: Array<string> | null;
971 1419
}
1420
/**
1421
 * 
1422
 * @export
1423
 * @interface SubTag
1424
 */
1425
export interface SubTag {
1426
    /**
1427
     * 
1428
     * @type {string}
1429
     * @memberof SubTag
1430
     */
1431
    'id'?: string;
1432
    /**
1433
     * 
1434
     * @type {string}
1435
     * @memberof SubTag
1436
     */
1437
    'name'?: string | null;
1438
    /**
1439
     * 
1440
     * @type {string}
1441
     * @memberof SubTag
1442
     */
1443
    'description'?: string | null;
1444
    /**
1445
     * 
1446
     * @type {Tag}
1447
     * @memberof SubTag
1448
     */
1449
    'tag'?: Tag;
1450
    /**
1451
     * 
1452
     * @type {boolean}
1453
     * @memberof SubTag
1454
     */
1455
    'sentimentEnabled'?: boolean;
1456
}
972 1457
/**
973 1458
 * 
974 1459
 * @export
......
994 1479
     */
995 1480
    'description'?: string | null;
996 1481
}
1482
/**
1483
 * 
1484
 * @export
1485
 * @interface Tag
1486
 */
1487
export interface Tag {
1488
    /**
1489
     * 
1490
     * @type {string}
1491
     * @memberof Tag
1492
     */
1493
    'id'?: string;
1494
    /**
1495
     * 
1496
     * @type {TagCategory}
1497
     * @memberof Tag
1498
     */
1499
    'category'?: TagCategory;
1500
    /**
1501
     * 
1502
     * @type {string}
1503
     * @memberof Tag
1504
     */
1505
    'name'?: string | null;
1506
    /**
1507
     * 
1508
     * @type {string}
1509
     * @memberof Tag
1510
     */
1511
    'description'?: string | null;
1512
    /**
1513
     * 
1514
     * @type {string}
1515
     * @memberof Tag
1516
     */
1517
    'color'?: string | null;
1518
    /**
1519
     * 
1520
     * @type {boolean}
1521
     * @memberof Tag
1522
     */
1523
    'sentimentEnabled'?: boolean;
1524
}
1525
/**
1526
 * 
1527
 * @export
1528
 * @interface TagCategory
1529
 */
1530
export interface TagCategory {
1531
    /**
1532
     * 
1533
     * @type {string}
1534
     * @memberof TagCategory
1535
     */
1536
    'id'?: string;
1537
    /**
1538
     * 
1539
     * @type {string}
1540
     * @memberof TagCategory
1541
     */
1542
    'name'?: string | null;
1543
    /**
1544
     * 
1545
     * @type {string}
1546
     * @memberof TagCategory
1547
     */
1548
    'color'?: string | null;
1549
    /**
1550
     * 
1551
     * @type {string}
1552
     * @memberof TagCategory
1553
     */
1554
    'description'?: string | null;
1555
    /**
1556
     * 
1557
     * @type {boolean}
1558
     * @memberof TagCategory
1559
     */
1560
    'disabledForAnnotators'?: boolean;
1561
}
997 1562
/**
998 1563
 * 
999 1564
 * @export
......
1183 1748
     * @memberof TagInstanceInfo
1184 1749
     */
1185 1750
    'selectedText'?: string | null;
1751
    /**
1752
     * 
1753
     * @type {Array<UserInfo>}
1754
     * @memberof TagInstanceInfo
1755
     */
1756
    'users'?: Array<UserInfo> | null;
1757
    /**
1758
     * 
1759
     * @type {boolean}
1760
     * @memberof TagInstanceInfo
1761
     */
1762
    'isFinal'?: boolean | null;
1186 1763
}
1187 1764
/**
1188 1765
 * 
......
1233 1810
     * @memberof User
1234 1811
     */
1235 1812
    'role'?: ERole;
1813
    /**
1814
     * 
1815
     * @type {Array<FinalAnnotationTag>}
1816
     * @memberof User
1817
     */
1818
    'finalAnnotationTags'?: Array<FinalAnnotationTag> | null;
1236 1819
}
1237 1820
/**
1238 1821
 * 
......
1507 2090
                options: localVarRequestOptions,
1508 2091
            };
1509 2092
        },
2093
        /**
2094
         * 
2095
         * @param {string} annotationId 
2096
         * @param {string} occurenceId 
2097
         * @param {SetInstanceIsFinalRequest} [setInstanceIsFinalRequest] 
2098
         * @param {*} [options] Override http request option.
2099
         * @throws {RequiredError}
2100
         */
2101
        annotationAnnotationIdOccurenceIdFinalPut: async (annotationId: string, occurenceId: string, setInstanceIsFinalRequest?: SetInstanceIsFinalRequest, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
2102
            // verify required parameter 'annotationId' is not null or undefined
2103
            assertParamExists('annotationAnnotationIdOccurenceIdFinalPut', 'annotationId', annotationId)
2104
            // verify required parameter 'occurenceId' is not null or undefined
2105
            assertParamExists('annotationAnnotationIdOccurenceIdFinalPut', 'occurenceId', occurenceId)
2106
            const localVarPath = `/annotation/{annotationId}/{occurenceId}/final`
2107
                .replace(`{${"annotationId"}}`, encodeURIComponent(String(annotationId)))
2108
                .replace(`{${"occurenceId"}}`, encodeURIComponent(String(occurenceId)));
2109
            // use dummy base URL string because the URL constructor only accepts absolute URLs.
2110
            const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
2111
            let baseOptions;
2112
            if (configuration) {
2113
                baseOptions = configuration.baseOptions;
2114
            }
2115

  
2116
            const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options};
2117
            const localVarHeaderParameter = {} as any;
2118
            const localVarQueryParameter = {} as any;
2119

  
2120

  
2121
    
2122
            localVarHeaderParameter['Content-Type'] = 'application/json';
2123

  
2124
            setSearchParams(localVarUrlObj, localVarQueryParameter);
2125
            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
2126
            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
2127
            localVarRequestOptions.data = serializeDataIfNeeded(setInstanceIsFinalRequest, localVarRequestOptions, configuration)
2128

  
2129
            return {
2130
                url: toPathString(localVarUrlObj),
2131
                options: localVarRequestOptions,
2132
            };
2133
        },
1510 2134
        /**
1511 2135
         * 
1512 2136
         * @param {string} annotationId 
......
1698 2322
            const localVarAxiosArgs = await localVarAxiosParamCreator.annotationAnnotationIdOccurenceIdDelete(annotationId, occurenceId, isFinal, options);
1699 2323
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
1700 2324
        },
2325
        /**
2326
         * 
2327
         * @param {string} annotationId 
2328
         * @param {string} occurenceId 
2329
         * @param {SetInstanceIsFinalRequest} [setInstanceIsFinalRequest] 
2330
         * @param {*} [options] Override http request option.
2331
         * @throws {RequiredError}
2332
         */
2333
        async annotationAnnotationIdOccurenceIdFinalPut(annotationId: string, occurenceId: string, setInstanceIsFinalRequest?: SetInstanceIsFinalRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
2334
            const localVarAxiosArgs = await localVarAxiosParamCreator.annotationAnnotationIdOccurenceIdFinalPut(annotationId, occurenceId, setInstanceIsFinalRequest, options);
2335
            return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
2336
        },
1701 2337
        /**
1702 2338
         * 
1703 2339
         * @param {string} annotationId 
......
1798 2434
        annotationAnnotationIdOccurenceIdDelete(annotationId: string, occurenceId: string, isFinal?: boolean, options?: any): AxiosPromise<void> {
1799 2435
            return localVarFp.annotationAnnotationIdOccurenceIdDelete(annotationId, occurenceId, isFinal, options).then((request) => request(axios, basePath));
1800 2436
        },
2437
        /**
2438
         * 
2439
         * @param {string} annotationId 
2440
         * @param {string} occurenceId 
2441
         * @param {SetInstanceIsFinalRequest} [setInstanceIsFinalRequest] 
2442
         * @param {*} [options] Override http request option.
2443
         * @throws {RequiredError}
2444
         */
2445
        annotationAnnotationIdOccurenceIdFinalPut(annotationId: string, occurenceId: string, setInstanceIsFinalRequest?: SetInstanceIsFinalRequest, options?: any): AxiosPromise<void> {
2446
            return localVarFp.annotationAnnotationIdOccurenceIdFinalPut(annotationId, occurenceId, setInstanceIsFinalRequest, options).then((request) => request(axios, basePath));
2447
        },
1801 2448
        /**
1802 2449
         * 
1803 2450
         * @param {string} annotationId 
......
1905 2552
        return AnnotationApiFp(this.configuration).annotationAnnotationIdOccurenceIdDelete(annotationId, occurenceId, isFinal, options).then((request) => request(this.axios, this.basePath));
1906 2553
    }
1907 2554

  
2555
    /**
2556
     * 
2557
     * @param {string} annotationId 
2558
     * @param {string} occurenceId 
2559
     * @param {SetInstanceIsFinalRequest} [setInstanceIsFinalRequest] 
2560
     * @param {*} [options] Override http request option.
2561
     * @throws {RequiredError}
2562
     * @memberof AnnotationApi
2563
     */
2564
    public annotationAnnotationIdOccurenceIdFinalPut(annotationId: string, occurenceId: string, setInstanceIsFinalRequest?: SetInstanceIsFinalRequest, options?: AxiosRequestConfig) {
2565
        return AnnotationApiFp(this.configuration).annotationAnnotationIdOccurenceIdFinalPut(annotationId, occurenceId, setInstanceIsFinalRequest, options).then((request) => request(this.axios, this.basePath));
2566
    }
2567

  
1908 2568
    /**
1909 2569
     * 
1910 2570
     * @param {string} annotationId 
webapp/components/annotation/AnnotationItem.tsx
1 1
import { Col, Container, Row, Stack } from 'react-bootstrap';
2 2
import { Tag } from '../types/tag';
3
import { ChangeEvent, useContext, useState } from 'react';
3
import { useContext, useState } from 'react';
4 4
import 'antd/dist/antd.css';
5
import { Button, Input, Select } from 'antd';
6
import {
7
    PlusOutlined,
8
    DownOutlined,
9
    DeleteOutlined,
10
    TagOutlined,
11
    EyeOutlined,
12
} from '@ant-design/icons';
5
import { Button, Select } from 'antd';
6
import { DownOutlined, PlusOutlined, TagOutlined } from '@ant-design/icons';
13 7
import { AnnotationContext } from '../../contexts/AnnotationContext';
14
import { ETagSentiment, TagInstanceInfo } from '../../api';
15
import { getTextMaxLength } from '../../utils/strings';
8
import { AnnotationOccurrenceItem } from './AnnotationOccurrenceItem';
9
import { COLOR_ALL_OCCURRENCES_ACCEPTED, COLOR_HIGHLIGHTED_TAG } from '../../constants';
10
import { ABadge, BadgeStyle } from '../common/ABadge';
11
import { getNameTruncated } from '../../utils/strings';
12
import { ShowConfirm } from '../../utils/alerts';
16 13

  
17 14
const { Option } = Select;
18 15

  
......
25 22
    /**
26 23
     * Should properties of this annotation be visible?
27 24
     */
28
    const [visibleProperties, setVisibleProperties] = useState(false);
25
    const [detailsVisible, setDetailsVisible] = useState(false);
29 26

  
30 27
    /**
31 28
     * Context that manages annotations.
32 29
     */
33 30
    const {
34 31
        addOccurrence,
35
        deleteOccurrence,
36
        changePosition,
37
        changeNote,
38
        changeSentiment,
39
        changeLength,
40
        selectedOccurrenceId,
41 32
        selectedInstanceId,
42 33
        setSelectedOccurrenceId,
43 34
        setSelectedInstanceId,
35
        isFinal,
36
        makeOccurrenceFinal,
44 37
    } = useContext(AnnotationContext);
45 38

  
46 39
    /**
......
50 43
        addOccurrence(props.tag);
51 44
    };
52 45

  
53
    /**
54
     * Removes an occurrence of this annotation from the context.
55
     * @param occurrence The occurrence that should be removed.
56
     */
57
    const onDeleteOccurrence = (occurrence: TagInstanceInfo) => (e: any) => {
58
        deleteOccurrence(occurrence);
59
    };
60

  
61
    /**
62
     * Changes a position of an occurrence of this annotation in the context.
63
     * @param occurrence The occurrence that should be changed.
64
     */
65
    const onChangePosition =
66
        (occurrence: TagInstanceInfo) => (e: ChangeEvent<HTMLInputElement>) => {
67
            changePosition(occurrence, Number(e.currentTarget.value));
68
        };
69

  
70
    /**
71
     * Changes a length of an occurrence of this annotation in the context.
72
     * @param occurrence The occurrence that should be changed.
73
     */
74
    const onChangeLength =
75
        (occurrence: TagInstanceInfo) => (e: ChangeEvent<HTMLInputElement>) => {
76
            changeLength(occurrence, Number(e.currentTarget.value));
77
        };
78

  
79
    const onChangeSentiment = (occurrence: TagInstanceInfo) => (val: ETagSentiment) => {
80
        changeSentiment(occurrence, val);
81
    };
82

  
83
    const onChangeNote =
84
        (occurrence: TagInstanceInfo) => (e: ChangeEvent<HTMLTextAreaElement>) => {
85
            changeNote(occurrence, e.currentTarget.value);
86
        };
87

  
88 46
    /**
89 47
     * Changes visibility of properties of this annotation.
90 48
     */
91 49
    const changePropertiesVisibility = () => {
92
        setVisibleProperties(!visibleProperties);
50
        setDetailsVisible(!detailsVisible);
93 51
    };
94 52

  
53
    function isAllAccepted() {
54
        return props.tag.occurrences.filter((o) => !o.isFinal).length === 0;
55
    }
56
    function getBackgroundColor(): string {
57
        if (selectedInstanceId === props.tag.instanceId) {
58
            // highlighted tag
59
            return COLOR_HIGHLIGHTED_TAG;
60
        }
61

  
62
        if (isFinal) {
63
            if (isAllAccepted()) {
64
                return COLOR_ALL_OCCURRENCES_ACCEPTED;
65
            } else {
66
                return '#E4C8CC';
67
            }
68
        }
69

  
70
        return 'white';
71
    }
95 72
    return (
96
        <Container>
97
            <Row
98
                className="border rounded"
99
                style={{
100
                    backgroundColor:
101
                        selectedInstanceId === props.tag.instanceId ? '#FCF3CF' : 'white',
102
                }}
103
            >
73
        <Container
74
            className="border rounded"
75
            style={{
76
                backgroundColor: getBackgroundColor(),
77
            }}
78
        >
79
            <Row className="">
104 80
                <Col sm="auto" className="d-flex align-items-center">
105 81
                    <Button
106 82
                        icon={<TagOutlined style={{ marginLeft: 0 }} />}
......
111 87
                        style={{
112 88
                            border: 'none',
113 89
                            paddingLeft: 0,
114
                            backgroundColor:
115
                                selectedInstanceId === props.tag.instanceId
116
                                    ? '#FCF3CF'
117
                                    : 'white',
90
                            backgroundColor: getBackgroundColor(),
118 91
                        }}
119 92
                        title={'Zvýraznit značky'}
120 93
                    />
......
124 97
                    {props.tag.subtagName ? ' (' + props.tag.subtagName + ')' : ''}
125 98
                </Col>
126 99
                <Col sm="auto">
100
                    {props.tag.occurrences.length > 1 && (
101
                        <ABadge style={BadgeStyle.GENERAL}>
102
                            {props.tag.occurrences.length}
103
                        </ABadge>
104
                    )}
105

  
127 106
                    <Button
128 107
                        type="text"
129 108
                        shape="circle"
......
138 117
                    />
139 118
                </Col>
140 119
            </Row>
141
            {visibleProperties && (
142
                <Stack gap={1} className="mb-2">
143
                    <div>Kategorie: {props.tag.category}</div>
144
                    <div>Výskyty:</div>
145
                    {props.tag.occurrences.map((occurrence, index) => {
146
                        return (
147
                            <Container
148
                                key={index}
149
                                className="shadow-sm"
150
                                style={{
151
                                    backgroundColor:
152
                                        selectedOccurrenceId === occurrence.occurenceId
153
                                            ? '#D8E1E9'
154
                                            : 'white',
155
                                }}
156
                            >
157
                                <Row className="mb-1 mt-1">
158
                                    <Col>
159
                                        <Row>
160
                                            <Col>Pozice: {occurrence.position}</Col>
161
                                            <Col>Délka: {occurrence.length}</Col>
162
                                        </Row>
163
                                        <Row>
164
                                            <i title={occurrence.selectedText ?? ''}>
165
                                                {getTextMaxLength(
166
                                                    occurrence.selectedText ?? '',
167
                                                    35
168
                                                )}
169
                                            </i>
170
                                        </Row>
171
                                        <Row>
172
                                            <Col
173
                                                className="d-flex align-items-center"
174
                                                sm="4"
120
            {isFinal && !isAllAccepted() && (
121
                <>
122
                    <Row
123
                        style={{
124
                            backgroundColor: getBackgroundColor(),
125
                        }}
126
                    >
127
                        <Col sm="12" className="d-flex align-items-center">
128
                            {props.tag.occurrences.length === 1 && (
129
                                <div
130
                                    style={{
131
                                        display: 'flex',
132
                                        flexDirection: 'row',
133
                                        width: '100%',
134
                                        justifyContent: 'space-between',
135
                                    }}
136
                                >
137
                                    <div style={{ width: '60%' }}>
138
                                        Anotovali:{' '}
139
                                        {props.tag.occurrences[0].users?.map((u) => (
140
                                            <span
141
                                                title={
142
                                                    u.name +
143
                                                    ' ' +
144
                                                    u.surname +
145
                                                    ' (' +
146
                                                    u.username +
147
                                                    ')'
148
                                                }
149
                                                key={
150
                                                    props.tag.occurrences[0].occurenceId +
151
                                                    '.' +
152
                                                    u.id
153
                                                }
154
                                                style={{ marginRight: 10 }}
175 155
                                            >
176
                                                Poznámka:
177
                                            </Col>
178
                                            <Col>
179
                                                <Input.TextArea
180
                                                    defaultValue={occurrence.note ?? ''}
181
                                                    onBlur={onChangeNote(occurrence)}
182
                                                    rows={1}
183
                                                />
184
                                            </Col>
185
                                        </Row>
186
                                        {occurrence.sentiment && (
187
                                            <Row>
188
                                                <Col
189
                                                    className="d-flex align-items-center"
190
                                                    sm="4"
191
                                                >
192
                                                    Sentiment:
193
                                                </Col>
194
                                                <Col>
195
                                                    <Select
196
                                                        defaultValue={
197
                                                            occurrence.sentiment
198
                                                        }
199
                                                        style={{ width: '100%' }}
200
                                                        onChange={onChangeSentiment(
201
                                                            occurrence
202
                                                        )}
203
                                                    >
204
                                                        <Option
205
                                                            value={ETagSentiment.Positive}
206
                                                        >
207
                                                            <span
208
                                                                style={{ color: 'green' }}
209
                                                            >
210
                                                                Pozitivní
211
                                                            </span>
212
                                                        </Option>
213
                                                        <Option
214
                                                            value={ETagSentiment.Neutral}
215
                                                        >
216
                                                            Neutrální
217
                                                        </Option>
218
                                                        <Option
219
                                                            value={ETagSentiment.Negative}
220
                                                        >
221
                                                            <span
222
                                                                style={{
223
                                                                    color: '#ff4d4f',
224
                                                                }}
225
                                                            >
226
                                                                Negativní
227
                                                            </span>
228
                                                        </Option>
229
                                                    </Select>
230
                                                </Col>
231
                                            </Row>
232
                                        )}
233
                                    </Col>
234
                                    <Col
235
                                        sm="auto"
236
                                        className="d-flex align-items-center flex-column justify-content-sm-evenly"
237
                                    >
156
                                                {getNameTruncated(u)}
157
                                            </span>
158
                                        ))}
159
                                    </div>
160
                                    <div>
238 161
                                        <Button
239
                                            icon={<EyeOutlined />}
240 162
                                            onClick={() => {
241
                                                setSelectedOccurrenceId(
242
                                                    occurrence.occurenceId ?? null
243
                                                );
244
                                                setSelectedInstanceId(
245
                                                    props.tag.instanceId
246
                                                );
163
                                                ShowConfirm(() => {
164
                                                    makeOccurrenceFinal(
165
                                                        props.tag.occurrences[0]
166
                                                    );
167
                                                }, 'označit toto řešení jako správné');
247 168
                                            }}
248
                                            title={'Zvýraznit výskyt'}
249
                                        />
250
                                        <Button
251
                                            icon={<DeleteOutlined />}
252
                                            onClick={onDeleteOccurrence(occurrence)}
253
                                            danger
254
                                        />
255
                                    </Col>
256
                                </Row>
257
                            </Container>
169
                                        >
170
                                            Přijmout toto řešení
171
                                        </Button>
172
                                    </div>
173
                                </div>
174
                            )}
175
                        </Col>
176
                    </Row>
177
                </>
178
            )}
179

  
180
            {detailsVisible && (
181
                <Stack gap={1} className="mb-2">
182
                    <div>Kategorie: {props.tag.category}</div>
183
                    <div>Výskyty (části):</div>
184
                    {props.tag.occurrences.map((occurrence, index) => {
185
                        return (
186
                            <AnnotationOccurrenceItem
187
                                occurrence={occurrence}
188
                                tag={props.tag}
189
                                key={'occ-' + occurrence.occurenceId}
190
                            />
258 191
                        );
259 192
                    })}
260 193
                </Stack>
webapp/components/annotation/AnnotationOccurrenceItem.tsx
1
import { Col, Container, Row } from 'react-bootstrap';
2
import { Tag } from '../types/tag';
3
import { ChangeEvent, useContext } from 'react';
4
import 'antd/dist/antd.css';
5
import { Button, Input, Select } from 'antd';
6
import { DeleteOutlined, EyeOutlined, LikeOutlined } from '@ant-design/icons';
7
import { AnnotationContext } from '../../contexts/AnnotationContext';
8
import { ETagSentiment, TagInstanceInfo } from '../../api';
9
import { getNameTruncated, getTextMaxLength } from '../../utils/strings';
10
import {
11
    COLOR_ALL_OCCURRENCES_ACCEPTED,
12
    COLOR_HIGHLIGHTED_OCCURRENCE,
13
    COLOR_HIGHLIGHTED_TAG,
14
    COLOR_OCCURRENCE_ACCEPTED,
15
} from '../../constants';
16
import { ShowConfirm } from '../../utils/alerts';
17

  
18
const { Option } = Select;
19

  
20
/**
21
 * Creates a single item in an annotation panel.
22
 * @param props Properties should contain a tag that will be shown in this annotation.
23
 * @returns The item that represents an annotation.
24
 */
25
export function AnnotationOccurrenceItem(props: {
26
    tag: Tag;
27
    occurrence: TagInstanceInfo;
28
}) {
29
    /**
30
     * Context that manages annotations.
31
     */
32
    const {
33
        deleteOccurrence,
34
        changeNote,
35
        changeSentiment,
36
        selectedOccurrenceId,
37
        setSelectedOccurrenceId,
38
        setSelectedInstanceId,
39
        isFinal,
40
        makeOccurrenceFinal,
41
    } = useContext(AnnotationContext);
42

  
43
    const onChangeSentiment = (occurrence: TagInstanceInfo) => (val: ETagSentiment) => {
44
        changeSentiment(occurrence, val);
45
    };
46

  
47
    /**
48
     * Removes an occurrence of this annotation from the context.
49
     * @param occurrence The occurrence that should be removed.
50
     */
51
    const onDeleteOccurrence = (occurrence: TagInstanceInfo) => (e: any) => {
52
        deleteOccurrence(occurrence);
53
    };
54

  
55
    const onChangeNote =
56
        (occurrence: TagInstanceInfo) => (e: ChangeEvent<HTMLTextAreaElement>) => {
57
            changeNote(occurrence, e.currentTarget.value);
58
        };
59

  
60
    function getBackgroundColor(): string {
61
        if (selectedOccurrenceId === props.occurrence.occurenceId) {
62
            // highlighted occurrence
63
            return COLOR_HIGHLIGHTED_OCCURRENCE;
64
        }
65

  
66
        if (isFinal) {
67
            const allAccepted =
68
                props.tag.occurrences.filter((o) => !o.isFinal).length === 0;
69
            if (allAccepted) {
70
                return COLOR_OCCURRENCE_ACCEPTED;
71
            }
72
        }
73

  
74
        return 'white';
75
    }
76

  
77
    return (
78
        <Container
79
            className="shadow-sm"
80
            style={{
81
                backgroundColor: getBackgroundColor(),
82
            }}
83
        >
84
            <Row className="mb-1 mt-1">
85
                <Col>
86
                    <Row>
87
                        <Col>Pozice: {props.occurrence.position}</Col>
88
                        <Col>Délka: {props.occurrence.length}</Col>
89
                    </Row>
90
                    <Row>
91
                        <i title={props.occurrence.selectedText ?? ''}>
92
                            {getTextMaxLength(props.occurrence.selectedText ?? '', 35)}
93
                        </i>
94
                    </Row>
95
                    <Row>
96
                        <Col className="d-flex align-items-center" sm="4">
97
                            Poznámka:
98
                        </Col>
99
                        <Col>
100
                            <Input.TextArea
101
                                defaultValue={props.occurrence.note ?? ''}
102
                                onBlur={onChangeNote(props.occurrence)}
103
                                rows={1}
104
                            />
105
                        </Col>
106
                    </Row>
107
                    {props.occurrence.sentiment && (
108
                        <Row>
109
                            <Col className="d-flex align-items-center" sm="4">
110
                                Sentiment:
111
                            </Col>
112
                            <Col>
113
                                <Select
114
                                    defaultValue={props.occurrence.sentiment}
115
                                    style={{ width: '100%' }}
116
                                    onChange={onChangeSentiment(props.occurrence)}
117
                                >
118
                                    <Option value={ETagSentiment.Positive}>
119
                                        <span style={{ color: 'green' }}>Pozitivní</span>
120
                                    </Option>
121
                                    <Option value={ETagSentiment.Neutral}>
122
                                        Neutrální
123
                                    </Option>
124
                                    <Option value={ETagSentiment.Negative}>
125
                                        <span
126
                                            style={{
127
                                                color: '#ff4d4f',
128
                                            }}
129
                                        >
130
                                            Negativní
131
                                        </span>
132
                                    </Option>
133
                                </Select>
134
                            </Col>
135
                        </Row>
136
                    )}
137
                </Col>
138
                <Col
139
                    sm="auto"
140
                    className="d-flex align-items-center flex-column justify-content-sm-evenly"
141
                >
142
                    <Button
143
                        icon={<EyeOutlined />}
144
                        onClick={() => {
145
                            setSelectedOccurrenceId(props.occurrence.occurenceId ?? null);
146
                            setSelectedInstanceId(props.tag.instanceId);
147
                        }}
148
                        title={'Zvýraznit výskyt'}
149
                    />
150
                    <Button
151
                        icon={<DeleteOutlined />}
152
                        onClick={onDeleteOccurrence(props.occurrence)}
153
                        danger
154
                        className={'mt-1'}
155
                    />
156
                    <Button
157
                        icon={<LikeOutlined />}
158
                        title={'Označit jako správné řešení'}
159
                        onClick={() => {
160
                            ShowConfirm(() => {
161
                                makeOccurrenceFinal(props.occurrence);
162
                            }, 'označit toto řešení jako správné');
163
                        }}
164
                        className={'mt-1'}
165
                    />
166
                </Col>
167
            </Row>
168
            <Row className="mb-1 mt-1">
169
                <Col>
170
                    Označili:{' '}
171
                    {props.occurrence.users?.map((u) => (
172
                        <span
173
                            title={u.name + ' ' + u.surname + ' (' + u.username + ')'}
174
                            key={props.occurrence.occurenceId + '.' + u.id}
175
                            style={{ marginRight: 10 }}
176
                        >
177
                            {getNameTruncated(u)}
178
                        </span>
179
                    ))}
180
                </Col>
181
            </Row>
182
        </Container>
183
    );
184
}
webapp/components/annotation/DocumentAnnotationView.tsx
6 6
import { AnnotationContext } from '../../contexts/AnnotationContext';
7 7
import parse from 'html-react-parser';
8 8
import {
9
    COLOR_HIGHLIGHTED_TAG,
9 10
    DOCUMENT_INSTANCE_ID_ATTRIBUTE_NAME,
10 11
    DOCUMENT_OCCURRENCE_ID_ATTRIBUTE_NAME,
11 12
    DOCUMENT_TAG_ID_ATTRIBUTE_NAME,
......
58 59
        }
59 60

  
60 61
        if (selectedInstanceId) {
61
            css += `span[${DOCUMENT_INSTANCE_ID_ATTRIBUTE_NAME}="${selectedInstanceId}"] { background-color: #FCF3CF;  }\n`;
62
            css += `span[${DOCUMENT_INSTANCE_ID_ATTRIBUTE_NAME}="${selectedInstanceId}"] { background-color: ${COLOR_HIGHLIGHTED_TAG};  }\n`;
62 63
        }
63 64
        if (selectedOccurrenceId) {
64 65
            css += `span[${DOCUMENT_OCCURRENCE_ID_ATTRIBUTE_NAME}="${selectedOccurrenceId}"] { border-bottom: 4px dotted;  }\n`;
webapp/constants.ts
16 16
export const COLOR_WARNING = 'darkorange';
17 17
export const COLOR_ERROR = 'indianred';
18 18

  
19
export const COLOR_HIGHLIGHTED_TAG = '#97BDC4';
20
export const COLOR_HIGHLIGHTED_OCCURRENCE = '#D8E1E9';
21

  
22
export const COLOR_ALL_OCCURRENCES_ACCEPTED = '#B6CEB7';
23
export const COLOR_OCCURRENCE_ACCEPTED = '#9DBE9E';
24

  
19 25
export const BORDER_RADIUS = 4;
20 26

  
21 27
export const DOCUMENT_TAG_ID_ATTRIBUTE_NAME = 'aswi-tag-id';
webapp/contexts/AnnotationContext.tsx
77 77
     */
78 78
    changeSentiment: (occurrence: TagInstanceInfo, newValue: ETagSentiment) => void;
79 79

  
80
    makeOccurrenceFinal: (occurrence: TagInstanceInfo) => void;
81

  
80 82
    annotation: AnnotationInfo | null;
81 83
    mappedTags: Tag[] | null;
82 84
    refreshAnnotation: () => void;
......
92 94

  
93 95
    selectedOccurrenceId: string | null;
94 96
    setSelectedOccurrenceId: (newId: string | null) => void;
97

  
98
    isFinal: boolean;
95 99
}
96 100

  
97 101
/**
......
194 198
    setSelectedOccurrenceId: (newId: string | null) => {
195 199
        return;
196 200
    },
201

  
202
    isFinal: false,
203
    makeOccurrenceFinal: (occurrence: TagInstanceInfo) => {
204
        return;
205
    },
197 206
});
198 207

  
199 208
/**
......
282 291
            annotationController
283 292
                .annotationAnnotationIdOccurenceIdDelete(
284 293
                    props.annotationId,
285
                    occurrence.occurenceId ?? ''
294
                    occurrence.occurenceId ?? '',
295
                    props.isFinal
286 296
                )
287 297
                .then(() => refreshAnnotation());
288 298
        }, 'značku');
......
397 407
        setMappedTags(Array.from(map.values()));
398 408
    };
399 409

  
410
    async function makeOccurrenceFinal(occurrence: TagInstanceInfo) {
411
        if (!occurrence?.occurenceId) {
412
            return;
413
        }
414

  
415
        await annotationController.annotationAnnotationIdOccurenceIdFinalPut(
416
            props.annotationId,
417
            occurrence.occurenceId,
418
            { isFinal: true }
419
        );
420

  
421
        await refreshAnnotation();
422
    }
423

  
400 424
    async function refreshAnnotation() {
401 425
        const data = await annotationController.annotationAnnotationIdGet(
402 426
            props.annotationId,
......
436 460
                setSelectedInstanceId,
437 461
                selectedOccurrenceId,
438 462
                setSelectedOccurrenceId,
463
                isFinal: props.isFinal,
464
                makeOccurrenceFinal,
439 465
            }}
440 466
        >
441 467
            {props.children}

Také k dispozici: Unified diff