Skip to content

Commit

Permalink
Merge pull request #348 from MetaCell/feature/SCKAN-326
Browse files Browse the repository at this point in the history
extra graph styling
  • Loading branch information
ddelpiano authored Dec 8, 2024
2 parents beb38bd + 65eb695 commit acae898
Show file tree
Hide file tree
Showing 29 changed files with 2,292 additions and 678 deletions.
6 changes: 6 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/user-event": "13.5.0",
"@types/dagre": "^0.7.52",
"axios": "1.2.4",
"dagre": "^0.8.5",
"jest": "^28.1.0",
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/Pages/SentenceDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ const SentencesDetails = () => {
<Grid item xs={12} mb={4}>
<Grid container>
<Grid item xs={12} md={6}>
<Box>
<Box ref={refs[0]}>
<Typography variant="h3" mb={1}>
Sentence Details #{sentenceId}{" "}
<span>
Expand Down Expand Up @@ -296,7 +296,7 @@ const SentencesDetails = () => {
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Box ref={refs[0]}>
<Box>
<Paper sx={{ mb: 2, ...sectionStyle }}>
<Grid container>
<Grid item xs={12}>
Expand Down
51 changes: 48 additions & 3 deletions frontend/src/Pages/StatementDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ import {ViaIcon, DestinationIcon, OriginIcon} from "../components/icons";
import {CircularProgress} from "@mui/material";
import {checkOwnership, getOwnershipAlertMessage} from "../helpers/ownershipAlert";
import {ChangeRequestStatus} from "../helpers/settings";
import {useDispatch, useSelector} from "react-redux";
import {RootState} from "../redux/store";
import ConfirmationDialog from "../components/ConfirmationDialog";
import {CONFIRMATION_DIALOG_CONFIG} from "../settings";
import {setDialogState, setPositionChangeOnly, setWasChangeDetected} from "../redux/statementSlice";

const StatementDetails = () => {
const {statementId} = useParams();
Expand All @@ -43,6 +48,10 @@ const StatementDetails = () => {
const [activeTab, setActiveTab] = useState(0);
const [selectedIndex, setSelectedIndex] = React.useState(0);
const [refetch, setRefetch] = useState(false);
const [isNavigateDialogOpen, setIsNavigateDialogOpen] = useState(false);
const dispatch = useDispatch();
const dialogsState = useSelector((state: RootState) => state.statement.dialogs);

const refs = [
useRef<HTMLElement | null>(null),
useRef<HTMLElement | null>(null),
Expand All @@ -53,7 +62,33 @@ const StatementDetails = () => {
useRef<HTMLElement | null>(null),
useRef<HTMLElement | null>(null),
];

const wasChangeDetected = useSelector((state: RootState) => state.statement.wasChangeDetected);
const positionChangeOnly = useSelector((state: RootState) => state.statement.positionChangeOnly);
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
if (dialogsState.navigate) {
setActiveTab(newValue);
dispatch(setWasChangeDetected(false));
dispatch(setPositionChangeOnly(false));
return;
}
if (wasChangeDetected || positionChangeOnly) {
setIsNavigateDialogOpen(true);
} else {
setActiveTab(newValue);
}
};

const handleNavigateConfirm = () => {
setIsNavigateDialogOpen(false);
setActiveTab(0)
dispatch(setWasChangeDetected(false));
dispatch(setPositionChangeOnly(false));
};

const handleNavigateCancel = () => {
setIsNavigateDialogOpen(false);
};

const scrollToElement = (index: number) => {
const element = refs[index].current;
if (element) {
Expand Down Expand Up @@ -226,7 +261,7 @@ const StatementDetails = () => {
<Grid item xs={12} mb={4}>
<Grid container>
<Grid item xs={12} md={6}>
<Box>
<Box ref={refs[0]}>
<Typography variant="h3" mb={1}>
Statement Details #{statementId}{" "}
<span>
Expand Down Expand Up @@ -279,7 +314,7 @@ const StatementDetails = () => {
<Tabs
value={activeTab}
variant="standard"
onChange={(e, i: number) => setActiveTab(i)}
onChange={handleTabChange}
sx={{
borderBottom: "1px solid #EAECF0",
}}
Expand Down Expand Up @@ -351,6 +386,16 @@ const StatementDetails = () => {
</Grid>
</>
)}
<ConfirmationDialog
open={isNavigateDialogOpen}
onConfirm={handleNavigateConfirm}
onCancel={handleNavigateCancel}
title={CONFIRMATION_DIALOG_CONFIG.Navigate.title}
confirmationText={CONFIRMATION_DIALOG_CONFIG.Navigate.confirmationText}
Icon={<CONFIRMATION_DIALOG_CONFIG.Navigate.Icon />}
dontShowAgain={dialogsState.navigate}
setDontShowAgain={() => dispatch(setDialogState({ dialogKey: "navigate", dontShow: true }))}
/>
</Grid>
);
};
Expand Down
87 changes: 87 additions & 0 deletions frontend/src/components/ConfirmationDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {Button, Dialog, DialogActions, DialogContent, DialogTitle, FormControlLabel, IconButton, Typography} from "@mui/material";
import React from "react";
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import Stack from "@mui/material/Stack";
import { vars } from "../theme/variables";
import CustomCheckBox from "./CustomCheckBox";
const ConfirmationDialog = ({
open, onConfirm, onCancel, title, confirmationText, Icon, dontShowAgain, setDontShowAgain
}: {
open: boolean,
onConfirm: () => void,
onCancel: () => void,
title: string,
confirmationText: string,
Icon: React.ReactNode,
dontShowAgain?: boolean;
setDontShowAgain?: (checked: boolean) => void;
}) => {
return (
<Dialog open={open} onClose={onCancel} PaperProps={{
sx: {
width: '25rem',
padding: '1.5rem'
}
}}>
<DialogTitle sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
p: 0,
mb: '1rem',

'& .MuiButtonBase-root': {
p: 0,
'& .MuiSvgIcon-root': {
color: vars.iconPrimaryColor
}
}
}}>
{Icon}
<IconButton onClick={onCancel}>
<CloseRoundedIcon />
</IconButton>
</DialogTitle>
<DialogContent sx={{
p: 0,
mb: '2rem'
}}>
<Stack spacing='.25rem' mb='1.25rem'>
<Typography variant='h4'>
{title}
</Typography>
<Typography variant='body2' color={vars.gray600}>
{confirmationText}
</Typography>
</Stack>
<FormControlLabel
sx={{ml: 0}}
control={
<CustomCheckBox
checked={dontShowAgain || false}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setDontShowAgain?.(e.target.checked)}
/>
}
label="Don't show this again for this session." />
</DialogContent>
<DialogActions sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
p: 0,
'& .MuiButtonBase-root': {
fontSize: '1rem'
}
}}>
<Button fullWidth onClick={onCancel} color="secondary" variant='outlined'>
Cancel
</Button>
<Button fullWidth onClick={onConfirm} color="primary" variant='contained'>
Proceed
</Button>
</DialogActions>
</Dialog>
)
}

