From c917ea7a0f009a3e06ab8b3dd2b3ad9ff47fe18d Mon Sep 17 00:00:00 2001 From: Kheir Eddine Farfar Date: Mon, 25 Nov 2024 19:34:35 +0100 Subject: [PATCH] refactor: replace annotation service with nlp service --- README.md | 1 - default.env | 1 - package-lock.json | 22 +- package.json | 4 +- ...ractAnnotator.js => AbstractAnnotator.tsx} | 89 +++---- ...torModal.js => AbstractAnnotatorModal.tsx} | 229 ++++++++---------- .../AbstractAnnotatorView.js | 170 ------------- .../AbstractAnnotatorView.tsx | 113 +++++++++ .../AbstractInputView.js | 52 ---- .../AbstractInputView.tsx | 48 ++++ .../AbstractRangesList.js | 190 --------------- .../AbstractRangesList.tsx | 98 ++++++++ .../AnnotationTooltip.js | 81 ------- .../AnnotationTooltip.tsx | 82 +++++++ .../{AbstractModal.js => AbstractModal.tsx} | 27 +-- ...eWarningAlert.js => TitleWarningAlert.tsx} | 9 +- .../ViewPaper/hooks/useFetchAbstract.js | 13 +- src/constants/llmTasks.ts | 2 +- src/services/annotation/index.js | 12 - src/slices/types.ts | 25 ++ src/slices/viewPaperSlice.js | 21 +- 21 files changed, 580 insertions(+), 709 deletions(-) rename src/components/ViewPaper/AbstractAnnotatorModal/{AbstractAnnotator.js => AbstractAnnotator.tsx} (55%) rename src/components/ViewPaper/AbstractAnnotatorModal/{AbstractAnnotatorModal.js => AbstractAnnotatorModal.tsx} (55%) delete mode 100644 src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorView.js create mode 100644 src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorView.tsx delete mode 100644 src/components/ViewPaper/AbstractAnnotatorModal/AbstractInputView.js create mode 100644 src/components/ViewPaper/AbstractAnnotatorModal/AbstractInputView.tsx delete mode 100644 src/components/ViewPaper/AbstractAnnotatorModal/AbstractRangesList.js create mode 100644 src/components/ViewPaper/AbstractAnnotatorModal/AbstractRangesList.tsx delete mode 100644 src/components/ViewPaper/AbstractAnnotatorModal/AnnotationTooltip.js create mode 100644 src/components/ViewPaper/AbstractAnnotatorModal/AnnotationTooltip.tsx rename src/components/ViewPaper/AbstractModal/{AbstractModal.js => AbstractModal.tsx} (75%) rename src/components/ViewPaper/AbstractModal/{TitleWarningAlert.js => TitleWarningAlert.tsx} (57%) delete mode 100644 src/services/annotation/index.js diff --git a/README.md b/README.md index 5e3ffe1ec..30c3dcd32 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ The **environment variables** descriptions: | ESLINT_NO_DEV_ERRORS | ✅ Used | 🚫 Ignored | When set to `true`, ESLint errors are converted to warnings during development. As a result, ESLint output will no longer appear in the error overlay. | | NEXT_PUBLIC_BACKEND_URL | ✅ Used | ✅ Used | ORKG backend endpoint (use http://localhost:8080/ when running the backend locally) | | NEXT_PUBLIC_SIMILARITY_SERVICE_URL | ✅ Used | ✅ Used | ORKG similarity service endpoint (use http://localhost:5000/ when running the service locally) | -| NEXT_PUBLIC_ANNOTATION_SERVICE_URL | ✅ Used | ✅ Used | ORKG annotation service endpoint | | NEXT_PUBLIC_SIMILAR_PAPER_URL | ✅ Used | ✅ Used | ORKG [similar papers](https://gitlab.com/TIBHannover/orkg/orkg-simpaper-api) service endpoint | | NEXT_PUBLIC_NLP_SERVICE_URL | ✅ Used | ✅ Used | ORKG [NLP service](https://gitlab.com/TIBHannover/orkg/nlp/orkg-nlp-api) endpoint | | NEXT_PUBLIC_GROBID_URL | ✅ Used | ✅ Used | GROBID service endpoint (More details in ORKG annotation repository) | diff --git a/default.env b/default.env index 189d588a8..116bcd65d 100644 --- a/default.env +++ b/default.env @@ -6,7 +6,6 @@ NEXT_PUBLIC_URL=https://www.orkg.org NEXT_PUBLIC_BACKEND_URL=https://sandbox.orkg.org/ NEXT_PUBLIC_SIMILARITY_SERVICE_URL=https://sandbox.orkg.org/simcomp/ NEXT_PUBLIC_SIMILAR_PAPER_URL=https://orkg.org/simpaper/api/ -NEXT_PUBLIC_ANNOTATION_SERVICE_URL=http://localhost:7000/ NEXT_PUBLIC_NLP_SERVICE_URL=https://sandbox.orkg.org/nlp/api/ NEXT_PUBLIC_DATACITE_URL=https://api.test.datacite.org/dois NEXT_PUBLIC_GROBID_URL=https://orkg.org/grobid/ diff --git a/package-lock.json b/package-lock.json index c32d58f28..5438bda35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,7 +67,7 @@ "prop-types": "^15.8.1", "qs": "^6.11.1", "randomcolor": "^0.6.2", - "rangy": "^1.3.1", + "rangy": "^1.3.2", "rc-tabs": "^12.5.10", "rc-tree": "^5.7.2", "rdf": "github:Reddine/node-rdf", @@ -160,6 +160,8 @@ "@types/leaflet": "^1.9.12", "@types/node": "^20.4.9", "@types/pluralize": "^0.0.32", + "@types/randomcolor": "^0.5.9", + "@types/rangy": "^0.0.38", "@types/react": "^18.2.20", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-csv": "^1.1.10", @@ -9486,11 +9488,25 @@ "license": "MIT", "optional": true }, + "node_modules/@types/randomcolor": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@types/randomcolor/-/randomcolor-0.5.9.tgz", + "integrity": "sha512-k58cfpkK15AKn1m+oRd9nh5BnuiowhbyvBBdAzcddtARMr3xRzP0VlFaAKovSG6N6Knx08EicjPlOMzDejerrQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/range-parser": { "version": "1.2.4", "dev": true, "license": "MIT" }, + "node_modules/@types/rangy": { + "version": "0.0.38", + "resolved": "https://registry.npmjs.org/@types/rangy/-/rangy-0.0.38.tgz", + "integrity": "sha512-KMybA3NQLSc5Fl5VOyLVSZ10AMSY6anQqLxP8dxgNsui3dScPIB7smywq69gwJkud2ODVTIImMNN3RtHcFKYgA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/react": { "version": "18.2.20", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.20.tgz", @@ -24496,7 +24512,9 @@ } }, "node_modules/rangy": { - "version": "1.3.1" + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rangy/-/rangy-1.3.2.tgz", + "integrity": "sha512-fS1C4MOyk8T+ZJZdLcgrukPWxkyDXa+Hd2Kj+Zg4wIK71yrWgmjzHubzPMY1G+WD9EgGxMp3fIL0zQ1ickmSWA==" }, "node_modules/raw-body": { "version": "2.4.3", diff --git a/package.json b/package.json index 7a4cbe01f..338c3727c 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "prop-types": "^15.8.1", "qs": "^6.11.1", "randomcolor": "^0.6.2", - "rangy": "^1.3.1", + "rangy": "^1.3.2", "rc-tabs": "^12.5.10", "rc-tree": "^5.7.2", "rdf": "github:Reddine/node-rdf", @@ -175,6 +175,8 @@ "@types/leaflet": "^1.9.12", "@types/node": "^20.4.9", "@types/pluralize": "^0.0.32", + "@types/randomcolor": "^0.5.9", + "@types/rangy": "^0.0.38", "@types/react": "^18.2.20", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-csv": "^1.1.10", diff --git a/src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotator.js b/src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotator.tsx similarity index 55% rename from src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotator.js rename to src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotator.tsx index aa30c69d7..137fdb9ca 100644 --- a/src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotator.js +++ b/src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotator.tsx @@ -1,78 +1,88 @@ -import { useRef } from 'react'; -import PropTypes from 'prop-types'; +import { OptionType } from 'components/Autocomplete/types'; +import AnnotationTooltip from 'components/ViewPaper/AbstractAnnotatorModal/AnnotationTooltip'; import rangy from 'rangy'; -import { useSelector, useDispatch } from 'react-redux'; +import { FC, ReactElement, useRef } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Range, RootStore } from 'slices/types'; import { createAnnotation } from 'slices/viewPaperSlice'; -import AnnotationTooltip from 'components/ViewPaper/AbstractAnnotatorModal/AnnotationTooltip'; -function getAllIndexes(arr, val) { +function getAllIndexes(arr: string, val: string) { const indexes = []; let i = -1; - while ((i = arr.indexOf(val, i + 1)) !== -1) { - indexes.push(i); + let nextIndex = arr.indexOf(val, i + 1); + while (nextIndex !== -1) { + indexes.push(nextIndex); + i = nextIndex; + nextIndex = arr.indexOf(val, i + 1); } return indexes; } -function AbstractAnnotator(props) { - const annotatorRef = useRef(null); +type AbstractAnnotatorProps = { + predicateOptions: OptionType[]; + getPredicateColor: (id: string) => string; +}; + +const AbstractAnnotator: FC = ({ predicateOptions, getPredicateColor }) => { + const annotatorRef = useRef(null); const dispatch = useDispatch(); - const abstract = useSelector((state) => state.viewPaper.abstract); - const ranges = useSelector((state) => state.viewPaper.ranges); + const { abstract, ranges } = useSelector((state: RootStore) => state.viewPaper); - const renderCharNode = (charIndex) => ( + const renderCharNode = (charIndex: number) => ( {abstract[charIndex]} ); - const getRange = (charPosition) => - ranges && - Object.values(ranges).find( - (range) => charPosition >= range.start && charPosition <= range.end && range.certainty >= props.certaintyThreshold, - ); + const getRange = (charPosition: number) => + ranges && Object.values(ranges).find((range) => charPosition >= range.start && charPosition <= range.end); - const tooltipRenderer = (lettersNode, range) => ( + const tooltipRenderer = (lettersNode: ReactElement[], range: Range) => ( ); const getAnnotatedText = () => { const annotatedText = []; - for (let charPosition = 0; charPosition < abstract.length; charPosition++) { + for (let charPosition = 0; charPosition < abstract.length; charPosition += 1) { const range = getRange(charPosition); const charNode = renderCharNode(charPosition); - if (!range) { + if (range) { + const annotationGroup = [charNode]; + let rangeCharPosition = charPosition + 1; + for (; rangeCharPosition < range.end + 1; rangeCharPosition += 1) { + annotationGroup.push(renderCharNode(rangeCharPosition)); + charPosition = rangeCharPosition; + } + annotatedText.push(tooltipRenderer(annotationGroup, range)); + } else { annotatedText.push(charNode); - continue; - } - const annotationGroup = [charNode]; - let rangeCharPosition = charPosition + 1; - for (; rangeCharPosition < parseInt(range.end) + 1; rangeCharPosition++) { - annotationGroup.push(renderCharNode(rangeCharPosition)); - charPosition = rangeCharPosition; } - annotatedText.push(tooltipRenderer(annotationGroup, range)); } return annotatedText; }; const handleMouseUp = () => { + if (!annotatorRef.current) { + return null; + } + // Get the selection + // @ts-expect-error: rangy is not typed const sel = rangy.getSelection(annotatorRef.current); if (sel.isCollapsed) { return null; } // Get position of the node at which the user started selecting - let start = parseInt(sel.anchorNode.parentNode.dataset.position); + let start = parseInt((sel.anchorNode?.parentNode as HTMLElement)?.dataset.position ?? '', 10); // Get position of the node at which the user stopped selecting - let end = parseInt(sel.focusNode.parentNode.dataset.position); + let end = parseInt((sel.focusNode?.parentNode as HTMLElement)?.dataset.position ?? '', 10); // Get the text within the selection const text = sel.toString(); if (!text.length) { @@ -97,12 +107,13 @@ function AbstractAnnotator(props) { start, end, text, - class: { id: null, label: null }, + predicate: { id: null, label: null }, certainty: 1, isEditing: false, }; dispatch(createAnnotation(range)); - window.getSelection().empty(); + window?.getSelection()?.empty(); + return null; }; const annotatedText = getAnnotatedText(); @@ -110,7 +121,7 @@ function AbstractAnnotator(props) {
); -} +}; export default AbstractAnnotator; - -AbstractAnnotator.propTypes = { - certaintyThreshold: PropTypes.number, - classOptions: PropTypes.array.isRequired, - getClassColor: PropTypes.func.isRequired, -}; diff --git a/src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorModal.js b/src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorModal.tsx similarity index 55% rename from src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorModal.js rename to src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorModal.tsx index d00a01950..3162e398c 100644 --- a/src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorModal.js +++ b/src/components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorModal.tsx @@ -3,19 +3,21 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import AbstractAnnotatorView from 'components/ViewPaper/AbstractAnnotatorModal/AbstractAnnotatorView'; import AbstractInputView from 'components/ViewPaper/AbstractAnnotatorModal/AbstractInputView'; import AbstractRangesList from 'components/ViewPaper/AbstractAnnotatorModal/AbstractRangesList'; +import { CLASSES, PREDICATES } from 'constants/graphSettings'; +import LLM_TASK_NAMES from 'constants/llmTasks'; import toArray from 'lodash/toArray'; -import PropTypes from 'prop-types'; import randomcolor from 'randomcolor'; -import { useCallback, useEffect, useState } from 'react'; +import { FC, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { CSSTransition, TransitionGroup } from 'react-transition-group'; import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import { getAnnotations } from 'services/annotation/index'; import { createResource } from 'services/backend/resources'; import { createResourceStatement, statementsUrl } from 'services/backend/statements'; +import { getLlmResponse, nlpServiceUrl } from 'services/orkgNlp'; +import { Range, RootStore } from 'slices/types'; import { clearAnnotations, createAnnotation, setAbstractDialogView, setAbstract as setAbstractGlobal } from 'slices/viewPaperSlice'; import styled from 'styled-components'; -import { mutate } from 'swr'; +import useSWR, { mutate } from 'swr'; const AnimationContainer = styled(CSSTransition)` &.fadeIn-enter { @@ -28,114 +30,116 @@ const AnimationContainer = styled(CSSTransition)` } `; -const CLASS_OPTIONS = [ +const PREDICATE_OPTIONS = [ { - id: 'PROCESS', - label: 'Process', - description: 'Natural phenomenon, or independent/dependent activities.E.g., growing(Bio), cured(MS), flooding(ES).', + id: PREDICATES.HAS_RESEARCH_PROBLEM, + service_id: 'RESEARCH_PROBLEM', + label: 'Research Problem', + description: 'The research problem that the work addresses', + color: '#DAA520', }, { - id: 'DATA', - label: 'Data', + id: PREDICATES.LANGUAGE, + service_id: 'LANGUAGE', + label: 'Language', + description: 'The natural language focus of the work', + color: '#D2B8E5', + }, + { + id: PREDICATES.HAS_DATASET, + service_id: 'DATASET', + label: 'Dataset', description: 'The data themselves, or quantitative or qualitative characteristics of entities. E.g., rotational energy (Eng), tensile strength (MS), the Chern character (Mat).', + color: '#9df28a', }, { - id: 'MATERIAL', - label: 'Material', - description: 'A physical or digital entity used for scientific experiments. E.g., soil (Agr), the moon (Ast), the set (Mat).', + id: PREDICATES.TOOL, + service_id: 'TOOL', + label: 'Tool', + description: 'Tools used in the research', + color: '#EAB0A2', }, { - id: 'METHOD', + id: PREDICATES.METHOD, + service_id: 'METHOD', label: 'Method', description: 'A commonly used procedure that acts on entities. E.g., powder X-ray (Che), the PRAM analysis (CS), magnetoencephalography (Med).', + color: '#7fa2ff', }, ]; -const CLASS_COLORS = { - process: '#7fa2ff', - data: '#9df28a', - material: '#EAB0A2', - method: '#D2B8E5', +type AbstractAnnotatorModalProps = { + toggle: () => void; + resourceId: string; }; -function AbstractAnnotatorModal({ toggle, resourceId }) { - const [isAbstractLoading, setIsAbstractLoading] = useState(false); - const [isAbstractFailedLoading, setIsAbstractFailedLoading] = useState(false); - const [isAnnotationLoading, setIsAnnotationLoading] = useState(false); - const [isAnnotationFailedLoading, setIsAnnotationFailedLoading] = useState(false); - const [annotationError, setAnnotationError] = useState(null); - const [certaintyThreshold, setCertaintyThreshold] = useState([0.5]); +const AbstractAnnotatorModal: FC = ({ toggle, resourceId }) => { + const { abstract: abstractGlobal, abstractDialogView, ranges, isAbstractLoading } = useSelector((state: RootStore) => state.viewPaper); + const dispatch = useDispatch(); + const [validation, setValidation] = useState(true); - const [classColors, setClassColors] = useState(CLASS_COLORS); - const abstractGlobal = useSelector((state) => state.viewPaper.abstract); + const [predicateColors, setPredicateColors] = useState>( + PREDICATE_OPTIONS.reduce((acc, p) => ({ ...acc, [p.id]: p.color }), {}), + ); const [abstract, setAbstract] = useState(abstractGlobal); - const dispatch = useDispatch(); - - const abstractDialogView = useSelector((state) => state.viewPaper.abstractDialogView); - const ranges = useSelector((state) => state.viewPaper.ranges); - const getAnnotation = useCallback(() => { - if (!abstract) { - return Promise.resolve(); - } - setIsAnnotationLoading(true); - - return getAnnotations(abstract) - .then((data) => { - const annotated = []; - const nRanges = {}; - if (data && data.entities) { - data.entities - .map((entity) => { - const text = data.text.substring(entity[2][0][0], entity[2][0][1]); - if (annotated.indexOf(text.toLowerCase()) < 0) { - annotated.push(text.toLowerCase()); - // Predicate label entity[1] - let rangeClass = CLASS_OPTIONS.filter((c) => c.label.toLowerCase() === entity[1].toLowerCase()); - if (rangeClass.length > 0) { - [rangeClass] = rangeClass; - } else { - rangeClass = { id: entity[1], label: entity[1] }; - } - nRanges[entity[0]] = { + const { isLoading: isAnnotationLoading, error: _annotationError } = useSWR( + abstractGlobal + ? [ + { + taskName: LLM_TASK_NAMES.RECOMMEND_ANNOTATION, + placeholders: { text: abstractGlobal }, + }, + nlpServiceUrl, + 'getLlmResponse', + ] + : null, + ([params]) => + getLlmResponse(params).then((data) => { + const annotated: string[] = []; + const nRanges: Range[] = []; + if (data && data.values) { + data.values.map((entity: { span: [number, number]; id: string; class: string }) => { + const text = abstractGlobal.substring(entity.span[0], entity.span[1]); + if (annotated.indexOf(text.toLowerCase()) < 0) { + annotated.push(text.toLowerCase()); + let rangePredicate: { id: string; label: string } | null = null; + if (PREDICATE_OPTIONS.filter((c) => c.service_id === entity.class).length > 0) { + [rangePredicate] = PREDICATE_OPTIONS.filter((c) => c.service_id === entity.class); + nRanges.push({ + id: entity.id, text, - start: entity[2][0][0], - end: entity[2][0][1] - 1, - certainty: entity[3], - class: rangeClass, + start: entity.span[0], + end: entity.span[1], + predicate: rangePredicate, isEditing: false, - }; - return nRanges[entity[0]]; + }); } - return null; - }) - .filter((r) => r); + } + return null; + }); } // Clear annotations dispatch(clearAnnotations()); - toArray(nRanges).map((range) => dispatch(createAnnotation(range))); - setIsAnnotationLoading(false); - setIsAnnotationFailedLoading(false); - setIsAbstractLoading(false); - setIsAbstractFailedLoading(false); - }) - .catch((e) => { - if (e.statusCode === 422) { - setAnnotationError('Failed to annotate the abstract, please change the abstract and try again'); - setIsAnnotationLoading(false); - setIsAnnotationFailedLoading(true); - } else { - setAnnotationError(null); - setIsAnnotationLoading(false); - setIsAnnotationFailedLoading(true); - } - return null; - }); - }, [abstract, dispatch]); + nRanges.map((range) => dispatch(createAnnotation(range))); + return nRanges; + }), + ); + + const isAnnotationFailedLoading = _annotationError !== undefined; + + let annotationError = ''; + if (_annotationError) { + if (_annotationError.statusCode === 422) { + annotationError = 'Failed to annotate the abstract, please change the abstract and try again'; + } else { + annotationError = ''; + } + } const handleChangeAbstract = () => { if (abstractDialogView === 'input') { @@ -143,39 +147,32 @@ function AbstractAnnotatorModal({ toggle, resourceId }) { setValidation(false); return; } - getAnnotation(); } dispatch(setAbstractGlobal(abstract)); dispatch(setAbstractDialogView(abstractDialogView === 'input' ? 'annotator' : 'input')); setValidation(true); }; - useEffect(() => { - if (abstractDialogView !== 'input') { - getAnnotation(); - } - }, [abstract, getAnnotation]); - - const getClassColor = (rangeClass) => { - if (!rangeClass) { + const getPredicateColor = (rangePredicateId: string) => { + if (!rangePredicateId) { return '#ffb7b7'; } - if (classColors[rangeClass.toLowerCase()]) { - return classColors[rangeClass.toLowerCase()]; + if (predicateColors[rangePredicateId]) { + return predicateColors[rangePredicateId]; } - const newColor = randomcolor({ luminosity: 'light', seed: rangeClass.toLowerCase() }); - setClassColors({ ...classColors, [rangeClass.toLowerCase()]: newColor }); + const newColor = randomcolor({ luminosity: 'light', seed: rangePredicateId.toLowerCase() }); + setPredicateColors({ ...predicateColors, [rangePredicateId]: newColor }); return newColor; }; const handleInsertData = async () => { - const rangesArray = toArray(ranges).filter((r) => r.certainty >= certaintyThreshold); + const rangesArray = toArray(ranges); if (rangesArray.length > 0) { await Promise.all( rangesArray.map(async (range) => { - const object = await createResource(range.text); + const object = await createResource(range.text, range.predicate.id === PREDICATES.HAS_RESEARCH_PROBLEM ? [CLASSES.PROBLEM] : []); // Add the statements to the selected contribution - return createResourceStatement(resourceId, range.class.id, object.id); + return createResourceStatement(resourceId, range.predicate.id, object.id); }), ); } @@ -193,21 +190,18 @@ function AbstractAnnotatorModal({ toggle, resourceId }) { toggle(); }; - const handleChangeView = (view) => { + const handleChangeView = (view: 'input' | 'annotator' | 'list') => { dispatch(setAbstractDialogView(view)); }; let currentStepDetails = ( setCertaintyThreshold(v)} - classOptions={CLASS_OPTIONS} + predicateOptions={PREDICATE_OPTIONS} annotationError={annotationError} - getClassColor={getClassColor} + getPredicateColor={getPredicateColor} /> ); @@ -216,21 +210,14 @@ function AbstractAnnotatorModal({ toggle, resourceId }) { case 'input': currentStepDetails = ( - + ); break; case 'list': currentStepDetails = ( - + ); break; @@ -239,7 +226,7 @@ function AbstractAnnotatorModal({ toggle, resourceId }) { } return ( - + Abstract annotator
@@ -262,7 +249,7 @@ function AbstractAnnotatorModal({ toggle, resourceId }) { Annotate Abstract )} - {abstractDialogView === 'list' ? ( + {abstractDialogView === 'list' && ( <> - ) : ( + )} + {abstractDialogView !== 'list' && ( <>