Skip to content

Commit

Permalink
Merge pull request #1459 from alliance-genome/SCRUM-3794
Browse files Browse the repository at this point in the history
SCRUM-3794
  • Loading branch information
oblodgett authored Mar 14, 2024
2 parents dc4976b + 12bf3dd commit 9bccac0
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 42 deletions.
41 changes: 41 additions & 0 deletions src/main/cliapp/src/components/Editors/NotEditor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useState } from 'react';
import { Dropdown } from "primereact/dropdown";

export function NotEditor({ props, value, editorChange }) {
const [selectedValue, setSelectedValue] = useState(value);
const textString = selectedValue ? "NOT" : "";
const options = [
{ label: "NOT", value: true },
];

const onChange = (e) => {
let event;
if(e.value === undefined){
event = {
target: {
value: false,
name: e.target.name
}
}
} else {
event = e;
}
setSelectedValue(event.target.value);
editorChange(event, props);
}

return (
<>
<Dropdown
aria-label='dropdown'
name="negated"
value={selectedValue}
options={options}
onChange={(e) => onChange(e)}
showClear={true}
placeholder={textString}
style={{ width: '100%' }}
/>
</>
);
}
64 changes: 64 additions & 0 deletions src/main/cliapp/src/components/Editors/__tests__/NotEditor.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { render, fireEvent, within } from '@testing-library/react';
import { NotEditor } from '../NotEditor';
import '../../../tools/jest/setupTests';

