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"),