chore: among other things, fixed connection issue

fix: connection issue
conditional norm now able to undo
 and are updated via pings
goals are able to be achieved out of turn

ref: N25B-400
This commit is contained in:
Pim Hutting
2026-01-16 12:57:22 +01:00
parent a98a87f8ce
commit c4e3ab27b2
5 changed files with 126 additions and 59 deletions

View File

@@ -2,7 +2,7 @@ import React from 'react';
import styles from './MonitoringPage.module.css';
import useProgramStore from "../../utils/programStore.ts";
import { GestureControls, SpeechPresets, DirectSpeechInput, StatusList, RobotConnected } from './MonitoringPageComponents.tsx';
import { nextPhase, useExperimentLogger, pauseExperiment, playExperiment, resetExperiment, resetPhase, type ExperimentStreamData, type GoalUpdate, type TriggerUpdate, type CondNormsStateUpdate, type PhaseUpdate } from ".//MonitoringPageAPI.ts"
import { nextPhase, useExperimentLogger, useStatusLogger, pauseExperiment, playExperiment, resetExperiment, resetPhase, type ExperimentStreamData, type GoalUpdate, type TriggerUpdate, type CondNormsStateUpdate, type PhaseUpdate } from ".//MonitoringPageAPI.ts"
import type { NormNodeData } from '../VisProgPage/visualProgrammingUI/nodes/NormNode.tsx';
@@ -35,6 +35,7 @@ export type ReducedNorm = { id: string; label?: string; norm?: string; condition
const MonitoringPage: React.FC = () => {
const getPhaseIds = useProgramStore((s) => s.getPhaseIds);
const getPhaseNames = useProgramStore((s) => s.getPhaseNames);
const getNormsInPhase = useProgramStore((s) => s.getNormsInPhase);
const getGoalsInPhase = useProgramStore((s) => s.getGoalsInPhase);
const getTriggersInPhase = useProgramStore((s) => s.getTriggersInPhase);
@@ -46,9 +47,10 @@ const MonitoringPage: React.FC = () => {
const [isPlaying, setIsPlaying] = React.useState(false);
const phaseIds = getPhaseIds();
const phaseNames = getPhaseNames();
const [phaseIndex, setPhaseIndex] = React.useState(0);
//see if we reached end node
const [isFinished, setIsFinished] = React.useState(false);
@@ -56,6 +58,7 @@ const MonitoringPage: React.FC = () => {
// Check for phase updates
if (data.type === 'phase_update' && data.id) {
const payload = data as PhaseUpdate;
console.log(`${data.type} received, id : ${data.id}`)
if (payload.id === "end") {
setIsFinished(true);
} else {
@@ -73,8 +76,10 @@ const MonitoringPage: React.FC = () => {
const payload = data as GoalUpdate;
const currentPhaseGoals = getGoalsInPhase(phaseIds[phaseIndex]) as ReducedGoal[];
const gIndex = currentPhaseGoals.findIndex((g: ReducedGoal) => g.id === payload.id);
if (gIndex !== -1) {
console.log(`${data.type} received, id : ${data.id}`)
if (gIndex == -1)
{console.log(`goal to update with id ${payload.id} not found in current phase ${phaseNames[phaseIndex]}`)}
else {
//set current goal to the goal that is just started
setGoalIndex(gIndex);
@@ -101,24 +106,33 @@ const MonitoringPage: React.FC = () => {
...prev,
[payload.id]: payload.achieved
}));
}
else if (data.type === 'cond_norms_state_update') {
}
}, [getPhaseIds, getGoalsInPhase, phaseIds, phaseIndex]);
const handleStatusUpdate = React.useCallback((data: any) => {
if (data.type === 'cond_norms_state_update') {
const payload = data as CondNormsStateUpdate;
setActiveIds((prev) => {
const hasChanges = payload.norms.some(
(normUpdate) => prev[normUpdate.id] !== normUpdate.active
);
if (!hasChanges) {
return prev;
}
const nextState = { ...prev };
// payload.norms is typed on the union, so safe to use directly
payload.norms.forEach((normUpdate) => {
nextState[normUpdate.id] = normUpdate.active;
});
return nextState;
});
//commented out to avoid cluttering
//console.log("Updated conditional norms state:", payload.norms);
}
}, [getPhaseIds, getGoalsInPhase, phaseIds, phaseIndex]);
}, []);
//For incoming phase, goals and trigger updates
useExperimentLogger(handleStreamUpdate);
//For pings that update conditional norms
useStatusLogger(handleStatusUpdate);
if (phaseIds.length === 0) {
return <p className={styles.empty}>No program loaded.</p>;
@@ -229,19 +243,40 @@ const MonitoringPage: React.FC = () => {
<header className={styles.experimentOverview}>
<div className={styles.phaseName}>
<h2>Experiment Overview</h2>
<p><strong>Phase</strong> {` ${phaseIndex + 1}`} </p>
<p>
{isFinished ? (
<strong>Experiment finished</strong>
) : (
<>
<strong>Phase {phaseIndex + 1}:</strong> {phaseNames[phaseIndex]}
</>
)}
</p>
<div className={styles.phaseProgress}>
{phaseIds.map((id, index) => (
<span
key={id}
className={`${styles.phase} ${
index < phaseIndex ? styles.completed :
index === phaseIndex ? styles.current : ""
}`}
>
{index + 1}
</span>
))}
{phaseIds.map((id, index) => {
// Determine the status of the phase indicator
let phaseStatusClass = "";
if (isFinished) {
// If the whole experiment is done, all squares are green (completed)
phaseStatusClass = styles.completed;
} else if (index < phaseIndex) {
// Past phases
phaseStatusClass = styles.completed;
} else if (index === phaseIndex) {
// The current phase being worked on
phaseStatusClass = styles.current;
}
return (
<span
key={id}
className={`${styles.phase} ${phaseStatusClass}`}
>
{index + 1}
</span>
);
})}
</div>
</div>
@@ -314,7 +349,7 @@ const MonitoringPage: React.FC = () => {
</div>
) : (
<>
<StatusList title="Goals" items={goals} type="goal" activeIds={activeIds} currentGoalIndex={goalIndex} />
<StatusList title="Goals" items={goals} type="goal" activeIds={activeIds} setActiveIds = {setActiveIds} currentGoalIndex={goalIndex} />
<StatusList title="Triggers" items={triggers} type="trigger" activeIds={activeIds} />
<StatusList title="Norms" items={norms} type="norm" activeIds={activeIds} />
<StatusList title="Conditional Norms" items={conditionalNorms} type="cond_norm" activeIds={activeIds} />