diff --git a/src/components/Dashboard/EditBulkTerms/EditBulkTermsDialog.jsx b/src/components/Dashboard/EditBulkTerms/EditBulkTermsDialog.jsx index 47eeeb14..4fc33571 100644 --- a/src/components/Dashboard/EditBulkTerms/EditBulkTermsDialog.jsx +++ b/src/components/Dashboard/EditBulkTerms/EditBulkTermsDialog.jsx @@ -87,6 +87,11 @@ const EditBulkTermsDialog = ({ open, handleClose, activeStep, setActiveStep }) = isAllFieldsFilled={isAllFieldsFilled(searchConditions)} /> } + sx={{ + '& .MuiDialogContent-root': { + padding: 0 + } + }} > <> { diff --git a/src/components/Dashboard/EditBulkTerms/SearchTerms.jsx b/src/components/Dashboard/EditBulkTerms/SearchTerms.jsx index d63e13af..5b069152 100644 --- a/src/components/Dashboard/EditBulkTerms/SearchTerms.jsx +++ b/src/components/Dashboard/EditBulkTerms/SearchTerms.jsx @@ -1,16 +1,54 @@ import PropTypes from "prop-types"; +import { useState } from "react"; +import { + Button, + Grid, + Typography, + Box, + ToggleButton, + ToggleButtonGroup, + Divider, + Stack, + FormControlLabel, + RadioGroup +} from "@mui/material"; import DropDownConditions from "./DropDownConditions"; import CustomizedInput from "../../common/CustomizedInput"; import AddOutlinedIcon from "@mui/icons-material/AddOutlined"; import CustomSingleSelect from "../../common/CustomSingleSelect"; import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"; import SearchTermsData from "../../../static/SearchTermsData.json"; -import {Button, Grid, Typography, Box, ToggleButton, ToggleButtonGroup} from "@mui/material"; - +import CustomizedRadio from "../../common/CustomizedRadio"; +import OntologySearch from "../../SingleTermView/OntologySearch"; import { vars } from "../../../theme/variables"; -const { gray800 } = vars; -const SearchTerms = ({searchConditions, setSearchConditions, initialSearchConditions}) => { +const { gray800, gray700 } = vars; + +const Confirmation = { + Yes: "Yes", + No: "No" +} + +const styles = { + title: { + color: gray800, + fontWeight: 600 + }, + subtitle: { + color: gray800, + fontWeight: 500 + }, + radioLabel: { + "& .MuiFormControlLabel-label": { + color: gray700, + fontWeight: 500 + } + }, +} + +const SearchTerms = ({ searchConditions, setSearchConditions, initialSearchConditions }) => { + const [ontologyEditOption, setOntologyEditOption] = useState(Confirmation.No); + const handleTermChange = (index, field, value) => { const newTerms = [...searchConditions]; newTerms[index][field] = value; @@ -37,102 +75,149 @@ const SearchTerms = ({searchConditions, setSearchConditions, initialSearchCondit setSearchConditions([initialSearchConditions]); }; + const handleOntologyEditOptionChange = (event) => { + setOntologyEditOption((event.target).value); + } + const updatedColumnsArray = SearchTermsData.termsColumns.map(item => ({ ...item, value: item.id })); return ( - - + + Search terms, selecting their attributes and values. - {searchConditions.map((term, index) => ( - - - {index === 0 ? ( - - - Where - - - ) : ( - handleConditionChange(event, value, index)} - sx={{ - height: '2.5rem', - }} - > - - And - - - Or - - + + + + + + Do you want to edit a specific ontology? + + } value={Confirmation.Yes} label="Yes" sx={styles.radioLabel}/> + } value={Confirmation.No} label="No" sx={styles.radioLabel} /> + + + + {ontologyEditOption === Confirmation.Yes && ( + + )} + + + + + + Add filters + + {searchConditions.map((term, index) => ( + + + {index === 0 ? ( + + + Where + + + ) : ( + handleConditionChange(event, value, index)} + sx={{ + height: '2.5rem', + }} + > + + And + + + Or + + + )} + + + + + Search for attribute + + handleTermChange(index, 'attribute', v)} + options={updatedColumnsArray} + placeholder='Choose an attribute' + /> + + + + handleTermChange(index, 'relation', value)} + index={index} + handleTermChange={handleTermChange} + /> + + + 1 ? 3 : 4}> + handleTermChange(index, 'value', e.target.value)} + /> + + + {searchConditions.length > 1 && ( + 1 ? 1 : 0}> + + )} - - - Search for attribute - - handleTermChange(index, 'attribute', v)} - options={updatedColumnsArray} - placeholder='Choose an attribute' - /> - - - handleTermChange(index, 'relation', value)} - index={index} - handleTermChange={handleTermChange} - /> - - 1 ? 3 : 4}> - handleTermChange(index, 'value', e.target.value)} - /> - - {searchConditions.length > 1 && ( - 1 ? 1 : 0}> - - - )} - - ))} - - - + ))} + + + + + ); diff --git a/src/components/SingleTermView/OntologySearch.jsx b/src/components/SingleTermView/OntologySearch.jsx index 0c6700d6..93b55b1d 100644 --- a/src/components/SingleTermView/OntologySearch.jsx +++ b/src/components/SingleTermView/OntologySearch.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useRef, useCallback, useMemo } from "react"; import { Box, Button, @@ -13,42 +13,91 @@ import PropTypes from "prop-types"; import ListItem from '@mui/material/ListItem'; import CustomizedRadio from "../common/CustomizedRadio"; import FolderSharedOutlinedIcon from '@mui/icons-material/FolderSharedOutlined'; - import { vars } from "../../theme/variables"; + const { brand600, gray50 } = vars; -const OntologySearch = () => { - const options = [ - { label: 'Nervous system1', badge: 'My Organization 1', selected: false }, - { label: 'Nervous system2', badge: 'ODC-TBI', selected: false }, - { label: 'Nervous system3', badge: 'Dk-net', selected: false }, - { label: 'Nervous system4', badge: 'My Organization 2', selected: false } - ]; +const OPTIONS = [ + { label: 'Nervous system1', badge: 'My Organization 1', selected: false }, + { label: 'Nervous system2', badge: 'ODC-TBI', selected: false }, + { label: 'Nervous system3', badge: 'Dk-net', selected: false }, + { label: 'Nervous system4', badge: 'My Organization 2', selected: false } +]; + +const styles = { + autocomplete: (fullWidth, selectedValue, openList) => ({ + width: fullWidth ? '100%' : '21.75rem', + '& .MuiOutlinedInput-root': { + minWidth: fullWidth ? '100%' : (selectedValue ? '21.75rem' : '11.75rem'), + width: fullWidth ? '100%' : 'fit-content', + borderRadius: openList ? '0.5rem 0.5rem 0 0' : '0.5rem', + }, + '&.Mui-focused': { + transition: 'width 0.100s ease-in-out', + '& .MuiOutlinedInput-root': { + minWidth: fullWidth ? '100%' : '21.75rem', + border: `2px solid ${brand600}`, + background: gray50, + boxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05)', + borderRadius: '.5rem', + }, + '& .MuiOutlinedInput-notchedOutline': { + border: 0, + }, + } + }), + paper: { + borderRadius: '0.5rem', + '& .MuiAutocomplete-option': { + padding: '.06rem .38rem', + height: 'initial', + '& .MuiFormControlLabel-root': { + margin: 0, + '& .MuiTypography-root': { + fontSize: '0.875rem', + }, + '& .MuiButtonBase-root': { + padding: 0, + marginRight: '.5rem', + }, + }, + '&:hover': { + backgroundColor: gray50, + }, + '&[aria-selected="true"]': { + backgroundColor: 'transparent !important', + }, + }, + }, + popperBox: { + borderRadius: '0.5rem', + border: '1px solid #DADDDC', + boxShadow: '0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03)' + } +}; +const OntologySearch = ({ placeholder, fullWidth = false }) => { const [searchTerm, setSearchTerm] = React.useState(''); const [openList, setOpenList] = React.useState(false); const [selectedValue, setSelectedValue] = React.useState(null); const autocompleteRef = useRef(null); const popperRef = useRef(null); - const handleOpenList = () => { + const handleOpenList = useCallback(() => { setOpenList(true); - }; + }, []); - // eslint-disable-next-line no-unused-vars - const handleInputChange = (event, value) => { + const handleInputChange = useCallback((event) => { setSearchTerm(event.target.value); - }; + }, []); - const onSetActive = (event) => { + const onSetActive = useCallback((event) => { event.stopPropagation(); - event.preventDefault(); - console.log("selected value: ", selectedValue) setOpenList(false); - setSelectedValue({ ...selectedValue, selected: true }); - }; + setSelectedValue(prev => prev ? { ...prev, selected: true } : null); + }, []); - const handleClickOutside = (event) => { + const handleClickOutside = useCallback((event) => { if ( autocompleteRef.current && !autocompleteRef.current.contains(event.target) && @@ -57,172 +106,139 @@ const OntologySearch = () => { ) { setOpenList(false); } - }; + }, []); useEffect(() => { document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; + }, [handleClickOutside]); + + const isOptionEqualToValue = useCallback((option, value) => + option.label === value?.label && option.badge === value?.badge, + [] + ); + + const handleChange = useCallback((event, value) => { + setSearchTerm(''); + setSelectedValue(value); }, []); - const isOptionEqualToValue = (option, value) => - option.label === value?.label && option.badge === value?.badge; + const popperProps = useMemo(() => ({ + sx: { + width: fullWidth ? 'auto !important' : '21.75rem !important', + minWidth: fullWidth ? 'auto !important' : '21.75rem !important', + backgroundColor: 'white', + }, + ref: popperRef + }), [fullWidth]); + + const PaperComponent = useMemo(() => { + const Component = ({ children }) => ( + + {children} + + + + + + ); + Component.displayName = 'PaperComponent'; + return Component; + }, [onSetActive]); + + const renderOption = useCallback((props, option) => { + const { key, ...otherProps } = props; + return ( + + + + } + label={option.label} + /> + + + + ); + }, [selectedValue]); + + const renderInput = useCallback((params) => ( + + + + ), + endAdornment: selectedValue?.selected && ( + + + + ), + }} + /> + ), [handleInputChange, placeholder, selectedValue]); return ( -
+
{ - setSearchTerm(''); - setSelectedValue(value); - }} + onChange={handleChange} isOptionEqualToValue={isOptionEqualToValue} - sx={{ - '& .MuiOutlinedInput-root': { - minWidth: selectedValue ? '21.75rem' : '11.75rem', - width: 'fit-content', - borderRadius: openList ? '0.5rem 0.5rem 0 0' : '0.5rem', - }, - '&.Mui-focused': { - transition: 'width 0.100s ease-in-out', - '& .MuiOutlinedInput-root': { - minWidth: '21.75rem', - border: `2px solid ${brand600}`, - background: gray50, - boxShadow: '0px 1px 2px 0px rgba(16, 24, 40, 0.05)', - borderRadius: '.5rem', - }, - '& .MuiOutlinedInput-notchedOutline': { - border: 0, - }, - }, - }} + sx={styles.autocomplete(fullWidth, selectedValue, openList)} autoHighlight={false} componentsProps={{ - popper: { - sx: { - width: '21.75rem !important', - backgroundColor: 'white', - }, - ref: popperRef - }, - paper: { - sx: { - borderRadius: '0.5rem', - '& .MuiAutocomplete-option': { - padding: '.06rem .38rem', - height: 'initial', - '& .MuiFormControlLabel-root': { - margin: 0, - '& .MuiTypography-root': { - fontSize: '0.875rem', - }, - '& .MuiButtonBase-root': { - padding: 0, - marginRight: '.5rem', - }, - }, - '&:hover': { - backgroundColor: gray50, - }, - '&[aria-selected="true"]': { - backgroundColor: 'transparent !important', - }, - }, - }, - }, + popper: popperProps, + paper: { sx: styles.paper }, }} inputValue={searchTerm ? searchTerm : selectedValue?.selected ? selectedValue?.label : ''} - renderOption={(props, option) => { - const { key, ...otherProps } = props; - return ( - - - - } - label={option.label} - /> - - - - ); - }} - renderInput={(params) => ( - - - - ), - endAdornment: selectedValue?.selected && ( - - - - ), - }} - /> - )} - PaperComponent={({ children }) => ( - - {children} - - - - - - )} + renderOption={renderOption} + renderInput={renderInput} + PaperComponent={PaperComponent} />
); }; OntologySearch.propTypes = { + placeholder: PropTypes.string, + fullWidth: PropTypes.bool, key: PropTypes.string, + children: PropTypes.node, }; -export default OntologySearch; +export default OntologySearch; \ No newline at end of file diff --git a/src/components/common/CustomizedRadio.jsx b/src/components/common/CustomizedRadio.jsx index c0159b29..a66dc904 100644 --- a/src/components/common/CustomizedRadio.jsx +++ b/src/components/common/CustomizedRadio.jsx @@ -64,9 +64,9 @@ function BpRadio(props) { ); } -const CustomizedRadio = ({checked}) => { +const CustomizedRadio = ({ checked, ...rest }) => { return ( - + ); } diff --git a/src/theme/index.jsx b/src/theme/index.jsx index 29af2c1c..b166478a 100644 --- a/src/theme/index.jsx +++ b/src/theme/index.jsx @@ -494,6 +494,7 @@ const theme = createTheme({ textPrimary: { color: gray600, background: white, + padding: "0.625rem 0.875rem", "&:hover": { background: gray100, color: gray700,