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
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,57 @@ import { useTestMachineStepper } from "./useTestMachineStepper";
import { Label } from "@/control/Label";
import { EditValue } from "@/control/EditValue";
import { roundToDecimals } from "@/lib/decimal";
import { TouchButton } from "@/components/touch/TouchButton";
import { SelectionGroup } from "@/control/SelectionGroup";
import {
AccelerationFactor,
Frequency,
Mode,
} from "./testMachineStepperNamespace";
Comment thread
Snacj marked this conversation as resolved.
Dismissed

export function TestMachineStepperControlPage() {
const { state, setTargetSpeed, setEnabled, setFreq, setAccFreq } =
useTestMachineStepper();
const {
state,
setTargetSpeed,
setFreq,
setAccFactor,
setMode,
isDisabled,
isLoading,
} = useTestMachineStepper();

return (
<Page>
<ControlGrid columns={2}>
<ControlCard className="bg-red" title="Mode">
<SelectionGroup<Mode>
value={state?.mode_state.mode}
disabled={isDisabled}
loading={isLoading}
onChange={setMode}
orientation="vertical"
className="grid h-full grid-cols-2 gap-2"
options={{
Standby: {
children: "Standby",
icon: "lu:Power",
isActiveClassName: "bg-green-600",
className: "h-full",
},
Hold: {
children: "Hold",
icon: "lu:CirclePause",
isActiveClassName: "bg-green-600",
className: "h-full",
},
Turn: {
children: "Turn",
icon: "lu:ChevronsLeft",
isActiveClassName: "bg-green-600",
className: "h-full",
},
}}
/>
</ControlCard>
<ControlCard title="Stepper Speed">
<Label label="Target Speed">
<EditValue
Expand All @@ -27,101 +69,79 @@ export function TestMachineStepperControlPage() {
renderValue={(value) => roundToDecimals(value, 0)}
onChange={setTargetSpeed}
/>
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setEnabled(true)}
disabled={false}
isLoading={false}
>
Enable
</TouchButton>
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setEnabled(false)}
disabled={false}
isLoading={false}
>
Disable
</TouchButton>
</Label>
</ControlCard>
<ControlCard height={2} title="Frequency Prescaler">
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setFreq(0)}
disabled={false}
isLoading={false}
>
Default (00)
</TouchButton>
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setFreq(1)}
disabled={false}
isLoading={false}
>
Low (01)
</TouchButton>
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setFreq(2)}
disabled={false}
isLoading={false}
>
Mid (10)
</TouchButton>
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setFreq(3)}
disabled={false}
isLoading={false}
>
High (11)
</TouchButton>
<ControlCard className="bg-red" title="Frequency Prescaler">
<SelectionGroup<Frequency>
value={state?.frequency_state.frequency}
disabled={isDisabled}
loading={isLoading}
onChange={setFreq}
orientation="vertical"
className="grid h-full grid-cols-2 gap-2"
options={{
Default: {
children: "Default",
icon: "lu:Power",
isActiveClassName: "bg-green-600",
className: "h-full",
},
Low: {
children: "Low",
icon: "lu:CirclePause",
isActiveClassName: "bg-green-600",
className: "h-full",
},
Mid: {
children: "Mid",
icon: "lu:ChevronsLeft",
isActiveClassName: "bg-green-600",
className: "h-full",
},
Comment on lines +99 to +100
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI label spelling: the card title uses "Acceleration Faktor". If this UI is intended to be English (other labels are), this should be "Acceleration Factor" for consistency.

Copilot uses AI. Check for mistakes.
High: {
children: "High",
icon: "lu:ChevronsLeft",
isActiveClassName: "bg-green-600",
className: "h-full",
},
}}
/>
</ControlCard>
<ControlCard height={2} title="Acceleration Factor">
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setAccFreq(0)}
disabled={false}
isLoading={false}
>
Default (00)
</TouchButton>
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setAccFreq(1)}
disabled={false}
isLoading={false}
>
Low (01)
</TouchButton>
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setAccFreq(2)}
disabled={false}
isLoading={false}
>
Mid (10)
</TouchButton>
<TouchButton
variant="outline"
icon="lu:CirclePower"
onClick={() => setAccFreq(3)}
disabled={false}
isLoading={false}
>
High (11)
</TouchButton>
<ControlCard className="bg-red" title="Acceleration Faktor">
<SelectionGroup<AccelerationFactor>
value={state?.acceleration_state.factor}
disabled={isDisabled}
loading={isLoading}
onChange={setAccFactor}
orientation="vertical"
className="grid h-full grid-cols-2 gap-2"
options={{
Default: {
children: "Default",
icon: "lu:Power",
isActiveClassName: "bg-green-600",
className: "h-full",
},
Low: {
children: "Low",
icon: "lu:CirclePause",
isActiveClassName: "bg-green-600",
className: "h-full",
},
Mid: {
children: "Mid",
icon: "lu:ChevronsLeft",
isActiveClassName: "bg-green-600",
className: "h-full",
},
High: {
children: "High",
icon: "lu:ChevronsLeft",
isActiveClassName: "bg-green-600",
className: "h-full",
},
}}
/>
</ControlCard>
</ControlGrid>
</Page>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,52 @@ import {
} from "@/client/socketioStore";
import { MachineIdentificationUnique } from "@/machines/types";

