Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9ac010a
Add the starting bare bones of a package to upda pvws
noemifrisina Mar 23, 2026
fd86bc2
At least add loadConfiguration for a start
noemifrisina Mar 26, 2026
4b97826
Start adding config to i15-1
noemifrisina Mar 27, 2026
2d8d5c6
For now use known-to-work version of cs-web-lib
noemifrisina Mar 27, 2026
a38ba6c
Just a comment
noemifrisina Mar 27, 2026
7bd972c
Start adding utility functions and a hook
noemifrisina Mar 27, 2026
e4bf173
Add exports
noemifrisina Mar 27, 2026
ab94608
Add a dependency
noemifrisina Mar 27, 2026
f657ccb
Add a dependency - again
noemifrisina Mar 27, 2026
fe1a82f
Add some basic components to display PV with a fallback if connection…
noemifrisina Mar 27, 2026
a6becd0
Fix some bit and actually save changes
noemifrisina Mar 27, 2026
03ac75c
Merge branch 'main' into 30-31_pvws-and-component
noemifrisina Apr 9, 2026
d7508a3
Add dependency to i15-1 and remove property from config as stuck a fe…
noemifrisina Apr 9, 2026
7fb5624
A first attempt - not working, dependency issues to be worked out
noemifrisina Apr 9, 2026
a9181ca
Fix text filed
noemifrisina Apr 10, 2026
bde657b
Update fallback
noemifrisina Apr 10, 2026
0f6d0a3
Tidy up some bits
noemifrisina Apr 10, 2026
a37e361
First version of a card with PV info
noemifrisina Apr 10, 2026
3e49791
... and save it
noemifrisina Apr 10, 2026
f6b1aec
Put state card in a sort-of-sidebar
noemifrisina Apr 10, 2026
40d3834
Merge branch 'main' into 30-31_pvws-and-component
noemifrisina Apr 10, 2026
de43dd2
Add dependencies to i15-1 app
noemifrisina Apr 13, 2026
3c80ed2
Refactor the layout
noemifrisina Apr 13, 2026
e83bd35
Try to make it look slightly more aligned
noemifrisina Apr 14, 2026
d81d0a6
Make the default PV a box
noemifrisina Apr 14, 2026
894b156
Add another example
noemifrisina Apr 14, 2026
8f1cbc2
Tidy up robot page
noemifrisina Apr 17, 2026
f0b8843
Tidy up the Pv box
noemifrisina Apr 17, 2026
4aca3da
Merge branch 'main' into 30-31_pvws-and-component
noemifrisina Apr 17, 2026
2594000
Try adding one test
noemifrisina Apr 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/i15-1/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"dependencies": {
"@atlas/blueapi": "workspace:*",
"@atlas/blueapi-query": "workspace:*",
"@atlas/pvws-config": "workspace:*",
"@diamondlightsource/sci-react-ui": "^0.4.0",
"@diamondlightsource/cs-web-lib": "0.9.5",
"@mui/icons-material": "^6.5.0",
"@mui/material": "<7.0.0",
"@tanstack/react-query": "^5.90.21",
Expand All @@ -23,7 +25,9 @@
"@vitejs/plugin-react-swc": "^3.11.0",
"msw": "^2.10.4",
"react-router-dom": "^7.7.1",
"react-redux": "^7.2.9",
"typescript": "~5.9.3",
"@types/react-redux": "7.1.34",
"vite": "^7.3.1",
"vite-plugin-relay": "^2.1.0",
"vitest": "*"
Expand Down
5 changes: 5 additions & 0 deletions apps/i15-1/public/pvwsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"PVWS_SOCKET": "pvws.diamond.ac.uk",
"PVWS_SSL": true,
"THROTTLE_PERIOD": 100
}
55 changes: 55 additions & 0 deletions apps/i15-1/src/components/StatusCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Card, CardContent, Stack, Typography, useTheme } from "@mui/material";
import type { ReactNode } from "react";

type StatusCardProps = {
children: ReactNode;
title?: string;
bgColor?: string;
cardColor?: string;
};

