Merge pull request #1395 from dermotduffy/init-unsupported

Always render a view even if default is unsupported
This commit is contained in:
Dermot Duffy
2024-03-08 20:08:45 -08:00
committed by GitHub
7 changed files with 98 additions and 7 deletions
+1 -1
View File
@@ -128,7 +128,7 @@ export class FrigateCamera extends Camera {
hass: HomeAssistant,
cameraConfig: CameraConfig,
): Promise<PTZCapabilities | null> {
if (!cameraConfig.frigate.camera_name) {
if (!cameraConfig.frigate.camera_name || isBirdseye(cameraConfig)) {
return null;
}
+5
View File
@@ -24,6 +24,7 @@ export interface CameraManagerReadOnlyConfigStore {
getCameraIDs(): Set<string>;
getVisibleCameraIDs(): Set<string>;
getDefaultCameraID(): string | null;
getAllDependentCameras(cameraID: string): Set<string>;
}
@@ -61,6 +62,10 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore {
return this.getVisibleCameraIDs().size;
}
public getDefaultCameraID(): string | null {
return this._cameras.keys().next().value ?? null;
}
public getCameras(): Map<string, Camera> {
return this._cameras;
}
@@ -98,7 +98,7 @@ export class InitializationManager {
if (hasViewRelatedActions) {
this._api.getQueryStringManager().executeViewRelated();
} else {
this._api.getViewManager().setViewDefault();
this._api.getViewManager().setViewDefault({ failSafe: true });
}
}
+22 -4
View File
@@ -1,13 +1,23 @@
import { ViewContext } from 'view';
import { FrigateCardConfig, FrigateCardView, ViewDisplayMode } from '../config/types';
import { View } from '../view/view';
import {
FRIGATE_CARD_VIEW_DEFAULT,
FrigateCardConfig,
FrigateCardView,
ViewDisplayMode,
} from '../config/types';
import { log } from '../utils/debug';
import { executeMediaQueryForView } from '../utils/media-to-view';
import { View } from '../view/view';
import { CardViewAPI } from './types';
interface ViewManagerSetViewDefaultParameters {
cameraID?: string;
substream?: string;
// When failSafe is true, the view will be changed to an "always-works" view
// (e.g. `live`) if the proposed view is unsupported. By default the view will
// just not be changed.
failSafe?: boolean;
}
export interface ViewManagerSetViewParameters
@@ -75,8 +85,16 @@ export class ViewManager {
cameraID = cameras.keys().next().value;
}
}
const viewName = params?.viewName ?? this._view?.view ?? config.view.default;
if (cameraID && viewName && this.isViewSupportedByCamera(cameraID, viewName)) {
let viewName = params?.viewName ?? this._view?.view ?? config.view.default;
if (cameraID && viewName) {
if (!this.isViewSupportedByCamera(cameraID, viewName)) {
if (params.failSafe) {
viewName = FRIGATE_CARD_VIEW_DEFAULT;
} else {
return;
}
}
const displayMode =
this._view?.displayMode ??
this._getDefaultDisplayModeForView(viewName, config);
+7 -1
View File
@@ -143,13 +143,18 @@ describe('FrigateCamera', () => {
it('basic non-birdseye', async () => {
const camera = new FrigateCamera(
createCameraConfig(),
createCameraConfig({
frigate: {
camera_name: 'front_door',
},
}),
mock<CameraManagerEngine>(),
);
await camera.initialize(createHASS(), mock<EntityRegistryManager>());
expect(camera.getCapabilities()).toEqual(nonBirdseyeBaseCapabilities);
expect(vi.mocked(getPTZInfo)).toBeCalled();
});
it('basic birdseye', async () => {
@@ -173,6 +178,7 @@ describe('FrigateCamera', () => {
supportsRecordings: false,
supportsTimeline: false,
});
expect(vi.mocked(getPTZInfo)).not.toBeCalled();
});
describe('with ptz', () => {
+11
View File
@@ -61,6 +61,17 @@ describe('CameraManagerStore', async () => {
expect(store.getVisibleCameraCount()).toBe(1);
});
describe('getDefaultCameraID', () => {
it('with camera', async () => {
const store = setupStore();
expect(store.getDefaultCameraID()).toBe('camera-visible');
});
it('without camera', async () => {
const store = new CameraManagerStore();
expect(store.getDefaultCameraID()).toBeNull();
});
});
describe('getCamera', async () => {
it('present', async () => {
const store = setupStore();
@@ -324,6 +324,57 @@ describe('ViewManager.setViewByParameters', () => {
expect(manager.getView()).toBeNull();
});
describe('should handle unsupported view', () => {
it('without failsafe', () => {
const api = createCardAPI();
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
vi.mocked(api.getCameraManager().getStore).mockReturnValue(
createStore([
{
cameraID: 'camera.kitchen',
},
]),
);
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig());
vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue(createCameraCapabilities({
supportsSnapshots: false,
}));
const manager = new ViewManager(api);
manager.setViewByParameters({
viewName: 'snapshots',
});
expect(manager.hasView()).toBeFalsy();
expect(manager.getView()).toBeNull();
});
it('with failsafe', () => {
const api = createCardAPI();
vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager());
vi.mocked(api.getCameraManager().getStore).mockReturnValue(
createStore([
{
cameraID: 'camera.kitchen',
},
]),
);
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig());
vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue(createCameraCapabilities({
supportsSnapshots: false,
}));
const manager = new ViewManager(api);
manager.setViewByParameters({
viewName: 'snapshots',
failSafe: true,
});
expect(manager.hasView()).toBeTruthy();
expect(manager.getView()?.view).toBe('live');
});
});
describe('should set view by parameters and respect display mode in config for view', () => {
it.each([
['media' as const],