Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 35 additions & 0 deletions apps/gda-scan-definition/app/schemas/xspress3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {z} from 'zod';

export const Xspress3DetectorElementRegion = z.object({
roiName: z.string(),
roiStart: z.number(),
roiEnd: z.number(),
});

export const Xspress3DetectorElement = z.object({
name: z.string(),
number: z.number(),
windowStart: z.number(),
windowEnd: z.number(),
excluded: z.boolean(),
Region: Xspress3DetectorElementRegion
});

export type Xspress3DetectorElement = z.infer<typeof Xspress3DetectorElement>;

export const Xspress3ConfigSchema = z.object({
detectorName: z.string(),
resGrade: z.string(),
regionType: z.string(),
readoutMode: z.string(),
editIndividualElements: z.boolean(),
deadtimeCorrectionEnergy: z.number(),

onlyShowFF: z.boolean(),
showDTRawValues: z.boolean(),
saveRawSpectrum: z.boolean(),
selectedRegionNumber: z.number(),
DetectorElements: z.array(Xspress3DetectorElement)
});

export type Xspress3ConfigSchemaType = z.infer<typeof Xspress3ConfigSchema>;
17 changes: 17 additions & 0 deletions apps/gda-scan-definition/app/xspress3/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { actionClient } from "../clients/actionclient";
import { Xspress3ConfigSchema, Xspress3ConfigSchemaType } from "../schemas/xspress3";
import { readXspress3Parameters, updateXspress3Parameters } from "./server-xml";

export const readXspress3Definition = actionClient.action(async (): Promise<{
success: boolean, data: Xspress3ConfigSchemaType | null
}> => {
const result: Xspress3ConfigSchemaType = await readXspress3Parameters();
return { success: true, data: result }
});

