Refactor main types.ts .

This commit is contained in:
Dermot Duffy
2023-10-02 22:35:58 -07:00
parent 5ebd85e5e8
commit 9b72dd8089
77 changed files with 2268 additions and 1819 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ import { FrigateCameraManagerEngine } from '../../src/camera-manager/frigate/eng
import { GenericCameraManagerEngine } from '../../src/camera-manager/generic/engine-generic';
import { MotionEyeCameraManagerEngine } from '../../src/camera-manager/motioneye/engine-motioneye';
import { Engine } from '../../src/camera-manager/types.js';
import { CardWideConfig } from '../../src/types.js';
import { CardWideConfig } from '../../src/config/types.js';
import { EntityRegistryManager } from '../../src/utils/ha/entity-registry';
import { EntityCache } from '../../src/utils/ha/entity-registry/cache';
import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media';
@@ -6,7 +6,7 @@ import {
FrigateRecordingViewMedia,
} from '../../../src/camera-manager/frigate/media';
import { FrigateEvent, eventSchema } from '../../../src/camera-manager/frigate/types.js';
import { CameraConfig, RawFrigateCardConfig } from '../../../src/types';
import { CameraConfig, RawFrigateCardConfig } from '../../../src/config/types';
import { ViewMedia } from '../../../src/view/media';
import { createCameraConfig, createHASS } from '../../test-utils';
+1 -1
View File
@@ -9,7 +9,7 @@ import {
getRecordingMediaContentID,
getRecordingTitle,
} from '../../../src/camera-manager/frigate/util';
import { CameraConfig } from '../../../src/types';
import { CameraConfig } from '../../../src/config/types';
import {
createCameraConfig,
createFrigateEvent,
+1 -2
View File
@@ -5,8 +5,7 @@ import {
getCameraEntityFromConfig,
sortMedia,
} from '../../src/camera-manager/util.js';
import { CameraConfig, cameraConfigSchema } from '../../src/types.js';
import { ViewMedia, ViewMediaType } from '../../src/view/media.js';
import { CameraConfig, cameraConfigSchema } from '../../src/config/types.js';
import { TestViewMedia } from '../test-utils.js';
describe('convertRangeToCacheFriendlyTimes', () => {
+421
View File
@@ -0,0 +1,421 @@
import { describe, expect, it } from 'vitest';
import {
conditionalSchema,
customSchema,
dimensionsConfigSchema,
frigateCardCustomActionsBaseSchema,
frigateCardPTZSchema
} from '../../src/config/types';
import { createConfig } from '../test-utils';
// @vitest-environment jsdom
describe('config defaults', () => {
it('should be as expected', () => {
expect(createConfig()).toEqual({
cameras: [],
cameras_global: {
dependencies: {
all_cameras: false,
cameras: [],
},
engine: 'auto',
frigate: {
client_id: 'frigate',
},
hide: false,
image: {
refresh_seconds: 1,
},
live_provider: 'auto',
motioneye: {
images: {
directory_pattern: '%Y-%m-%d',
file_pattern: '%H-%M-%S',
},
movies: {
directory_pattern: '%Y-%m-%d',
file_pattern: '%H-%M-%S',
},
},
triggers: {
entities: [],
motion: false,
occupancy: true,
},
},
debug: {
logging: false,
},
dimensions: {
aspect_ratio: [16, 9],
aspect_ratio_mode: 'dynamic',
max_height: '100vh',
min_height: '100px',
},
image: {
mode: 'url',
refresh_seconds: 1,
zoomable: true,
},
live: {
auto_mute: 'all',
auto_pause: 'never',
auto_play: 'all',
auto_unmute: 'never',
controls: {
builtin: true,
next_previous: {
size: 48,
style: 'chevrons',
},
thumbnails: {
media: 'all',
mode: 'right',
show_details: true,
show_download_control: true,
show_favorite_control: true,
show_timeline_control: true,
size: 100,
},
timeline: {
clustering_threshold: 3,
media: 'all',
mode: 'none',
show_recordings: true,
style: 'ribbon',
window_seconds: 3600,
},
},
draggable: true,
lazy_load: true,
lazy_unload: 'never',
microphone: {
always_connected: false,
disconnect_seconds: 60,
},
preload: false,
show_image_during_load: true,
transition_effect: 'slide',
zoomable: true,
},
media_gallery: {
controls: {
filter: {
mode: 'right',
},
thumbnails: {
mode: 'right',
show_details: false,
show_download_control: true,
show_favorite_control: true,
show_timeline_control: true,
size: 100,
},
},
},
media_viewer: {
auto_mute: 'all',
auto_pause: 'all',
auto_play: 'all',
auto_unmute: 'never',
controls: {
builtin: true,
next_previous: {
size: 48,
style: 'thumbnails',
},
thumbnails: {
mode: 'right',
show_details: true,
show_download_control: true,
show_favorite_control: true,
show_timeline_control: true,
size: 100,
},
timeline: {
clustering_threshold: 3,
media: 'all',
mode: 'none',
show_recordings: true,
style: 'ribbon',
window_seconds: 3600,
},
},
draggable: true,
lazy_load: true,
snapshot_click_plays_clip: true,
transition_effect: 'slide',
zoomable: true,
},
menu: {
alignment: 'left',
button_size: 40,
buttons: {
camera_ui: {
enabled: true,
priority: 50,
},
cameras: {
enabled: true,
priority: 50,
},
clips: {
enabled: true,
priority: 50,
},
display_mode: {
enabled: true,
priority: 50,
},
download: {
enabled: true,
priority: 50,
},
expand: {
enabled: false,
priority: 50,
},
frigate: {
enabled: true,
priority: 50,
},
fullscreen: {
enabled: true,
priority: 50,
},
image: {
enabled: false,
priority: 50,
},
live: {
enabled: true,
priority: 50,
},
media_player: {
enabled: true,
priority: 50,
},
microphone: {
enabled: false,
priority: 50,
type: 'momentary',
},
mute: {
enabled: false,
priority: 50,
},
play: {
enabled: false,
priority: 50,
},
recordings: {
enabled: false,
priority: 50,
},
screenshot: {
enabled: false,
priority: 50,
},
snapshots: {
enabled: true,
priority: 50,
},
substreams: {
enabled: true,
priority: 50,
},
timeline: {
enabled: true,
priority: 50,
},
},
position: 'top',
style: 'hidden',
},
performance: {
features: {
animated_progress_indicator: true,
media_chunk_size: 50,
},
profile: 'high',
style: {
border_radius: true,
box_shadow: true,
},
},
timeline: {
clustering_threshold: 3,
controls: {
thumbnails: {
mode: 'right',
show_details: true,
show_download_control: true,
show_favorite_control: true,
show_timeline_control: true,
size: 100,
},
},
media: 'all',
show_recordings: true,
style: 'stack',
window_seconds: 3600,
},
type: 'frigate-hass-card',
view: {
camera_select: 'current',
dark_mode: 'off',
default: 'live',
scan: {
enabled: false,
show_trigger_status: true,
untrigger_reset: true,
untrigger_seconds: 0,
},
timeout_seconds: 300,
update_cycle_camera: false,
update_force: false,
update_seconds: 0,
},
});
});
});
it('should transform dimensions.aspect_ratio', () => {
expect(
dimensionsConfigSchema.parse({
aspect_ratio: '16 / 9',
}),
).toEqual(expect.objectContaining({ aspect_ratio: [16, 9] }));
expect(
dimensionsConfigSchema.parse({
aspect_ratio: '16 : 9',
}),
).toEqual(expect.objectContaining({ aspect_ratio: [16, 9] }));
expect(
dimensionsConfigSchema.parse({
aspect_ratio: [16, 9],
}),
).toEqual(expect.objectContaining({ aspect_ratio: [16, 9] }));
});
it('should transform action', () => {
expect(
frigateCardCustomActionsBaseSchema.parse({
action: 'custom:frigate-card-action',
}),
).toEqual({
action: 'fire-dom-event',
});
});
describe('should convert webrtc card PTZ to Frigate card PTZ', () => {
it.each([
['left' as const],
['right' as const],
['up' as const],
['down' as const],
['zoom_in' as const],
['zoom_out' as const],
['home' as const],
])('%s', (action: string) => {
expect(
frigateCardPTZSchema.parse({
type: 'custom:frigate-card-ptz',
service: 'foo',
[`data_${action}`]: {
tap_action: {
action: 'none',
},
},
}),
).toEqual({
[`actions_${action}`]: {
tap_action: {
action: 'call-service',
service: 'foo',
service_data: {
tap_action: {
action: 'none',
},
},
},
},
service: 'foo',
type: 'custom:frigate-card-ptz',
});
});
});
describe('should lazy evaluate', () => {
it('conditional picture element', () => {
expect(
conditionalSchema.parse({
type: 'conditional',
conditions: [
{
entity: 'light.office_main_lights',
state: 'on',
state_not: 'off',
},
],
elements: [
{
type: 'icon',
icon: 'mdi:dog',
title: 'Woof',
style: {
left: '100px',
top: '400px',
},
},
],
}),
).toEqual({
conditions: [
{
entity: 'light.office_main_lights',
state: 'on',
state_not: 'off',
},
],
elements: [
{
icon: 'mdi:dog',
style: {
left: '100px',
top: '400px',
},
title: 'Woof',
type: 'icon',
},
],
type: 'conditional',
});
});
});
describe('should handle custom frigate elements', () => {
it('should add custom error on frigate entry', () => {
const result = customSchema.safeParse({
type: 'custom:frigate-card-foo',
});
expect(result.success).toBeFalsy();
if (!result.success) {
expect(result.error.errors[0]).toEqual({
code: 'custom',
message: 'Frigate-card custom elements must match specific schemas',
fatal: true,
path: ['type'],
});
}
});
it('should not add custom error on valid entry', () => {
const result = customSchema.safeParse({
type: 'custom:foo',
});
expect(result.success).toBeTruthy();
});
});
+2 -3
View File
@@ -12,17 +12,16 @@ import {
} from '../src/camera-manager/types';
import {
CameraConfig,
ExtendedHomeAssistant,
FrigateCardCondition,
FrigateCardConfig,
MediaLoadedInfo,
PerformanceConfig,
RawFrigateCardConfig,
cameraConfigSchema,
frigateCardConditionSchema,
frigateCardConfigSchema,
performanceConfigSchema,
} from '../src/types';
} from '../src/config/types';
import { ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types';
import { ActionsManager } from '../src/utils/card-controller/actions-manager';
import { AutoUpdateManager } from '../src/utils/card-controller/auto-update-manager';
import { AutomationsManager } from '../src/utils/card-controller/automations-manager';
+1 -6
View File
@@ -1,12 +1,7 @@
import { handleActionConfig, hasAction } from 'custom-card-helpers';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { mock } from 'vitest-mock-extended';
import {
actionSchema,
FrigateCardAction,
FrigateCardCustomAction,
frigateCardCustomActionSchema,
} from '../../src/types';
import { actionSchema } from '../../src/config/types';
import {
convertActionToFrigateCardCustomAction,
createFrigateCardCustomAction,
@@ -3,10 +3,10 @@ import { mock } from 'vitest-mock-extended';
import {
ActionType,
FrigateCardCustomAction,
FrigateCardMediaPlayer,
FrigateCardView,
frigateCardCustomActionSchema,
} from '../../../src/types';
} from '../../../src/config/types';
import { FrigateCardMediaPlayer } from '../../../src/types';
import {
convertActionToFrigateCardCustomAction,
frigateCardHandleActionConfig,
@@ -139,9 +139,7 @@ describe('ActionsManager.getMergedActions', () => {
vi.mocked(api.getViewManager().getView).mockReturnValue(
createView({ view: viewName }),
);
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(
createConfig(config),
);
vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config));
const manager = new ActionsManager(api);
@@ -1,12 +1,12 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { FrigateCardCondition } from '../../../src/config/types';
import {
ConditionsManager,
ConditionEvaluateRequestEvent,
ConditionsManager,
evaluateConditionViaEvent,
getOverriddenConfig,
getOverridesByKey,
} from '../../../src/utils/card-controller/conditions-manager';
import { FrigateCardCondition } from '../../../src/types';
import {
createCardAPI,
createCondition,
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ZodError } from 'zod';
import { frigateCardConfigSchema } from '../../../src/types';
import { frigateCardConfigSchema } from '../../../src/config/types';
import { getOverriddenConfig } from '../../../src/utils/card-controller/conditions-manager';
import { ConfigManager } from '../../../src/utils/card-controller/config-manager';
import { InitializationAspect } from '../../../src/utils/card-controller/initialization-manager';
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { FrigateCardView } from '../../../src/config/types';
import { setPerformanceCSSStyles } from '../../../src/performance';
import { FrigateCardView } from '../../../src/types';
import { StyleManager } from '../../../src/utils/card-controller/style-manager';
import { createCardAPI, createConfig, createHASS, createView } from '../../test-utils';
@@ -1,7 +1,7 @@
import add from 'date-fns/add';
import { HassEntities } from 'home-assistant-js-websocket';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { ScanOptions } from '../../../src/types';
import { ScanOptions } from '../../../src/config/types';
import { TriggersManager } from '../../../src/utils/card-controller/triggers-manager';
import {
createCameraConfig,
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from 'vitest';
import { QueryType } from '../../../src/camera-manager/types';
import { FrigateCardView } from '../../../src/types';
import { FrigateCardView } from '../../../src/config/types';
import { getAllDependentCameras } from '../../../src/utils/camera';
import { ViewManager } from '../../../src/utils/card-controller/view-manager';
import { EventMediaQueries } from '../../../src/view/media-queries';
+16 -17
View File
@@ -4,16 +4,15 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
import { mock } from 'vitest-mock-extended';
import { CameraManager } from '../../src/camera-manager/manager';
import { CameraManagerCameraMetadata } from '../../src/camera-manager/types';
import {
FrigateCardConfig,
FrigateCardMediaPlayer,
MenuButton,
ViewDisplayMode,
} from '../../src/types';
import { FrigateCardConfig, MenuItem, ViewDisplayMode } from '../../src/config/types';
import { FrigateCardMediaPlayer } from '../../src/types';
import { createFrigateCardCustomAction } from '../../src/utils/action';
import { MediaPlayerManager } from '../../src/utils/card-controller/media-player-manager';
import { MicrophoneManager } from '../../src/utils/card-controller/microphone-manager';
import { MenuButtonController, MenuButtonControllerOptions } from '../../src/utils/menu-controller';
import {
MenuButtonController,
MenuButtonControllerOptions,
} from '../../src/utils/menu-controller';
import { ViewMedia } from '../../src/view/media';
import { MediaQueriesResults } from '../../src/view/media-queries-results';
import { View } from '../../src/view/view';
@@ -42,7 +41,7 @@ const calculateButtons = (
cameraManager?: CameraManager;
view?: View;
},
): MenuButton[] => {
): MenuItem[] => {
return controller.calculateButtons(
options?.hass ?? createHASS(),
options?.config ?? createConfig(),
@@ -61,7 +60,7 @@ const calculateButtons = (
// @vitest-environment jsdom
describe('MenuButtonController', () => {
let controller: MenuButtonController;
const dynamicButton: MenuButton = {
const dynamicButton: MenuItem = {
type: 'custom:frigate-card-menu-icon',
icon: 'mdi:alpha-a-circle',
title: 'Dynamic button',
@@ -1130,7 +1129,7 @@ describe('MenuButtonController', () => {
});
it('should handle dynamic buttons', () => {
const button: MenuButton = {
const button: MenuItem = {
...dynamicButton,
style: {},
};
@@ -1152,7 +1151,7 @@ describe('MenuButtonController', () => {
});
it('should not set style for dynamic button with stock action', () => {
const button: MenuButton = {
const button: MenuItem = {
...dynamicButton,
tap_action: { action: 'navigate', navigation_path: 'foo' },
};
@@ -1165,7 +1164,7 @@ describe('MenuButtonController', () => {
});
it('should not set style for dynamic button with non-Frigate fire-dom-event action', () => {
const button: MenuButton = {
const button: MenuItem = {
...dynamicButton,
tap_action: { action: 'fire-dom-event' },
};
@@ -1179,7 +1178,7 @@ describe('MenuButtonController', () => {
});
it('should set style for dynamic button with Frigate view action', () => {
const button: MenuButton = {
const button: MenuItem = {
...dynamicButton,
tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' },
};
@@ -1193,7 +1192,7 @@ describe('MenuButtonController', () => {
});
it('should set style for dynamic button with Frigate default action', () => {
const button: MenuButton = {
const button: MenuItem = {
...dynamicButton,
tap_action: { action: 'fire-dom-event', frigate_card_action: 'default' },
};
@@ -1206,7 +1205,7 @@ describe('MenuButtonController', () => {
});
it('should set style for dynamic button with fullscreen action', () => {
const button: MenuButton = {
const button: MenuItem = {
...dynamicButton,
tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' },
};
@@ -1219,7 +1218,7 @@ describe('MenuButtonController', () => {
});
it('should set style for dynamic button with camera_select action', () => {
const button: MenuButton = {
const button: MenuItem = {
...dynamicButton,
tap_action: {
action: 'fire-dom-event',
@@ -1237,7 +1236,7 @@ describe('MenuButtonController', () => {
});
it('should set style for dynamic button with array of actions', () => {
const button: MenuButton = {
const button: MenuItem = {
...dynamicButton,
tap_action: [
{ action: 'fire-dom-event' },