Rework the error message when entity is unavailable.

This commit is contained in:
Dermot Duffy
2022-07-24 19:36:32 -07:00
parent 53c262c056
commit d6f0282886
6 changed files with 148 additions and 60 deletions
+15 -1
View File
@@ -1,3 +1,17 @@
# Review comments generated by i18n-ally. Please commit this file.
{}
reviews:
error.live_camera_not_found:
locales:
pt-BR:
translation_candidate:
source: en
text: A camera_entity configurada não foi encontrada
time: '2022-07-24T05:32:49.977Z'
error.live_camera_unavailable:
locales:
pt-BR:
translation_candidate:
source: en
text: Câmera indisponível
time: '2022-07-24T05:34:22.088Z'
-1
View File
@@ -1904,7 +1904,6 @@ export class FrigateCard extends LitElement {
.conditionState=${this._conditionState}
.liveOverrides=${getOverridesByKey(this._getConfig().overrides, 'live')}
.cameras=${this._cameras}
.preloaded=${this._getConfig().live.preload && !this._view.is('live')}
class="${classMap(liveClasses)}"
>
</frigate-card-live>
+123 -54
View File
@@ -14,10 +14,12 @@ import {
import { customElement, property, state } from 'lit/decorators.js';
import { createRef, Ref, ref } from 'lit/directives/ref.js';
import { guard } from 'lit/directives/guard.js';
import { keyed } from 'lit/directives/keyed.js';
import { until } from 'lit/directives/until.js';
import { ConditionState, getOverriddenConfig } from '../card-condition.js';
import {
dispatchFrigateCardErrorEvent,
dispatchMessageEvent,
renderProgressIndicator,
} from '../components/message.js';
import { localize } from '../localize/localize.js';
@@ -37,6 +39,7 @@ import {
LiveOverrides,
LiveProvider,
MediaShowInfo,
Message,
TransitionEffect,
WebRTCCardConfig,
} from '../types.js';
@@ -89,33 +92,66 @@ export class FrigateCardLive extends LitElement {
@property({ attribute: false, hasChanged: contentsChanged })
public liveOverrides?: LiveOverrides;
set preloaded(preloaded: boolean) {
this._preloaded = preloaded;
// Whether or not the live view is currently in the background (i.e. preloaded
// but not visible)
@state()
protected _inBackground?: boolean = true;
if (!preloaded && this._savedMediaShowInfo) {
// Intersection handler is used to detect when the live view flips between
// foreground and background (in preload mode).
protected _intersectionObserver: IntersectionObserver;
// MediaShowInfo object and message from the underlying live object. In the
// case of pre-loading these may be propagated upwards later.
protected _savedMediaShowInfo: MediaShowInfo | null = null;
protected _messageReceivedPostRender = false;
protected _renderKey = 0;
constructor() {
super();
this._intersectionObserver = new IntersectionObserver(
this._intersectionHandler.bind(this),
);
}
/**
* Called when the live view intersects with the viewport.
* @param entries The IntersectionObserverEntry entries (should be only 1).
*/
protected _intersectionHandler(entries: IntersectionObserverEntry[]): void {
this._inBackground = entries.every((entry) => !entry.isIntersecting);
if (
!this._inBackground &&
!this._messageReceivedPostRender &&
this._savedMediaShowInfo
) {
// If this isn't being rendered in the background, the last render did not
// generate a message and there's a saved MediaInfo, dispatch it upwards.
dispatchExistingMediaShowInfoAsEvent(this, this._savedMediaShowInfo);
}
// Trigger a re-render which may be necessary if the prior render resulted
// in a message.
if (this._messageReceivedPostRender && !this._inBackground) {
this.requestUpdate();
}
}
// Whether or not the live view is currently being preloaded.
@state()
protected _preloaded?: boolean;
// MediaShowInfo object from the underlying live object. In the case of
// pre-loading it may be propagated upwards later.
protected _savedMediaShowInfo?: MediaShowInfo;
/**
* Component connected callback.
*/
connectedCallback(): void {
this._intersectionObserver.observe(this);
super.connectedCallback();
}
/**
* Handler for media show events that special cases preloaded live views.
* @param e The media show event.
* Component disconnected callback.
*/
protected _mediaShowHandler(e: CustomEvent<MediaShowInfo>): void {
this._savedMediaShowInfo = e.detail;
if (this._preloaded) {
// If live is being pre-loaded, don't let the event propagate upwards yet
// as the media is not really being shown.
e.stopPropagation();
}
disconnectedCallback(): void {
super.disconnectedCallback();
this._intersectionObserver.disconnect();
}
/**
@@ -148,37 +184,55 @@ export class FrigateCardLive extends LitElement {
// independently override the liveConfig to reflect the camera in the
// carousel (not necessarily the selected camera).
// - Fetching of thumbnails is disabled as long as live view is the
// background (preloaded) rather than foreground (not preloaded).
return html` <frigate-card-surround-thumbnails
.hass=${this.hass}
.view=${this.view}
.config=${config.controls.thumbnails}
.browseMediaParams=${browseMediaParams ?? undefined}
.cameras=${this.cameras}
?fetch=${!this._preloaded}
>
<frigate-card-live-carousel
// background.
// - Various events are captured to prevent them propagating upwards if the
// card is in the background.
// - The entire returned template is keyed to allow for the whole template
// to be re-rendered in certain circumstances (specifically: if a message
// is received when the card is in the background).
const result = html`${keyed(
this._renderKey,
html`<frigate-card-surround-thumbnails
.hass=${this.hass}
.view=${this.view}
.config=${config.controls.thumbnails}
.browseMediaParams=${browseMediaParams ?? undefined}
.cameras=${this.cameras}
.liveConfig=${this.liveConfig}
.preloaded=${this._preloaded}
.conditionState=${this.conditionState}
.liveOverrides=${this.liveOverrides}
@frigate-card:media-show=${this._mediaShowHandler}
@frigate-card:change-view=${(ev: CustomEvent) => {
if (this._preloaded) {
// Don't allow change-view events to propagate upwards if the card
// is only preloaded rather than being live displayed. These events
// could be triggered if the camera is switched and the carousel
// moves to focus on that camera -- as the card isn't actually being
// displayed, do not allow the view to actually be updated.
?fetch=${!this._inBackground}
@frigate-card:message=${(ev: CustomEvent<Message>) => {
this._renderKey++;
this._messageReceivedPostRender = true;
if (this._inBackground) {
ev.stopPropagation();
}
}}
@frigate-card:media-show=${(ev: CustomEvent<MediaShowInfo>) => {
this._savedMediaShowInfo = ev.detail;
if (this._inBackground) {
ev.stopPropagation();
}
}}
@frigate-card:change-view=${(ev: CustomEvent<View>) => {
if (this._inBackground) {
ev.stopPropagation();
}
}}
>
</frigate-card-live-carousel>
</frigate-card-surround-thumbnails>`;
<frigate-card-live-carousel
.hass=${this.hass}
.view=${this.view}
.cameras=${this.cameras}
.liveConfig=${this.liveConfig}
.inBackground=${this._inBackground}
.conditionState=${this.conditionState}
.liveOverrides=${this.liveOverrides}
>
</frigate-card-live-carousel>
</frigate-card-surround-thumbnails>`,
)}`;
this._messageReceivedPostRender = false;
return result;
}
/**
@@ -207,7 +261,7 @@ export class FrigateCardLiveCarousel extends LitElement {
public liveOverrides?: LiveOverrides;
@property({ attribute: false })
public preloaded?: boolean;
public inBackground?: boolean;
@property({ attribute: false })
public conditionState?: ConditionState;
@@ -235,7 +289,10 @@ export class FrigateCardLiveCarousel extends LitElement {
this.view?.camera != oldView.camera
) {
const slide: number | undefined = this._cameraToSlide[this.view.camera];
if (slide !== undefined && slide !== frigateCardCarousel.getCarouselSelected()?.index) {
if (
slide !== undefined &&
slide !== frigateCardCarousel.getCarouselSelected()?.index
) {
frigateCardCarousel.carouselScrollTo(slide);
}
}
@@ -244,11 +301,11 @@ export class FrigateCardLiveCarousel extends LitElement {
if (
frigateCardMediaCarousel &&
frigateCardCarousel &&
changedProperties.has('preloaded')
changedProperties.has('inBackground')
) {
// If this has changed to preloaded (i.e. is now loaded but in the
// background) take the appropriate play/pause/mute/unmute actions.
if (this.preloaded) {
// If this has changed to be in the background (i.e. preloaded but not
// visible) take the appropriate play/pause/mute/unmute actions.
if (this.inBackground) {
frigateCardMediaCarousel.autoPause();
frigateCardMediaCarousel.autoMute();
} else {
@@ -369,8 +426,7 @@ export class FrigateCardLiveCarousel extends LitElement {
protected _setViewHandler(): void {
const selectedCameraIndex = this._refMediaCarousel.value
?.frigateCardCarousel()
?.getCarouselSelected()
?.index;
?.getCarouselSelected()?.index;
if (selectedCameraIndex === undefined || !this.view || !this.cameras) {
return;
}
@@ -514,7 +570,7 @@ export class FrigateCardLiveCarousel extends LitElement {
.titlePopupConfig=${config.controls.title}
transitionEffect=${this._getTransitionEffect()}
@frigate-card:carousel:settle=${this._setViewHandler.bind(this)}
>
>
<frigate-card-next-previous-control
slot="previous"
.direction=${'previous'}
@@ -735,12 +791,25 @@ export class FrigateCardLiveFrigate extends LitElement {
}
const stateObj = this.hass.states[this.cameraConfig.camera_entity];
if (!stateObj || stateObj.state === 'unavailable') {
return dispatchErrorMessageEvent(this, localize('error.live_camera_unavailable'), {
if (!stateObj) {
return dispatchErrorMessageEvent(this, localize('error.live_camera_not_found'), {
context: this.cameraConfig,
});
}
if (stateObj.state === 'unavailable') {
// Don't treat state unavailability as an error per se.
return dispatchMessageEvent(
this,
localize('error.live_camera_unavailable'),
'info',
{
icon: 'mdi:connection',
context: getCameraTitle(this.hass, this.cameraConfig),
},
);
}
return html` <frigate-card-ha-camera-stream
${ref(this._playerRef)}
.hass=${this.hass}
+6 -2
View File
@@ -34,9 +34,13 @@ export class FrigateCardMessage extends LitElement {
</div>
<div class="contents">
<span class="${classMap(classes)}">
${this.message ? html`${this.message}` : ''}
${this.message
? html`${this.message}${this.context && typeof this.context === 'string'
? ': ' + this.context
: ''}`
: ''}
</span>
${this.context
${this.context && typeof this.context !== 'string'
? html`<pre>${JSON.stringify(this.context, null, 2)}</pre>`
: ''}
</div>
+2 -1
View File
@@ -328,7 +328,8 @@
"invalid_response": "Received invalid response from Home Assistant for request",
"jsmpeg_no_player": "Could not start JSMPEG player",
"jsmpeg_no_sign": "Could not retrieve or sign JSMPEG websocket path",
"live_camera_unavailable": "The configured camera_entity is unavailable",
"live_camera_not_found": "The configured camera_entity was not found",
"live_camera_unavailable": "Camera unavailable",
"no_camera_id": "Could not determine camera id for the following camera, may need to set 'id' parameter manually",
"no_camera_name": "Could not determine a Frigate camera name for camera (or one of its dependents), please specify either 'camera_entity' or 'camera_name'",
"no_cameras": "No valid cameras found, you must configure at least one camera entry",
+2 -1
View File
@@ -328,7 +328,8 @@
"invalid_response": "Resposta inválida recebida do Home Assistant para a solicitação",
"jsmpeg_no_player": "Não foi possível iniciar o player JSMPEG",
"jsmpeg_no_sign": "Não foi possível recuperar ou assinar o caminho do websocket JSMPEG",
"live_camera_unavailable": "camera_entity configurada não está disponível",
"live_camera_not_found": "",
"live_camera_unavailable": "",
"no_camera_id": "Não foi possível determinar o ID da câmera para a câmera a seguir, pode ser necessário definir o parâmetro 'id' manualmente",
"no_camera_name": "Não foi possível determinar o nome da câmera da Frigate, especifique 'camera_entity' ou 'camera_name' para a câmera a seguir",
"no_cameras": "Nenhuma câmera válida encontrada, você deve configurar pelo menos uma câmera",