export default ConfirmationDialog;
79 changes: 79 additions & 0 deletions frontend/src/components/CustomCheckBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from "react";

import Checkbox, { CheckboxProps } from '@mui/material/Checkbox';
import { styled } from "@mui/material/styles";
import {vars} from "../theme/variables";

const {
colorPrimary,
lightBlue,
radioBorderColor
} = vars;

const BpIcon = styled('span')(() => ({
borderRadius: 6,
width: 20,
height: 20,
boxShadow:`inset 0 0 0 0.0625rem ${radioBorderColor}, inset 0 -1px 0 ${radioBorderColor}`,

'input:hover ~ &': {
backgroundColor: lightBlue,
boxShadow:`inset 0 0 0 0.0625rem ${colorPrimary}, inset 0 -0.0625rem 0 ${colorPrimary}`,
},

'.Mui-focusVisible &': {
outline: `0.125rem auto ${lightBlue}`,
outlineOffset: 2,
},
'.Mui-checked &': {
boxShadow:`inset 0 0 0 0.0625rem ${colorPrimary}, inset 0 -0.0625rem 0 ${colorPrimary}`,
},

'input:disabled ~ &': {
boxShadow: 'none',
background: colorPrimary,
},
}));

const BpCheckedIcon = styled(BpIcon)({
backgroundColor: lightBlue,
'&:before': {
display: 'block',
width: 16,
height: 16,
marginTop: '10%',
marginRight: 'auto',
marginLeft: 'auto',
backgroundImage: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M10 3L4.5 8.5L2 6' stroke='%233779E1' stroke-width='1.6666' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\")",
content: '""',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
},
'input:hover ~ &': {
backgroundColor: lightBlue,
},
});

