Skip to content

Commit

Permalink
Merge pull request #612 from kbss-cvut/fix/fta-fmea-ui-227-RE-and-hin…
Browse files Browse the repository at this point in the history
…ts-to-event-properties

Add hints for fault event properties in fault event form FaultEventMenu
  • Loading branch information
blcham authored Oct 3, 2024
2 parents da9881a + db73b68 commit de3e56c
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 67 deletions.
132 changes: 93 additions & 39 deletions src/components/editor/faultTree/menu/faultEvent/FaultEventMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import { useSelectedSystemSummaries } from "@hooks/useSelectedSystemSummaries";
import { useForm } from "react-hook-form";
import UnsavedChangesDialog from "./UnsavedChangesDialog";
import { useAppBar } from "@contexts/AppBarContext";
import { warnIcon } from "@components/Icons";
import { syncProblemIcon, warnIcon } from "@components/Icons";
import HintText from "@components/hintText/HintText";

interface Props {
selectedShapeToolData?: FaultEvent;
outOfSync?: string;
onEventUpdated: (faultEvent: FaultEvent) => void;
refreshTree: () => void;
rootIri?: string;
Expand Down Expand Up @@ -60,7 +62,7 @@ const getFailureRateIris = (supertypes) => {
);
};

const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, rootIri }: Props) => {
const FaultEventMenu = ({ selectedShapeToolData, outOfSync = null, onEventUpdated, refreshTree, rootIri }: Props) => {
const { t } = useTranslation();
const formMethods = useForm();
const { formState, getValues } = formMethods;
Expand Down Expand Up @@ -289,12 +291,68 @@ const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, ro
const basedFailureRate = shapeToolData?.supertypes?.hasFailureRate?.estimate?.value;
const { predictionIri, operationalIri } = getFailureRateIris(shapeToolData?.supertypes?.supertypes);

const FailureRateBox = ({ value, label, rate, selected, outdated }) => (
const propertyLabelWithHint = (propertyKey: string) => {
return (
<Typography className={classes.label}>
{t(propertyKey + ".title")}
<HintText hint={t(propertyKey + ".description")} />:
</Typography>
);
};

const propertyWithValue = (propertyKey: string, value) => {
return (
<>
{propertyLabelWithHint(propertyKey)}
<span style={{ marginLeft: "8px" }} className={classes.notEditableValue}>
{value}
</span>
</>
);
};

const requiredFailureRateComponent = (failureRate, requirementStatusColor, violates) => {
return (
<Box className={classes.eventPropertyRow}>
{propertyLabelWithHint("eventDescription.requiredFailureRate")}
<Box className={[classes.eventPropertyRow, violates ? classes.violated : classes.notEditableValue]}>
<Tooltip title={<span className={classes.hint}>{failureRate}</span>}>
<Typography>{failureRate.toExponential(2)}</Typography>
</Tooltip>
{violates &&
warnIcon(
<span className={classes.hint}>{t("faultEventMessage.requirementViolated")}</span>,
requirementStatusColor,
)}
</Box>
</Box>
);
};

const calculatedFailureRateComponent = (failureRate, failureRateStatusColor, outOfSync) => {
return (
<Box className={classes.eventPropertyRow}>
{propertyLabelWithHint("eventDescription.calculatedFailureRate")}
<Box className={[classes.eventPropertyRow, outOfSync ? classes.outdated : classes.notEditableValue]}>
<Tooltip title={<span className={classes.hint}>{failureRate}</span>}>
<Typography>{failureRate.toExponential(2)}</Typography>
</Tooltip>
{outOfSync &&
syncProblemIcon(
<span className={classes.hint}>{t("faultEventMessage.outOfSyncValue")}</span>,
failureRateStatusColor,
)}
</Box>
</Box>
);
};

const FailureRateBox = ({ value, failureRateKey, rate, selected, outdated }) => (
<Box display="flex" flexDirection="row" alignItems="center">
<FormControlLabel
value={value}
control={<Radio style={{ color: theme.main.black }} />}
label={`${label}:`}
label={propertyLabelWithHint(failureRateKey)}
className={selected ? classes.selected : classes.notSelected}
/>
<Tooltip title={rate}>
Expand All @@ -305,22 +363,34 @@ const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, ro
</Box>
);

const renderFailureRateBox = (rateType, rateValue, iri, selectedRadioButton, labelKey) => {
const renderFailureRateBox = (rateType, rateValue, iri, selectedRadioButton, failureRateKey) => {
const rate =
shapeToolData.probability !== rateValue && shapeToolData?.selectedEstimate?.iri === iri
? shapeToolData.probability
: rateValue;
const selected = selectedRadioButton === rateType;
const outdated = selected && shapeToolData.probability !== rateValue;

return <FailureRateBox value={rateType} label={t(labelKey)} rate={rate} selected={selected} outdated={outdated} />;
const calculatedFailureRateStatusColor = outOfSync ? theme.notSynchronized.color : theme.main.black;

return (
<FailureRateBox
value={rateType}
failureRateKey={failureRateKey}
rate={rate}
selected={selected}
outdated={outdated}
/>
);
};

const violatesRequirement =
shapeToolData?.probability && getRequiredFailureRate() && shapeToolData.probability > getRequiredFailureRate();

const requiredFailureRateStatusColor = violatesRequirement ? theme.requirementViolation.color : theme.main.black;

const calculatedFailureRateStatusColor = outOfSync ? theme.notSynchronized.color : theme.main.black;

return (
<Box paddingLeft={2} marginRight={2}>
<ReusableFaultEventsProvider systemUri={selectedSystem?.iri}>
Expand All @@ -339,20 +409,12 @@ const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, ro
{basedFailureRate && (
<Box className={classes.eventPropertyRow}>
<Typography>
<span className={classes.label}>{t("faultEventMenu.fhaBasedFailureRate")}:</span>
{basedFailureRate.toExponential(2)}
{propertyWithValue("eventDescription.fhaBasedFailureRate", basedFailureRate.toExponential(2))}
</Typography>
</Box>
)}
{getRequiredFailureRate() && (
<Box className={classes.eventPropertyRow} style={{ color: requiredFailureRateStatusColor }}>
<Typography>
<span className={classes.label}>{t("faultEventMenu.requiredFailureRate")}:</span>
{getRequiredFailureRate().toExponential(2)}
</Typography>
{violatesRequirement && warnIcon(t("faultEventMessage.requirementViolated"))}
</Box>
)}
{getRequiredFailureRate() &&
requiredFailureRateComponent(getRequiredFailureRate(), requiredFailureRateStatusColor, violatesRequirement)}
<Divider className={classes.divider} />
</>
)}
Expand All @@ -362,26 +424,24 @@ const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, ro
<>
{shapeToolData?.probability && (
<Box className={classes.eventPropertyRow}>
<Typography>
<span className={classes.label}>{t("faultEventMenu.calculatedFailureRate")}:</span>
{shapeToolData?.probability.toExponential(2)}
</Typography>
{calculatedFailureRateComponent(shapeToolData.probability, calculatedFailureRateStatusColor, outOfSync)}
</Box>
)}

{basedFailureRate && (
<Box className={classes.eventPropertyRow}>
<Typography>
<span className={classes.label}>{t("faultEventMenu.fhaBasedFailureRate")}:</span>
{shapeToolData?.supertypes?.supertypes?.hasFailureRate?.estimate?.value.toExponential(2)}
{propertyWithValue(
"eventDescription.fhaBasedFailureRate",
shapeToolData?.supertypes?.supertypes?.hasFailureRate?.estimate?.value.toExponential(2),
)}
</Typography>
</Box>
)}
{getRequiredFailureRate() && (
<Box className={classes.eventPropertyRow} style={{ color: requiredFailureRateStatusColor }}>
<Typography>
<span className={classes.label}>{t("faultEventMenu.requiredFailureRate")}:</span>
{getRequiredFailureRate().toExponential(2)}
{propertyWithValue("eventDescription.requiredFailureRate", getRequiredFailureRate().toExponential(2))}
</Typography>
{violatesRequirement && warnIcon(t("faultEventMessage.requirementViolated"))}
</Box>
Expand All @@ -395,10 +455,7 @@ const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, ro
<>
{shapeToolData?.probability && (
<Box className={classes.eventPropertyRow}>
<Typography>
<span className={classes.label}>{t("faultEventMenu.calculatedFailureRate")}:</span>
{shapeToolData?.probability.toExponential(2)}
</Typography>
{calculatedFailureRateComponent(shapeToolData.probability, calculatedFailureRateStatusColor, outOfSync)}
</Box>
)}
</>
Expand All @@ -415,21 +472,21 @@ const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, ro
snsPredictedFailureRate,
predictionIri,
selectedRadioButton,
"faultEventMenu.predictedFailureRate",
"eventDescription.predictedFailureRate",
)}
{snsOperationalFailureRate &&
renderFailureRateBox(
RadioButtonType.Operational,
snsOperationalFailureRate,
operationalIri,
selectedRadioButton,
"faultEventMenu.operationalFailureRate",
"eventDescription.operationalFailureRate",
)}
<Box display={"flex"} flexDirection={"row"} alignItems="center">
<FormControlLabel
value={RadioButtonType.Manual}
control={snsOperationalFailureRate || snsPredictedFailureRate ? <Radio /> : <></>}
label={`${t("faultEventMenu.manuallyDefinedFailureRate")}:`}
label={propertyLabelWithHint("eventDescription.manuallyDefinedFailureRate")}
className={selectedRadioButton === RadioButtonType.Manual ? classes.selected : classes.notSelected}
// Compensate the removal of the radio button, 16px is the MUI <Box /> default left padding
sx={snsOperationalFailureRate || snsPredictedFailureRate ? {} : { pl: "16px" }}
Expand All @@ -455,7 +512,9 @@ const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, ro
{/* EXTERNAL NODE */}
{shapeToolData && shapeToolData.eventType === EventType.EXTERNAL && !shapeToolData.isReference && (
<Box className={classes.eventPropertyRow}>
<Typography className={classes.label}>{`${t("faultEventMenu.manuallyDefinedFailureRate")}:`}</Typography>
<Typography className={classes.label}>
{propertyLabelWithHint("eventDescription.manuallyDefinedFailureRate")}
</Typography>
<TextField
className={classes.numberInput}
InputLabelProps={{ shrink: false }}
Expand All @@ -478,12 +537,7 @@ const FaultEventMenu = ({ selectedShapeToolData, onEventUpdated, refreshTree, ro
{shapeToolData && (
<EventFailureModeProvider eventIri={shapeToolData?.iri}>
<Box>
{criticality && (
<Typography>
<span className={classes.label}>{t("faultEventMenu.criticality")}:</span>
<span className={classes.notEditableValue}>{criticality}</span>
</Typography>
)}
{criticality && <Typography>{propertyWithValue("eventDescription.severity", criticality)}</Typography>}
{ataSystem && (
<Typography>
<span className={classes.label}>{t("faultEventMenu.ataSystem")}:</span>
Expand Down
18 changes: 5 additions & 13 deletions src/components/hintText/HintText.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,12 @@ import { makeStyles } from "tss-react/mui";
import { Theme } from "@mui/material";

const useStyles = makeStyles()((theme: Theme) => ({
container: {
width: "100%",
},
innerContainer: {
position: "relative",
display: "inline-block",
},
toolTip: {
position: "absolute",
top: -6,
right: -16,
},
hintFont: {
fontSize: 12,
fontSize: 16,
},
helpIcon: {
transform: "scale(0.88)",
color: "#777777",
},
}));

Expand Down
21 changes: 6 additions & 15 deletions src/components/hintText/HintText.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
import React from "react";
import { Typography, IconButton, Tooltip } from "@mui/material";
import QuestionMarkIcon from "@mui/icons-material/QuestionMark";
import { Tooltip } from "@mui/material";
import useStyles from "./HintText.styles";
import { HelpOutline } from "@mui/icons-material";

interface HintTextProps {
text: string;
hint: string;
}

const HintText: React.FC<HintTextProps> = ({ text, hint }) => {
const HintText: React.FC<HintTextProps> = ({ hint }) => {
const { classes } = useStyles();
return (
<div className={classes.container}>
<div className={classes.innerContainer}>
<Typography variant="body1">{text}</Typography>
<div className={classes.toolTip}>
<Tooltip title={hint} arrow placement="bottom">
<IconButton size="small" aria-label="hint">
<QuestionMarkIcon className={classes.hintFont} />
</IconButton>
</Tooltip>
</div>
</div>
</div>
<Tooltip title={<span className={classes.hintFont}>{hint}</span>} arrow placement="bottom">
<HelpOutline className={classes.helpIcon} />
</Tooltip>
);
};

Expand Down
3 changes: 3 additions & 0 deletions src/styles/App.styles.declarations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ declare module "@mui/material/styles" {
requirementViolation?: {
color: COLOR;
};
hint?: {
fontSize: number;
};
}
// allow configuration using `createMuiTheme`
interface DeprecatedThemeOptions {
Expand Down
3 changes: 3 additions & 0 deletions src/styles/App.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@ export const appTheme = createCustomMuiTheme({
requirementViolation: {
color: "#FF0000",
},
hint: {
fontSize: 16,
},
});

0 comments on commit de3e56c

Please sign in to comment.