From 299d21acab6f810ef187b950daae05e072efce8a Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 22 Sep 2024 16:00:08 -0700 Subject: [PATCH] fix: Untriggering to default should reset to default camera (#1571) --- src/card-controller/view/factory.ts | 30 ++++++++----- tests/card-controller/view/factory.test.ts | 49 ++++++++++++++++++++-- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/card-controller/view/factory.ts b/src/card-controller/view/factory.ts index 0327a7e0..69a8fadc 100644 --- a/src/card-controller/view/factory.ts +++ b/src/card-controller/view/factory.ts @@ -35,27 +35,37 @@ export class ViewFactory { return null; } - let forceCameraID: string | null = options?.params?.camera ?? null; + // Neither options.baseView.camera nor options.baseView.view are respected + // here, since this is the default view / camera. + // See: https://github.com/dermotduffy/frigate-hass-card/issues/1564 + + let cameraID: string | null = null; const viewName = options?.params?.view ?? config.view.default; - if ( - !forceCameraID && - options?.baseView?.camera && - config.view.default_cycle_camera - ) { + if (options?.params?.camera) { + cameraID = options.params.camera; + } else { const cameraIDs = [ ...getCameraIDsForViewName(this._api.getCameraManager(), viewName), ]; - const currentIndex = cameraIDs.indexOf(options?.baseView?.camera); - const targetIndex = currentIndex + 1 >= cameraIDs.length ? 0 : currentIndex + 1; - forceCameraID = cameraIDs[targetIndex]; + if (!cameraIDs.length) { + return null; + } + + if (options?.baseView?.camera && config.view.default_cycle_camera) { + const currentIndex = cameraIDs.indexOf(options.baseView.camera); + const targetIndex = currentIndex + 1 >= cameraIDs.length ? 0 : currentIndex + 1; + cameraID = cameraIDs[targetIndex]; + } else { + cameraID = cameraIDs[0]; + } } return this.getViewByParameters({ params: { ...options?.params, view: viewName, - ...(forceCameraID && { camera: forceCameraID }), + camera: cameraID, }, baseView: options?.baseView, }); diff --git a/tests/card-controller/view/factory.test.ts b/tests/card-controller/view/factory.test.ts index c0fcae8c..6a293be7 100644 --- a/tests/card-controller/view/factory.test.ts +++ b/tests/card-controller/view/factory.test.ts @@ -27,6 +27,33 @@ describe('getViewDefault', () => { expect(factory.getViewDefault()).toBeNull(); }); + it('should return null if no cameras support view', () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + + // No cameras support live. + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.office', + capabilities: createCapabilities({ + live: false, + }), + }, + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ + live: false, + }), + }, + ]), + ); + + const factory = new ViewFactory(api); + expect(factory.getViewDefault()).toBeNull(); + }); + it('should create view', () => { const factory = new ViewFactory(createPopulatedAPI()); const view = factory.getViewDefault(); @@ -64,17 +91,31 @@ describe('getViewDefault', () => { expect(view?.camera).toBe('camera.office'); }); - it('should respect parameters', () => { + it('should use default camera when camera unspecified', () => { + // Even though baseView has a camera, since default is called it should + // use that camera. + const factory = new ViewFactory(createPopulatedAPI()); + const baseView = createView({ camera: 'camera.kitchen' }); const view = factory.getViewDefault({ - params: { - camera: 'camera.office', - }, + baseView: baseView, }); expect(view?.is('live')).toBeTruthy(); expect(view?.camera).toBe('camera.office'); }); + + it('should respect parameters', () => { + const factory = new ViewFactory(createPopulatedAPI()); + const view = factory.getViewDefault({ + params: { + camera: 'camera.kitchen', + }, + }); + + expect(view?.is('live')).toBeTruthy(); + expect(view?.camera).toBe('camera.kitchen'); + }); }); describe('getViewByParameters', () => {