function BpCheckbox(props: CheckboxProps) {
return (
<Checkbox
sx={{
'&:hover': { bgcolor: 'transparent' },
}}
disableRipple
color="default"
checkedIcon={<BpCheckedIcon />}
icon={<BpIcon />}
inputProps={{ 'aria-label': 'Checkbox demo' }}
{...props}
/>
);
}

const CheckBoxWidget = ({ checked = false, onChange }: { checked?: boolean; onChange: (e: React.ChangeEvent<HTMLInputElement>) => void }) => {
return (
<BpCheckbox checked={checked} onChange={onChange}/>
);
};

export default CheckBoxWidget;
89 changes: 89 additions & 0 deletions frontend/src/components/CustomSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';
import { Tooltip } from '@mui/material';

const MaterialUISwitch = styled(Switch)(() => ({
width: 44,
height: 24,
padding: 2,
margin: '0 !important',
'& .MuiSwitch-switchBase': {
margin: 2.7,
'&.Mui-disabled': {
'& + .MuiSwitch-track': {
opacity: .8,
cursor: 'default'
}
},
'&.Mui-checked': {
'& .MuiSwitch-thumb:before': {
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" width="14" viewBox="0 0 14 14"><path fill="${encodeURIComponent(
'#8300BF',
)}" d="M10.5002 4.95833H9.91683V3.79167C9.91683 2.18167 8.61016 0.875 7.00016 0.875C5.39016 0.875 4.0835 2.18167 4.0835 3.79167V4.95833H3.50016C2.8585 4.95833 2.3335 5.48333 2.3335 6.125V11.9583C2.3335 12.6 2.8585 13.125 3.50016 13.125H10.5002C11.1418 13.125 11.6668 12.6 11.6668 11.9583V6.125C11.6668 5.48333 11.1418 4.95833 10.5002 4.95833ZM5.25016 3.79167C5.25016 2.82333 6.03183 2.04167 7.00016 2.04167C7.9685 2.04167 8.75016 2.82333 8.75016 3.79167V4.95833H5.25016V3.79167ZM10.5002 11.9583H3.50016V6.125H10.5002V11.9583ZM7.00016 10.2083C7.64183 10.2083 8.16683 9.68333 8.16683 9.04167C8.16683 8.4 7.64183 7.875 7.00016 7.875C6.3585 7.875 5.8335 8.4 5.8335 9.04167C5.8335 9.68333 6.3585 10.2083 7.00016 10.2083Z"/></svg>')`,
},
'& + .MuiSwitch-track': {
opacity: 1,
backgroundColor: '#8300BF',
},
},
'&:hover': {
'& .MuiSwitch-thumb:before': {
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" width="14" viewBox="0 0 14 14"><path fill="${encodeURIComponent(
'#6C707A',
)}" d="M10.5002 4.95833H9.91683V3.79167C9.91683 2.18167 8.61016 0.875 7.00016 0.875C5.39016 0.875 4.0835 2.18167 4.0835 3.79167V4.95833H3.50016C2.8585 4.95833 2.3335 5.48333 2.3335 6.125V11.9583C2.3335 12.6 2.8585 13.125 3.50016 13.125H10.5002C11.1418 13.125 11.6668 12.6 11.6668 11.9583V6.125C11.6668 5.48333 11.1418 4.95833 10.5002 4.95833ZM5.25016 3.79167C5.25016 2.82333 6.03183 2.04167 7.00016 2.04167C7.9685 2.04167 8.75016 2.82333 8.75016 3.79167V4.95833H5.25016V3.79167ZM10.5002 11.9583H3.50016V6.125H10.5002V11.9583ZM7.00016 10.2083C7.64183 10.2083 8.16683 9.68333 8.16683 9.04167C8.16683 8.4 7.64183 7.875 7.00016 7.875C6.3585 7.875 5.8335 8.4 5.8335 9.04167C5.8335 9.68333 6.3585 10.2083 7.00016 10.2083Z"/></svg>')`,
},
'&.Mui-checked': {
'& .MuiSwitch-thumb:before': {
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" width="14" viewBox="0 0 14 14"><path fill="${encodeURIComponent(
'#5E008A',
)}" d="M10.5002 4.95833H9.91683V3.79167C9.91683 2.18167 8.61016 0.875 7.00016 0.875C5.39016 0.875 4.0835 2.18167 4.0835 3.79167V4.95833H3.50016C2.8585 4.95833 2.3335 5.48333 2.3335 6.125V11.9583C2.3335 12.6 2.8585 13.125 3.50016 13.125H10.5002C11.1418 13.125 11.6668 12.6 11.6668 11.9583V6.125C11.6668 5.48333 11.1418 4.95833 10.5002 4.95833ZM5.25016 3.79167C5.25016 2.82333 6.03183 2.04167 7.00016 2.04167C7.9685 2.04167 8.75016 2.82333 8.75016 3.79167V4.95833H5.25016V3.79167ZM10.5002 11.9583H3.50016V6.125H10.5002V11.9583ZM7.00016 10.2083C7.64183 10.2083 8.16683 9.68333 8.16683 9.04167C8.16683 8.4 7.64183 7.875 7.00016 7.875C6.3585 7.875 5.8335 8.4 5.8335 9.04167C5.8335 9.68333 6.3585 10.2083 7.00016 10.2083Z"/></svg>')`,
},
'& + .MuiSwitch-track': {
opacity: 1,
backgroundColor: '#5E008A',
},
},
}
},
'& .MuiSwitch-thumb': {
backgroundColor: '#fff',
width: 18,
height: 18,
boxShadow: '0px 1px 3px 0px rgba(16, 24, 40, 0.10), 0px 1px 2px 0px rgba(16, 24, 40, 0.06)',
'&::before': {
content: "''",
position: 'absolute',
width: '100%',
height: '100%',
left: 0,
top: 0,
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="14" width="14" viewBox="0 0 14 14"><path fill="${encodeURIComponent(
'#818898',
)}" d="M10.5007 4.95833H9.91732V3.79167C9.91732 2.18167 8.61065 0.875 7.00065 0.875C5.39065 0.875 4.08398 2.18167 4.08398 3.79167H5.25065C5.25065 2.82333 6.03232 2.04167 7.00065 2.04167C7.96898 2.04167 8.75065 2.82333 8.75065 3.79167V4.95833H3.50065C2.85898 4.95833 2.33398 5.48333 2.33398 6.125V11.9583C2.33398 12.6 2.85898 13.125 3.50065 13.125H10.5007C11.1423 13.125 11.6673 12.6 11.6673 11.9583V6.125C11.6673 5.48333 11.1423 4.95833 10.5007 4.95833ZM10.5007 11.9583H3.50065V6.125H10.5007V11.9583ZM7.00065 10.2083C7.64232 10.2083 8.16732 9.68333 8.16732 9.04167C8.16732 8.4 7.64232 7.875 7.00065 7.875C6.35898 7.875 5.83398 8.4 5.83398 9.04167C5.83398 9.68333 6.35898 10.2083 7.00065 10.2083Z"/></svg>')`,
},
},
'& .MuiSwitch-track': {
opacity: 1,
backgroundColor: '#EDEFF2',
borderRadius: 20 / 2,
},
}));

const CustomizedSwitches = ({locked, setLocked, disabled}: {locked: boolean, setLocked: (locked: boolean) => void, disabled: boolean})=> {
return (
<FormControlLabel
control={
<Tooltip arrow title={locked ? 'The diagram is locked and saved. You cannot change the positions of the entities' : 'The diagram is unlocked. You can move the population entities freely. Lock to persist.'}>
<MaterialUISwitch disabled={disabled} sx={{ m: 1 }} checked={locked} onClick={() => setLocked(!locked)} />
</Tooltip>
}
label=""
/>
);
}

export default CustomizedSwitches
Loading

0 comments on commit acae898

Please sign in to comment.