describe('NotEditor', () => {
it('should display "NOT" as the placeholder text when the initial value is true', () => {
const props = {};
const value = true;
const editorChange = jest.fn();

const result = render(<NotEditor props={props} value={value} editorChange={editorChange} />);

expect(result.getAllByText("NOT")).toHaveLength(2);
});

it('should render a Dropdown component with no options when value prop is undefined', () => {
const props = {};
const value = undefined;
const editorChange = jest.fn();

const result = render(<NotEditor props={props} value={value} editorChange={editorChange} />);


expect(result.getByText("empty")).toBeInTheDocument();
});

it('should update the selected value when an option is selected', () => {
const props = {};
const value = false;
const editorChange = jest.fn();


const result = render(<NotEditor props={props} value={value} editorChange={editorChange} />);
const span = result.container.getElementsByTagName('span')[0];

expect(within(span).getByText('empty')).toBeInTheDocument();

fireEvent.click(span);

const option = result.getAllByText('NOT');
fireEvent.click(option[0]);
const updatedSpan = result.container.getElementsByTagName('span')[0];


expect(within(updatedSpan).getByText('NOT')).toBeInTheDocument();
});

it('should call editorChange when an option is selected', () => {
const props = {};
const value = false;
const editorChange = jest.fn();
const result = render(<NotEditor props={props} value={value} editorChange={editorChange} />);
const span = result.container.getElementsByTagName('span')[0];

fireEvent.click(span);


const option = result.getAllByText('NOT');
fireEvent.click(option[0]);

expect(editorChange).toHaveBeenCalledTimes(1);
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useRef } from "react";
import { Dropdown } from "primereact/dropdown";

export function FilterComponentBinaryDropDown({ isInEditMode, filterConfig, currentFilters, onFilter }) {
const options = useRef(["true", "false"]);
const options = useRef(filterConfig.options || ["true", "false"]);

const fieldSet = filterConfig.fieldSets[0];

Expand Down
8 changes: 8 additions & 0 deletions src/main/cliapp/src/components/Templates/NotTemplate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react'
import { EllipsisTableCell } from '../EllipsisTableCell';

export const NotTemplate = ({ value }) => {
if (value === null || value === undefined || typeof value !== 'boolean') return null;
const textString = value ? "NOT" : "";
return <EllipsisTableCell>{textString}</EllipsisTableCell>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { render } from '@testing-library/react';
import { NotTemplate } from '../NotTemplate';
import '../../../tools/jest/setupTests';

describe('NotTemplate', () => {

it('should return null when value is null', () => {
const { container } = render(<NotTemplate value={null} />);
expect(container.firstChild).toBeNull();
});

it('should return a component with the text "NOT" when the value is true', () => {
const { getByText } = render(<NotTemplate value={true} />);
expect(getByText("NOT")).toBeInTheDocument();
});
it('should return a component with an empty string when the value is false', () => {
const { container } = render(<NotTemplate value={false} />);
expect(container.textContent).toBe('');
});

it('should return null when value is not a boolean', () => {
const { container } = render(<NotTemplate value={123} />);
expect(container.firstChild).toBeNull();
});
});
8 changes: 4 additions & 4 deletions src/main/cliapp/src/constants/FilterFields.js
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ export const FILTER_CONFIGS = Object.freeze({
isExtinctFilterConfig: { filterComponentType: "dropdown", fieldSets: [FIELD_SETS.isExtinctFieldSet] },
obsoleteFilterConfig: { filterComponentType: "dropdown", fieldSets: [FIELD_SETS.obsoleteFieldSet] },
internalFilterConfig: { filterComponentType: "dropdown", fieldSets: [FIELD_SETS.internalFieldSet] },
negatedFilterConfig: { filterComponentType: "dropdown", fieldSets: [FIELD_SETS.negatedFieldSet] },
negatedFilterConfig: { filterComponentType: "dropdown", fieldSets: [FIELD_SETS.negatedFieldSet], options: [ { label: "NOT", value: "true" }, { label: "null", value: "false" } ] },

annotationTypeFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.annotationTypeFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
diseaseDataProviderFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.dataProviderFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
Expand All @@ -605,12 +605,12 @@ export const FILTER_CONFIGS = Object.freeze({
agmDataProviderFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.dataProviderFieldSet], aggregationFieldSet: FIELD_SETS.agmAggregationFieldSet, useKeywordFields: true },
diseaseQualifiersFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.diseaseQualifiersFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
relationFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.relationFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
paRelationFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.relationFieldSet], aggregationFieldSet: FIELD_SETS.paAggregationFieldSet, useKeywordFields: true },
paRelationFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.relationFieldSet], aggregationFieldSet: FIELD_SETS.paAggregationFieldSet, useKeywordFields: true },
geneticModifierRelationFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.geneticModifierRelationFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
geneticSexFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.geneticSexFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
secondaryDataProviderFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.secondaryDataProviderFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
speciesDataProviderFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.dataProviderFieldSet], aggregationFieldSet: FIELD_SETS.speciesAggregationFieldSet, useKeywordFields: true },
evidenceCodesFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.evidenceCodesFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
speciesDataProviderFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.dataProviderFieldSet], aggregationFieldSet: FIELD_SETS.speciesAggregationFieldSet, useKeywordFields: true },
evidenceCodesFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.evidenceCodesFieldSet], aggregationFieldSet: FIELD_SETS.daAggregationFieldSet, useKeywordFields: true },
variantDataProviderFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.dataProviderFieldSet], aggregationFieldSet: FIELD_SETS.variantAggregationFieldSet, useKeywordFields: true },
variantStatusFilterConfig: { filterComponentType: "multiselect", fieldSets: [FIELD_SETS.variantStatusFieldSet], aggregationFieldSet: FIELD_SETS.variantAggregationFieldSet,useKeywordFields: true },

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import { DiseaseTemplate } from '../../components/Templates/DiseaseTemplate';
import { GenomicEntityTemplate } from '../../components/Templates/genomicEntity/GenomicEntityTemplate';
import { GenomicEntityListTemplate } from '../../components/Templates/genomicEntity/GenomicEntityListTemplate';
import { BooleanTemplate } from '../../components/Templates/BooleanTemplate';
import { NotTemplate } from '../../components/Templates/NotTemplate';

import { NotEditor } from '../../components/Editors/NotEditor';

import { ControlledVocabularyDropdown } from '../../components/ControlledVocabularySelector';
import { ConditionRelationHandleDropdown } from '../../components/ConditionRelationHandleSelector';
Expand Down Expand Up @@ -428,26 +431,12 @@ export const DiseaseAnnotationsTable = () => {
);
};

const onNegatedEditorValueChange = (props, event) => {
let updatedAnnotations = [...props.props.value];
if (event.value || event.value === '') {
updatedAnnotations[props.rowIndex].negated = JSON.parse(event.value.name);
}
};
const onNegatedEditorValueChange = (event, props) => {
if(event.target.value === undefined || event.target.value === null) return;

const negatedEditor = (props) => {
return (
<>
<TrueFalseDropdown
options={booleanTerms}
editorChange={onNegatedEditorValueChange}
props={props}
field={"negated"}
/>
<ErrorMessageComponent errorMessages={errorMessagesRef.current[props.rowIndex]} errorField={"negated"} />
</>
);
};
let updatedAnnotations = [...props.props.value];
updatedAnnotations[props.rowIndex].negated = event.target.value;
}

