Batch of GUI improvements from beamline operation feedback.
Safety principle: opening the GUI never moves hardware
A login-default state POST (staff -> Beam location, users -> Sample
alignment) was added during this branch and then deliberately REMOVED:
a state transition can move motors, and merely starting or logging
into the GUI must never move anything. The GUI now only adopts the
state the server reports and posts no transition on startup. A comment
in update_daq_status pins this decision so it does not come back.
Same principle applied to input paths: typing into motor boxes stages
values only; nothing moves until the Move button is clicked. Wheel
events on value widgets are guarded, and a left click on the state
strip never starts a transition (right-click menu only).
Busy-state UX
BEAMLINE BUSY flag in Gonio camera, Beamline view and combined view is
now plain shadowed status text (same look as the sample camera
warnings), not the badge pill that read as a button.
The state strip greys out completely while the beamline is busy or
Moving, so no transition looks clickable mid-operation.
While busy, the video tab switches to the Beamline combined view so
the motion can be observed, and returns to the Sample camera when done
(generalizes the old robot-mount auto-switch).
Role-dependent behavior
Non-staff now see the Beamline setup / ABR meas. pos. / Beam
configuration banners as locked stand-ins instead of nothing; clicking
one explains the staff gate and points to the local contact.
A click on the pgroup-gated (disabled) Beamline tab is no longer eaten
silently: staff get the visitor-pgroup explanation, users the
staff-only message (same pattern as the Auxiliary-puck tab).
Motor and panel work
Motor entries stage values and apply moves in one click; new
MotorMoveGroup widget with unit tests.
Light slider changes emit from every input path, readback guarded.
Batch of GUI improvements from beamline operation feedback.
Safety principle: opening the GUI never moves hardware
- A login-default state POST (staff -> Beam location, users -> Sample
alignment) was added during this branch and then deliberately REMOVED:
a state transition can move motors, and merely starting or logging
into the GUI must never move anything. The GUI now only adopts the
state the server reports and posts no transition on startup. A comment
in update_daq_status pins this decision so it does not come back.
- Same principle applied to input paths: typing into motor boxes stages
values only; nothing moves until the Move button is clicked. Wheel
events on value widgets are guarded, and a left click on the state
strip never starts a transition (right-click menu only).
Busy-state UX
- BEAMLINE BUSY flag in Gonio camera, Beamline view and combined view is
now plain shadowed status text (same look as the sample camera
warnings), not the badge pill that read as a button.
- The state strip greys out completely while the beamline is busy or
Moving, so no transition looks clickable mid-operation.
- While busy, the video tab switches to the Beamline combined view so
the motion can be observed, and returns to the Sample camera when done
(generalizes the old robot-mount auto-switch).
Role-dependent behavior
- Non-staff now see the Beamline setup / ABR meas. pos. / Beam
configuration banners as locked stand-ins instead of nothing; clicking
one explains the staff gate and points to the local contact.
- A click on the pgroup-gated (disabled) Beamline tab is no longer eaten
silently: staff get the visitor-pgroup explanation, users the
staff-only message (same pattern as the Auxiliary-puck tab).
Motor and panel work
- Motor entries stage values and apply moves in one click; new
MotorMoveGroup widget with unit tests.
- Light slider changes emit from every input path, readback guarded.
- Smargon Chi/Phi row unsqueezed, GM labels reserve sign width.
- Change Energy row in experiment configuration; Monochromator panel
renamed to Beamline setup (case-consistent).
Stability and CI
- Prediction subscriber no longer aborts libzmq or logs per-frame decode
errors.
- Exposure wheel guard, banner PNG fallback for RHEL9 consoles, misc
naming and comment cleanups.
- All four CI gates green: ruff format and lint, basedpyright diff at
100 percent, diff coverage vs main at 100 percent (was 62).
Generated with Claude Code (https://claude.com/claude-code)
Sniff for '{' before JSON-parsing zmq parts: JPEG frames start with 0xff
and raised UnicodeDecodeError on every frame. Stop closing the socket
from the GUI thread in stop(): zmq sockets are not thread-safe and the
concurrent close/recv tripped the signaler.cpp POLLIN assertion (core
dump); run() closes it in its own thread via the 500ms RCVTIMEO.
uv.lock: sync version to 0.8.3.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Qt xcb/windows swap wheel axes while Alt is held, so angleDelta().y() is 0
and copysign(_, 0) is always positive. Fall back to angleDelta().x() and
ignore genuine zero deltas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Chi/Phi boxes in the Smargon tab no longer move on Enter: edits stage
the target (orange), the Move button sends all staged axes at once
(green), and boxes return to neutral when the motor reports arrival.
Out-of-range entries stay red and are never sent; limit tips pop as
tooltips. MotorMoveGroup is opt-in per box so other panels can adopt
the same logic later.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Underlined 'More… (F1)' line at the bottom of the painted help box emits
open_full_help, wired to the existing Mouse / Keyboard Controls dialog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Value column was content-sized, so rows shifted whenever a value flipped
negative. Labels now reserve '-88.888' width; right alignment keeps digits
anchored. Also TODO: red colors on live aerotech while labels display
aerotech_meas - intent unconfirmed, do not change condition until decided.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move button gets its own full-width row instead of sharing row 1 with the
Chi/Phi entries; Step box spans columns 1-4 instead of the narrow Chi
column.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copy of the Beamline Setup energy row (keV display, eV emit), placed
below the ML Loop Centring / Make Raster Grid row and always visible.
Wired to the same daq.change_energy; not staff-gated, server enforces
write permission.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Display title only; class and file keep their names. New full-width
'Move Beam to Box (center) (WIP)' button under the Energy row, disabled
with a coming-soon tooltip until a DAQ endpoint exists.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sliders only emitted on sliderReleased, so right-click+wheel, arrow keys
and groove clicks changed the value locally without a PUT and the 500 ms
status poll snapped it back. setTracking(False) + valueChanged now sends
one PUT per deliberate change; readback setValue is wrapped in
blockSignals to avoid echoing PUTs, and a 1.5 s grace window stops
in-flight stale status responses from bouncing the slider.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Switching to a visitor pgroup means running a user experiment: grey out
the Beamline tab (tooltip: beamline scientists only), bring the
Experiment tab forward with Dataset path and Exp. Config. opened.
Gate applies on transitions only so manual tab choices survive the
1 Hz status ticks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Staff land in BeamLocation, users in SampleAlignment. One-shot on the
first status tick where the GUI owns the session and the beamline is
idle, so a running operation or a watch-only GUI is never disturbed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beamline setup, ABR meas. pos. and Beam configuration banners stay
visible for non-staff instead of vanishing, but are locked stand-ins:
clicking one pops the staff-only notice (same pattern as the
Auxiliary-puck tab) telling the user to log in as staff or contact
their local contact.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Panel title case now matches the other banner names. Also clarify the
splash banner comment in gui.py.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gonio camera, Beamline view and the combined view showed BEAMLINE BUSY
in the rounded badge pill, which reads as a clickable button. These
views are passive, so draw the same shadowed colored text the sample
camera uses for its warnings; the pill stays only on the sample-camera
session badges, which really are click targets.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Busy now empties the available-target set exactly like Moving, so no
entry looks clickable and no transition can be posted mid-operation
(same guard the status-bar menu already had). The current/pending
entry keeps its highlight as orientation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generalize the robot-mount auto-switch: any busy period now brings up
the combined view so the motion can be watched, and the sample camera
returns when busy clears. Edge-triggered, so manual tab choices
survive between transitions; _mounting renamed to _watching_motion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ruff format collapsed lines the Beamline setup rename and other edits
left splittable; SIM201 wanted != over 'not ... ==' in the prediction
subscriber's JSON sniff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rename NumberLineEdit.validator to range_validator: the instance attr
shadowed QLineEdit.validator() and broke type checking at call sites.
Annotate the smargon _move_axes dict and cast the stand-in self in the
prediction subscriber test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Promote the illumination panel's __main__ self-check to a real pytest
file so CI counts it, add busy-overlay render checks (status text
paints, video view routes through it), and cover the motor group's
incomplete-entry and below-min Enter paths. Local diff coverage from
the gui suite alone: 82 percent.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
duan_j
marked the pull request as work in progress 2026-08-14 09:05:25 +02:00
Two changes folded together because they touch the same status path:
- Revert the login-default state POST: a state transition can move
motors, and merely opening the GUI must never move hardware. The GUI
now adopts whatever state the server reports.
- A click on the pgroup-gated (disabled) Beamline tab used to be eaten
silently by the tab bar. An event filter now pops the explanation:
visitor-pgroup wording for staff, the staff-only message for users
(same pattern as the Auxiliary-puck tab).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diff coverage vs main now 100 percent from the gui suite alone:
non-staff locked banners and both gated-tab popups, remote-close
bookkeeping in update_daq_status, smargon staged moves, camera More
link and Alt-wheel axis fallback, number box relimits, energy row
emit, and the gui.main() banner/graceful-exit path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
duan_j
marked the pull request as ready for review 2026-08-14 09:26:22 +02:00
Per-test lines and live (uncaptured) output: the pxiii_bec job sat
silent at 81 percent for hours, and file-level dots could not say which
test wedged. With -s -vv a hang names its test and streams the last
log lines before it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The locked-banner and Beamline-tab-bar filters were installed mid
__init__, but MainWindow.eventFilter reads sample_lists_tabs, which is
created later - every event delivered in between raised AttributeError
inside the filter ('Error calling Python override of eventFilter()'
spam) and broke widget teardown, cascading errors across CI tests and
wedging the pxiii_bec job. Filters now install late, next to
installEventFilter(self), and the filter guards its attribute reads so
construction/teardown-time events can never raise.
Also fold the staff-gate assertions into test_main_window_init: every
extra MainWindow construction raises the odds of the pre-existing
PySide SystemError flake, so don't build a window just for them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
duan_j
merged commit 190e728734 into main2026-08-17 13:42:00 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Batch of GUI improvements from beamline operation feedback.
Safety principle: opening the GUI never moves hardware
alignment) was added during this branch and then deliberately REMOVED:
a state transition can move motors, and merely starting or logging
into the GUI must never move anything. The GUI now only adopts the
state the server reports and posts no transition on startup. A comment
in update_daq_status pins this decision so it does not come back.
values only; nothing moves until the Move button is clicked. Wheel
events on value widgets are guarded, and a left click on the state
strip never starts a transition (right-click menu only).
Busy-state UX
now plain shadowed status text (same look as the sample camera
warnings), not the badge pill that read as a button.
Moving, so no transition looks clickable mid-operation.
the motion can be observed, and returns to the Sample camera when done
(generalizes the old robot-mount auto-switch).
Role-dependent behavior
configuration banners as locked stand-ins instead of nothing; clicking
one explains the staff gate and points to the local contact.
silently: staff get the visitor-pgroup explanation, users the
staff-only message (same pattern as the Auxiliary-puck tab).
Motor and panel work
MotorMoveGroup widget with unit tests.
renamed to Beamline setup (case-consistent).
Stability and CI
errors.
naming and comment cleanups.
100 percent, diff coverage vs main at 100 percent (was 62).
Generated with Claude Code (https://claude.com/claude-code)
Sniff for '{' before JSON-parsing zmq parts: JPEG frames start with 0xff and raised UnicodeDecodeError on every frame. Stop closing the socket from the GUI thread in stop(): zmq sockets are not thread-safe and the concurrent close/recv tripped the signaler.cpp POLLIN assertion (core dump); run() closes it in its own thread via the 500ms RCVTIMEO. uv.lock: sync version to 0.8.3. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Coverage report (automated)
Total line + branch coverage: 48%
Diff coverage vs main: 99% (minimum 80%)
Full report: coverage artifact on this run.
The locked-banner and Beamline-tab-bar filters were installed mid __init__, but MainWindow.eventFilter reads sample_lists_tabs, which is created later - every event delivered in between raised AttributeError inside the filter ('Error calling Python override of eventFilter()' spam) and broke widget teardown, cascading errors across CI tests and wedging the pxiii_bec job. Filters now install late, next to installEventFilter(self), and the filter guards its attribute reads so construction/teardown-time events can never raise. Also fold the staff-gate assertions into test_main_window_init: every extra MainWindow construction raises the odds of the pre-existing PySide SystemError flake, so don't build a window just for them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>