export const updateXspress3Definition = actionClient
.schema(Xspress3ConfigSchema).action(async ({ parsedInput}): Promise<{ success: boolean }> => {
console.log(`Updating xspres3 configuration: ${parsedInput}`);
await updateXspress3Parameters(parsedInput);
return { success: true }
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"use client";

import React from 'react'
import { useXspress3Configuration } from '../hooks'
import { Box, Button, InputLabel, Typography } from '@mui/material';
import { CheckBox } from '@mui/icons-material';
import Input from "@mui/material/Input";


function Xspress3Configurator() {
const { config, loading } = useXspress3Configuration();

console.dir(config);
if (loading) {
return <Typography variant='h3'>Loading...</Typography>
}
return (
<Box>
<Button>
Read configuration
</Button>
{config ? (
<>
<InputLabel>
Detector Name:
<Input
type="text"
placeholder="Detector Name"
value={config.detectorName || ""}
onChange={(e) => {
window.alert("not implemented yet")
}} />
</InputLabel>
<pre style={{ color: 'black' }}>{JSON.stringify(config, null, 2)}</pre>

</>

) : (
<p style={{ color: 'black' }}>No configuration available. Please fetch the configuration.</p>
)}


</Box>
)
}

export default Xspress3Configurator
77 changes: 77 additions & 0 deletions apps/gda-scan-definition/app/xspress3/hooks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { useEffect, useState } from "react";
import { Xspress3ConfigSchemaType } from "../schemas/xspress3";
import { readXspress3Definition } from "./action";


// export const updateConfig = async (
// dispatch: React.Dispatch<QexafsAction>,
// newConfig: FullQexafsSchemaType
// ) => {
// dispatch({ type: "START_CONFIG_UPDATE" });

// try {
// const response = await updateScanDefinition(newConfig);
// if (response === undefined) {
// dispatch({ type: "CONFIG_ERROR", payload: "Error updating configuration" });
// } else {
// dispatch({ type: "CONFIG_UPDATE_SUCCESS" });
// }
// } catch (error) {
// dispatch({ type: "CONFIG_ERROR", payload: "Config server error" });
// }
// };

// todo add the update logic
export const useXspress3Configuration = () => {
const [config, setConfig] = useState<Xspress3ConfigSchemaType | null>(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
const fetchConfig = async () => {
try {
const response = await readXspress3Definition();
if(response?.data){
setConfig(response.data.data); // Assuming API returns an array of strings
}

} catch (err: any) {
console.error(err);
} finally {
setLoading(false);
}
};

fetchConfig();
}, []);

return { config, loading };
};


// export const usePlanByName = (name: string) => {
// const [plan, setPlan] = useState<{ name: string; schema: any } | null>(null);
// const [loading, setLoading] = useState(true);
// const [error, setError] = useState<string | null>(null);

// useEffect(() => {
// if (!name) return;

// setLoading(true);
// api.get(`/plans/${name}`)
// .then((response) => {
// setPlan(response.data);
// })
// .catch((err) => {
// console.log(`response: ${err}`)
// console.log(`name: ${name}`);
// console.dir(name);
// setError(err.message);
// })
// .finally(() => {
// setLoading(false);
// });
// }, [name]);

// return { plan, loading, error };

// }
17 changes: 17 additions & 0 deletions apps/gda-scan-definition/app/xspress3/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@



import { Typography } from '@mui/material'
import React from 'react'
import Xspress3Configurator from './components/Xspress3Configurator'

function Xspress3ConfigPage() {
return (
<div>
<Typography variant="h2" sx={{color: 'black'}}>xpress3 config here</Typography>
<Xspress3Configurator/>
</div>
)
}

export default Xspress3ConfigPage
69 changes: 69 additions & 0 deletions apps/gda-scan-definition/app/xspress3/server-xml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"use server";
import { basePath } from "../actions/basePath";
import { fixXmlToWrapInList } from "../qexafs/fixXmlToWrapInList";
import { PREPEND_FOR_XML } from "../qexafs/server-xml";
import { Xspress3ConfigSchema, Xspress3ConfigSchemaType } from "../schemas/xspress3";
import { XMLBuilder, XmlBuilderOptions, XMLParser } from "fast-xml-parser";
import fs from "fs";

const parserOptions = {
ignoreAttributes: false, // Keep attributes if present
// alwaysCreateTextNode: true, // Ensures text nodes are explicitly stored
isArray: (name: string, jpath) => {
return false;
// Define elements that should be arrays when duplicated
const arrayFields = ["sampleParameterMotorPosition", "detectorConfiguration"]; // Example duplicated elements
return arrayFields.includes(name); // Only convert these to arrays
},
};
const options: XmlBuilderOptions = {
// processEntities: false,
// preserveOrder: true,
format: true,
// ignoreAttributes: false,
// commentPropName: "phone"
};


const xspress3Path = `${basePath}/Xspress3.xml`;
const parser = new XMLParser(parserOptions);
const builder = new XMLBuilder(options);

export async function readXspress3Parameters(): Promise<Xspress3ConfigSchemaType> {
const content = fs.readFileSync(xspress3Path);
console.log(`raw content: ${content}`);
const fixed = fixXmlToWrapInList(content.toString(), "DetectorElement", "DetectorElements")
const parsedResult = parser.parse(fixed);

console.log(fixed)
console.log(parsedResult);
const p = parsedResult.XspressParameters;
console.log(`trying to read the parameters, ${p}`)
console.dir(p)
const tmpFirstItem = p.DetectorElements;
const tmpArrayCopy = p.DetectorElements;
delete p.DetectorElements;
p.DetectorElement = tmpFirstItem;
// todo temporary reset to []
p.DetectorElements = [];

try {
const params:Xspress3ConfigSchemaType = Xspress3ConfigSchema.parse(p);
params.DetectorElements = tmpArrayCopy;
console.log(`should be parsed by now`)
console.dir(params);
return params
} catch (e) {
console.log("Error", e);
}
throw new Error("Failed to parse xspress3 parameters at path " + xspress3Path);
}

export async function updateXspress3Parameters(data: Xspress3ConfigSchemaType): Promise<void> {
const fullObject = {
"XspressParameters": data
}
const xml = builder.build(fullObject);
fs.writeFileSync(xspress3Path, `${PREPEND_FOR_XML}\n${xml}`);
}

97 changes: 97 additions & 0 deletions apps/gda-scan-definition/reference/Xspress3.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<XspressParameters>
<detectorName>xspress3X</detectorName>
<resGrade>res-none</resGrade>
<regionType>Virtual Scaler</regionType>
<readoutMode>Scalers and MCA</readoutMode>
<editIndividualElements>false</editIndividualElements>
<deadtimeCorrectionEnergy>10.0</deadtimeCorrectionEnergy>
<DetectorElement>
<name>Element 0</name>
<number>0</number>
<windowStart>742</windowStart>
<windowEnd>850</windowEnd>
<excluded>false</excluded>
<Region>
<roiName>ROI_1</roiName>
<roiStart>760</roiStart>
<roiEnd>841</roiEnd>
</Region>
</DetectorElement>
<DetectorElement>
<name>Element 1</name>
<number>1</number>
<windowStart>742</windowStart>
<windowEnd>850</windowEnd>
<excluded>false</excluded>
<Region>
<roiName>ROI_1</roiName>
<roiStart>760</roiStart>
<roiEnd>841</roiEnd>
</Region>
</DetectorElement>
<DetectorElement>
<name>Element 2</name>
<number>2</number>
<windowStart>742</windowStart>
<windowEnd>850</windowEnd>
<excluded>false</excluded>
<Region>
<roiName>ROI_1</roiName>
<roiStart>760</roiStart>
<roiEnd>841</roiEnd>
</Region>
</DetectorElement>
<DetectorElement>
<name>Element 3</name>
<number>3</number>
<windowStart>742</windowStart>
<windowEnd>850</windowEnd>
<excluded>false</excluded>
<Region>
<roiName>ROI_1</roiName>
<roiStart>760</roiStart>
<roiEnd>841</roiEnd>
</Region>
</DetectorElement>
<DetectorElement>
<name>Element 4</name>
<number>4</number>
<windowStart>742</windowStart>
<windowEnd>850</windowEnd>
<excluded>false</excluded>
<Region>
<roiName>ROI_1</roiName>
<roiStart>760</roiStart>
<roiEnd>841</roiEnd>
</Region>
</DetectorElement>
<DetectorElement>
<name>Element 5</name>
<number>5</number>
<windowStart>742</windowStart>
<windowEnd>850</windowEnd>
<excluded>false</excluded>
<Region>
<roiName>ROI_1</roiName>
<roiStart>760</roiStart>
<roiEnd>841</roiEnd>
</Region>
</DetectorElement>
<DetectorElement>
<name>Element 6</name>
<number>6</number>
<windowStart>742</windowStart>
<windowEnd>850</windowEnd>
<excluded>false</excluded>
<Region>
<roiName>ROI_1</roiName>
<roiStart>760</roiStart>
<roiEnd>841</roiEnd>
</Region>
</DetectorElement>
<onlyShowFF>false</onlyShowFF>
<showDTRawValues>false</showDTRawValues>
<saveRawSpectrum>false</saveRawSpectrum>
<selectedRegionNumber>0</selectedRegionNumber>
</XspressParameters>
1 change: 1 addition & 0 deletions apps/gda-scan-definition/scripts/setupFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const fileNames = [
"QEXAFS_Parameters.xml",
"Sample_Parameters.xml",
"long.xml",
"Xspress3.xml"
]; // Array of file names to copy

// const basePath = "./targetFolder"; // Base folder where files will be copied to
Expand Down
Loading