diff --git a/src/frigate-card.scss b/src/frigate-card.scss index a53b2e6f..38745d3f 100644 --- a/src/frigate-card.scss +++ b/src/frigate-card.scss @@ -19,7 +19,7 @@ scrollbar-width: none; // Hide scrollbar: Firefox } -.frigate-card-exception { +.frigate-card-attention { display: flex; justify-content: center; align-items: center; diff --git a/src/frigate-card.ts b/src/frigate-card.ts index 37099112..7799ac00 100644 --- a/src/frigate-card.ts +++ b/src/frigate-card.ts @@ -4,8 +4,6 @@ // TODO Action handlers. -// TODO _getEvents may throw errors, catch them when called. - // TODO Can I use Zod for FrigateCardConfig validation? /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -34,7 +32,7 @@ import './editor'; import style from './frigate-card.scss' -import { frigateEventSchema, frigateGetEventsResponseSchema } from './types'; +import { frigateGetEventsResponseSchema } from './types'; import type { FrigateCardConfig, FrigateEvent, FrigateGetEventsResponse, GetEventsParameters, ControlVideosParameters } from './types'; import { actionHandler } from './action-handler-directive'; import { CARD_VERSION } from './const'; @@ -228,35 +226,51 @@ export class FrigateCard extends LitElement { try { raw_json = await response.json(); } catch(e) { + console.warn(e); throw new Error(`Could not JSON decode Frigate API response: ${e}`); } try { return frigateGetEventsResponseSchema.parse(raw_json); } catch(e) { + console.warn(e); throw new Error(`Frigate events were malformed: ${e}`); } } else { - // TODO: Catch when json decoding fails. - throw new Error(`Frigate API request failed with status: ${response.status}`); + const error_message = `Frigate API request failed with status: ${response.status}`; + console.warn(error_message); + throw new Error(error_message); } } + protected _renderAttentionIcon(icon: string): TemplateResult { + return html` +
+ + +
`; + } + + // Render an embedded error situation. + // eslint-disable-next-line @typescript-eslint/no-unused-vars + protected _renderError(_error: string) : TemplateResult { + return this._renderAttentionIcon("mdi:alert-circle"); + } + // Render Frigate events into a card gallery. protected async _renderEvents() : Promise { const want_clips = this._viewMode == FrigateCardView.CLIPS; - - const events = await this._getEvents({ - has_clip: want_clips, - has_snapshot: !want_clips, - }); + let events; + try { + events = await this._getEvents({ + has_clip: want_clips, + has_snapshot: !want_clips, + }); + } catch (e) { + return this._renderError(e); + } if (!events.length) { - return html` -
- -
` + return this._renderAttentionIcon(want_clips ? "mdi:filmstrip-off" : "mdi:camera-off"); } return html` @@ -281,7 +295,7 @@ export class FrigateCard extends LitElement { // Render a progress spinner while content loads. protected _renderProgressIndicator(): TemplateResult { return html` -
+
{ - let event: FrigateEvent; + let event: FrigateEvent, events: FrigateGetEventsResponse; if (this._viewEvent) { event = this._viewEvent; } else { - const events = await this._getEvents({ - has_clip: true, - limit: 1 - }); + try { + events = await this._getEvents({ + has_clip: true, + limit: 1 + }); + } catch (e) { + return this._renderError(e); + } if (!events.length) { - return html` -
- - -
` + return this._renderAttentionIcon("mdi:camera-off"); } event = events[0]; } @@ -396,20 +410,20 @@ export class FrigateCard extends LitElement { // Render a snapshot. protected async _renderSnapshotViewer(): Promise { - let event: FrigateEvent; + let event: FrigateEvent, events: FrigateGetEventsResponse; if (this._viewEvent) { event = this._viewEvent; } else { - const events = await this._getEvents({ - has_snapshot: true, - limit: 1 - }); + try { + events = await this._getEvents({ + has_snapshot: true, + limit: 1 + }); + } catch (e) { + return this._renderError(e); + } if (!events.length) { - return html` -
- - -
` + return this._renderAttentionIcon("mdi:filmstrip-off"); } event = events[0]; }