fix: Expose gallery and media views as media type agnostic (#2335)
This commit is contained in:
@@ -568,48 +568,54 @@ describe('ViewQueryExecutor', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('with a media view', () => {
|
||||
it('should set query and queryResults for events', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const cameraManager = api.getCameraManager();
|
||||
if (cameraManager) {
|
||||
vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue(
|
||||
new Capabilities({ clips: true }),
|
||||
);
|
||||
}
|
||||
describe('with a media or gallery view', () => {
|
||||
it.each(['media' as const, 'gallery' as const])(
|
||||
'should set query and queryResults for events with %s view',
|
||||
async (viewName) => {
|
||||
const api = createPopulatedAPI();
|
||||
const cameraManager = api.getCameraManager();
|
||||
if (cameraManager) {
|
||||
vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue(
|
||||
new Capabilities({ clips: true }),
|
||||
);
|
||||
}
|
||||
|
||||
const viewQueryExecutor = new ViewQueryExecutor(api);
|
||||
const view = new View({
|
||||
view: 'media',
|
||||
camera: 'camera.office',
|
||||
});
|
||||
const viewQueryExecutor = new ViewQueryExecutor(api);
|
||||
const view = new View({
|
||||
view: viewName,
|
||||
camera: 'camera.office',
|
||||
});
|
||||
|
||||
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
||||
applyViewModifiers(view, modifiers);
|
||||
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
||||
applyViewModifiers(view, modifiers);
|
||||
|
||||
expect(view.query).toBeInstanceOf(UnifiedQuery);
|
||||
const queries = view.query?.getMediaQueries({ type: QueryType.Event });
|
||||
expect(queries?.length).toBeGreaterThan(0);
|
||||
expect(queries?.[0].cameraIDs.has('camera.office')).toBe(true);
|
||||
expect(view.queryResults).toBeDefined();
|
||||
});
|
||||
expect(view.query).toBeInstanceOf(UnifiedQuery);
|
||||
const queries = view.query?.getMediaQueries({ type: QueryType.Event });
|
||||
expect(queries?.length).toBeGreaterThan(0);
|
||||
expect(queries?.[0].cameraIDs.has('camera.office')).toBe(true);
|
||||
expect(view.queryResults).toBeDefined();
|
||||
},
|
||||
);
|
||||
|
||||
it('should query all cameras in media view grid mode', async () => {
|
||||
const api = createPopulatedAPI();
|
||||
const viewQueryExecutor = new ViewQueryExecutor(api);
|
||||
const view = createView({
|
||||
view: 'media',
|
||||
camera: 'camera.office',
|
||||
displayMode: 'grid',
|
||||
});
|
||||
it.each(['media' as const, 'gallery' as const])(
|
||||
'should query all cameras in %s view grid mode',
|
||||
async (viewName) => {
|
||||
const api = createPopulatedAPI();
|
||||
const viewQueryExecutor = new ViewQueryExecutor(api);
|
||||
const view = createView({
|
||||
view: viewName,
|
||||
camera: 'camera.office',
|
||||
displayMode: 'grid',
|
||||
});
|
||||
|
||||
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
||||
applyViewModifiers(view, modifiers);
|
||||
const modifiers = await viewQueryExecutor.getNewQueryModifiers(view);
|
||||
applyViewModifiers(view, modifiers);
|
||||
|
||||
expect(view.query).toBeInstanceOf(UnifiedQuery);
|
||||
const allCameraIDs = view.query?.getAllCameraIDs();
|
||||
expect(allCameraIDs?.size).toBeGreaterThan(0);
|
||||
});
|
||||
expect(view.query).toBeInstanceOf(UnifiedQuery);
|
||||
const allCameraIDs = view.query?.getAllCameraIDs();
|
||||
expect(allCameraIDs?.size).toBeGreaterThan(0);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('with an events-based view', () => {
|
||||
|
||||
@@ -561,9 +561,7 @@ describe('MenuButtonController', () => {
|
||||
describe('should have clips menu button', () => {
|
||||
it('when in clips view', () => {
|
||||
const viewManager = mock<ViewManager>();
|
||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
||||
(view) => view !== 'reviews',
|
||||
);
|
||||
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||
const buttons = calculateButtons(controller, {
|
||||
view: createView({ view: 'clips' }),
|
||||
viewManager: viewManager,
|
||||
@@ -571,7 +569,7 @@ describe('MenuButtonController', () => {
|
||||
|
||||
expect(buttons).toContainEqual({
|
||||
icon: 'mdi:filmstrip',
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
priority: 50,
|
||||
type: 'custom:advanced-camera-card-menu-icon',
|
||||
title: 'Clips gallery',
|
||||
@@ -583,16 +581,14 @@ describe('MenuButtonController', () => {
|
||||
|
||||
it('when not in clips view', () => {
|
||||
const viewManager = mock<ViewManager>();
|
||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
||||
(view) => view !== 'reviews',
|
||||
);
|
||||
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||
const buttons = calculateButtons(controller, {
|
||||
viewManager: viewManager,
|
||||
});
|
||||
|
||||
expect(buttons).toContainEqual({
|
||||
icon: 'mdi:filmstrip',
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
priority: 50,
|
||||
type: 'custom:advanced-camera-card-menu-icon',
|
||||
title: 'Clips gallery',
|
||||
@@ -613,30 +609,6 @@ describe('MenuButtonController', () => {
|
||||
expect.arrayContaining([expect.objectContaining({ title: 'Clips gallery' })]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should be hidden when reviews are supported', () => {
|
||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
||||
(view) => view === 'clips' || view === 'reviews',
|
||||
);
|
||||
const buttons = calculateButtons(controller);
|
||||
|
||||
expect(buttons).not.toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ title: 'Clips gallery' })]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should be shown when reviews are supported but button is explicitly enabled', () => {
|
||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
||||
(view) => view === 'clips' || view === 'reviews',
|
||||
);
|
||||
const buttons = calculateButtons(controller, {
|
||||
config: createConfig({ menu: { buttons: { clips: { enabled: true } } } }),
|
||||
});
|
||||
|
||||
expect(buttons).toContainEqual(
|
||||
expect.objectContaining({ title: 'Clips gallery', enabled: true }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('should have snapshots menu button', () => {
|
||||
@@ -652,7 +624,7 @@ describe('MenuButtonController', () => {
|
||||
|
||||
expect(buttons).toContainEqual({
|
||||
icon: 'mdi:camera',
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
priority: 50,
|
||||
type: 'custom:advanced-camera-card-menu-icon',
|
||||
title: 'Snapshots gallery',
|
||||
@@ -670,16 +642,14 @@ describe('MenuButtonController', () => {
|
||||
|
||||
it('when not in snapshots view', () => {
|
||||
const viewManager = mock<ViewManager>();
|
||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
||||
(view) => view !== 'reviews',
|
||||
);
|
||||
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||
const buttons = calculateButtons(controller, {
|
||||
viewManager: viewManager,
|
||||
});
|
||||
|
||||
expect(buttons).toContainEqual({
|
||||
icon: 'mdi:camera',
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
priority: 50,
|
||||
type: 'custom:advanced-camera-card-menu-icon',
|
||||
title: 'Snapshots gallery',
|
||||
@@ -708,32 +678,6 @@ describe('MenuButtonController', () => {
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should be hidden when reviews are supported', () => {
|
||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
||||
(view) => view === 'snapshots' || view === 'reviews',
|
||||
);
|
||||
const buttons = calculateButtons(controller);
|
||||
|
||||
expect(buttons).not.toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ title: 'Snapshots gallery' }),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should be shown when reviews are supported but button is explicitly enabled', () => {
|
||||
vi.mocked(isViewSupportedByCamera).mockImplementation(
|
||||
(view) => view === 'snapshots' || view === 'reviews',
|
||||
);
|
||||
const buttons = calculateButtons(controller, {
|
||||
config: createConfig({ menu: { buttons: { snapshots: { enabled: true } } } }),
|
||||
});
|
||||
|
||||
expect(buttons).toContainEqual(
|
||||
expect.objectContaining({ title: 'Snapshots gallery', enabled: true }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('should have reviews menu button', () => {
|
||||
@@ -746,8 +690,8 @@ describe('MenuButtonController', () => {
|
||||
});
|
||||
|
||||
expect(buttons).toContainEqual({
|
||||
icon: 'mdi:play-box-multiple',
|
||||
enabled: true,
|
||||
icon: 'mdi:play-box-edit-outline',
|
||||
enabled: false,
|
||||
priority: 50,
|
||||
type: 'custom:advanced-camera-card-menu-icon',
|
||||
title: 'Reviews gallery',
|
||||
@@ -771,8 +715,8 @@ describe('MenuButtonController', () => {
|
||||
});
|
||||
|
||||
expect(buttons).toContainEqual({
|
||||
icon: 'mdi:play-box-multiple',
|
||||
enabled: true,
|
||||
icon: 'mdi:play-box-edit-outline',
|
||||
enabled: false,
|
||||
priority: 50,
|
||||
type: 'custom:advanced-camera-card-menu-icon',
|
||||
title: 'Reviews gallery',
|
||||
@@ -801,6 +745,71 @@ describe('MenuButtonController', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('should have gallery menu button', () => {
|
||||
it('when in gallery view', () => {
|
||||
const viewManager = mock<ViewManager>();
|
||||
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||
const buttons = calculateButtons(controller, {
|
||||
view: createView({ view: 'gallery' }),
|
||||
viewManager: viewManager,
|
||||
});
|
||||
|
||||
expect(buttons).toContainEqual({
|
||||
icon: 'mdi:play-box-multiple',
|
||||
enabled: true,
|
||||
priority: 50,
|
||||
type: 'custom:advanced-camera-card-menu-icon',
|
||||
title: 'Gallery',
|
||||
style: { color: 'var(--advanced-camera-card-menu-button-active-color)' },
|
||||
tap_action: {
|
||||
action: 'fire-dom-event',
|
||||
advanced_camera_card_action: 'gallery',
|
||||
},
|
||||
hold_action: {
|
||||
action: 'fire-dom-event',
|
||||
advanced_camera_card_action: 'media',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('when not in gallery view', () => {
|
||||
const viewManager = mock<ViewManager>();
|
||||
vi.mocked(isViewSupportedByCamera).mockReturnValue(true);
|
||||
const buttons = calculateButtons(controller, {
|
||||
viewManager: viewManager,
|
||||
});
|
||||
|
||||
expect(buttons).toContainEqual({
|
||||
icon: 'mdi:play-box-multiple',
|
||||
enabled: true,
|
||||
priority: 50,
|
||||
type: 'custom:advanced-camera-card-menu-icon',
|
||||
title: 'Gallery',
|
||||
style: {},
|
||||
tap_action: {
|
||||
action: 'fire-dom-event',
|
||||
advanced_camera_card_action: 'gallery',
|
||||
},
|
||||
hold_action: {
|
||||
action: 'fire-dom-event',
|
||||
advanced_camera_card_action: 'media',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('when not supported', () => {
|
||||
const viewManager = mock<ViewManager>();
|
||||
vi.mocked(isViewSupportedByCamera).mockReturnValue(false);
|
||||
const buttons = calculateButtons(controller, {
|
||||
viewManager: viewManager,
|
||||
});
|
||||
|
||||
expect(buttons).not.toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ title: 'Gallery' })]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('should have recordings menu button', () => {
|
||||
it('when in recordings view', () => {
|
||||
const viewManager = mock<ViewManager>();
|
||||
|
||||
@@ -231,6 +231,10 @@ describe('config defaults', () => {
|
||||
enabled: true,
|
||||
priority: 50,
|
||||
},
|
||||
gallery: {
|
||||
enabled: true,
|
||||
priority: 50,
|
||||
},
|
||||
image: {
|
||||
enabled: false,
|
||||
priority: 50,
|
||||
@@ -277,7 +281,7 @@ describe('config defaults', () => {
|
||||
priority: 50,
|
||||
},
|
||||
reviews: {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
priority: 50,
|
||||
},
|
||||
set_review: {
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
|
||||
describe('getCameraIDsForViewName', () => {
|
||||
describe('views that are always supported', () => {
|
||||
it.each([['diagnostics' as const], ['image' as const], ['media' as const]])(
|
||||
it.each([['diagnostics' as const], ['image' as const]])(
|
||||
'%s',
|
||||
(viewName: AdvancedCameraCardView) => {
|
||||
const cameraManager = createCameraManager();
|
||||
@@ -51,6 +51,15 @@ describe('getCameraIDsForViewName', () => {
|
||||
['timeline' as const, 'clips' as const],
|
||||
['timeline' as const, 'recordings' as const],
|
||||
['timeline' as const, 'snapshots' as const],
|
||||
['timeline' as const, 'reviews' as const],
|
||||
['media' as const, 'clips' as const],
|
||||
['media' as const, 'recordings' as const],
|
||||
['media' as const, 'snapshots' as const],
|
||||
['media' as const, 'reviews' as const],
|
||||
['gallery' as const, 'clips' as const],
|
||||
['gallery' as const, 'recordings' as const],
|
||||
['gallery' as const, 'snapshots' as const],
|
||||
['gallery' as const, 'reviews' as const],
|
||||
])('%s', (viewName: AdvancedCameraCardView, capabilityKey: CapabilityKey) => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
@@ -111,67 +120,73 @@ describe('getCameraIDsForViewName', () => {
|
||||
|
||||
describe('views that respect a folder', () => {
|
||||
describe('should return cameras when a folder is present', () => {
|
||||
it.each([['folder' as const], ['folders' as const], ['timeline' as const]])(
|
||||
'%s',
|
||||
(viewName: AdvancedCameraCardView) => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera-1',
|
||||
config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }),
|
||||
},
|
||||
{
|
||||
cameraID: 'camera-2',
|
||||
},
|
||||
]),
|
||||
);
|
||||
const foldersManager = mock<FoldersManager>();
|
||||
vi.mocked(foldersManager.getFolder).mockReturnValue(createFolder());
|
||||
it.each([
|
||||
['folder' as const],
|
||||
['folders' as const],
|
||||
['timeline' as const],
|
||||
['media' as const],
|
||||
['gallery' as const],
|
||||
])('%s', (viewName: AdvancedCameraCardView) => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera-1',
|
||||
config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }),
|
||||
},
|
||||
{
|
||||
cameraID: 'camera-2',
|
||||
},
|
||||
]),
|
||||
);
|
||||
const foldersManager = mock<FoldersManager>();
|
||||
vi.mocked(foldersManager.getFolder).mockReturnValue(createFolder());
|
||||
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager),
|
||||
).toEqual(new Set(['camera-1', 'camera-2']));
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-1'),
|
||||
).toEqual(new Set(['camera-1', 'camera-2']));
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-2'),
|
||||
).toEqual(new Set(['camera-1', 'camera-2']));
|
||||
},
|
||||
);
|
||||
expect(getCameraIDsForViewName(viewName, cameraManager, foldersManager)).toEqual(
|
||||
new Set(['camera-1', 'camera-2']),
|
||||
);
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-1'),
|
||||
).toEqual(new Set(['camera-1', 'camera-2']));
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-2'),
|
||||
).toEqual(new Set(['camera-1', 'camera-2']));
|
||||
});
|
||||
});
|
||||
|
||||
describe('should not return cameras when a folder is absent', () => {
|
||||
it.each([['folder' as const], ['folders' as const], ['timeline' as const]])(
|
||||
'%s',
|
||||
(viewName: AdvancedCameraCardView) => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera-1',
|
||||
config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }),
|
||||
},
|
||||
{
|
||||
cameraID: 'camera-2',
|
||||
},
|
||||
]),
|
||||
);
|
||||
const foldersManager = mock<FoldersManager>();
|
||||
vi.mocked(foldersManager.getFolder).mockReturnValue(null);
|
||||
it.each([
|
||||
['folder' as const],
|
||||
['folders' as const],
|
||||
['timeline' as const],
|
||||
['media' as const],
|
||||
['gallery' as const],
|
||||
])('%s', (viewName: AdvancedCameraCardView) => {
|
||||
const cameraManager = createCameraManager();
|
||||
vi.mocked(cameraManager.getStore).mockReturnValue(
|
||||
createStore([
|
||||
{
|
||||
cameraID: 'camera-1',
|
||||
config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }),
|
||||
},
|
||||
{
|
||||
cameraID: 'camera-2',
|
||||
},
|
||||
]),
|
||||
);
|
||||
const foldersManager = mock<FoldersManager>();
|
||||
vi.mocked(foldersManager.getFolder).mockReturnValue(null);
|
||||
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager),
|
||||
).toEqual(new Set());
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-1'),
|
||||
).toEqual(new Set());
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-2'),
|
||||
).toEqual(new Set());
|
||||
},
|
||||
);
|
||||
expect(getCameraIDsForViewName(viewName, cameraManager, foldersManager)).toEqual(
|
||||
new Set(),
|
||||
);
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-1'),
|
||||
).toEqual(new Set());
|
||||
expect(
|
||||
getCameraIDsForViewName(viewName, cameraManager, foldersManager, 'camera-2'),
|
||||
).toEqual(new Set());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user