export function StatusCard(props: StatusCardProps) {
const theme = useTheme();
const bgColor = props.bgColor
? props.bgColor
: theme.palette.background.paper;
const cardColor = props.cardColor
? props.cardColor
: theme.palette.text.primary;
if (props.title) {
return (
<Card
variant="outlined"
sx={{
minWidth: 250,
maxHeight: 200,
bgcolor: bgColor,
borderColor: cardColor,
}}
>
<CardContent>
<Stack spacing={1}>
<Typography
variant="body1"
sx={{
fontSize: 16,
fontStyle: "italic",
fontWeight: "bold",
color: cardColor,
}}
>
{props.title}
</Typography>
{props.children}
</Stack>
</CardContent>
</Card>
);
} else {
return (
<Card variant="outlined" sx={{ minWidth: 250, bgColor: bgColor }}>
<CardContent>{props.children}</CardContent>
</Card>
);
}
}
35 changes: 27 additions & 8 deletions apps/i15-1/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { DiamondTheme, ThemeProvider } from "@diamondlightsource/sci-react-ui";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { createRoot } from "react-dom/client";
import { StrictMode } from "react";
import { StrictMode, useEffect, useState } from "react";

import { Layout } from "./routes/Layout.tsx";
import Dashboard from "./routes/Dashboard.tsx";
import Robot from "./routes/Robot.tsx";
import { InstrumentSessionProvider } from "./context/instrumentSession/InstrumentSessionProvider.tsx";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { type CsWebLibConfig, store } from "@diamondlightsource/cs-web-lib";
import { Provider } from "react-redux";

