Move overrides to a single configuration section.

This commit is contained in:
Dermot Duffy
2022-01-14 21:31:16 -08:00
parent 55ca108a9b
commit ee9f22f9f7
4 changed files with 82 additions and 44 deletions
+26 -15
View File
@@ -1,5 +1,6 @@
import type {
FrigateCardCondition,
OverrideConfigurationKey,
RawFrigateCardConfig,
} from './types';
import { merge, cloneDeep } from 'lodash-es';
@@ -27,7 +28,8 @@ export function evaluateCondition(
result &&= !!state.view && condition.view.includes(state.view);
}
if (condition?.fullscreen !== undefined) {
result &&= state.fullscreen !== undefined && condition.fullscreen == state.fullscreen;
result &&=
state.fullscreen !== undefined && condition.fullscreen == state.fullscreen;
}
if (condition?.camera?.length) {
result &&= !!state.camera && condition.camera.includes(state.camera);
@@ -78,32 +80,41 @@ export function conditionStateRequestHandler(
ev.conditionState = conditionState;
}
type Overrides = {
type RawOverrides = {
conditions: FrigateCardCondition;
overrides: RawFrigateCardConfig;
}[];
export function getOverriddenConfig(
config: Readonly<RawFrigateCardConfig>,
overrides: Readonly<RawOverrides> | undefined,
conditionState?: Readonly<ConditionState>,
overrides?: Readonly<Overrides>,
): RawFrigateCardConfig {
const overridesSource =
overrides || (config['overrides'] as Readonly<Overrides> | undefined);
if (!overridesSource) {
return config;
}
const output = cloneDeep(config);
let overridden = false;
for (const override of overridesSource) {
if (evaluateCondition(override.conditions, conditionState)) {
merge(output, override.overrides);
overridden = true;
if (overrides) {
for (const override of overrides) {
if (evaluateCondition(override.conditions, conditionState)) {
merge(output, override.overrides);
overridden = true;
}
}
}
// Attempt to return the same configuration object if it has not been
// overridden (to reduce re-renders for a configuration that has not changed).
return overridden ? output : config;
}
}
export function getOverridesByKey(
overrides: Readonly<RawOverrides> | undefined,
key: OverrideConfigurationKey,
): RawOverrides {
return (
overrides
?.filter((o) => key in o.overrides)
.map((o) => ({
conditions: o.conditions,
overrides: o.overrides[key] as RawFrigateCardConfig,
})) ?? []
);
}
+14 -9
View File
@@ -26,7 +26,6 @@ import {
ActionType,
CameraConfig,
GetFrigateCardMenuButtonParameters,
LiveConfig,
RawFrigateCardConfig,
entitySchema,
frigateCardConfigSchema,
@@ -79,6 +78,7 @@ import {
ConditionState,
conditionStateRequestHandler,
getOverriddenConfig,
getOverridesByKey,
} from './card-condition.js';
/** A note on media callbacks:
@@ -135,6 +135,9 @@ export class FrigateCard extends LitElement {
@state()
public config!: FrigateCardConfig;
@state()
public _overriddenConfig?: FrigateCardConfig;
protected _interactionTimerID: number | null = null;
@property({ attribute: false })
@@ -226,6 +229,11 @@ export class FrigateCard extends LitElement {
fullscreen: screenfull.isEnabled && screenfull.isFullscreen,
camera: this._view?.camera,
};
this._overriddenConfig = getOverriddenConfig(
this.config,
this.config.overrides,
this._conditionState) as FrigateCardConfig;
}
/**
@@ -1040,17 +1048,13 @@ export class FrigateCard extends LitElement {
let specificActions: Actions | undefined = undefined;
if (this._view?.is('live')) {
const config = getOverriddenConfig(
this.config.live,
this._conditionState,
) as LiveConfig;
specificActions = config.actions;
specificActions = this._overriddenConfig?.live.actions;
} else if (this._view?.isGalleryView()) {
specificActions = this.config.event_gallery?.actions;
specificActions = this._overriddenConfig?.event_gallery?.actions;
} else if (this._view?.isViewerView()) {
specificActions = this.config.event_viewer.actions;
specificActions = this._overriddenConfig?.event_viewer.actions;
} else if (this._view?.is('image')) {
specificActions = this.config.image?.actions;
specificActions = this._overriddenConfig?.image?.actions;
}
return { ...this.config.view.actions, ...specificActions };
}
@@ -1208,6 +1212,7 @@ export class FrigateCard extends LitElement {
.view=${this._view}
.liveConfig=${this.config.live}
.conditionState=${this._conditionState}
.liveOverrides=${getOverridesByKey(this.config.overrides, 'live')}
.cameras=${this._cameras}
.preload=${this.config.live.preload && !this._view.is('live')}
class="${classMap(liveClasses)}"
+14 -1
View File
@@ -24,6 +24,7 @@ import {
MediaShowInfo,
WebRTCConfig,
FrigateCardError,
LiveOverrides,
} from '../types.js';
import { EmblaOptionsType } from 'embla-carousel';
import { HomeAssistant } from 'custom-card-helpers';
@@ -79,6 +80,9 @@ export class FrigateCardLive extends LitElement {
@property({ attribute: false })
protected liveConfig?: LiveConfig;
@property({ attribute: false })
protected liveOverrides?: LiveOverrides;
@property({ attribute: false })
protected conditionState?: ConditionState;
@@ -177,6 +181,7 @@ export class FrigateCardLive extends LitElement {
const config = getOverriddenConfig(
this.liveConfig,
this.liveOverrides,
this.conditionState,
) as LiveConfig;
@@ -192,6 +197,7 @@ export class FrigateCardLive extends LitElement {
.liveConfig=${this.liveConfig}
.preload=${this._preload}
.conditionState=${this.conditionState}
.liveOverrides=${this.liveOverrides}
@frigate-card:media-show=${this._mediaShowHandler}
@frigate-card:carousel:select=${() => {
// Re-rendering the component will cause the thumbnails to be
@@ -226,6 +232,9 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
@property({ attribute: false })
protected liveConfig?: LiveConfig;
@property({ attribute: false })
protected liveOverrides?: LiveOverrides;
@property({ attribute: false })
protected preload?: boolean;
@@ -366,7 +375,10 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
camera: camera,
});
const config = getOverriddenConfig(this.liveConfig, conditionState) as LiveConfig;
const config = getOverriddenConfig(
this.liveConfig,
this.liveOverrides,
conditionState) as LiveConfig;
return html` <div class="embla__slide">
<frigate-card-live-provider
@@ -441,6 +453,7 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
const config = getOverriddenConfig(
this.liveConfig,
this.liveOverrides,
this.conditionState,
) as LiveConfig;
+28 -19
View File
@@ -379,18 +379,6 @@ export type PictureElement = z.infer<typeof pictureElementSchema>;
const pictureElementsSchema = pictureElementSchema.array().optional();
export type PictureElements = z.infer<typeof pictureElementsSchema>;
/**
* Configuration overrides
*/
const overridesSchema = z
.object({
conditions: frigateCardConditionSchema,
overrides: z.record(z.unknown()),
})
.array()
.optional();
export type Overrides = z.infer<typeof overridesSchema>;
/**
* View configuration section.
*/
@@ -562,13 +550,6 @@ const liveConfigSchema = liveOverridableConfigSchema
preload: z.boolean().default(liveConfigDefault.preload),
lazy_load: z.boolean().default(liveConfigDefault.lazy_load),
draggable: z.boolean().default(liveConfigDefault.draggable),
overrides: z
.object({
conditions: frigateCardConditionSchema,
overrides: liveOverridableConfigSchema,
})
.array()
.optional(),
})
.default(liveConfigDefault);
export type LiveConfig = z.infer<typeof liveConfigSchema>;
@@ -702,6 +683,31 @@ const dimensionsConfigSchema = z
})
.default(dimensionsConfigDefault);
/**
* Configuration overrides
*/
const overrideConfigurationSchema = z.object({
live: liveOverridableConfigSchema.optional(),
});
export type OverrideConfigurationKey = keyof z.infer<typeof overrideConfigurationSchema>;
const overridesSchema = z
.object({
conditions: frigateCardConditionSchema,
overrides: overrideConfigurationSchema,
})
.array()
.optional();
const liveOverridesSchema = z
.object({
conditions: frigateCardConditionSchema,
overrides: liveOverridableConfigSchema,
})
.array()
.optional();
export type LiveOverrides = z.infer<typeof liveOverridesSchema>;
/**
* Main card config.
*/
@@ -717,6 +723,9 @@ export const frigateCardConfigSchema = z.object({
elements: pictureElementsSchema,
dimensions: dimensionsConfigSchema,
// Configuration overrides.
overrides: overridesSchema,
// Stock lovelace card config.
type: z.string(),
test_gui: z.boolean().optional(),