diff --git a/src/components/live.ts b/src/components/live.ts
index 92fa484c..4b767caa 100644
--- a/src/components/live.ts
+++ b/src/components/live.ts
@@ -65,6 +65,7 @@ import './title-control.js';
import './surround-thumbnails';
import '../patches/ha-camera-stream';
import { EmblaCarouselPlugins } from './carousel.js';
+import { renderTask } from '../utils/task.js';
// Number of seconds a signed URL is valid for.
const URL_SIGN_EXPIRY_SECONDS = 24 * 60 * 60;
@@ -142,7 +143,7 @@ export class FrigateCardLive extends LitElement {
* Determine whether the element should be updated.
* @param _changedProps The changed properties if any.
* @returns `true` if the element should be updated.
- */
+ */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected shouldUpdate(_changedProps: PropertyValues): boolean {
// Don't process updates if it's in the background and a message was
@@ -981,12 +982,9 @@ export class FrigateCardLiveWebRTCCard extends LitElement {
// Use a task to allow us to asynchronously wait for the WebRTC card to
// load, but yet still have the card load be followed by the updated()
// lifecycle callback (unlike just using `until`).
- return html`${this._webrtcTask.render({
- initial: () => renderProgressIndicator(localize('error.webrtc_card_waiting')),
- pending: () => renderProgressIndicator(localize('error.webrtc_card_waiting')),
- error: (e: unknown) => dispatchFrigateCardErrorEvent(this, e as Error),
- complete: () => render(),
- })}`;
+ return renderTask(this, this._webrtcTask, render, () =>
+ renderProgressIndicator(localize('error.webrtc_card_waiting')),
+ );
}
/**
diff --git a/src/components/next-prev-control.ts b/src/components/next-prev-control.ts
index 435a2b35..5a7ccd67 100644
--- a/src/components/next-prev-control.ts
+++ b/src/components/next-prev-control.ts
@@ -7,8 +7,7 @@ import { NextPreviousControlConfig } from '../types.js';
import controlStyle from '../scss/next-previous-control.scss';
import { createFetchThumbnailTask } from '../utils/thumbnail.js';
import { HomeAssistant } from 'custom-card-helpers';
-import { dispatchFrigateCardErrorEvent } from './message.js';
-import { errorToConsole } from '../utils/basic.js';
+import { renderTask } from '../utils/task.js';
@customElement('frigate-card-next-previous-control')
export class FrigateCardNextPreviousControl extends LitElement {
@@ -80,29 +79,20 @@ export class FrigateCardNextPreviousControl extends LitElement {
return html``;
}
- const renderControlInProgress = (): TemplateResult => {
- // Just render an 'empty' thumbnail control until the thumbnail loads.
- return html`
`;
- };
-
- return html`${this._embedThumbnailTask.render({
- initial: () => renderControlInProgress(),
- pending: () => renderControlInProgress(),
- error: (e: unknown) => {
- errorToConsole(e as Error);
- dispatchFrigateCardErrorEvent(this, e as Error);
- },
- complete: (embeddedThumbnail: string | null) => {
- return embeddedThumbnail
+ return renderTask(
+ this,
+ this._embedThumbnailTask,
+ (embeddedThumbnail: string | null) =>
+ embeddedThumbnail
? html`
`
- : html``;
- },
- })}`;
+ : html``,
+ () => html``,
+ );
}
static get styles(): CSSResultGroup {
diff --git a/src/components/thumbnail.ts b/src/components/thumbnail.ts
index 5617e729..ca224410 100644
--- a/src/components/thumbnail.ts
+++ b/src/components/thumbnail.ts
@@ -17,9 +17,9 @@ import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
import { errorToConsole, prettifyTitle } from '../utils/basic.js';
import { retainEvent } from '../utils/frigate.js';
import { getEventDurationString } from '../utils/ha/browse-media.js';
+import { renderTask } from '../utils/task.js';
import { createFetchThumbnailTask } from '../utils/thumbnail.js';
import { View } from '../view.js';
-import { dispatchFrigateCardErrorEvent, renderProgressIndicator } from './message.js';
// The minimum width of a thumbnail with details enabled.
export const THUMBNAIL_DETAILS_WIDTH_MIN = 300;
@@ -41,19 +41,14 @@ export class FrigateCardThumbnailFeatureEvent extends LitElement {
protected render(): TemplateResult | void {
return html`
${this.thumbnail
- ? html` ${this._embedThumbnailTask.render({
- initial: () => renderProgressIndicator(),
- pending: () => renderProgressIndicator(),
- error: (e: unknown) => {
- errorToConsole(e as Error);
- dispatchFrigateCardErrorEvent(this, e as Error);
- },
- complete: (embeddedThumbnail: string | null) => {
- return embeddedThumbnail
+ ? renderTask(
+ this,
+ this._embedThumbnailTask,
+ (embeddedThumbnail: string | null) =>
+ embeddedThumbnail
? html`
`
- : html``;
- },
- })}`
+ : html``
+ )
: html` renderProgressIndicator(),
- pending: () => renderProgressIndicator(),
- error: (e: unknown) => dispatchFrigateCardErrorEvent(this, e as Error),
- complete: () => this._render(),
- })}`;
+ return renderTask(this, this._mediaResolutionTask, this._render.bind(this));
}
return this._render();
}
diff --git a/src/utils/task.ts b/src/utils/task.ts
new file mode 100644
index 00000000..afb91518
--- /dev/null
+++ b/src/utils/task.ts
@@ -0,0 +1,32 @@
+import { Task } from '@lit-labs/task';
+import { html, TemplateResult } from 'lit';
+import {
+ dispatchFrigateCardErrorEvent,
+ renderProgressIndicator,
+} from '../components/message';
+import { errorToConsole } from './basic';
+
+/**
+ * Render the result of a Lit task.
+ * @param host The host object.
+ * @param task The Lit task.
+ * @param completeFunc The function to call with the result.
+ * @param inProgressFunc The function to call whilst in progress.
+ * @returns A template.
+ */
+export const renderTask = (
+ host: EventTarget,
+ task: Task,
+ completeFunc: (result: R) => TemplateResult | void,
+ inProgressFunc?: () => TemplateResult | void,
+): TemplateResult => {
+ return html` ${task.render({
+ initial: () => inProgressFunc?.() ?? renderProgressIndicator(),
+ pending: () => inProgressFunc?.() ?? renderProgressIndicator(),
+ error: (e: unknown) => {
+ errorToConsole(e as Error);
+ dispatchFrigateCardErrorEvent(host, e as Error);
+ },
+ complete: completeFunc,
+ })}`;
+};
diff --git a/src/utils/thumbnail.ts b/src/utils/thumbnail.ts
index cb4c62b9..2a002adb 100644
--- a/src/utils/thumbnail.ts
+++ b/src/utils/thumbnail.ts
@@ -42,6 +42,8 @@ export const fetchThumbnail = async (
});
};
+type FetchThumbnailTaskArgs = [boolean, string | undefined];
+
/**
* Create a Lit task to fetch a thumbnail.
* @param host The Lit Element.
@@ -53,10 +55,10 @@ export const createFetchThumbnailTask = (
host: ReactiveControllerHost,
getHASS: () => HomeAssistant | undefined,
getThumbnailURL: () => string | undefined,
-): Task => {
+): Task => {
return new Task(
host,
- async ([haveHASS, thumbnailURL]: [boolean, string | undefined]): Promise<
+ async ([haveHASS, thumbnailURL]: FetchThumbnailTaskArgs): Promise<
string | null
> => {
const hass = getHASS();
@@ -66,6 +68,6 @@ export const createFetchThumbnailTask = (
return fetchThumbnail(hass, thumbnailURL);
},
// Do not re-run the task if hass changes, unless it was previously undefined.
- (): [boolean, string | undefined] => [!!getHASS(), getThumbnailURL()],
+ (): FetchThumbnailTaskArgs => [!!getHASS(), getThumbnailURL()],
);
};