Reduce boilerplate associated with lit tasks
This commit is contained in:
@@ -65,6 +65,7 @@ import './title-control.js';
|
|||||||
import './surround-thumbnails';
|
import './surround-thumbnails';
|
||||||
import '../patches/ha-camera-stream';
|
import '../patches/ha-camera-stream';
|
||||||
import { EmblaCarouselPlugins } from './carousel.js';
|
import { EmblaCarouselPlugins } from './carousel.js';
|
||||||
|
import { renderTask } from '../utils/task.js';
|
||||||
|
|
||||||
// Number of seconds a signed URL is valid for.
|
// Number of seconds a signed URL is valid for.
|
||||||
const URL_SIGN_EXPIRY_SECONDS = 24 * 60 * 60;
|
const URL_SIGN_EXPIRY_SECONDS = 24 * 60 * 60;
|
||||||
@@ -142,7 +143,7 @@ export class FrigateCardLive extends LitElement {
|
|||||||
* Determine whether the element should be updated.
|
* Determine whether the element should be updated.
|
||||||
* @param _changedProps The changed properties if any.
|
* @param _changedProps The changed properties if any.
|
||||||
* @returns `true` if the element should be updated.
|
* @returns `true` if the element should be updated.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
protected shouldUpdate(_changedProps: PropertyValues): boolean {
|
protected shouldUpdate(_changedProps: PropertyValues): boolean {
|
||||||
// Don't process updates if it's in the background and a message was
|
// 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
|
// 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()
|
// load, but yet still have the card load be followed by the updated()
|
||||||
// lifecycle callback (unlike just using `until`).
|
// lifecycle callback (unlike just using `until`).
|
||||||
return html`${this._webrtcTask.render({
|
return renderTask(this, this._webrtcTask, render, () =>
|
||||||
initial: () => renderProgressIndicator(localize('error.webrtc_card_waiting')),
|
renderProgressIndicator(localize('error.webrtc_card_waiting')),
|
||||||
pending: () => renderProgressIndicator(localize('error.webrtc_card_waiting')),
|
);
|
||||||
error: (e: unknown) => dispatchFrigateCardErrorEvent(this, e as Error),
|
|
||||||
complete: () => render(),
|
|
||||||
})}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import { NextPreviousControlConfig } from '../types.js';
|
|||||||
import controlStyle from '../scss/next-previous-control.scss';
|
import controlStyle from '../scss/next-previous-control.scss';
|
||||||
import { createFetchThumbnailTask } from '../utils/thumbnail.js';
|
import { createFetchThumbnailTask } from '../utils/thumbnail.js';
|
||||||
import { HomeAssistant } from 'custom-card-helpers';
|
import { HomeAssistant } from 'custom-card-helpers';
|
||||||
import { dispatchFrigateCardErrorEvent } from './message.js';
|
import { renderTask } from '../utils/task.js';
|
||||||
import { errorToConsole } from '../utils/basic.js';
|
|
||||||
|
|
||||||
@customElement('frigate-card-next-previous-control')
|
@customElement('frigate-card-next-previous-control')
|
||||||
export class FrigateCardNextPreviousControl extends LitElement {
|
export class FrigateCardNextPreviousControl extends LitElement {
|
||||||
@@ -80,29 +79,20 @@ export class FrigateCardNextPreviousControl extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderControlInProgress = (): TemplateResult => {
|
return renderTask(
|
||||||
// Just render an 'empty' thumbnail control until the thumbnail loads.
|
this,
|
||||||
return html`<div class=${classMap(classes)}></div>`;
|
this._embedThumbnailTask,
|
||||||
};
|
(embeddedThumbnail: string | null) =>
|
||||||
|
embeddedThumbnail
|
||||||
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
|
|
||||||
? html`<img
|
? html`<img
|
||||||
src="${embeddedThumbnail}"
|
src="${embeddedThumbnail}"
|
||||||
class="${classMap(classes)}"
|
class="${classMap(classes)}"
|
||||||
title="${this.label}"
|
title="${this.label}"
|
||||||
aria-label="${this.label}"
|
aria-label="${this.label}"
|
||||||
/>`
|
/>`
|
||||||
: html``;
|
: html``,
|
||||||
},
|
() => html`<div class=${classMap(classes)}></div>`,
|
||||||
})}`;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
|
|||||||
import { errorToConsole, prettifyTitle } from '../utils/basic.js';
|
import { errorToConsole, prettifyTitle } from '../utils/basic.js';
|
||||||
import { retainEvent } from '../utils/frigate.js';
|
import { retainEvent } from '../utils/frigate.js';
|
||||||
import { getEventDurationString } from '../utils/ha/browse-media.js';
|
import { getEventDurationString } from '../utils/ha/browse-media.js';
|
||||||
|
import { renderTask } from '../utils/task.js';
|
||||||
import { createFetchThumbnailTask } from '../utils/thumbnail.js';
|
import { createFetchThumbnailTask } from '../utils/thumbnail.js';
|
||||||
import { View } from '../view.js';
|
import { View } from '../view.js';
|
||||||
import { dispatchFrigateCardErrorEvent, renderProgressIndicator } from './message.js';
|
|
||||||
|
|
||||||
// The minimum width of a thumbnail with details enabled.
|
// The minimum width of a thumbnail with details enabled.
|
||||||
export const THUMBNAIL_DETAILS_WIDTH_MIN = 300;
|
export const THUMBNAIL_DETAILS_WIDTH_MIN = 300;
|
||||||
@@ -41,19 +41,14 @@ export class FrigateCardThumbnailFeatureEvent extends LitElement {
|
|||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
${this.thumbnail
|
${this.thumbnail
|
||||||
? html` ${this._embedThumbnailTask.render({
|
? renderTask(
|
||||||
initial: () => renderProgressIndicator(),
|
this,
|
||||||
pending: () => renderProgressIndicator(),
|
this._embedThumbnailTask,
|
||||||
error: (e: unknown) => {
|
(embeddedThumbnail: string | null) =>
|
||||||
errorToConsole(e as Error);
|
embeddedThumbnail
|
||||||
dispatchFrigateCardErrorEvent(this, e as Error);
|
|
||||||
},
|
|
||||||
complete: (embeddedThumbnail: string | null) => {
|
|
||||||
return embeddedThumbnail
|
|
||||||
? html`<img src="${embeddedThumbnail}" />`
|
? html`<img src="${embeddedThumbnail}" />`
|
||||||
: html``;
|
: html``
|
||||||
},
|
)
|
||||||
})}`
|
|
||||||
: html`<ha-icon
|
: html`<ha-icon
|
||||||
icon="mdi:image-off"
|
icon="mdi:image-off"
|
||||||
title=${localize('thumbnail.no_thumbnail')}
|
title=${localize('thumbnail.no_thumbnail')}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import './title-control.js';
|
|||||||
import '../patches/ha-hls-player';
|
import '../patches/ha-hls-player';
|
||||||
import './surround-thumbnails';
|
import './surround-thumbnails';
|
||||||
import { EmblaCarouselPlugins } from './carousel.js';
|
import { EmblaCarouselPlugins } from './carousel.js';
|
||||||
|
import { renderTask } from '../utils/task.js';
|
||||||
|
|
||||||
@customElement('frigate-card-viewer')
|
@customElement('frigate-card-viewer')
|
||||||
export class FrigateCardViewer extends LitElement {
|
export class FrigateCardViewer extends LitElement {
|
||||||
@@ -584,12 +585,7 @@ export class FrigateCardViewerCarousel extends LitElement {
|
|||||||
// If lazy loading is not enabled, wait for the media resolver task to
|
// If lazy loading is not enabled, wait for the media resolver task to
|
||||||
// complete and show a progress indictator until this.
|
// complete and show a progress indictator until this.
|
||||||
if (!this.viewerConfig?.lazy_load && !this._isMediaFullyResolved()) {
|
if (!this.viewerConfig?.lazy_load && !this._isMediaFullyResolved()) {
|
||||||
return html`${this._mediaResolutionTask.render({
|
return renderTask(this, this._mediaResolutionTask, this._render.bind(this));
|
||||||
initial: () => renderProgressIndicator(),
|
|
||||||
pending: () => renderProgressIndicator(),
|
|
||||||
error: (e: unknown) => dispatchFrigateCardErrorEvent(this, e as Error),
|
|
||||||
complete: () => this._render(),
|
|
||||||
})}`;
|
|
||||||
}
|
}
|
||||||
return this._render();
|
return this._render();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 = <R>(
|
||||||
|
host: EventTarget,
|
||||||
|
task: Task<unknown[], R>,
|
||||||
|
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,
|
||||||
|
})}`;
|
||||||
|
};
|
||||||
@@ -42,6 +42,8 @@ export const fetchThumbnail = async (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type FetchThumbnailTaskArgs = [boolean, string | undefined];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Lit task to fetch a thumbnail.
|
* Create a Lit task to fetch a thumbnail.
|
||||||
* @param host The Lit Element.
|
* @param host The Lit Element.
|
||||||
@@ -53,10 +55,10 @@ export const createFetchThumbnailTask = (
|
|||||||
host: ReactiveControllerHost,
|
host: ReactiveControllerHost,
|
||||||
getHASS: () => HomeAssistant | undefined,
|
getHASS: () => HomeAssistant | undefined,
|
||||||
getThumbnailURL: () => string | undefined,
|
getThumbnailURL: () => string | undefined,
|
||||||
): Task => {
|
): Task<FetchThumbnailTaskArgs, string | null> => {
|
||||||
return new Task(
|
return new Task(
|
||||||
host,
|
host,
|
||||||
async ([haveHASS, thumbnailURL]: [boolean, string | undefined]): Promise<
|
async ([haveHASS, thumbnailURL]: FetchThumbnailTaskArgs): Promise<
|
||||||
string | null
|
string | null
|
||||||
> => {
|
> => {
|
||||||
const hass = getHASS();
|
const hass = getHASS();
|
||||||
@@ -66,6 +68,6 @@ export const createFetchThumbnailTask = (
|
|||||||
return fetchThumbnail(hass, thumbnailURL);
|
return fetchThumbnail(hass, thumbnailURL);
|
||||||
},
|
},
|
||||||
// Do not re-run the task if hass changes, unless it was previously undefined.
|
// Do not re-run the task if hass changes, unless it was previously undefined.
|
||||||
(): [boolean, string | undefined] => [!!getHASS(), getThumbnailURL()],
|
(): FetchThumbnailTaskArgs => [!!getHASS(), getThumbnailURL()],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user