Skip to content

Commit

Permalink
Merge pull request #618 from kbss-cvut/fix/out-of-synch-and-requireme…
Browse files Browse the repository at this point in the history
…nt-violation

Fix/out of synch and requirement violation
  • Loading branch information
kostobog authored Oct 8, 2024
2 parents 9977fe5 + c420c78 commit 477683b
Show file tree
Hide file tree
Showing 12 changed files with 191 additions and 79 deletions.
2 changes: 2 additions & 0 deletions public/locales/cs/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
},
"faultEventMessage": {
"outOfSyncValue": "Hodnota je zastaralá!",
"referencedValueOutdated": "Referenční hodnota byla změněna. Hodnota bude aktualizována při vyhodnocení stromu",
"experimental": "Min. provozní hodiny (MOH) poruchoveho stromu se liší od MOH jeho systému",
"requirementViolated": "Vypočtená intenzita poruch je větší, než je požadováno!"
},
"faultTreeOverviewTable": {
Expand Down
2 changes: 2 additions & 0 deletions public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
},
"faultEventMessage": {
"outOfSyncValue": "The value is outdated!",
"referencedValueOutdated": "The referenced value has changed. The value will be updated on tree evaluation.",
"experimental": "Fault tree's min. operational hours (MOH) is different from its system's MOH",
"requirementViolated": "Calculated failure rate is bigger than required!"
},
"faultTreeOverviewTable": {
Expand Down
22 changes: 16 additions & 6 deletions src/components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@ import { SyncProblem, Warning } from "@mui/icons-material";
import { Tooltip } from "@mui/material";
import React from "react";

export const warnIcon = (message: string) => {
return iconWithMessage(<Warning transform={"scale(0.9)"} />, message);
const transform = "scale(0.88)";

export const warnIcon = (message: any) => {
return iconWithMessage(<Warning transform={transform} />, message);
};

export const syncProblemIcon = (message: string) => {
return iconWithMessage(<SyncProblem transform={"scale(0.9)"} />, message);
export const syncProblemIcon = (message: any, messageCount = 1) => {
return iconWithMessage(
<SyncProblem transform={transform} />,
message,
messageCount && messageCount > 1 ? messageCount : null,
);
};

export const iconWithMessage = (icon, message: string) => {
return <Tooltip title={message}>{icon}</Tooltip>;
export const iconWithMessage = (icon, message: any, label: string | number = "") => {
return (
<Tooltip title={message}>
{icon} {<span style={{ verticalAlign: "top", position: "fixed" }}>{label}</span>}
</Tooltip>
);
};
2 changes: 2 additions & 0 deletions src/components/editor/faultTree/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { JOINTJS_NODE_MODEL } from "@components/editor/faultTree/shapes/constant
import { FaultEventScenario } from "@models/faultEventScenario";
import { useAppBar } from "@contexts/AppBarContext";
import { asArray } from "@utils/utils";
import { getFaultTreeCalculationStatus } from "@models/faultTreeModel";

const Editor = () => {
const history = useNavigate();
Expand Down Expand Up @@ -237,6 +238,7 @@ const Editor = () => {
{faultTree && (
<EditorCanvas
treeName={faultTree?.name}
faultTreeStatus={getFaultTreeCalculationStatus(faultTree)}
rootEvent={rootEvent}
onEventUpdated={handleEventUpdate}
sidebarSelectedEvent={sidebarSelectedEvent}
Expand Down
4 changes: 4 additions & 0 deletions src/components/editor/faultTree/canvas/EditorCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { calculateCutSets } from "@services/faultTreeService";
import { SnackbarType, useSnackbar } from "@hooks/useSnackbar";
import { useNavigate } from "react-router-dom";
import { useAppBar } from "@contexts/AppBarContext";
import { FaultTreeStatus } from "@models/faultTreeModel";

enum MOVE_NODE {
DRAGGING = 0,
Expand All @@ -35,6 +36,7 @@ enum MOVE_NODE {

interface Props {
treeName: string;
faultTreeStatus?: FaultTreeStatus;
rootEvent: FaultEvent;
sidebarSelectedEvent: FaultEvent;
onElementContextMenu: (element: any, evt: any) => void;
Expand All @@ -56,6 +58,7 @@ interface Props {

const EditorCanvas = ({
treeName,
faultTreeStatus = false,
rootEvent,
sidebarSelectedEvent,
onElementContextMenu,
Expand Down Expand Up @@ -357,6 +360,7 @@ const EditorCanvas = ({
{!showTable && (
<FaultEventMenu
selectedShapeToolData={sidebarSelectedEvent}
faultTreeStatus={faultTreeStatus}
onEventUpdated={onEventUpdated}
refreshTree={refreshTree}
rootIri={rootEvent?.iri}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,17 @@ const useStyles = makeStyles()((theme: Theme) => ({
color: theme.main.grey,
},
outdated: {
color: theme.main.orange,
color: theme.notSynchronized.color,
alignItems: "baseline",
"&.Mui-checked": {
color: theme.main.orange,
color: theme.notSynchronized.color,
},
},
violated: {
color: theme.requirementViolation.color,
alignItems: "baseline",
"&.Mui-checked": {
color: theme.requirementViolation.color,
},
},
divider: {
Expand All @@ -48,6 +56,9 @@ const useStyles = makeStyles()((theme: Theme) => ({
padding: "8px 12px",
},
},
hint: {
fontSize: 16,
},
}));

export default useStyles;
141 changes: 76 additions & 65 deletions src/components/editor/faultTree/menu/faultEvent/FaultEventMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ import UnsavedChangesDialog from "./UnsavedChangesDialog";
import { useAppBar } from "@contexts/AppBarContext";
import { syncProblemIcon, warnIcon } from "@components/Icons";
import HintText from "@components/hintText/HintText";
import { calculationStatusMessages } from "@components/fta/FTAStatus";
import { FaultTreeStatus } from "@models/faultTreeModel";

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

const FaultEventMenu = ({ selectedShapeToolData, outOfSync = null, onEventUpdated, refreshTree, rootIri }: Props) => {
const FaultEventMenu = ({
selectedShapeToolData,
faultTreeStatus = null,
onEventUpdated,
refreshTree,
rootIri,
}: Props) => {
const { t } = useTranslation();
const formMethods = useForm();
const { formState, getValues } = formMethods;
Expand Down Expand Up @@ -288,62 +296,76 @@ const FaultEventMenu = ({ selectedShapeToolData, outOfSync = null, onEventUpdate
const basedFailureRate = shapeToolData?.supertypes?.hasFailureRate?.estimate?.value;
const { predictionIri, operationalIri } = getFailureRateIris(shapeToolData?.supertypes?.supertypes);

const isReferenceProbabilityOutdated = (shapeToolData: FaultEvent) => {
return (
(shapeToolData?.references?.probability || shapeToolData?.references?.probability === 0) &&
shapeToolData?.probability !== shapeToolData?.references?.probability
);
};

const propertyLabelWithHint = (propertyKey: string) => {
return (
<Typography className={classes.label}>
<span className={classes.label}>
{t(propertyKey + ".title")}
<HintText hint={t(propertyKey + ".description")} />:
</Typography>
</span>
);
};

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

const numberValue = (value, cls = classes.notEditableValue) => {
return <Tooltip title={<span className={classes.hint}>{value}</span>}>{value.toExponential(2)}</Tooltip>;
};

const requiredFailureRateComponent = (failureRate, requirementStatusColor, violates) => {
const cls = violates ? classes.violated : classes.notEditableValue;
return (
<Box className={classes.eventPropertyRow}>
<Typography 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>
<Box className={[classes.eventPropertyRow, cls]}>
{numberValue(failureRate)}
{violates &&
warnIcon(
<span className={classes.hint}>{t("faultEventMessage.requirementViolated")}</span>,
requirementStatusColor,
)}
warnIcon(calculationStatusMessages("faultEventMessage.requirementViolated", t), requirementStatusColor)}
</Box>
</Box>
</Typography>
);
};

const calculatedFailureRateComponent = (failureRate, failureRateStatusColor, outOfSync) => {
const failureRateComponent = (failureRate, failureRateCode, statusCodes: string[] = []) => {
const isOutOfSync = statusCodes && statusCodes.length > 0;
const cls = isOutOfSync ? classes.outdated : classes.notEditableValue;
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,
)}
<Typography className={classes.eventPropertyRow}>
{propertyLabelWithHint(failureRateCode)}
<Box className={[classes.eventPropertyRow, cls]}>
{numberValue(failureRate)}
{isOutOfSync && syncProblemIcon(calculationStatusMessages(statusCodes, t), statusCodes.length)}
</Box>
</Box>
</Typography>
);
};

const fhaFailureRateComponent = (failureRate, failureRateStatusColor, faultTreeStatus: FaultTreeStatus) => {
return failureRateComponent(
failureRate,
"eventDescription.fhaBasedFailureRate",
failureRateStatusColor,
faultTreeStatus,
);
};

const calculatedFailureRateComponent = (failureRate, failureRateStatusColor, statusCodes: string[]) => {
return failureRateComponent(failureRate, "eventDescription.calculatedFailureRate", statusCodes);
};

const FailureRateBox = ({ value, failureRateKey, rate, selected, outdated }) => (
<Box display="flex" flexDirection="row" alignItems="center">
<FormControlLabel
Expand All @@ -352,7 +374,7 @@ const FaultEventMenu = ({ selectedShapeToolData, outOfSync = null, onEventUpdate
label={propertyLabelWithHint(failureRateKey)}
className={selected ? classes.selected : classes.notSelected}
/>
<Tooltip title={rate}>
<Tooltip title={<span className={classes.hint}>{rate}</span>}>
<Typography className={outdated ? classes.outdated : classes.notEditableValue}>
{rate.toExponential(2)}
</Typography>
Expand All @@ -368,8 +390,6 @@ const FaultEventMenu = ({ selectedShapeToolData, outOfSync = null, onEventUpdate
const selected = selectedRadioButton === rateType;
const outdated = selected && shapeToolData.probability !== rateValue;

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

return (
<FailureRateBox
value={rateType}
Expand All @@ -386,7 +406,7 @@ const FaultEventMenu = ({ selectedShapeToolData, outOfSync = null, onEventUpdate

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

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

return (
<Box paddingLeft={2} marginRight={2}>
Expand All @@ -399,60 +419,51 @@ const FaultEventMenu = ({ selectedShapeToolData, outOfSync = null, onEventUpdate
{/* ROOT NODE */}
{shapeToolData && shapeToolData.iri === rootIri && (
<>
<Typography className={classes.eventPropertyRow}>
<span className={classes.label}>{`${t("faultEventMenu.eventName")}: `}</span>
{shapeToolData.name}
</Typography>
{basedFailureRate && (
<Box className={classes.eventPropertyRow}>
<Typography>
{propertyWithValue("eventDescription.fhaBasedFailureRate", basedFailureRate.toExponential(2))}
</Typography>
</Box>
<Box className={classes.eventPropertyRow}>{fhaFailureRateComponent(basedFailureRate, null, null)}</Box>
)}
{getRequiredFailureRate() &&
requiredFailureRateComponent(getRequiredFailureRate(), requiredFailureRateStatusColor, violatesRequirement)}
{shapeToolData?.probability && (
<Box className={classes.eventPropertyRow}>
{calculatedFailureRateComponent(
shapeToolData.probability,
calculatedFailureRateStatusColor,
faultTreeStatus.statusCodes,
)}
</Box>
)}
<Divider className={classes.divider} />
</>
)}

{/* EXTERNAL NODE */}
{shapeToolData && shapeToolData.eventType === EventType.EXTERNAL && shapeToolData.isReference && (
<>
{shapeToolData?.probability && (
<Box className={classes.eventPropertyRow}>
{calculatedFailureRateComponent(shapeToolData.probability, calculatedFailureRateStatusColor, outOfSync)}
</Box>
)}

{basedFailureRate && (
<Box className={classes.eventPropertyRow}>
<Typography>
{propertyWithValue(
"eventDescription.fhaBasedFailureRate",
shapeToolData?.supertypes?.supertypes?.hasFailureRate?.estimate?.value.toExponential(2),
)}
</Typography>
</Box>
<Box className={classes.eventPropertyRow}>{fhaFailureRateComponent(basedFailureRate, null, null)}</Box>
)}
{getRequiredFailureRate() && (
<Box className={classes.eventPropertyRow} style={{ color: requiredFailureRateStatusColor }}>
<Typography>
{propertyWithValue("eventDescription.requiredFailureRate", getRequiredFailureRate().toExponential(2))}
</Typography>
{violatesRequirement && warnIcon(t("faultEventMessage.requirementViolated"))}
{getRequiredFailureRate() &&
requiredFailureRateComponent(getRequiredFailureRate(), requiredFailureRateStatusColor, violatesRequirement)}
{shapeToolData?.probability && (
<Box className={classes.eventPropertyRow}>
{calculatedFailureRateComponent(
shapeToolData.probability,
null,
isReferenceProbabilityOutdated(shapeToolData) ? ["faultEventMessage.referencedValueOutdated"] : [],
)}
</Box>
)}
<Divider className={classes.divider} />
</>
)}

{/* INTERMEDIATE NODE */}
{shapeToolData && shapeToolData.eventType === EventType.INTERMEDIATE && (
{shapeToolData && shapeToolData.eventType === EventType.INTERMEDIATE && shapeToolData.iri !== rootIri && (
<>
{shapeToolData?.probability && (
<Box className={classes.eventPropertyRow}>
{calculatedFailureRateComponent(shapeToolData.probability, calculatedFailureRateStatusColor, outOfSync)}
{failureRateComponent(shapeToolData.probability, theme.main.black, [])}
</Box>
)}
</>
Expand Down
18 changes: 18 additions & 0 deletions src/components/fta/FTAStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from "react";
import { asArray } from "@utils/utils";
import { Typography } from "@mui/material";

export const calculationStatusMessages = (statusCodes: string[], t: any) => {
const _statusCodes = asArray(statusCodes);
return _statusCodes.length > 1 ? (
<ul style={{ fontSize: 16, margin: "0px", paddingInlineStart: "25px", paddingInlineEnd: "0px" }}>
{_statusCodes.map((c) => (
<li key={c}>{t(c)}</li>
))}
</ul>
) : _statusCodes.length == 1 ? (
<Typography style={{ margin: "0px", paddingInlineStart: "20px", paddingInlineEnd: "0px", textAlign: "start" }}>
{t(_statusCodes[0])}
</Typography>
) : null;
};
3 changes: 3 additions & 0 deletions src/components/table/FaultTreeOverviewTable.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ const useStyles = makeStyles()((theme: Theme) => ({
systemFirstColumn: {
...commonCellStyle,
},
hint: {
fontSize: 16,
},
}));

export default useStyles;
Loading

0 comments on commit 477683b

Please sign in to comment.