declare global {
interface Window {
Expand All @@ -17,6 +19,8 @@ declare global {

import { createApi } from "@atlas/blueapi";
import { BlueapiProvider } from "@atlas/blueapi-query";
import { loadPvwsConfig } from "@atlas/pvws-config";
import { Store } from "@mui/icons-material";
import { UserAuthProvider } from "./context/userAuth/UserAuthProvider.tsx";

async function enableMocking() {
Expand Down Expand Up @@ -46,18 +50,33 @@ const router = createBrowserRouter([
const api = createApi("/api");
const queryClient = new QueryClient();

function App() {
const [config, setConfig] = useState<CsWebLibConfig>();
useEffect(() => {
loadPvwsConfig().then((config) => {
setConfig(config);
});
}, []);

return (
<Provider store={store(config)}>
<QueryClientProvider client={queryClient}>
<UserAuthProvider>
<BlueapiProvider api={api}>
<RouterProvider router={router} />
</BlueapiProvider>
</UserAuthProvider>
</QueryClientProvider>
</Provider>
);
}

enableMocking().then(() => {
createRoot(document.getElementById("root")!).render(
<InstrumentSessionProvider>
<StrictMode>
<ThemeProvider theme={DiamondTheme} defaultMode="light">
<QueryClientProvider client={queryClient}>
<UserAuthProvider>
<BlueapiProvider api={api}>
<RouterProvider router={router} />
</BlueapiProvider>
</UserAuthProvider>
</QueryClientProvider>
<App />
</ThemeProvider>
</StrictMode>
</InstrumentSessionProvider>,
Expand Down
85 changes: 66 additions & 19 deletions apps/i15-1/src/routes/Robot.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,86 @@
import { useInstrumentSession } from "../context/instrumentSession/useInstrumentSession";
import { Box, Typography, Stack } from "@mui/material";
import { Box, Typography, Stack, useTheme, TextField } from "@mui/material";
import { useState } from "react";
import { NumberInput } from "../components/NumberInput";
import RunPlanButton from "../components/RunPlanButton";
import { ReadOnlyPv } from "@atlas/pvws-config";
import { StatusCard } from "../components/StatusCard";

type RobotSampleFormData = {
puck: number;
position: number;
};

function StatusSidebar() {
const theme = useTheme();
return (
<Box sx={{ ml: 5 }}>
<Stack direction={"column"} spacing={2}>
<StatusCard
title="Currently loaded"
bgColor={theme.palette.info.light}
cardColor={theme.palette.primary.main}
>
<ReadOnlyPv label="Puck" pv="ca://BL15J-EA-LOC-01:PUCK:INDEX" />
<ReadOnlyPv
label="Sample Pin"
pv="ca://BL15J-EA-LOC-01:SAMPLE:INDEX"
/>
</StatusCard>
<StatusCard
title="Ring status"
bgColor={theme.palette.success.light}
cardColor={theme.palette.primary.main}
>
<ReadOnlyPv
label="Ring Current"
pv="ca://SR-DI-DCCT-01:SIGNAL"
parseNumeric
units="mA"
/>
<ReadOnlyPv
label="Ring Energy"
pv="ca://CS-CS-MSTAT-01:BEAMENERGY"
parseNumeric
units="GeV"
/>
</StatusCard>
</Stack>
</Box>
);
}

function Robot() {
const { instrumentSession, setInstrumentSession } = useInstrumentSession();
const { instrumentSession } = useInstrumentSession();
const [formData, setFormData] = useState<RobotSampleFormData>({
puck: 1,
position: 1,
});
const theme = useTheme();
return (
<>
<Box display={"flex"} justifyContent={"center"} sx={{ mt: 3 }}>
<Box
// component={"section"}
sx={{
display: "flex",
justifyContent: "center",
mt: 3,
mr: 5,
ml: 5,
}}
>
<Box
sx={{
padding: 5,
borderRadius: 1,
border: "1px solid",
borderColor: theme.palette.primary.main,
}}
>
<Stack direction={"column"} spacing={3} alignItems={"center"}>
<Typography component="h1" variant="h5">
Sample Position
</Typography>
<Box
sx={{
display: "flex",
justifyContent: "center",
gridTemplateColumns: {
xs: "1fr",
sm: "1fr 1fr",
md: "1fr 1fr 1fr",
},
gap: 3,
flexGrow: 1,
}}
>
<Stack direction={"row"} spacing={3} alignItems={"center"}>
<NumberInput
label="Puck"
numberMode="natural"
Expand All @@ -51,7 +97,7 @@ function Robot() {
setFormData({ ...formData, ["position"]: parsedValue });
}}
/>
</Box>
</Stack>
<RunPlanButton
name="robot_load"
params={formData}
Expand All @@ -65,7 +111,8 @@ function Robot() {
/>
</Stack>
</Box>
</>
<StatusSidebar />
</Box>
);
}

Expand Down
4 changes: 4 additions & 0 deletions apps/i15-1/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import relay from "vite-plugin-relay";
export default defineConfig({
plugins: [react(), relay],
define: {
"process.env": {
VITE_PVWS_SOCKET: "pvws.diamond.ac.uk",
VITE_PVWS_SSL: "true",
},
global: {},
},
});
11 changes: 11 additions & 0 deletions packages/pvws-config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# `@atlas/pvws-config`

## Installation

To install it to an application `@atlas/myapp`:

```
pnpm add @atlas/pvws-config --filter myapp --workspace
```

## Usage
22 changes: 22 additions & 0 deletions packages/pvws-config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@atlas/pvws-config",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"test": "vitest run",
"coverage": "vitest run --coverage"
},
"dependencies": {
"@diamondlightsource/cs-web-lib": "0.9.5",
"@mui/material": "<7.0.0",
"react-error-boundary": "^6.0.0"
},
"devDependencies": {
"@atlas/vitest-conf": "workspace:*",
"vitest": "*"
}
}
14 changes: 14 additions & 0 deletions packages/pvws-config/src/components/PvwsFallback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { TextField } from "@mui/material";
import type { ReactNode } from "react";

export function PvwsFallback(): ReactNode {
const errorMsg = <b>Error Connecting!</b>;
return (
<TextField
slotProps={{
input: { readOnly: true, color: "error" },
}}
defaultValue={errorMsg}
/>
);
}
46 changes: 46 additions & 0 deletions packages/pvws-config/src/components/ReadOnlyPv.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Box, Typography, useTheme } from "@mui/material";
import { ErrorBoundary } from "react-error-boundary";
import type { ParsePvProps, RenderPvProps } from "../types";
import { useParsedPvConnection } from "../useParsedPvConnection";
import { PvwsFallback } from "./PvwsFallback";

function renderValueWithUnits({
value,
units,
}: {
value: string;
units: string;
}) {
if (value != "not connected" && value != undefined) {
return value.concat(units);
} else {
return value;
}
}

function DefaultPvBox({ label, value }: { label: string; value: string }) {
const theme = useTheme();
return (
<Box>
<Typography variant="body1" color={theme.palette.text.primary}>
<b>{label} </b> {value}
</Typography>
</Box>
);
}

function PvComponent(props: ParsePvProps) {
const latestValue = useParsedPvConnection(props);
const fullValue = props.units
? renderValueWithUnits({ value: latestValue, units: props.units })
: latestValue;
return <DefaultPvBox label={props.label} value={fullValue} />;
}

export function ReadOnlyPv(props: ParsePvProps) {
return (
<ErrorBoundary fallback={<PvwsFallback />}>
{PvComponent(props)}
</ErrorBoundary>
);
}
4 changes: 4 additions & 0 deletions packages/pvws-config/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./loadConfiguration";
export * from "./types";
export * from "./useParsedPvConnection";
export * from "./components/ReadOnlyPv";
Loading
Loading