const onInternalEditorValueChange = (props, event) => {
let updatedAnnotations = [...props.props.value];
Expand Down Expand Up @@ -934,11 +923,11 @@ export const DiseaseAnnotationsTable = () => {
},
{
field: "negated",
header: "Negated",
body: (rowData) => <BooleanTemplate value={rowData.negated}/>,
header: "NOT",
body: (rowData) => <NotTemplate value={rowData.negated}/>,
sortable: true,
filterConfig: FILTER_CONFIGS.negatedFilterConfig,
editor: (props) => negatedEditor(props)
editor: (props) => <NotEditor props={props} value={props.value} editorChange={onNegatedEditorValueChange}/>
},
{
field: "diseaseAnnotationObject.name",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Toast } from "primereact/toast";
import { MultiSelect } from 'primereact/multiselect';
import { useMutation, useQueryClient } from "react-query";
import { FormErrorMessageComponent } from "../../components/Error/FormErrorMessageComponent";
import { NotEditor } from "../../components/Editors/NotEditor";
import { classNames } from "primereact/utils";
import { DiseaseAnnotationService } from "../../service/DiseaseAnnotationService";
import { Splitter, SplitterPanel } from "primereact/splitter";
Expand Down Expand Up @@ -75,7 +76,7 @@ export const NewAnnotationForm = ({
const geneticModifierRelationTerms = useControlledVocabularyService('disease_genetic_modifier_relation');
const [uiErrorMessages, setUiErrorMessages] = useState({});
const areUiErrors = useRef(false);
const newAnnotationOptionalFields = ["Asserted Genes", "Asserted Allele", "Negated", "With", "Related Notes", "Experimental Conditions", "Experiments", "Genetic Sex",
const newAnnotationOptionalFields = ["Asserted Genes", "Asserted Allele", "NOT", "With", "Related Notes", "Experimental Conditions", "Experiments", "Genetic Sex",
"Disease Qualifiers", "SGD Strain Background", "Annotation Type", "Genetic Modifier Relation", "Genetic Modifiers","Internal"];
let defaultUserSettings = getDefaultFormState("DiseaseAnnotations", newAnnotationOptionalFields, undefined);
const { settings: settingsKey , mutate: setSettingsKey } = useGetUserSettings('DiseaseAnnotationsFormSettings', defaultUserSettings, false);
Expand Down Expand Up @@ -566,22 +567,14 @@ export const NewAnnotationForm = ({
</div>
</div>

{selectedFormFields?.includes("Negated") && (
{selectedFormFields?.includes("NOT") && (
<>
<div className="grid">
<div className={labelColumnSize}>
<label htmlFor="negated">Negated</label>
<label htmlFor="negated">NOT</label>
</div>
<div className={widgetColumnSize}>
<Dropdown
name="negated"
value={newAnnotation.negated}
options={negatedTerms}
optionLabel='text'
optionValue='name'
onChange={onDropdownFieldChange}
className={classNames({'p-invalid': submitted && errorMessages.negated})}
/>
<NotEditor value={newAnnotation.negated} editorChange={onDropdownFieldChange}/>
</div>
<div className={fieldDetailsColumnSize}>
<FormErrorMessageComponent errorMessages={errorMessages} errorField={"negated"}/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ describe("<DiseaseAnnotationsPage />", () => {
const modInternalIdTd = await result.findByText("mockModInternalId");
const subjectTd = await result.findByText(/C57BL\/6J-Rfx3/i);
const relationTd = await result.findByText("is_model_of");
const negatedInternalObsoleteArray = await result.findAllByText("false");
const internalObsoleteArray = await result.findAllByText("false");
const NOTArray = await result.findAllByText("NOT");
const diseaseTd = await result.findByText(/visceral heterotaxy/i);
const referenceTd = await result.findByText(/MGI:5284969/i);
const evidenceCodeTd = await result.findByText(/TAS/i);
Expand All @@ -63,7 +64,8 @@ describe("<DiseaseAnnotationsPage />", () => {
expect(modInternalIdTd).toBeInTheDocument();
expect(subjectTd).toBeInTheDocument();
expect(relationTd).toBeInTheDocument();
expect(negatedInternalObsoleteArray.length).toEqual(3);
expect(internalObsoleteArray.length).toEqual(2);
expect(NOTArray.length).toEqual(2);
expect(diseaseTd).toBeInTheDocument();
expect(referenceTd).toBeInTheDocument();
expect(evidenceCodeTd).toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export const data = {
}
]
},
"negated": false,
"negated": true,
"relation": {
"dateCreated": "2022-01-26T09:40:54.020724Z",
"dateUpdated": "2022-01-26T09:40:54.020726Z",
Expand Down

0 comments on commit 9bccac0

Please sign in to comment.