Skip to content

Commit

Permalink
Merge branch 'main' into stu-346-placeholder-test
Browse files Browse the repository at this point in the history
  • Loading branch information
LatentDream authored Apr 18, 2024
2 parents be7f5ca + 8d389cb commit e22897d
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 15 deletions.
10 changes: 7 additions & 3 deletions captain/routes/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class Project(CloudModel):
updated_at: Optional[datetime.datetime] = Field(..., alias="updatedAt")
part_variation_id: str = Field(..., alias="partVariationId")
repo_url: Optional[str] = Field(..., alias="repoUrl")
num_cycles: int = Field(..., alias="numCycles")


class Part(CloudModel):
Expand Down Expand Up @@ -144,6 +145,7 @@ class Measurement(BaseModel):
pass_: Optional[bool]
completion_time: float = Field(..., alias="completionTime")
created_at: str = Field(..., alias="createdAt")
unit: str


class Session(BaseModel):
Expand All @@ -160,7 +162,7 @@ class Session(BaseModel):
MeasurementType = Literal["boolean", "dataframe", "scalar"]


def make_payload(data: MeasurementData):
def make_payload(data: MeasurementData, unit: str):
match data:
case bool():
return {"type": "boolean", "value": data}
Expand All @@ -172,7 +174,7 @@ def make_payload(data: MeasurementData):

return {"type": "dataframe", "value": value}
case int() | float():
return {"type": "scalar", "value": data}
return {"type": "scalar", "value": data, "unit": unit}
case _:
raise TypeError(f"Unsupported data type: {type(data)}")

