diff --git a/.env b/.env index c28008f..3750ccc 100644 --- a/.env +++ b/.env @@ -121,6 +121,11 @@ REACT_APP_PVWS_ALLOW_WAVEFORMS=false # if your recceiver instance is not working but the PVs themselves are alive and accessible. REACT_APP_PVWS_IGNORE_CF_PVSTATUS=false +# By default, PV Info shows "Disconnected" for PVs that are not connected to their IOC +# Switch this to false to revert to the old behavior where instead the box is left blank +# Somewhat goes in tandem with IGNORE_CF_PVSTATUS variable +REACT_APP_SHOW_DISCONNECTED=true + ###################################################################################### # Archiver Web Viewer ###################################################################################### diff --git a/src/components/home/queryresults/QueryResults.jsx b/src/components/home/queryresults/QueryResults.jsx index 39d6ca9..8b092b8 100644 --- a/src/components/home/queryresults/QueryResults.jsx +++ b/src/components/home/queryresults/QueryResults.jsx @@ -90,7 +90,11 @@ function QueryResults(props) { [firstRow, lastRow] = [parseInt(start) - 1, parseInt(end) - 1]; } for (let i = firstRow; i <= lastRow; ++i) { - updateCurrentChecked(i, event.target.checked); + // only check mark active PVs, unless we are ignoring CF PV status + // matters now that we show "Disconnected" for PVs that are not connected to their IOC + if (import.meta.env.REACT_APP_PVWS_IGNORE_CF_PVSTATUS === "true" || pvs[i].pvStatus === "Active") { + updateCurrentChecked(i, event.target.checked); + } } return }, [updateCurrentChecked]) diff --git a/src/components/home/queryresults/value/Value.jsx b/src/components/home/queryresults/value/Value.jsx index c00ee19..c2b5a22 100644 --- a/src/components/home/queryresults/value/Value.jsx +++ b/src/components/home/queryresults/value/Value.jsx @@ -13,9 +13,12 @@ const propTypes = { } function Value(props) { - const [pvValue, setPVValue] = useState(""); + const [pvValue, setPVValue] = useState(null); const [pvSeverity, setPVSeverity] = useState(""); const [pvUnit, setPVUnit] = useState(""); + // debounce the value display to avoid flashing "Disconnected" since web socket always sends message without value on connect + const [show, setShow] = useState(false); + const [startTimer, setStartTimer] = useState(false); // https://github.com/robtaussig/react-use-websocket/issues/40#issuecomment-616676102 // pattern for sharing web socket among components @@ -24,19 +27,38 @@ function Value(props) { filter: message => JSON.parse(message.data).pv === props.pvName, }); + + useEffect(() => { + // wait to start timer until we get first message for this PV + if (!startTimer) { + return; + } + // the debouncing is only useful if we are showing "Disconnected" for non-reachable PVs + if (import.meta.env.REACT_APP_SHOW_DISCONNECTED !== "true" || show) { + return; + } + const timeout = setTimeout(() => { + setShow(true) + }, 500) + + return () => clearTimeout(timeout); + }, [show, startTimer]) + + // parse web socket message. filter on useWebSocket above means we only parse messages for this PV useEffect(() => { const jsonMessage = api.PARSE_WEBSOCKET_MSG(lastJsonMessage, 2); // fix precision to 2 on the PV table if (jsonMessage === null) { return; // unable to parse, could be invalid message type, no PV name, null lastJsonMessage } + setStartTimer(true); if ("severity" in jsonMessage) { setPVSeverity(jsonMessage.severity); } if ("units" in jsonMessage) { setPVUnit(jsonMessage.units); } - if ("pv_value" in jsonMessage) { + if (jsonMessage.pv_value !== null && "pv_value" in jsonMessage) { setPVValue(jsonMessage.pv_value); } }, [lastJsonMessage]); @@ -59,7 +81,7 @@ function Value(props) { } const severityName = pvSeverity === "UNDEFINED" || pvSeverity === "INVALID" ? ` (${pvSeverity})` : null - if (pvValue !== undefined) { + if (pvValue !== undefined && pvValue !== null) { if (Array.isArray(pvValue)) { return (
{`[ ${pvValue.join(', ')} ] ${pvUnit}`}{severityName}
@@ -70,11 +92,23 @@ function Value(props) {
{`${pvValue} ${pvUnit}`}{severityName}
); } - } - else { - return ( - null - ); + } else { + if (import.meta.env.REACT_APP_SHOW_DISCONNECTED !== "true") { + return ( +
+ ); + } else { + // debounce showing "Disconnected" to avoid flashing for PVs that are actually connected + if (!show) { + return ( +
+ ); + } + textColor = colors.SEV_COLORS["UNDEFINED"]; + return ( +
(DISCONNECTED)
+ ); + } } } } diff --git a/src/components/home/queryresults/valuecheckbox/ValueCheckbox.jsx b/src/components/home/queryresults/valuecheckbox/ValueCheckbox.jsx index da9d004..934ce81 100644 --- a/src/components/home/queryresults/valuecheckbox/ValueCheckbox.jsx +++ b/src/components/home/queryresults/valuecheckbox/ValueCheckbox.jsx @@ -35,7 +35,10 @@ function ValueCheckbox(props) { else if (props.recordType === "waveform" && import.meta.env.REACT_APP_PVWS_ALLOW_WAVEFORMS !== "true") { setEnabled(false); } - }, [props.pvStatus, props.recordType]) + else { + setEnabled(true); + } + }, [props.pvStatus, props.recordType, props.pvName]) // watch for changes in checked, if so send a subscribe message useEffect(() => { diff --git a/src/components/pv/valuetable/ValueTable.jsx b/src/components/pv/valuetable/ValueTable.jsx index cf12765..7a7f928 100644 --- a/src/components/pv/valuetable/ValueTable.jsx +++ b/src/components/pv/valuetable/ValueTable.jsx @@ -124,6 +124,8 @@ function ValueTable(props) { } } if (message.pv_value === null) { + setPVSeverity("DISCONNECTED"); + setAlarmColor(colors.SEV_COLORS["UNDEFINED"]); return; // only if no text, b64dbl, b64int, ..., value property found } if (!props.snapshot) {