diff --git a/src/App.tsx b/src/App.tsx index 5cf7a24..23bc7b5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import { QueryClient, QueryClientProvider } from "react-query"; import { BeamlineI24 } from "routes/BeamlineI24.tsx"; import { FixedTarget } from "routes/FixedTarget.tsx"; import { Extruder } from "routes/Extruder.tsx"; +import { JfRotation } from "routes/JungfrauRotation.tsx"; import { loadConfig } from "./config.ts"; import { useEffect, useState } from "react"; @@ -33,6 +34,10 @@ const router = createBrowserRouter( path: "extruder", element: , }, + { + path: "jungfrau", + element: , + }, ], }, ], diff --git a/src/CustomTheme.tsx b/src/CustomTheme.tsx index 075e73f..93a206b 100644 --- a/src/CustomTheme.tsx +++ b/src/CustomTheme.tsx @@ -27,11 +27,14 @@ const I24DiamondThemeOptions = mergeThemeOptions( colorSchemes: { light: { palette: { + primary: { + contrastText: "#000000", + }, custom: { main: "#1976d2", light: "#68a0e2", dark: "#10569b", - contrastText: "#ffffff", // white + contrastText: "#ffffff", }, }, }, diff --git a/src/components/JungFrau/CollectDarksPanel.tsx b/src/components/JungFrau/CollectDarksPanel.tsx new file mode 100644 index 0000000..724da16 --- /dev/null +++ b/src/components/JungFrau/CollectDarksPanel.tsx @@ -0,0 +1,150 @@ +import { + Box, + Card, + CardContent, + FormControl, + InputLabel, + MenuItem, + Select, + Stack, + Tooltip, + Typography, + useTheme, +} from "@mui/material"; +import React from "react"; +import { ParameterInput } from "../ParameterInputs"; +import { RunPlanButton } from "../../blueapi/BlueapiComponents"; +import { GainModes } from "./constants"; + +export function CollectDarksPanel() { + const theme = useTheme(); + const [filename, setFilename] = React.useState("darks"); + const [expTime, setExpTime] = React.useState(0.001); + const [pedestalFrames, setPedestalFrames] = React.useState(20); + const [pedestalLoops, setPedestalLoops] = React.useState(200); + const [totTriggers, setTotTriggers] = React.useState(1000); + const [gainMode, setGainMode] = React.useState(GainModes[0]); + + return ( + + + + + Collect Darks + + + + + + + + Pedestal + + + + + + + + Standard + + + + + + Gain Mode + + + + + + + + + + ); +} diff --git a/src/components/JungFrau/CollectionSetupJf.tsx b/src/components/JungFrau/CollectionSetupJf.tsx new file mode 100644 index 0000000..2d7c3f0 --- /dev/null +++ b/src/components/JungFrau/CollectionSetupJf.tsx @@ -0,0 +1,136 @@ +import { + Box, + Grid2 as Grid, + Stack, + TextField, + Typography, + useTheme, +} from "@mui/material"; +import { AbortButton, RunPlanButton } from "blueapi/BlueapiComponents"; +import { ParameterInput } from "components/ParameterInputs"; +import { JungfrauRotationContext } from "context/jungfrau/JungfrauRotationContext"; +import { VisitContext } from "context/VisitContext"; +import React from "react"; +import { useContext } from "react"; + +function fullStorageDirectory(visit: string): string { + const date = new Date(); + const year = date.getFullYear(); + return `/dls/i24/data/${year}/${visit}/jungfrau/`; +} + +function RunButtons(): JSX.Element { + const { + expTime, + detDist, + fileName, + omegaStart, + omegaIncrement, + transFract, + sampleId, + } = useContext(JungfrauRotationContext); + console.log(transFract); + return ( + + + + + + + ); +} + +export function CollectionSetupJf() { + const theme = useTheme(); + const context = useContext(JungfrauRotationContext); + const { visit } = useContext(VisitContext); + const storageDirectory = fullStorageDirectory(visit); + return ( + + + + Collection Parameters + + + + + + + + + + + + + + + + + + + ); +} diff --git a/src/components/JungFrau/constants.ts b/src/components/JungFrau/constants.ts new file mode 100644 index 0000000..6a5ba9a --- /dev/null +++ b/src/components/JungFrau/constants.ts @@ -0,0 +1,16 @@ +export type GainModeType = + | "Dynamic" + | "ForceSwitchG1" + | "ForceSwitchG2" + | "FixG1" + | "FixG2" + | "FixG0"; + +export const GainModes = [ + "Dynamic", + "ForceSwitchG1", + "ForceSwitchG2", + "FixG1", + "FixG2", + "FixG0", +]; diff --git a/src/components/SerialNavBar.tsx b/src/components/SerialNavBar.tsx index 584f8c7..f0bc5dd 100644 --- a/src/components/SerialNavBar.tsx +++ b/src/components/SerialNavBar.tsx @@ -27,6 +27,9 @@ export function SerialNavBar() { Extruder + + JF Rotation + ); diff --git a/src/context/VisitContext.ts b/src/context/VisitContext.ts new file mode 100644 index 0000000..dde7f83 --- /dev/null +++ b/src/context/VisitContext.ts @@ -0,0 +1,10 @@ +import React, { createContext } from "react"; + +export type VisitContextType = { + visit: string; + setVisit: React.Dispatch>; +}; + +export const VisitContext = createContext( + null as unknown as VisitContextType, +); diff --git a/src/context/VisitProvider.tsx b/src/context/VisitProvider.tsx new file mode 100644 index 0000000..ee1fbe5 --- /dev/null +++ b/src/context/VisitProvider.tsx @@ -0,0 +1,14 @@ +import { ReactNode, useState } from "react"; +import { VisitContext } from "./VisitContext"; + +const defaultVisit = "cm44177-1"; // Until we can grab it after authentication + +export const VisitProvider = ({ children }: { children: ReactNode }) => { + const [visit, setVisit] = useState(defaultVisit); + + return ( + + {children} + + ); +}; diff --git a/src/context/jungfrau/JungfrauRotationContext.ts b/src/context/jungfrau/JungfrauRotationContext.ts new file mode 100644 index 0000000..857642e --- /dev/null +++ b/src/context/jungfrau/JungfrauRotationContext.ts @@ -0,0 +1,23 @@ +import { createContext } from "react"; + +export type JungfrauRotationContextType = { + fileName: string; + expTime: number; + detDist: number; + transFract: number[]; + omegaStart: number; + omegaIncrement: number; + sampleId: number; + setFileName: React.Dispatch>; + setExpTime: React.Dispatch>; + setDetDist: React.Dispatch>; + setTransFract: React.Dispatch>; + setOmegaStart: React.Dispatch>; + setOmegaIncrement: React.Dispatch>; + setSampleId: React.Dispatch>; +}; + +export const JungfrauRotationContext = + createContext( + null as unknown as JungfrauRotationContextType, + ); diff --git a/src/context/jungfrau/JungfrauRotationProvider.tsx b/src/context/jungfrau/JungfrauRotationProvider.tsx new file mode 100644 index 0000000..f825624 --- /dev/null +++ b/src/context/jungfrau/JungfrauRotationProvider.tsx @@ -0,0 +1,39 @@ +import { ReactNode, useState } from "react"; +import { JungfrauRotationContext } from "./JungfrauRotationContext"; + +export const JungfrauRotationProvider = ({ + children, +}: { + children: ReactNode; +}) => { + const [fileName, setFileName] = useState("jf_rotation"); + const [expTime, setExpTime] = useState(0.001); + const [detDist, setDetDist] = useState(200); + const [transFract, setTransFract] = useState([0.5]); + const [omegaStart, setOmegaStart] = useState(0); + const [omegaIncrement, setOmegaIncrement] = useState(0.1); + const [sampleId, setSampleId] = useState(0); + + return ( + + {children} + + ); +}; diff --git a/src/routes/BeamlineI24.tsx b/src/routes/BeamlineI24.tsx index 2cd11c9..7ed2a4f 100644 --- a/src/routes/BeamlineI24.tsx +++ b/src/routes/BeamlineI24.tsx @@ -3,6 +3,8 @@ import { BeamlineStatsTabPanel } from "screens/BeamlineStats"; import { DetectorMotionTabPanel } from "screens/DetectorMotion"; import { OavMover } from "screens/OavMover/OAVStageController"; import React from "react"; +import { ErrorBoundary } from "react-error-boundary"; +import { FallbackScreen } from "screens/FallbackScreen"; interface TabPanelProps { children?: React.ReactNode; @@ -42,36 +44,38 @@ export function BeamlineI24() { }; return ( - - - }> + + - - - - + + + + + + + + + + + + + + + - - - - - - - - - - + ); } diff --git a/src/routes/Extruder.tsx b/src/routes/Extruder.tsx index 922ce92..5cb9806 100644 --- a/src/routes/Extruder.tsx +++ b/src/routes/Extruder.tsx @@ -1,26 +1,30 @@ import { Box, Typography, useTheme } from "@mui/material"; import { ReadOnlyInputs } from "components/ReadOnlyInputs"; import { ParamsPanel } from "screens/CollectionPanel"; +import { ErrorBoundary } from "react-error-boundary"; +import { FallbackScreen } from "screens/FallbackScreen"; export function Extruder() { const theme = useTheme(); return ( - - - Extruder Data Collection Setup - - - - + }> + + + Extruder Data Collection Setup + + + + + ); } diff --git a/src/routes/FixedTarget.tsx b/src/routes/FixedTarget.tsx index 6226125..1258508 100644 --- a/src/routes/FixedTarget.tsx +++ b/src/routes/FixedTarget.tsx @@ -1,26 +1,30 @@ import { Box, Typography, useTheme } from "@mui/material"; import { ParamsPanel } from "screens/CollectionPanel"; import { ReadOnlyInputs } from "components/ReadOnlyInputs"; +import { ErrorBoundary } from "react-error-boundary"; +import { FallbackScreen } from "screens/FallbackScreen"; export function FixedTarget() { const theme = useTheme(); return ( - - - Fixed Target Data Collection Setup - - - - + }> + + + Fixed Target Data Collection Setup + + + + + ); } diff --git a/src/routes/JungfrauRotation.tsx b/src/routes/JungfrauRotation.tsx new file mode 100644 index 0000000..5e37c7a --- /dev/null +++ b/src/routes/JungfrauRotation.tsx @@ -0,0 +1,31 @@ +import { Box, Grid2, Typography, useTheme } from "@mui/material"; +import { ParamsPanel } from "../screens/CollectionPanel"; +import { CollectDarksPanel } from "../components/JungFrau/CollectDarksPanel"; +import { ErrorBoundary } from "react-error-boundary"; +import { FallbackScreen } from "screens/FallbackScreen"; + +export function JfRotation() { + const theme = useTheme(); + return ( + }> + + + Jungfrau Rotation Scans Setup + + + + + + + + + + ); +} diff --git a/src/screens/CollectionPanel.tsx b/src/screens/CollectionPanel.tsx index fcb17a4..91b2227 100644 --- a/src/screens/CollectionPanel.tsx +++ b/src/screens/CollectionPanel.tsx @@ -1,14 +1,18 @@ import { Box, Typography } from "@mui/material"; import { CollectionSetupFt } from "components/FixedTarget/CollectionSetupFt"; import { CollectionSetupEx } from "components/Extruder/CollectionSetupEx"; - +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; +import { CollectionSetupJf } from "components/JungFrau/CollectionSetupJf"; +import { JungfrauRotationProvider } from "context/jungfrau/JungfrauRotationProvider"; +import { VisitProvider } from "context/VisitProvider"; type ExptType = { - expt: "extruder" | "fixed-target"; + expt: "extruder" | "fixed-target" | "jf"; }; function FallbackScreen() { return ( - + + Page currently unavailable @@ -22,6 +26,14 @@ export function ParamsPanel(expt: ExptType) { return ; case "extruder": return ; + case "jf": + return ( + + + + + + ); default: return ; } diff --git a/src/screens/FallbackScreen.tsx b/src/screens/FallbackScreen.tsx new file mode 100644 index 0000000..27725b8 --- /dev/null +++ b/src/screens/FallbackScreen.tsx @@ -0,0 +1,14 @@ +import { Box, Typography } from "@mui/material"; + +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; + +export function FallbackScreen() { + return ( + + + + Page currently unavailable + + + ); +} diff --git a/vite.config.ts b/vite.config.ts index d817bea..3ddbe57 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -16,6 +16,7 @@ export default defineConfig({ assets: path.resolve(__dirname, "./src/assets"), blueapi: path.resolve(__dirname, "./src/blueapi"), components: path.resolve(__dirname, "./src/components"), + context: path.resolve(__dirname, "./src/context"), pv: path.resolve(__dirname, "./src/pv"), routes: path.resolve(__dirname, "./src/routes"), screens: path.resolve(__dirname, "./src/screens"),