Skip to content
Merged
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
41 changes: 31 additions & 10 deletions libs/FastSenseCompanion/NotificationCenterPane.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
end

properties (SetAccess = private)
IsAttached logical = false
IsAttached = false % logical flag (no type-constraint syntax — Octave-incompatible)
end

properties (Access = private)
Expand All @@ -48,7 +48,7 @@
hLastUpdateLbl_ = [] % "Updated: HH:MM:SS" label
hPopoutBtn_ = [] % pop-out icon uibutton
Companion_ = [] % FastSenseCompanion handle (or [])
LastGoodEvents_ = Event.empty % last successfully-read unacked set (survives detach)
LastGoodEvents_ = [] % last successfully-read unacked set (survives detach)
LastIds_ = {} % cellstr of LastGoodEvents_ ids (diff key)
Listeners_ = {} % addlistener handles; deleted on teardown
IsStale_ = false % true when the last EventStore read failed
Expand All @@ -69,7 +69,7 @@
end
obj.ThemeStruct_ = themeStruct;
obj.IsAttached = false;
obj.LastGoodEvents_ = Event.empty;
obj.LastGoodEvents_ = [];
obj.LastIds_ = {};
obj.Listeners_ = {};
obj.IsStale_ = false;
Expand Down Expand Up @@ -232,14 +232,14 @@ function refresh(obj, eventStore)
% (stale) marker; never clear the inbox and never uialert.
if ~obj.IsAttached; return; end
if isempty(eventStore) || ~isvalid(eventStore)
obj.LastGoodEvents_ = Event.empty;
obj.LastGoodEvents_ = [];
obj.LastIds_ = {};
obj.IsStale_ = false;
obj.applyFilterAndRender_();
obj.setUpdatedLabel_(datetime('now'), false);
return;
end
allEvents = Event.empty;
allEvents = [];
readOk = true;
try
allEvents = eventStore.getEvents();
Expand Down Expand Up @@ -353,7 +353,13 @@ function applyFilterAndRender_(obj)
otherwise, wanted = [];
end
if ~isempty(wanted)
events = events([events.Severity] == wanted);
% Explicit loop (Octave can't comma-list-expand [events.Severity]
% over a classdef object array) — mirrors the text filter below.
sevMask = false(1, numel(events));
for i = 1:numel(events)
sevMask(i) = (events(i).Severity == wanted);
end
events = events(sevMask);
end
end
% Free-text filter over SensorName + ThresholdLabel (case-insensitive).
Expand Down Expand Up @@ -640,7 +646,7 @@ function ackForTest_(obj, eventId)
% An event is unacked iff AckedAt is empty OR all-NaN (mirrors
% Event.computeDisplayState). Empty input returns an empty Event array.
if isempty(allEvents)
evs = Event.empty;
evs = [];
return;
end
mask = false(1, numel(allEvents));
Expand All @@ -654,7 +660,13 @@ function ackForTest_(obj, eventId)
function evs = sortNewestFirst_(events)
%SORTNEWESTFIRST_ Order events by StartTime, newest first.
if numel(events) > 1
[~, ord] = sort([events.StartTime], 'descend');
% Explicit loop (Octave can't comma-list-expand [events.StartTime]
% over a classdef object array).
starts = zeros(1, numel(events));
for i = 1:numel(events)
starts(i) = events(i).StartTime;
end
[~, ord] = sort(starts, 'descend');
evs = events(ord);
else
evs = events;
Expand All @@ -666,7 +678,12 @@ function ackForTest_(obj, eventId)
if isempty(events)
s = 0;
else
s = max([events.Severity]);
% Explicit loop (Octave can't comma-list-expand [events.Severity]).
sevs = zeros(1, numel(events));
for i = 1:numel(events)
sevs(i) = events(i).Severity;
end
s = max(sevs);
end
end

Expand All @@ -675,7 +692,11 @@ function ackForTest_(obj, eventId)
if isempty(events)
ids = {};
else
ids = arrayfun(@(e) e.Id, events, 'UniformOutput', false);
% Explicit loop (Octave can't arrayfun over a classdef object array).
ids = cell(1, numel(events));
for i = 1:numel(events)
ids{i} = events(i).Id;
end
end
end

Expand Down
2 changes: 1 addition & 1 deletion tests/StubEventStore.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
% See also EventStore, Event, NotificationCenterPane, CaptureNotificationService.

properties
Events_ = Event.empty % Event array; configure in test setup
Events_ = [] % Event array (configure in test setup); [] not Event.empty for Octave parity
AckedIds_ = {} % cellstr: each eventId passed to acknowledgeEvent, in call order
ThrowOnAck_ = false % when true, acknowledgeEvent throws EventStore:unknownEventId
ThrowOnGet_ = false % when true, getEvents throws (exercises the stale path)
Expand Down
47 changes: 25 additions & 22 deletions tests/suite/TestFastSenseCompanionPlantLogToolbar.m
Original file line number Diff line number Diff line change
Expand Up @@ -114,19 +114,20 @@ function cleanupAll(testCase)
end

function g = findToolbarGrid_(testCase, c) %#ok<INUSL>
% After v3.1 Plant Log + v4.0 Wiki Browser merges, the
% Companion toolbar is a 1x9 grid:
% {110, 110, 110, 130, 70, 90, 70, '1x', 36}
% After v3.1 Plant Log + v4.0 Wiki Browser + v4.0 Phase 1040
% notification bell, the Companion toolbar is a 1x10 grid:
% {110, 110, 110, 130, 70, 90, 70, 70, '1x', 36}
fig = c.getFigForTest_();
grids = findobj(fig, 'Type', 'uigridlayout');
g = [];
for i = 1:numel(grids)
if numel(grids(i).ColumnWidth) == 9
if numel(grids(i).ColumnWidth) == 10
cw = grids(i).ColumnWidth;
if iscell(cw) && isequal(cw{1}, 110) && isequal(cw{2}, 110) && ...
isequal(cw{3}, 110) && isequal(cw{4}, 130) && ...
isequal(cw{5}, 70) && isequal(cw{6}, 90) && ...
isequal(cw{7}, 70) && isequal(cw{9}, 36)
isequal(cw{7}, 70) && isequal(cw{8}, 70) && ...
isequal(cw{10}, 36)
g = grids(i);
return;
end
Expand All @@ -139,22 +140,23 @@ function cleanupAll(testCase)
methods (Test)

function testToolbarGridIs1x5(testCase)
% v3.1 Plant Log + v4.0 Wiki Browser merged: toolbar grew from
% 1x4 to 1x9.
% col 1 = Events (110)
% col 2 = Live (110)
% col 3 = Tags (110, v4.0 quick task 260519-bs4)
% col 4 = Plant Log (130, v3.1 Phase 1033 PLOG-INT-03)
% col 5 = Tile ( 70, v4.0 S0Y-01)
% col 6 = Close all ( 90, v4.0 S0Y-02)
% col 7 = Wiki ( 70, v4.0 Phase 1034)
% col 8 = flex spacer
% col 9 = gear ( 36)
% v3.1 Plant Log + v4.0 Wiki Browser + Phase 1040 bell: toolbar
% grew from 1x4 to 1x10.
% col 1 = Events (110)
% col 2 = Live (110)
% col 3 = Tags (110, v4.0 quick task 260519-bs4)
% col 4 = Plant Log (130, v3.1 Phase 1033 PLOG-INT-03)
% col 5 = Tile ( 70, v4.0 S0Y-01)
% col 6 = Close all ( 90, v4.0 S0Y-02)
% col 7 = Wiki ( 70, v4.0 Phase 1034)
% col 8 = Bell ( 70, v4.0 Phase 1040 notification center)
% col 9 = flex spacer
% col 10 = gear ( 36)
d1 = testCase.makeEngine_('A');
c = testCase.makeCompanion_({d1});
g = testCase.findToolbarGrid_(c);
testCase.verifyNotEmpty(g, ...
'toolbar grid (1x8 with ColumnWidth {110 110 110 130 70 90 ''1x'' 36}) must exist');
'toolbar grid (1x10 with ColumnWidth {110 110 110 130 70 90 70 70 ''1x'' 36}) must exist');
cw = g.ColumnWidth;
testCase.verifyEqual(cw{1}, 110, 'ColumnWidth{1} (Events)');
testCase.verifyEqual(cw{2}, 110, 'ColumnWidth{2} (Live)');
Expand All @@ -163,8 +165,9 @@ function testToolbarGridIs1x5(testCase)
testCase.verifyEqual(cw{5}, 70, 'ColumnWidth{5} (Tile, v4.0)');
testCase.verifyEqual(cw{6}, 90, 'ColumnWidth{6} (Close all, v4.0)');
testCase.verifyEqual(cw{7}, 70, 'ColumnWidth{7} (Wiki, v4.0 Phase 1034)');
testCase.verifyEqual(cw{8}, '1x', 'ColumnWidth{8} flex spacer');
testCase.verifyEqual(cw{9}, 36, 'ColumnWidth{9} (gear)');
testCase.verifyEqual(cw{8}, 70, 'ColumnWidth{8} (Bell, v4.0 Phase 1040)');
testCase.verifyEqual(cw{9}, '1x', 'ColumnWidth{9} flex spacer');
testCase.verifyEqual(cw{10}, 36, 'ColumnWidth{10} (gear)');
end

function testPlantLogButtonExists(testCase)
Expand Down Expand Up @@ -211,13 +214,13 @@ function testPlantLogButtonDisabledWithoutDashboards(testCase)
end

function testSettingsButtonMovedToCol5(testCase)
% After v3.1 + v4.0 merge, gear lives at col 8 (1x8 grid).
% After v3.1 + v4.0 + Phase 1040 bell, gear lives at col 10 (1x10 grid).
d1 = testCase.makeEngine_('A');
c = testCase.makeCompanion_({d1});
gear = findobj(c.getFigForTest_(), 'Tooltip', 'Companion settings');
testCase.verifyNotEmpty(gear);
testCase.verifyEqual(gear.Layout.Column, 9, ...
'settings gear must be at col 9 (1x9 grid post-v3.1+Wiki-Browser merge)');
testCase.verifyEqual(gear.Layout.Column, 10, ...
'settings gear must be at col 10 (1x10 grid post-Phase-1040 bell)');
end

function testFindObjResolvesViaTag(testCase)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_notification_center_pane.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function test_notification_center_pane()

% 4. maxSeverity_.
n = n + 1; check(NotificationCenterPane.maxSeverity_([e1 e2]) == 3, 'maxSeverity_([3 2]) should be 3');
n = n + 1; check(NotificationCenterPane.maxSeverity_(Event.empty) == 0, 'maxSeverity_(empty) should be 0');
n = n + 1; check(NotificationCenterPane.maxSeverity_([]) == 0, 'maxSeverity_(empty) should be 0');

% 5. diffIds_ — order-insensitive set comparison.
n = n + 1; check(~NotificationCenterPane.diffIds_({'a', 'b'}, {'b', 'a'}), ...
Expand Down
Loading