Skip to content

Commit c2ef047

Browse files
HanSur94claude
andauthored
Rename dashboard toolbar Reset button to Redraw (260602-p2t) (#187)
* Rename dashboard toolbar 'Reset' button to 'Redraw' (260602-p2t) The top-bar button labelled 'Reset' actually forces a full re-render of every widget on the active page (onReset -> DashboardEngine.rerenderWidgets), not a reset. Rename the user-facing label to 'Redraw' so its purpose is clear; the tooltip already described the re-render behaviour. Internal handle/handler (hResetBtn/onReset) keep their historical names. The time-panel 'Reset' button (resetTimeRange) is a genuine reset and is left unchanged. Updates test_dashboard_toolbar_buttons label assertion + button-names list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(quick-260602-p2t): Rename dashboard toolbar Reset button to Redraw Quick-task artifacts (PLAN/SUMMARY) + STATE.md tracking row for the toolbar 'Reset' -> 'Redraw' label rename. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 833dae8 commit c2ef047

5 files changed

Lines changed: 121 additions & 10 deletions

File tree

.planning/STATE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Phase: 1040
2727
Plan: Not started
2828
Milestone: v3.0 FastSense Companion — SHIPPED 2026-04-30; v4.0 Multi-User LAN Concurrency — shipping via PR #152 (parallel branch); v1.0 perf line tracks phase 1028 — now COMPLETE via PR #114.
2929
Status: Phase complete — ready for verification
30-
Last activity: 2026-06-02 - Completed quick task 260602-mri: crosshair-link toggle on the FastSense widget bar (mirrors the hover crosshair across active-page FastSense widgets)
30+
Last activity: 2026-06-02 - Completed quick task 260602-p2t: renamed dashboard toolbar "Reset" button to "Redraw" (the button forces a full widget re-render, not a reset)
3131

3232
### Note on parallel v4.0 work (main branch state)
3333

@@ -97,6 +97,7 @@ Other main PRs (#138, #139, #141, #144, #145, #146) auto-merged without conflict
9797
| 260529-rxf | Real per-event email alerts for background monitoring — new `EmailTransport` (SMTP auth/STARTTLS:587 default, also `none`/`ssl`; Octave `exist('sendmail','file')` log-and-skip guard; pure static `buildMailProps` CI seam) that `NotificationService` now delegates to via an injectable `Transport` property; per-(sensor,threshold) email cooldown (default 5 min, 0 disables; dry-run honors it too) with public `SuppressedCount`; `LiveEventPipeline.processMonitorTag_`/`runCycle` now forward real per-event `sensorData` (X/Y/thresholdValue/thresholdDirection from the live tick) so `IncludeSnapshot` rules attach PNGs in live mode. MATLAB-only per user decision. **Backward-compat preserved**: pipeline still defaults to `NotificationService('DryRun', true)` and all prior tests stay green. Verified locally (R2025a, live MATLAB MCP): `test_email_transport` 5/5, `test_notification_service` 10/10 (7 original + 3 new: delegation / cooldown-suppress / cooldown-expiry-via-Hidden-DI-seam), `test_live_event_pipeline_tag` 3/3, plus class suites `TestEmailTransport` 5/5, `TestNotificationService` 7/7, `TestLiveEventPipelineTag` 3/3. MISS_HIT (`mh_style`+`mh_lint`) clean on all 8 files; MATLAB Code Analyzer clean on the 3 new/edited libs. Real SMTP delivery is the single manual step via `examples/05-events/smoke_email_send.m` (FASTSENSE_SMTP_* env vars, STARTTLS:587), out of CI. | 2026-05-29 | 203da7a, 2ac6887, 341bab2, cef1fc5 | Verified | [260529-rxf-real-per-event-email-alerts-for-backgrou](./quick/260529-rxf-real-per-event-email-alerts-for-backgrou/) |
9898
| 260529-fnt | Add `FunctionTransport` adapter (`libs/EventDetection/FunctionTransport.m`) — wraps a user-supplied function handle as a `NotificationService` `Transport` so an existing site/company MATLAB mailer can be reused for alerts with **no SMTP config** (no server/port/creds, no Gmail App Password). Drop-in duck-typed `send(recipients,subject,body,attachments)` (same as EmailTransport), normalizes recipients to a flat cellstr, defaults attachments to `{}`, Octave-safe (only calls user code). Purely additive — EmailTransport/NotificationService behavior unchanged. Built via **/gsd:fast** (inline, no subagents). Verified (R2025a): `test_function_transport` 5/5 (forwarding / recipients-normalization / attachments-default / invalid-handle / NotificationService integration), `test_notification_service` 10/10 (no regression); MISS_HIT + Code Analyzer clean on all touched files. `example_live_pipeline.m` gains a commented FunctionTransport option. Follow-up to 260529-rxf after the user opted to reuse their company mailer instead of configuring Gmail SMTP. | 2026-05-29 | 706e9d5 | Verified | (inline) |
9999
| 260602-mri | Add a crosshair-link toggle ('X') to the FastSenseWidget grey WidgetButtonBar that mirrors the hover crosshair across all FastSense widgets on the **active dashboard page**. New `CrosshairLinked` public property + `setCrosshairLink(tf)` on `FastSenseWidget` (default OFF; `toStruct` omits when false so legacy serialized dashboards are byte-identical; `fromStruct` restores). `HoverCrosshair` gains `setBroadcastFcn`/`onMoveExternal`/`onLeaveExternal` + a **deterministic `IsMirrored_` suppress flag** so a mirrored peer's same-dispatch self-leave is a no-op — **ZERO new figure-WBM closures**, respecting the 260512-egv/eu2 chained-WBM constraint; the broadcast rides on existing per-crosshair `onMove`/`onLeave` and each peer computes its OWN per-series datatip at the shared data-x via `computeYAtX_` (raw-x, no Y transmitted). `DashboardEngine` derives the active-page link set on demand (`collectLinkedCrosshairs_`, flattens GroupWidget children via `flattenWidgetsForPreview_`) through `broadcastCrosshairX_`/`broadcastCrosshairLeave_`/`onCrosshairLinkToggle`, and re-primes broadcast hooks via `rewireCrosshairLinks_` after `rerenderWidgets`/`switchPage`/`detachWidget`. Duck-typed 'X' button injected in `DashboardLayout.realizeWidget` via `ismethod(widget,'setCrosshairLink')` (leftmost chrome button, left of V/A), re-anchored by `reflowChrome_`, protected in `DashboardWidget.clearPanelControls`. **Orchestrator verification (R2025a, live MCP)** replaced the executor's flaky `tic`-window suppress (`SuppressLeaveUntil_`/`SuppressWindow_` — passed in isolation, failed in-suite) with the deterministic `IsMirrored_` flag, and fixed a **latent unbounded leave ping-pong** (`onLeaveExternal` now hides directly via a private `hideGraphics_` instead of re-entering broadcasting `onLeave`). Tests: new `test_fastsense_crosshair_link` **11/11**; regressions green (`test_hover_crosshair` 11/11, `test_fastsense_widget_ylimit_modes` 11/11, `test_time_range_selector_reinstall_after_rerender` pass, `test_dashboard_time_sync_all_pages` 5/5); MISS_HIT clean on all 6 files; Code Analyzer no new findings; live UI smoke on a rendered 2-widget dashboard (button renders + toggles, hovering one linked widget mirrors crosshair+datatip on the other, leave hides both, unlink stops mirroring). DetachedMirror crosshair-link parity OUT OF SCOPE (detached widgets use a figure-level `FastSenseToolbar`, not a WidgetButtonBar — matches 260513-sfp). | 2026-06-02 | a495cbc9, 635632e2, 8950abd5, 485154b7 | Verified | [260602-mri-add-crosshair-link-toggle-to-fastsense-w](./quick/260602-mri-add-crosshair-link-toggle-to-fastsense-w/) |
100+
| 260602-p2t | Rename the dashboard top-bar (toolbar) button from "Reset" to "Redraw". The button forces a full re-render of every widget on the active page (`onReset` → `DashboardEngine.rerenderWidgets`), so "Reset" was misleading — the label now matches the behaviour (and the existing tooltip, "Force re-render of all widgets…"). Label-only change in `libs/Dashboard/DashboardToolbar.m`; internal handle/handler `hResetBtn`/`onReset` kept (not user-facing). The **time-panel** "Reset" button (`DashboardEngine.hTimeResetBtn` → `resetTimeRange`) is a genuine time-window reset and is NOT in the top bar — left unchanged. Synced `tests/test_dashboard_toolbar_buttons.m` (button-names list + label assertion `'Reset'`→`'Redraw'`). Verified R2025a (live MCP): `test_dashboard_toolbar_buttons` **7/7** (label, tooltip-mentions-widget, onReset re-render); MATLAB Code Analyzer no new findings on both files. Executed inline (single-label rename + test sync) with GSD bookkeeping — no separate planner/executor subagents. | 2026-06-02 | 84a5ec2 | Verified | [260602-p2t-rename-dashboard-toolbar-reset-button-to](./quick/260602-p2t-rename-dashboard-toolbar-reset-button-to/) |
100101

101102
## Progress Bar
102103

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Quick Task 260602-p2t: Rename dashboard toolbar "Reset" button to "Redraw"
2+
3+
**Created:** 2026-06-02
4+
**Mode:** quick (inline execution)
5+
6+
## Task Boundary
7+
8+
The dashboard top bar (toolbar) has a button labelled "Reset" whose callback
9+
(`onReset``DashboardEngine.rerenderWidgets`) deletes and re-creates every
10+
widget panel on the active page — i.e. it forces a full re-render. The label
11+
"Reset" is misleading; rename the user-facing label to "Redraw" so the button's
12+
purpose is clear.
13+
14+
Out of scope: the **time-panel** "Reset" button (`DashboardEngine.hTimeResetBtn`
15+
`resetTimeRange`) is a genuine time-window reset and is NOT in the top bar —
16+
leave it unchanged.
17+
18+
## Approach Note
19+
20+
This is a single-string user-facing rename with a matching test assertion. Given
21+
the change was fully scoped during investigation, it was executed inline (no
22+
separate planner/executor subagents) while preserving GSD guarantees: scoped
23+
artifacts, STATE.md tracking, and an atomic commit.
24+
25+
## Tasks
26+
27+
### Task 1 — Rename the toolbar button label
28+
29+
- **Files:** `libs/Dashboard/DashboardToolbar.m`
30+
- **Action:** Change the toolbar push-button `'String'` from `'Reset'` to
31+
`'Redraw'` (~line 163). Update the adjacent explanatory comment to use the new
32+
label and note that the internal handle/handler (`hResetBtn`/`onReset`) keep
33+
their historical names. Leave the tooltip ("Force re-render of all widgets…")
34+
unchanged — it already describes the redraw behaviour.
35+
- **Verify:** Static analysis clean (no new issues); button label reads
36+
"Redraw" after render.
37+
- **Done:** Toolbar shows "Redraw"; internal names and behaviour untouched.
38+
39+
### Task 2 — Sync the toolbar-button test
40+
41+
- **Files:** `tests/test_dashboard_toolbar_buttons.m`
42+
- **Action:** Update the button-names list (`'Reset'``'Redraw'`) and the
43+
label assertion (`strcmp(..., 'Reset')``'Redraw'`) plus its comment/message.
44+
- **Verify:** `test_dashboard_toolbar_buttons` passes (7/7).
45+
- **Done:** Test asserts the label is "Redraw" and is green.
46+
47+
## must_haves
48+
49+
- truths:
50+
- The toolbar button that triggers a full widget re-render is labelled "Redraw".
51+
- The time-panel "Reset" button (`resetTimeRange`) is unchanged.
52+
- Internal handle `hResetBtn` and handler `onReset` are unchanged.
53+
- artifacts:
54+
- `libs/Dashboard/DashboardToolbar.m` (label = "Redraw")
55+
- `tests/test_dashboard_toolbar_buttons.m` (asserts "Redraw")
56+
- key_links:
57+
- `libs/Dashboard/DashboardToolbar.m` onReset → DashboardEngine.rerenderWidgets
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Quick Task 260602-p2t: Summary
2+
3+
**Completed:** 2026-06-02
4+
**Status:** Done — verified (7/7 tests pass)
5+
6+
## What changed
7+
8+
Renamed the dashboard top-bar (toolbar) button from **"Reset" → "Redraw"** so the
9+
label matches what the button actually does: force a full re-render of every
10+
widget on the active page (a manual recovery action).
11+
12+
### Files
13+
14+
- **`libs/Dashboard/DashboardToolbar.m`**
15+
- Button `'String'`: `'Reset'``'Redraw'` (the toolbar push-button wired to
16+
`onReset``DashboardEngine.rerenderWidgets`).
17+
- Updated the adjacent comment to use the new label and to note that the
18+
internal handle/handler (`hResetBtn` / `onReset`) intentionally keep their
19+
historical names — only the user-facing label changed.
20+
- Tooltip left unchanged ("Force re-render of all widgets on the active page…")
21+
— it already describes the redraw behaviour.
22+
23+
- **`tests/test_dashboard_toolbar_buttons.m`**
24+
- Button-names list: `'Reset'``'Redraw'`.
25+
- Label assertion: `strcmp(get(hResetBtn,'String'), 'Reset')``'Redraw'`,
26+
plus comment/message wording.
27+
28+
## Deliberately NOT changed
29+
30+
- **Time-panel "Reset" button** (`DashboardEngine.hTimeResetBtn`
31+
`resetTimeRange`): this is a genuine time-window reset and is on the time
32+
panel, not the top bar. Left as "Reset" — renaming it would be wrong.
33+
- **Internal names** `hResetBtn` / `onReset`: not user-facing; kept to avoid
34+
rippling changes through `DashboardEngine.m` and the test suite for no user
35+
benefit.
36+
37+
## Verification
38+
39+
- `mh`-style static analysis (MATLAB Code Analyzer) on both files: no new issues
40+
(only pre-existing `info`-level suggestions outside the edited lines).
41+
- `test_dashboard_toolbar_buttons`: **7 passed, 0 failed**, including:
42+
- label assertion now expects "Redraw" ✓
43+
- tooltip still mentions "widget" ✓
44+
- `onReset()` still re-renders widgets (replaces panel handle) ✓
45+
46+
## Notes
47+
48+
Executed inline rather than via separate planner/executor subagents: the change
49+
was a fully-scoped single-label rename + matching test sync, so the subagent
50+
orchestration would have added cost/worktree complexity with no benefit. GSD
51+
guarantees preserved (scoped artifacts, STATE.md tracking, atomic commit).

libs/Dashboard/DashboardToolbar.m

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,18 @@
151151
'TooltipString', 'Reset all widgets to global time range', ...
152152
'Callback', @(~,~) obj.Engine.resetGlobalTime());
153153

154-
% Reset button — manual recovery; forces full re-render of every
154+
% Redraw button — manual recovery; forces full re-render of every
155155
% widget on the active page. Placed next to Sync because both
156156
% are "fix the dashboard" actions, but their roles differ:
157-
% Sync resets the time range; Reset re-renders widget panels.
157+
% Sync resets the time range; Redraw re-renders widget panels.
158+
% (Internal handle/handler keep the historical hResetBtn/onReset
159+
% names — only the user-facing label was renamed to "Redraw".)
158160
rightEdge = rightEdge - btnW - 0.005;
159161
obj.hResetBtn = uicontrol('Parent', obj.hPanel, ...
160162
'Style', 'pushbutton', ...
161163
'Units', 'normalized', ...
162164
'Position', [rightEdge btnY btnW btnH], ...
163-
'String', 'Reset', ...
165+
'String', 'Redraw', ...
164166
'TooltipString', ['Force re-render of all widgets on the active page ' ...
165167
'(recovery action when widgets get stuck)'], ...
166168
'Callback', @(~,~) obj.onReset());

tests/test_dashboard_toolbar_buttons.m

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ function test_dashboard_toolbar_buttons()
5353
d.Toolbar.hExportBtn, d.Toolbar.hSyncBtn, ...
5454
d.Toolbar.hResetBtn, ...
5555
d.Toolbar.hInfoBtn};
56-
names = {'Live', 'Config', 'Image', 'Export', 'Sync', 'Reset', 'Info'};
56+
names = {'Live', 'Config', 'Image', 'Export', 'Sync', 'Redraw', 'Info'};
5757
for i = 1:numel(handles)
5858
tip = get(handles{i}, 'TooltipString');
5959
assert(~isempty(tip), ...
@@ -100,18 +100,18 @@ function test_dashboard_toolbar_buttons()
100100
nFailed = nFailed + 1;
101101
end
102102

103-
% Reset button is created and labelled "Reset" after render
103+
% Redraw button is created and labelled "Redraw" after render
104104
try
105105
d = DashboardEngine('ResetButtonExistsTest');
106106
d.addWidget('number', 'Title', 'T', 'Position', [1 1 6 2], 'StaticValue', 1);
107107
d.render();
108108
set(d.hFigure, 'Visible', 'off');
109109
assert(~isempty(d.Toolbar.hResetBtn), ...
110-
'reset button should exist after render');
110+
'redraw button should exist after render');
111111
assert(ishandle(d.Toolbar.hResetBtn), ...
112-
'reset button should be a valid handle');
113-
assert(strcmp(get(d.Toolbar.hResetBtn, 'String'), 'Reset'), ...
114-
'reset button label should be "Reset"');
112+
'redraw button should be a valid handle');
113+
assert(strcmp(get(d.Toolbar.hResetBtn, 'String'), 'Redraw'), ...
114+
'redraw button label should be "Redraw"');
115115
close(d.hFigure);
116116
nPassed = nPassed + 1;
117117
catch err

0 commit comments

Comments
 (0)