Commit d8f740e
Phase 1034: Wiki Browser (project-wide in-app help system) (#159)
* docs(1034-02): add wiki/Companion-Overview.md root help page
- Hand-written entry page opened by the new Wiki button on the
FastSenseCompanion main toolbar (Plan 06 task 6.1 will set
'OpenTo','Companion-Overview').
- Describes the three-pane layout, top toolbar, log strip, dashboard
opening flow, and Live mode semantics.
- Cross-links to Tag-Status-Table, Event-Viewer, Live-Log,
Dashboard-Info-vs-Wiki, Home using bare-page-name links the Plan 04
Wiki Browser will resolve as in-window navigation.
- No AUTO-GENERATED marker (Phase 1034 D-04 hand-written constraint).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(1034-01): scaffold WikiPageIndex pure-logic class shell
- New libs/Help/ directory for Phase 1034 (Wiki Browser System 2)
- libs/Help/WikiPageIndex.m: classdef with five static method stubs
(listPages, buildToc, readPage, search, collidesWithGenerator) plus
two private helpers (extractH1_, isAutoGenerated_)
- Full Doxygen-style header documenting each method's contract per
CONTEXT.md D-08/D-09 (TOC + full-text substring search) and D-05
(generator collision guard)
- All methods are methods(Static) so the Plan 04 UI layer can call
without instantiating, mirroring MarkdownRenderer.render
- Bodies return sensible empty defaults — Task 1.2 fills them
* docs(1034-02): add Tag-Status-Table, Event-Viewer, Live-Log wiki pages
Three hand-written wiki pages, one per Companion surface that gets a
Wiki button in Phase 1034:
- wiki/Tag-Status-Table.md — user manual for TagStatusTableWindow.
Documents the 12 columns, chip filters (AND across groups, OR within),
the dual refresh paths (push-on-write + window-owned 1s timer), and
the Pause polling toggle.
- wiki/Event-Viewer.md — user manual for CompanionEventViewer plus the
detached EventsLogPane (both will open this page in Plan 06/07).
Documents the Gantt/Table view switch, severity tri-toggle, click /
double-click behaviour, and the relationship to the Live log.
- wiki/Live-Log.md — user manual for the LiveLogPane (inline + detached).
Documents the 4 columns (Time/Tag/Delta/Latest), the 500-row buffer
cap, the FastSenseCompanion.scanLiveTagUpdates_ boundary (per-tag
cursor state lives upstream, not in the pane), the filter, and the
Live-mode dependency.
All three: exactly one H1, no AUTO-GENERATED marker, cross-doc links via
bare page names (Companion-Overview / Tag-Status-Table / Event-Viewer /
Live-Log) so Plan 04's WikiBrowser resolves them in-window.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(1034-02): add Dashboard-Info-vs-Wiki.md explaining the two systems
Hand-written page that disambiguates the two parallel help systems for
dashboard authors:
- System 1: DashboardEngine.InfoFile (modal, per-dashboard, scoped) +
DashboardWidget.Description (tooltip-only).
- System 2: Wiki Browser (non-modal, project-wide, with TOC + search +
back/forward), opened from the new Wiki button on Companion windows.
Includes a coexistence matrix showing which surfaces carry which
buttons, plus authoring guidance pointing out the PAGE_MAP collision
hazard for new hand-written wiki pages.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(1034-03): complete install-path plan
- Add SUMMARY.md for Plan 1034-03 (libs/Help addpath in install.m)
- Record decision in STATE.md (Decisions Phase 1034)
- Update ROADMAP.md plan-progress row for phase 1034
- Note: Task 3.1 work (install.m diff) landed in commit 95eb030
alongside Plan 1034-02 due to parallel-execution git-index race;
SUMMARY.md documents the attribution. Functional outcome verified
via `which WikiPageIndex` returning libs/Help/WikiPageIndex.m.
* test(1034-01): add headless function-based test for WikiPageIndex
- tests/test_wiki_page_index.m: 14 sub-tests covering every public
method and key edge case (listPages count, API-Reference grouping,
H1 extraction, TOC group order + alphabetical sort, _Sidebar.md
exclusion, readPage Home + .md-extension tolerance + Home fallback,
search empty/whitespace/match/no-match, collidesWithGenerator with
Home.md auto-generated + empty input)
- Sub-tests are independent local functions (t1..t14) returning 1 on
pass so a failure fails fast with an informative assert message
- Adds an Octave-compatible endsWith_ helper because the built-in
endsWith is unavailable on Octave 7+
- No UI dependencies; runs headless on both MATLAB R2020b+ and Octave
Verified: All 14 tests passed on Octave 11.1.0 AND MATLAB
(via matlab -batch). Test path setup uses addpath + install() so
libs/Help/ is on the path when WikiPageIndex.listPages is invoked.
* feat(1034-04): WikiBrowser shell + headless/Octave fallback (Task 4.1)
- Add libs/Help/WikiBrowser.m: classdef < handle with public/private
properties, NV-pair constructor, isInteractiveDesktop_ guard, and
openInBrowser_ shell-out fallback for Octave / headless / -batch.
- Stub public methods (navigateTo/back/forward/applyTheme/focus/close/
delete) and private buildFigure_ — filled by Tasks 4.2-4.4.
- Mirrors DashboardEngine.writeAndOpenInfoHtml's gate logic
(~OCTAVE_VERSION + usejava('desktop') + ~batchStartupOptionUsed) so
headless runs write a temp HTML file but never try to open a uifigure.
- Namespaced errors WikiBrowser:invalidArgs and WikiBrowser:unknownOption.
- checkcode clean; constructor smoke test passes headless (IsOpen=false).
* feat(1034-04): WikiBrowser three-pane uifigure layout (Task 4.2)
- Implement buildFigure_: non-modal uifigure with WindowStyle='normal',
Tag='WikiBrowserRoot' (Plan 08 walker-skip anchor), Position
[100 100 1100 750], centered. Two-row root grid hosts a 32-px
breadcrumb strip (< back / fwd > / crumb label) and a body grid
({260 px, '1x'}) split into sidebar + uihtml content.
- Sidebar = uipanel housing a 2-row uigridlayout: search uieditfield
on top, uitree (TOC) + uilistbox (search results) layered inside a
shared uigridlayout cell (plan-checker I4 Option A — children of
uigridlayout auto-fill and ignore .Position, so figure resize reflows
correctly).
- Add helpers buildTocTree_, onTocSelected_, onSearchChanged_,
onSearchHitSelected_, onHtmlEvent_, alert_. onHtmlEvent_ is wired to
uihtml.HTMLEventReceivedFcn so Task 4.3's JS bridge can post
{page, ts} back to MATLAB on a.wiki-internal clicks.
- Theme colours sourced from CompanionTheme.get(obj.Theme); BorderColor
/ Placeholder gracefully degrade on R2020b.
- checkcode clean; headless smoke test still passes (constructor takes
openInBrowser_ path).
* feat(1034-04): WikiBrowser navigation + cross-doc link rewrite (Task 4.3)
- Implement navigateTo: tolerate './' prefix and '.md' suffix, fall back
to Home.md with user alert when page missing, render via cache keyed
by 'page|theme', push onto history with truncate-forward + 50-entry
cap (HistoryCap_).
- Implement back / forward: no-op at edges; non-pushing re-render via
renderHistoryCurrent_.
- Implement applyTheme: invalidate cache, re-render current page, best-
effort restyle of sidebar + breadcrumb widgets via CompanionTheme.get.
- Add rewriteCrossDocLinks_: SINGLE regexprep with negative lookahead
(?!https?://|mailto:|#) marks internal anchors with class='wiki-internal'
+ data-page='PageName' (preserved verbatim); external + anchor links
left untouched. Injects a JS click-interceptor <script> before </body>
that posts {page, ts} to htmlComponent.Data — the Task 4.2
HTMLEventReceivedFcn maps it back into navigateTo on the MATLAB side.
- Plan-checker I5 fix: removed any chance of orphan href='' or multi-
step index juggling.
- checkcode clean. Inline regex test confirms the rewrite leaves
https://, mailto:, and #anchor links untouched while internal
bare-page hrefs get the bridge-friendly substitution. Headless
navigateTo/back/forward/applyTheme no-op safely on IsOpen=false
instances.
* feat(1034-04): WikiBrowser close/focus/delete lifecycle (Task 4.4)
- focus: bring uifigure to front via figure(hFig_); idempotent no-op when
IsOpen=false or handle invalid.
- close: idempotent disposal — clears CloseRequestFcn first (avoids
recursion via X-button), tears down Listeners_ entries, deletes the
uifigure, nils every internal UI handle (incl. hTreeHostGrid_),
resets HistoryStack_, HistoryIdx_, CurrentPage, and re-initialises
Cache_ to an empty containers.Map. Safe to call twice or after
external delete().
- delete(obj): handle-class destructor defers to close().
- Final headless smoke test passes (IsOpen=0 throughout; navigateTo
updates CurrentPage; applyTheme updates Theme; double-close
idempotent; no crashes).
* test(1034-05): add TestWikiBrowser class-based UI test suite
13 test methods covering the WikiBrowser public API on MATLAB desktop:
constructor (defaults + unknownOption + invalidArgs), navigateTo (known
+ unknown fallback), back/forward history with no-op endpoints, history
cap at 50 entries (behavioural via back-step count, no reflection),
forward truncation on new navigation, applyTheme re-render, close
idempotency, focus on closed = no-op, WikiBrowserRoot tag contract
(supports Plan 08's theme walker skip), and cross-doc link rewrite
(asserts class="wiki-internal" + data-page="..." + htmlComponent.Data).
- TestClassSetup.addPaths follows the TestFastSenseCompanion pattern:
Octave skip via assumeFail, headless skip via assumeTrue(usejava
('desktop')), then addpath + install + resolve <repo>/wiki.
- TestMethodTeardown aggressively closes the per-test WikiBrowser and
sweeps any stray WikiBrowserRoot figures so test ordering is
irrelevant.
- testCrossDocLinkRewriteInjectsJsBridge uses the canonical
findobj(parent, '-depth', 1, 'Type', 'uihtml') idiom shared with
TestDashboardInfo.testShowInfoOpensModalFigure (line 230) and
DashboardEngine.showInfoModal_ (lines 966-967), with a deep-walk
findobj fallback for releases where the uihtml sits deeper in the
uigridlayout body grid. Asserts the rewrite preserves the page name
verbatim in data-page (plan-checker I5).
- Headless verification: matlab -batch runtests filters all 13 tests
cleanly via the headless assumption (zero PASSED, zero FAILED, 13
INCOMPLETE) — exactly the contract for CI runs without a desktop.
Plan 1034-05 / Task 5.1.
* feat(1034-08): add WikiBrowserRoot skip rule to applyThemeToChildren_ walker
- Extend existing LogPaneRoot skip rule into combined OR condition matching
both 'LogPaneRoot' and 'WikiBrowserRoot' on the Panel arm of the walker.
- Update header docstring with parallel paragraph documenting the
WikiBrowserRoot skip rule (Phase 1034) alongside the existing
LogPaneRoot rule (Phase 1027.1).
- WikiBrowser owns its theming via WikiBrowser.applyTheme which
FastSenseCompanion.applyTheme invokes explicitly (Plan 06 task 6.2).
Walking into the Wiki subtree would stomp its uihtml + uitree styling.
- The WikiBrowser is currently a separate top-level uifigure so the
walker will never reach it today — the skip rule is preventative,
symmetric with LogPaneRoot, protecting against future refactors that
might embed WikiBrowser inside the Companion uifigure.
* feat(1034-06): reflow Companion toolbar to 1x8 with Wiki button at col 6
- Added private properties hWikiBtn_ and WikiBrowser_ for the new Wiki
toolbar button and the shared WikiBrowser handle (Phase 1034 D-06).
- Reflowed hToolbarPanel_ inner grid from [1 7] to [1 8]:
ColumnWidth {110,110,110,70,90,'1x',36} -> {110,110,110,70,90,70,'1x',36}.
- Inserted Wiki button between Close all (col 5) and the spacer:
Tag='CompanionWikiBtn', Text='Wiki ↥' (char 8689 pop-out arrow),
ButtonPushedFcn -> obj.openWiki_('Companion-Overview').
- Bumped Settings gear Layout.Column from 7 to 8.
Static analysis: only NEW warning is MCNPN on openWiki_ (private method
added in Task 6.2); pre-existing warnings unchanged.
* test(1034-08): extend test_companion_apply_theme_walker with WikiBrowserRoot regression
- Add a third skip-rule fixture: a uipanel tagged 'WikiBrowserRoot' with
a screaming-red [0.99 0.01 0.01] BackgroundColor sentinel + a child
uilabel with a magenta [0.99 0.01 0.99] FontColor sentinel. Both
sentinels are values no CompanionTheme will ever produce, so any
walker-overwrite is immediately visible.
- Add 6 new assertions (2 per apply pass: dark, light, second-dark)
asserting the WikiBrowserRoot subtree stays untouched across the full
dark->light->dark theme cycle. Mirrors the LogPaneRoot fixture pattern
on lines 90-104 and the per-pass assertions on lines 121-126 / 222-225
/ 254-257 of the existing test.
- Pre-edit count was 30 passing assertions; post-edit count is 36
(verified on local MATLAB R2025b: 'All 36 tests passed').
- Existing LogPaneRoot regression remains intact and continues to pass.
* feat(1034-06): add Companion openWiki API + WikiBrowser teardown + theme propagation
- New public method openWiki(pageName) — public alias used by tests and
sibling windows; defaults pageName to 'Companion-Overview' when omitted.
- New private openWiki_(pageName) — canonical implementation used by the
toolbar callback (wired in Task 6.1). Lazily constructs a WikiBrowser
cached in obj.WikiBrowser_; subsequent calls navigateTo + focus.
Resolves <repo>/wiki from this file's location and passes it via the
WikiDir NV-pair (falls back to WikiBrowser's own default if missing).
All failure paths surface a non-blocking uialert; never crash the app.
- close() now closes + deletes WikiBrowser_ (independent try/catch,
mirrors the existing TagStatusTableWindow_ teardown pattern).
- applyTheme() propagates the theme to WikiBrowser_ when open via its
own applyTheme — Plan 08 keeps WikiBrowserRoot out of the recursive
walker, so the Wiki window restyles itself.
Static analysis: previous MCNPN warning on openWiki_ is gone; no new
warnings introduced (all remaining warnings pre-existing).
* test(1034-06): add Wiki toolbar button regression tests
Three new tests appended after the Task-13 Events-button block:
- testToolbarHasWikiButton — finds CompanionWikiBtn via findall and
verifies it sits in Layout.Column 6 (the Phase 1034 reflow target).
- testToolbarGearMovedToColumn8 — walks every uibutton, picks the one
whose Text matches char(9881) (gear glyph), and verifies its
Layout.Column is 8 (was 7 before Phase 1034).
- testOpenWikiOpensWikiBrowser — drives openWiki('Companion-Overview')
and verifies a WikiBrowserRoot uifigure appears, then companion close
tears it down. Mirrors TestWikiBrowser by gating on usejava('desktop')
via assumeTrue so headless batch runners skip cleanly.
Result: 64 existing tests still pass + 2 new tests pass + the third
filters cleanly headless (will pass on interactive desktop).
* feat(1034-07): wire Wiki button into TagStatusTableWindow
- Add hWikiBtn_ private uicontrol property alongside hPauseBtn_
- Insert Wiki button at [0.87 0.945 0.12 0.04] (top-right corner)
- Shift hPauseBtn_ left to [0.74 0.945 0.12 0.04]
- Add openWiki_ private method routing through Companion_.openWiki('Tag-Status-Table') with WikiBrowser fallback
- Extend applyTheme to restyle hWikiBtn_
- Nil hWikiBtn_ in onCloseRequest_ alongside hPauseBtn_
Reuses existing Companion_ property at line 62; no constructor change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(1034-07): wire Wiki button into CompanionEventViewer
- Add hWikiBtn_ private uibutton property (reuses existing Companion_ at line 92; no duplication)
- Reflow hLeftHeaderGrid from [1 3] to [1 5] with ColumnWidth {8, '1x', 8, 70, 8} adding column 4 for Wiki button
- Wiki button text 'Wiki [pop-out arrow]' (char(8689)), tooltip 'Open Wiki: Event Viewer'
- Add openWiki_ private method calling obj.Companion_.openWiki('Event-Viewer') with WikiBrowser fallback
- Nil obj.hWikiBtn_ in close()
Constructor signature unchanged (still positional store/registry/companion).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(1034-07): wire Wiki button into EventsLogPane + LiveLogPane detached headers
EventsLogPane:
- Add hWikiBtn_ + Companion_ private properties
- Add public setCompanion(companion) method
- Reflow header grid [1 5] -> [1 6] with new column at index 5 for Wiki button
- Wiki button Visible toggles via isa(parent, 'matlab.ui.Figure'); only shown when detached
- Add openWiki_ private method routing through Companion_.openWiki('Event-Viewer')
- Extend detach() and applyTheme() to cover hWikiBtn_
LiveLogPane (mirror changes):
- Same property + setCompanion + openWiki_ additions
- Reflow header grid [1 4] -> [1 5] with Wiki button at column 4 (PopoutBtn shifted to col 5)
- Default page 'Live-Log', tooltip 'Open Wiki: Live Log'
FastSenseCompanion:
- Right after instantiating obj.EventsLogPane_ and obj.LiveLogPane_, call setCompanion(obj) inside try/catch so the Wiki button can reach back through openWiki().
Per CONTEXT.md D-13, inline panes share the Companion toolbar's main Wiki button -- only the detached header strips show their own button. Regression: 168 passed / 0 failed / 1 incomplete (testOpenWikiOpensWikiBrowser filtered by headless assumption, expected).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(1034-09): Wiki Browser Home button + DataChangedFcn callback wiring
- Add ⌂ Home button to the breadcrumb bar (back / forward / home / crumb).
Tooltip: "Home (wiki/Home.md)". Click navigates to wiki/Home.md.
- Fix cross-doc click callback wiring from HTMLEventReceivedFcn to
DataChangedFcn. The JS bridge writes htmlComponent.Data which only
fires DataChangedFcn on the MATLAB side; HTMLEventReceivedFcn is for
the sendEventToMATLAB API which we don't use.
- Add regression test that asserts DataChangedFcn is a function_handle
and HTMLEventReceivedFcn stays empty — guards against the wrong-wiring
bug recurring.
Note: In-window cross-doc link CLICK navigation still has a runtime
issue (JS bridge fires but downstream navigation doesn't happen for
in-page anchors). Tracked as a follow-up — TOC navigation, Home, Back,
Forward, and search all work as expected.
Plan 1034-09 spot-check feedback (user-requested).
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 5ecb4c8 commit d8f740e
18 files changed
Lines changed: 2563 additions & 35 deletions
File tree
- libs
- FastSenseCompanion
- private
- Help
- tests
- suite
- wiki
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
| |||
56 | 57 | | |
57 | 58 | | |
58 | 59 | | |
| 60 | + | |
59 | 61 | | |
60 | 62 | | |
61 | 63 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
107 | 108 | | |
108 | 109 | | |
109 | 110 | | |
| |||
383 | 384 | | |
384 | 385 | | |
385 | 386 | | |
| 387 | + | |
386 | 388 | | |
387 | 389 | | |
388 | 390 | | |
| |||
515 | 517 | | |
516 | 518 | | |
517 | 519 | | |
518 | | - | |
519 | | - | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
520 | 524 | | |
521 | | - | |
| 525 | + | |
522 | 526 | | |
523 | 527 | | |
524 | 528 | | |
| |||
531 | 535 | | |
532 | 536 | | |
533 | 537 | | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
534 | 551 | | |
535 | 552 | | |
536 | 553 | | |
| |||
1446 | 1463 | | |
1447 | 1464 | | |
1448 | 1465 | | |
| 1466 | + | |
| 1467 | + | |
| 1468 | + | |
| 1469 | + | |
| 1470 | + | |
| 1471 | + | |
| 1472 | + | |
| 1473 | + | |
| 1474 | + | |
| 1475 | + | |
| 1476 | + | |
| 1477 | + | |
| 1478 | + | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
1449 | 1485 | | |
1450 | 1486 | | |
1451 | 1487 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
49 | | - | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
50 | 52 | | |
51 | 53 | | |
52 | 54 | | |
| |||
66 | 68 | | |
67 | 69 | | |
68 | 70 | | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
69 | 81 | | |
70 | 82 | | |
71 | 83 | | |
| |||
93 | 105 | | |
94 | 106 | | |
95 | 107 | | |
96 | | - | |
97 | | - | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
98 | 114 | | |
99 | 115 | | |
100 | | - | |
| 116 | + | |
101 | 117 | | |
102 | 118 | | |
103 | 119 | | |
| |||
133 | 149 | | |
134 | 150 | | |
135 | 151 | | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
136 | 173 | | |
137 | | - | |
| 174 | + | |
138 | 175 | | |
139 | 176 | | |
140 | 177 | | |
| |||
185 | 222 | | |
186 | 223 | | |
187 | 224 | | |
| 225 | + | |
188 | 226 | | |
189 | 227 | | |
190 | 228 | | |
| |||
263 | 301 | | |
264 | 302 | | |
265 | 303 | | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
266 | 309 | | |
267 | 310 | | |
268 | 311 | | |
| |||
331 | 374 | | |
332 | 375 | | |
333 | 376 | | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
334 | 396 | | |
335 | 397 | | |
336 | 398 | | |
| |||
0 commit comments