fix: Timeline window should match selected events for media views (#1555)
This commit is contained in:
@@ -245,7 +245,6 @@ export class ViewFactory {
|
|||||||
} else {
|
} else {
|
||||||
switch (view.view) {
|
switch (view.view) {
|
||||||
case 'live':
|
case 'live':
|
||||||
this._setTimelineWindowToLive(view);
|
|
||||||
if (config.live.controls.thumbnails.mode !== 'none') {
|
if (config.live.controls.thumbnails.mode !== 'none') {
|
||||||
await executeMediaQuery(
|
await executeMediaQuery(
|
||||||
config.live.controls.thumbnails.media_type === 'recordings'
|
config.live.controls.thumbnails.media_type === 'recordings'
|
||||||
@@ -282,6 +281,7 @@ export class ViewFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._setOrRemoveTimelineWindow(view);
|
||||||
this._setOrRemoveSeekTime(
|
this._setOrRemoveSeekTime(
|
||||||
view,
|
view,
|
||||||
options?.queryExecutorOptions?.selectResult?.time?.time,
|
options?.queryExecutorOptions?.selectResult?.time?.time,
|
||||||
@@ -289,29 +289,37 @@ export class ViewFactory {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _setTimelineWindowToLive(view: View): void {
|
protected _setOrRemoveTimelineWindow(view: View): void {
|
||||||
const now = new Date();
|
if (view.is('live')) {
|
||||||
const liveConfig = this._api.getConfigManager().getConfig()?.live;
|
// For live views, always force the timeline to now, regardless of
|
||||||
|
// presence or not of events.
|
||||||
|
const now = new Date();
|
||||||
|
const liveConfig = this._api.getConfigManager().getConfig()?.live;
|
||||||
|
|
||||||
/* istanbul ignore if: this if branch cannot be reached as if the config is
|
/* istanbul ignore if: this if branch cannot be reached as if the config is
|
||||||
empty this function is never called -- @preserve */
|
empty this function is never called -- @preserve */
|
||||||
if (!liveConfig) {
|
if (!liveConfig) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
view.mergeInContext({
|
view.mergeInContext({
|
||||||
// Force the window to start at the most recent time, not
|
// Force the window to start at the most recent time, not
|
||||||
// necessarily when the most recent event/recording was:
|
// necessarily when the most recent event/recording was:
|
||||||
// https://github.com/dermotduffy/frigate-hass-card/issues/1301
|
// https://github.com/dermotduffy/frigate-hass-card/issues/1301
|
||||||
timeline: {
|
timeline: {
|
||||||
window: {
|
window: {
|
||||||
start: sub(now, {
|
start: sub(now, {
|
||||||
seconds: liveConfig.controls.timeline.window_seconds,
|
seconds: liveConfig.controls.timeline.window_seconds,
|
||||||
}),
|
}),
|
||||||
end: now,
|
end: now,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
});
|
} else {
|
||||||
|
// For non-live views stick to default timeline behavior (will select and
|
||||||
|
// scroll to event).
|
||||||
|
view.removeContextProperty('timeline', 'window');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _setOrRemoveSeekTime(view: View, time?: Date): void {
|
protected _setOrRemoveSeekTime(view: View, time?: Date): void {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
createCardAPI,
|
createCardAPI,
|
||||||
createConfig,
|
createConfig,
|
||||||
createStore,
|
createStore,
|
||||||
|
createView,
|
||||||
} from '../../test-utils';
|
} from '../../test-utils';
|
||||||
import { createPopulatedAPI } from './test-utils';
|
import { createPopulatedAPI } from './test-utils';
|
||||||
|
|
||||||
@@ -340,22 +341,46 @@ describe('getViewByParametersWithNewQuery', () => {
|
|||||||
vi.useRealTimers();
|
vi.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set timeline window', async () => {
|
describe('should set timeline window', async () => {
|
||||||
const executor = mock<QueryExecutor>();
|
it('should set timeline to now for live views', async () => {
|
||||||
const factory = new ViewFactory(createPopulatedAPI(), executor);
|
const executor = mock<QueryExecutor>();
|
||||||
const view = await factory.getViewByParametersWithNewQuery({
|
const factory = new ViewFactory(createPopulatedAPI(), executor);
|
||||||
params: {
|
const view = await factory.getViewByParametersWithNewQuery({
|
||||||
view: 'live',
|
params: {
|
||||||
},
|
view: 'live',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(view?.context).toEqual({
|
||||||
|
timeline: {
|
||||||
|
window: {
|
||||||
|
start: new Date('2024-07-21T12:22:06.000Z'),
|
||||||
|
end: new Date('2024-07-21T13:22:06.000Z'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(view?.context).toEqual({
|
it('should unset timeline for non-live views', async () => {
|
||||||
timeline: {
|
const executor = mock<QueryExecutor>();
|
||||||
window: {
|
const factory = new ViewFactory(createPopulatedAPI(), executor);
|
||||||
start: new Date('2024-07-21T12:22:06.000Z'),
|
const view = await factory.getViewByParametersWithNewQuery({
|
||||||
end: new Date('2024-07-21T13:22:06.000Z'),
|
baseView: createView({
|
||||||
|
context: {
|
||||||
|
timeline: {
|
||||||
|
window: {
|
||||||
|
start: new Date('2024-07-21T12:22:06.000Z'),
|
||||||
|
end: new Date('2024-07-21T13:22:06.000Z'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
params: {
|
||||||
|
view: 'clip',
|
||||||
},
|
},
|
||||||
},
|
});
|
||||||
|
|
||||||
|
expect(view?.context).toEqual({ timeline: {} });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user