Expand Down Expand Up @@ -220,6 +222,7 @@ async def get_cloud_projects():
"value": p.id,
"part": part_var.model_dump(by_alias=True),
"repoUrl": p.repo_url,
"numCycles": p.num_cycles,
"productName": part.product_name,
}
)
Expand Down Expand Up @@ -277,9 +280,10 @@ async def post_cloud_session(_: Response, body: Session):
payload = body.model_dump(by_alias=True)
payload["createdAt"] = utcnow_str()
for i, m in enumerate(payload["measurements"]):
m["data"] = make_payload(get_measurement(body.measurements[i]))
m["data"] = make_payload(get_measurement(body.measurements[i]), m["unit"])
m["pass"] = m.pop("pass_")
m["durationMs"] = int(m.pop("completionTime") * 1000)
del m["unit"]
response = requests.post(url, json=payload, headers=headers_builder())
if response.status_code == 200:
return Response(status_code=200, content=json.dumps(response.json()))
Expand Down
9 changes: 8 additions & 1 deletion src/renderer/hooks/useTestSequencerProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,14 @@ export const useLoadTestProfile = () => {
const manager = usePrepareStateManager();
const { isAdmin } = useWithPermission();
const clearState = useSequencerStore(useShallow((state) => state.clearState));
const setCycleCount = useSequencerStore(
useShallow((state) => state.setCycleCount),
);

const setCommitHash = useSequencerStore(
useShallow((state) => state.setCommitHash),
);
const handleImport = async (gitRepoUrlHttp: string) => {
const handleImport = async (gitRepoUrlHttp: string, numberCycles: number) => {
async function importSequences(): Promise<Result<void, Error>> {
// Confirmation if admin
if (isAdmin()) {
Expand All @@ -144,6 +148,9 @@ export const useLoadTestProfile = () => {
return err(Error("No sequences associated with the test profile"));
}

// Set number of cycles
setCycleCount(numberCycles);

// Load test profile
const res = await installTestProfile(gitRepoUrlHttp);
if (res.isErr()) {
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ const Project = z.object({
.transform((value) => value ?? ""),
part: Part,
productName: z.string(),
numCycles: z.number(),
});
export type Project = z.infer<typeof Project>;
export const getCloudProjects = () =>
Expand Down Expand Up @@ -234,6 +235,7 @@ export const postSession = (
pass_: elem.status === "pass",
completionTime: elem.completionTime ?? 0,
createdAt: elem.createdAt!,
unit: elem.unit ?? "",
});
}
});
Expand Down Expand Up @@ -263,6 +265,7 @@ const Measurement = z.object({
pass_: z.boolean().optional(),
completionTime: z.number(),
createdAt: z.string(),
unit: z.string(),
});
export type Measurement = z.infer<typeof Measurement>;

Expand Down
34 changes: 27 additions & 7 deletions src/renderer/routes/test_sequencer_panel/components/CloudPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import {
import { toastQueryError } from "@/renderer/utils/report-error";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Spinner } from "@/renderer/components/ui/spinner";
import { TestSequenceContainer } from "@/renderer/types/test-sequencer";
import {
CycleConfig,
TestSequenceContainer,
} from "@/renderer/types/test-sequencer";
import { Badge } from "@/renderer/components/ui/badge";
import { Checkbox } from "@/renderer/components/ui/checkbox";
import useWithPermission from "@/renderer/hooks/useWithPermission";
Expand All @@ -51,6 +54,7 @@ export function CloudPanel() {
const { sequences, handleUpload } = useSequencerState();
const handleLoadProfile = useLoadTestProfile();
const [testProfileUrl, setTestProfileUrl] = useState<string | null>(null);
const [numberCycles, setNumberCycles] = useState<number | null>(null);
const {
serialNumber,
isUploaded,
Expand All @@ -59,6 +63,7 @@ export function CloudPanel() {
setStationId,
uploadAfterRun,
setUploadAfterRun,
cycleConfig,
} = useSequencerStore(
useShallow((state) => ({
serialNumber: state.serialNumber,
Expand All @@ -68,6 +73,7 @@ export function CloudPanel() {
setStationId: state.setStationId,
uploadAfterRun: state.uploadAfterRun,
setUploadAfterRun: state.setUploadAfterRun,
cycleConfig: state.cycleConfig,
})),
);

Expand All @@ -87,11 +93,15 @@ export function CloudPanel() {
setUploadAfterRun(!isAdmin());
}, [isAdmin]);

const getIntegrity = (sequences: TestSequenceContainer[]): boolean => {
const getIntegrity = (
sequences: TestSequenceContainer[],
cycleConf: CycleConfig,
): boolean => {
let integrity = true;
sequences.forEach((seq) => {
integrity = integrity && seq.runable;
});
integrity = integrity && cycleConf.cycleCount === numberCycles;
setIntegrity(integrity);
return integrity;
};
Expand Down Expand Up @@ -188,6 +198,12 @@ export function CloudPanel() {
enabled: projectsQuery.isSuccess, // Enable only when projectsQuery is successful
});

const loadProfile = () => {
if (testProfileUrl !== null && numberCycles !== null) {
handleLoadProfile(testProfileUrl, numberCycles);
}
};

useEffect(() => {
if (projectId !== "") {
stationsQuery.refetch();
Expand All @@ -200,9 +216,7 @@ export function CloudPanel() {
}, [partVarId]);

useEffect(() => {
if (testProfileUrl !== null) {
handleLoadProfile(testProfileUrl);
}
loadProfile();
}, [testProfileUrl]);

useEffect(() => {
Expand All @@ -220,6 +234,7 @@ export function CloudPanel() {
setPartNumber(newValue.part.partNumber);
setPartVarId(newValue.part.partVariationId);
setTestProfileUrl(newValue.repoUrl);
setNumberCycles(newValue.numCycles);
setProductName(newValue.productName);
};

Expand Down Expand Up @@ -381,10 +396,15 @@ export function CloudPanel() {
<p>Sequencer: {"TS-" + packageJson.version} </p>
<p className="ml-6">
Integrity:{" "}
{getIntegrity(sequences) ? (
{getIntegrity(sequences, cycleConfig) ? (
<Badge className="h-4 bg-green-500">Pass</Badge>
) : (
<Badge className="h-4 bg-red-500">Fail</Badge>
<Badge
className="h-4 cursor-pointer bg-red-500"
onClick={() => loadProfile()}
>
Fail
</Badge>
)}
</p>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const mapStatusToDisplay: { [k in StatusType] } = {
FAIL
</Badge>
</HoverCardTrigger>
<HoverCardContent className="w-256 h-max-256 z-20 mt-2 overscroll-y-auto rounded-lg border bg-card px-3 py-2 text-card-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
<HoverCardContent className="z-20 mt-2 h-[306px] w-[600px] overscroll-y-auto rounded-lg border bg-card px-3 py-2 text-card-foreground shadow-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
<h2 className="text-muted-foreground">Error Message:</h2>
{renderErrorMessage(status)}
</HoverCardContent>
Expand All @@ -63,7 +63,7 @@ export const mapStatusToDisplay: { [k in StatusType] } = {
function renderErrorMessage(text: string): JSX.Element {
const lines = text.split("\n");
return (
<div className="mt-2 whitespace-pre rounded-md bg-secondary p-2">
<div className="mt-2 h-[256px] overflow-scroll whitespace-pre rounded-md bg-secondary p-2">
{lines.map((line, index) => (
<div key={index}>{line}</div>
))}
Expand Down
7 changes: 5 additions & 2 deletions src/renderer/stores/sequencer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ export const useSequencerStore = create<State & Actions>()(
},

// Cycles state management ===================================

setCycleCount: (val: number) => {
if (val < 1) {
set((state) => {
Expand All @@ -347,10 +348,12 @@ export const useSequencerStore = create<State & Actions>()(
}
},

setInfinite: (val: boolean) =>
setInfinite: (val: boolean) => {
set((state) => {
state.cycleConfig.infinite = val;
}),
state.cycleConfig.cycleCount = val ? -1 : 1;
});
},
saveCycle: () => {
if (
get().cycleRuns.length > get().cycleConfig.cycleCount &&
Expand Down

0 comments on commit e22897d

Please sign in to comment.