From 8c41a25ebc034876a9220fd6d0b033ab30aef5b5 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Mon, 11 Nov 2024 15:45:40 +0000 Subject: [PATCH 1/9] show update timestamps --- app/components/Block.tsx | 8 ++++++++ app/components/Group.tsx | 3 +++ app/components/Groups.tsx | 3 +++ app/components/InstrumentPage.tsx | 10 +++++++++- app/types.ts | 1 + 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/components/Block.tsx b/app/components/Block.tsx index e679656..7ab651e 100644 --- a/app/components/Block.tsx +++ b/app/components/Block.tsx @@ -10,11 +10,13 @@ export default function Block({ instName, showHiddenBlocks, showSetpoints, + showTimestamps, }: { pv: IfcBlock; instName: string; showHiddenBlocks: boolean; showSetpoints: boolean; + showTimestamps: boolean; }) { const [currentValue, setCurrentValue] = useState< string | number | undefined @@ -67,6 +69,12 @@ export default function Block({ {`(SP: ${pv.sp_value})`} ) : null} + {showTimestamps && pv.updateSeconds != null ? ( + <> +
+ {`(Last update: ${new Date(pv.updateSeconds * 1000).toLocaleString()})`} + + ) : null} {pv.severity != "NONE" ? ( Loading...; @@ -46,6 +48,7 @@ export default function Group({ instName={instName} showHiddenBlocks={showHiddenBlocks} showSetpoints={showSetpoints} + showTimestamps={showTimestamps} /> ); })} diff --git a/app/components/Groups.tsx b/app/components/Groups.tsx index ef61b70..7b38754 100644 --- a/app/components/Groups.tsx +++ b/app/components/Groups.tsx @@ -8,11 +8,13 @@ export default function Groups({ instName, showHiddenBlocks, showSetpoints, + showTimestamps, }: { groupsMap: Array; instName: string; showHiddenBlocks: boolean; showSetpoints: boolean; + showTimestamps: boolean; }) { if (!groupsMap) { return

Loading...

; @@ -28,6 +30,7 @@ export default function Groups({ instName={instName} showHiddenBlocks={showHiddenBlocks} showSetpoints={showSetpoints} + showTimestamps={showTimestamps} /> ); })} diff --git a/app/components/InstrumentPage.tsx b/app/components/InstrumentPage.tsx index 16198a3..bc21cc8 100644 --- a/app/components/InstrumentPage.tsx +++ b/app/components/InstrumentPage.tsx @@ -99,6 +99,7 @@ export function toPrecision( function InstrumentData({ instrumentName }: { instrumentName: string }) { const [showHiddenBlocks, setShowHiddenBlocks] = useState(false); const [showSetpoints, setShowSetpoints] = useState(false); + const [showTimestamps, setShowTimestamps] = useState(false); const CONFIG_DETAILS = "CS:BLOCKSERVER:GET_CURR_CONFIG_DETAILS"; const [instlist, setInstlist] = useState | null>(null); const [currentInstrument, setCurrentInstrument] = useState( @@ -242,6 +243,7 @@ function InstrumentData({ instrumentName }: { instrumentName: string }) { } // if a block has precision truncate it here block.value = toPrecision(block, pvVal); + if (updatedPV.seconds) block.updateSeconds = updatedPV.seconds; if (updatedPV.units) block.units = updatedPV.units; if (updatedPV.severity) block.severity = updatedPV.severity; @@ -268,7 +270,7 @@ function InstrumentData({ instrumentName }: { instrumentName: string }) { instName={instName} runInfoPVs={currentInstrument.runInfoPVs} /> -
+
+
); diff --git a/app/types.ts b/app/types.ts index a18fea3..8ac765f 100644 --- a/app/types.ts +++ b/app/types.ts @@ -15,6 +15,7 @@ export interface IfcPV { alarm_low?: number; alarm_high?: number; value?: string | number; + updateSeconds?: number; // Seconds from epoch } export interface IfcBlock extends IfcPV { From 90cb9fc525b8ecc6902d78712bd666df6c33dccf Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Mon, 11 Nov 2024 16:26:27 +0000 Subject: [PATCH 2/9] toggle advanced block details --- app/components/Block.test.tsx | 97 +++++++++---------- app/components/Block.tsx | 42 ++++---- app/components/Group.tsx | 6 -- app/components/Groups.tsx | 6 -- app/components/InstrumentPage.tsx | 12 --- .../__snapshots__/Block.test.tsx.snap | 5 + 6 files changed, 76 insertions(+), 92 deletions(-) diff --git a/app/components/Block.test.tsx b/app/components/Block.test.tsx index 184896e..5dd11b4 100644 --- a/app/components/Block.test.tsx +++ b/app/components/Block.test.tsx @@ -1,4 +1,4 @@ -import { render } from "@testing-library/react"; +import { fireEvent, render } from "@testing-library/react"; import Block from "@/app/components/Block"; import { IfcBlock } from "@/app/types"; @@ -20,12 +20,7 @@ it("renders topbar unchanged", () => { }; const instName = "Instrument"; const { container } = render( - , + , { container: tableBody, }, @@ -36,12 +31,7 @@ it("renders topbar unchanged", () => { it("renders nothing if pv is hidden", () => { const aBlock: IfcBlock = { pvaddress: "SOME:PV", visible: false }; const { container } = render( - , + , { container: tableBody, }, @@ -56,12 +46,7 @@ it("renders block with correct name", () => { human_readable_name: "MyBlock", }; const { container } = render( - , + , { container: tableBody, }, @@ -80,12 +65,7 @@ it("renders block with run control that is in range as a tick", () => { runcontrol_enabled: true, }; const { container } = render( - , + , { container: tableBody, }, @@ -105,12 +85,7 @@ it("renders block with run control that is not in range as a cross", () => { runcontrol_enabled: true, }; const { container } = render( - , + , { container: tableBody, }, @@ -130,12 +105,7 @@ it("renders block without run control without tick or cross", () => { runcontrol_enabled: false, }; const { container } = render( - , + , { container: tableBody, }, @@ -159,19 +129,49 @@ it("renders block with SP and shows SP value", () => { value: expectedValue, }; const { container } = render( - , + , { container: tableBody, }, ); + const valueSpan = container.querySelector( + `#${aBlock.human_readable_name}_VALUE`, + )!; + + fireEvent.click(valueSpan); + expect(valueSpan.innerHTML).toContain(`${expectedValue}`); expect( - container.querySelector(`#${aBlock.human_readable_name}_VALUE`)!.innerHTML, - ).toContain(`${expectedValue}
(SP: ${expectedSpValue})`); + container.querySelector(`#${aBlock.human_readable_name}_SP`)!.innerHTML, + ).toContain(expectedSpValue.toString()); +}); + +it("renders block with timestamp and shows timestamp value", () => { + const expectedValue = 123; + const expectedTimeStamp = 1731342022; + const aBlock: IfcBlock = { + pvaddress: "SOME:PV", + visible: true, + human_readable_name: "MyBlock", + runcontrol_inrange: false, + runcontrol_enabled: false, + updateSeconds: expectedTimeStamp, + value: expectedValue, + }; + const { container } = render( + , + { + container: tableBody, + }, + ); + const valueSpan = container.querySelector( + `#${aBlock.human_readable_name}_VALUE`, + )!; + fireEvent.click(valueSpan); + expect(valueSpan.innerHTML).toContain(`${expectedValue}`); + expect( + container.querySelector(`#${aBlock.human_readable_name}_TIMESTAMP`)! + .innerHTML, + ).toContain(new Date(expectedTimeStamp * 1000).toLocaleString()); }); it("renders block without SP and hides SP value", () => { @@ -187,12 +187,7 @@ it("renders block without SP and hides SP value", () => { sp_value: expectedSpValue, }; const { container } = render( - , + , { container: tableBody, }, diff --git a/app/components/Block.tsx b/app/components/Block.tsx index 7ab651e..50c10da 100644 --- a/app/components/Block.tsx +++ b/app/components/Block.tsx @@ -1,6 +1,6 @@ "use client"; import { IfcBlock } from "@/app/types"; -import { useState } from "react"; +import React, { useState } from "react"; const grafana_stub = "https://shadow.nd.rl.ac.uk/grafana/d/wMlwwaHMk/block-history?viewPanel=2&orgId=1&var-block="; @@ -9,18 +9,15 @@ export default function Block({ pv, instName, showHiddenBlocks, - showSetpoints, - showTimestamps, }: { pv: IfcBlock; instName: string; showHiddenBlocks: boolean; - showSetpoints: boolean; - showTimestamps: boolean; }) { const [currentValue, setCurrentValue] = useState< string | number | undefined >(); + const [showAdvanced, setShowAdvanced] = useState(false); if (!pv.visible && !showHiddenBlocks && !instName) { return null; } @@ -44,6 +41,9 @@ export default function Block({ { + setShowAdvanced(!showAdvanced); + }} >
+ {showAdvanced && "Readback: "} {pv.value} {pv.units != null && pv.units} - {showSetpoints && pv.sp_value != null ? ( - <> -
- {`(SP: ${pv.sp_value})`} - - ) : null} - {showTimestamps && pv.updateSeconds != null ? ( - <> -
- {`(Last update: ${new Date(pv.updateSeconds * 1000).toLocaleString()})`} - - ) : null} {pv.severity != "NONE" ? (
) : null} + {showAdvanced && ( +
+
+ {pv.sp_value != null ? ( + + {`Setpoint: ${pv.sp_value}`} +
+
+ ) : null} + {pv.updateSeconds != null ? ( + + {`Last update: ${new Date(pv.updateSeconds * 1000).toLocaleString()}`} + + ) : null} +
+ )} @@ -99,6 +104,9 @@ export default function Block({ > + + {showAdvanced ? "-" : "+"} + ); diff --git a/app/components/Group.tsx b/app/components/Group.tsx index c7e4d50..0cd97ec 100644 --- a/app/components/Group.tsx +++ b/app/components/Group.tsx @@ -8,14 +8,10 @@ export default function Group({ group, instName, showHiddenBlocks, - showSetpoints, - showTimestamps, }: { group: IfcGroup; instName: string; showHiddenBlocks: boolean; - showSetpoints: boolean; - showTimestamps: boolean; }) { if (!group) { return

Loading...

; @@ -47,8 +43,6 @@ export default function Group({ pv={pv} instName={instName} showHiddenBlocks={showHiddenBlocks} - showSetpoints={showSetpoints} - showTimestamps={showTimestamps} /> ); })} diff --git a/app/components/Groups.tsx b/app/components/Groups.tsx index 7b38754..b9c74a1 100644 --- a/app/components/Groups.tsx +++ b/app/components/Groups.tsx @@ -7,14 +7,10 @@ export default function Groups({ groupsMap, instName, showHiddenBlocks, - showSetpoints, - showTimestamps, }: { groupsMap: Array; instName: string; showHiddenBlocks: boolean; - showSetpoints: boolean; - showTimestamps: boolean; }) { if (!groupsMap) { return

Loading...

; @@ -29,8 +25,6 @@ export default function Groups({ group={group} instName={instName} showHiddenBlocks={showHiddenBlocks} - showSetpoints={showSetpoints} - showTimestamps={showTimestamps} /> ); })} diff --git a/app/components/InstrumentPage.tsx b/app/components/InstrumentPage.tsx index bc21cc8..d11cd66 100644 --- a/app/components/InstrumentPage.tsx +++ b/app/components/InstrumentPage.tsx @@ -276,23 +276,11 @@ function InstrumentData({ instrumentName }: { instrumentName: string }) { setChecked={setShowHiddenBlocks} text={"Show hidden blocks"} /> - - ); diff --git a/app/components/__snapshots__/Block.test.tsx.snap b/app/components/__snapshots__/Block.test.tsx.snap index 4290876..234abff 100644 --- a/app/components/__snapshots__/Block.test.tsx.snap +++ b/app/components/__snapshots__/Block.test.tsx.snap @@ -50,6 +50,11 @@ exports[`renders topbar unchanged 1`] = ` r="12" /> + + + + From 30f1a5bf9daac70477d5f77b95a88f45c46550d0 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Tue, 12 Nov 2024 10:37:48 +0000 Subject: [PATCH 3/9] layout fixes - fix overflow, make desktop use white space, reduce padding on mobile, keep table headers etc. fixed at w-1/3 --- app/components/Block.tsx | 6 +++--- app/components/Group.tsx | 12 ++++++------ app/components/InstrumentPage.tsx | 2 +- app/components/__snapshots__/Block.test.tsx.snap | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/components/Block.tsx b/app/components/Block.tsx index 50c10da..dc9ad0d 100644 --- a/app/components/Block.tsx +++ b/app/components/Block.tsx @@ -45,7 +45,7 @@ export default function Block({ setShowAdvanced(!showAdvanced); }} > - +
- + {showAdvanced && "Readback: "} {pv.value} {pv.units != null && pv.units} @@ -91,7 +91,7 @@ export default function Block({ )} - + {pv.runcontrol_enabled && (pv.runcontrol_inrange ? "✅" : "❌")} diff --git a/app/components/Group.tsx b/app/components/Group.tsx index 0cd97ec..7928d2a 100644 --- a/app/components/Group.tsx +++ b/app/components/Group.tsx @@ -28,14 +28,14 @@ export default function Group({ {group.name} - - - - - + + + + + - + {group.blocks.map((pv) => { return ( Loading...; } return ( -
+
- - diff --git a/app/components/Group.tsx b/app/components/Group.tsx index 7928d2a..d9837a6 100644 --- a/app/components/Group.tsx +++ b/app/components/Group.tsx @@ -31,8 +31,8 @@ export default function Group({ - - + + diff --git a/app/components/Groups.tsx b/app/components/Groups.tsx index b9c74a1..389dc22 100644 --- a/app/components/Groups.tsx +++ b/app/components/Groups.tsx @@ -17,7 +17,7 @@ export default function Groups({ } return ( -
+
{groupsMap.map((group) => { return ( Loading...; } return ( -
+
{ runInfoPVs: instrument.runInfoPVs, }), ); - expect(container.querySelector("#instNameSpan")!.innerHTML).toBe( + expect(container.querySelector("#instNameLabel")!.innerHTML).toContain( instName.toUpperCase(), ); }); diff --git a/app/components/TopBar.tsx b/app/components/TopBar.tsx index 458b051..1e87c20 100644 --- a/app/components/TopBar.tsx +++ b/app/components/TopBar.tsx @@ -42,22 +42,6 @@ export default function TopBar({ id="top_bar" className="w-full bg-white shadow-lg text-black rounded-xl text-md" > -
-

- Instrument:{" "} - - {instName.toUpperCase()} - -

-

- Config:{" "} - - {findPVByHumanReadableName(runInfoPVs, configName) - ? findPVByHumanReadableName(runInfoPVs, configName)!.value - : "UNKNOWN"} - -

-
{instName.toUpperCase()} is{" "} {getRunstate(runInfoPVs)} -
+

+ Config:{" "} + + {findPVByHumanReadableName(runInfoPVs, configName) + ? findPVByHumanReadableName(runInfoPVs, configName)!.value + : "UNKNOWN"} + +

+ +
BlockValueIn-Range
BlockValueIn-Range
Date: Tue, 12 Nov 2024 11:26:47 +0000 Subject: [PATCH 4/9] remove runcontrol table header and make blockname/value bigger, make 4 cols the default on large screen, remove whitespace at top of page by getting rid of instName(duplicated) and moving config name under runstate --- app/components/Block.tsx | 49 +++++++++++------- app/components/Group.tsx | 4 +- app/components/Groups.tsx | 2 +- app/components/InstrumentPage.tsx | 2 +- app/components/TopBar.test.ts | 2 +- app/components/TopBar.tsx | 35 ++++++------- .../__snapshots__/Block.test.tsx.snap | 50 +++++++++++-------- .../__snapshots__/TopBar.test.ts.snap | 42 ++++++---------- 8 files changed, 96 insertions(+), 90 deletions(-) diff --git a/app/components/Block.tsx b/app/components/Block.tsx index dc9ad0d..8df995d 100644 --- a/app/components/Block.tsx +++ b/app/components/Block.tsx @@ -37,6 +37,7 @@ export default function Block({ }, 2000); } + const minimum_date_to_be_shown = 631152000; // This is what PVWS thinks epoch time is for some reason. don't bother showing it as the instrument wasn't running EPICS on 01/01/1990 return (
+ - - {showAdvanced && "Readback: "} - {pv.value} {pv.units != null && pv.units} + + +
+ + {showAdvanced && "Readback: "} + {pv.value} {pv.units != null && pv.units} + + + + +
{pv.severity != "NONE" ? ( -
- {pv.severity} + Alarm: {pv.severity}
) : null} {showAdvanced && ( @@ -82,8 +95,10 @@ export default function Block({
) : null} - {pv.updateSeconds != null ? ( + {pv.updateSeconds != null && + pv.updateSeconds > minimum_date_to_be_shown ? ( + {/*Multiply by 1000 here as Date() expects milliseconds*/} {`Last update: ${new Date(pv.updateSeconds * 1000).toLocaleString()}`} ) : null} @@ -92,19 +107,17 @@ export default function Block({
- + {pv.runcontrol_enabled && (pv.runcontrol_inrange ? "✅" : "❌")} - - - - {showAdvanced ? "-" : "+"}
BlockValueIn-RangeValue
- @@ -36,22 +57,11 @@ exports[`renders topbar unchanged 1`] = ` > - - - + diff --git a/app/components/__snapshots__/TopBar.test.ts.snap b/app/components/__snapshots__/TopBar.test.ts.snap index b8dcccd..d80096e 100644 --- a/app/components/__snapshots__/TopBar.test.ts.snap +++ b/app/components/__snapshots__/TopBar.test.ts.snap @@ -6,32 +6,6 @@ exports[`renders topbar unchanged 1`] = ` class="w-full bg-white shadow-lg text-black rounded-xl text-md" id="top_bar" > -
-

- Instrument: - - - INSTRUMENT - -

-

- Config: - - -

-
INSTRUMENT is @@ -53,8 +28,18 @@ exports[`renders topbar unchanged 1`] = ` UNKNOWN +

+ Config: + + +

- 123 - - mm +
+ + 123 + + mm + + + + +
-
+ Alarm:
{dashboard.map((column: Array>, index: number) => ( - + {column.map((row: Array, index: number) => ( - - +
{row[0].value} + + {row[0].value} + {row[1].value != null ? row[1].value : "Hidden/unknown"} @@ -92,20 +94,23 @@ export default function TopBar({
-