/**
* Machine operation mode enum
*/
export const modeSchema = z.enum(["Standby", "Hold", "Turn"]);
export type Mode = z.infer<typeof modeSchema>;

/**
* Frequency Prescaler
*/
export const frequencySchema = z.enum(["Default", "Low", "Mid", "High"]);
export type Frequency = z.infer<typeof frequencySchema>;

/**
* Acceleration Factor
*/
export const accelerationSchema = z.enum(["Default", "Low", "Mid", "High"]);
export type AccelerationFactor = z.infer<typeof accelerationSchema>;

Comment on lines +30 to +32
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exported type name AccelerationFaktor mixes languages and differs from the Rust/backend AccelerationFactor, which makes the API surface harder to follow (and forces aliases in consumers). Consider renaming this to AccelerationFactor for consistency across frontend/backend.

Copilot generated this review using guidance from repository custom instructions.
/**
* Mode state schema
*/
export const modeStateSchema = z.object({
mode: modeSchema,
});

/**
* Frequency Prescaler Schema
*/
export const frequencyStateSchema = z.object({
frequency: frequencySchema,
});

/**
* Accleration Factor Schema
*/
export const accelerationStateSchema = z.object({
factor: accelerationSchema,
});
Comment on lines +47 to +52
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling: "Accleration" is misspelled in the comment. Correcting it helps keep the public-facing schema/docs readable.

Copilot uses AI. Check for mistakes.

// ========== Event Schema ==========

export const stateEventDataSchema = z.object({
target_speed: z.number(),
enabled: z.boolean(),
freq: z.number(),
acc_freq: z.number(),
mode_state: modeStateSchema,
frequency_state: frequencyStateSchema,
acceleration_state: accelerationStateSchema,
});

export const stateEventSchema = eventSchema(stateEventDataSchema);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { MachineIdentificationUnique } from "@/machines/types";
import {
useTestMachineStepperNamespace,
StateEvent,
modeSchema,
Mode,
AccelerationFactor as AccelerationFactor,
Frequency,
} from "./testMachineStepperNamespace";
Comment on lines 5 to 12
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modeSchema is imported but never used in this file. If the Electron project enforces @typescript-eslint/no-unused-vars (it appears to elsewhere), this can fail lint/CI; remove the unused import.

Copilot uses AI. Check for mistakes.
import { useMachineMutate } from "@/client/useClient";
import { produce } from "immer";
Expand Down Expand Up @@ -53,7 +57,6 @@ export function useTestMachineStepper() {
value: z.any(),
}),
);

const updateStateOptimistically = (
producer: (current: StateEvent) => void,
serverRequest?: () => void,
Expand All @@ -77,50 +80,56 @@ export function useTestMachineStepper() {
);
};

const setEnabled = (enabled: boolean) => {
const setFreq = (frequency: Frequency) => {
updateStateOptimistically(
(current) => {
current.enabled = enabled;
current.frequency_state.frequency = frequency;
},
() =>
sendMutation({
machine_identification_unique: machineIdentification,
data: { action: "SetEnabled", value: { enabled } },
data: { action: "SetFreq", value: frequency },
}),
);
};

const setFreq = (factor: number) => {
const setAccFactor = (factor: AccelerationFactor) => {
updateStateOptimistically(
(current) => {
current.freq = factor;
current.acceleration_state.factor = factor;
},
() =>
sendMutation({
machine_identification_unique: machineIdentification,
data: { action: "SetFreq", value: { factor } },
data: { action: "SetAccFactor", value: factor },
}),
);
};

const setAccFreq = (factor: number) => {
const setMode = (mode: Mode) => {
updateStateOptimistically(
(current) => {
current.acc_freq = factor;
current.mode_state.mode = mode;
},
() =>
sendMutation({
machine_identification_unique: machineIdentification,
data: { action: "SetAccFreq", value: { factor } },
data: { action: "SetMode", value: mode },
}),
);
};

const isLoading = stateOptimistic.isOptimistic;
const isDisabled = !stateOptimistic.isInitialized;

return {
state: stateOptimistic.value,
setTargetSpeed,
setEnabled,
setFreq,
setAccFreq,
setAccFactor,
setMode,

isLoading,
isDisabled,
};
}
Loading
Loading