refactor: Retire the use of unmaintained custom-card-helpers (#1956)

- Closes #1295
This commit is contained in:
Dermot Duffy
2025-03-09 16:02:33 -07:00
committed by GitHub
parent c65ee3f0f2
commit a79ffa6edc
116 changed files with 933 additions and 545 deletions
+2 -5
View File
@@ -1,8 +1,3 @@
import {
ActionConfig,
ServiceCallRequest,
hasAction as customCardHasAction,
} from '@dermotduffy/custom-card-helpers';
import { CardActionsAPI } from '../card-controller/types.js';
import { ZoomSettingsBase } from '../components-lib/zoom/types.js';
import { PTZAction } from '../config/ptz.js';
@@ -29,6 +24,8 @@ import {
ViewActionConfig,
internalAdvancedCameraCardCustomActionSchema,
} from '../config/types.js';
import { hasAction as customCardHasAction } from '../ha/has-action.js';
import { ActionConfig, ServiceCallRequest } from '../ha/types.js';
import { arrayify } from './basic.js';
/**
-20
View File
@@ -13,26 +13,6 @@ import { AdvancedCameraCardError } from '../types';
export type ModifyInterface<T, R> = Omit<T, keyof R> & R;
/**
* Dispatch an Advanced Camera Card event.
* @param target The target from which send the event.
* @param name The name of the Advanced Camera Card event to send.
* @param detail An optional detail object to attach.
*/
export function dispatchAdvancedCameraCardEvent<T>(
target: EventTarget,
name: string,
detail?: T,
): void {
target.dispatchEvent(
new CustomEvent<T>(`advanced-camera-card:${name}`, {
bubbles: true,
composed: true,
detail: detail,
}),
);
}
/**
* Prettify a title by converting '_' to spaces and capitalizing words.
* @param input The input string.
+1 -1
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import pkg from '../../package.json';
import { RawAdvancedCameraCardConfig } from '../config/types';
import { HomeAssistant } from '../ha/types';
import { getLanguage } from '../localize/localize';
import { getIntegrationManifest } from './ha/integration';
import { IntegrationManifest } from './ha/integration/types';
+8 -7
View File
@@ -1,10 +1,11 @@
import { format } from 'date-fns';
import { CameraManager } from '../camera-manager/manager';
import { localize } from '../localize/localize';
import { AdvancedCameraCardError, ExtendedHomeAssistant } from '../types';
import { ViewMedia } from '../view/media';
import { errorToConsole } from './basic';
import { homeAssistantSignPath } from './ha';
import { CameraManager } from '../camera-manager/manager.js';
import { HomeAssistant } from '../ha/types.js';
import { localize } from '../localize/localize.js';
import { AdvancedCameraCardError } from '../types.js';
import { ViewMedia } from '../view/media.js';
import { errorToConsole } from './basic.js';
import { homeAssistantSignPath } from './ha/index.js';
export const downloadURL = (url: string, filename = 'download'): void => {
// The download attribute only works on the same origin.
@@ -27,7 +28,7 @@ export const downloadURL = (url: string, filename = 'download'): void => {
};
export const downloadMedia = async (
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
cameraManager: CameraManager,
media: ViewMedia,
): Promise<void> => {
+4 -3
View File
@@ -3,7 +3,8 @@ import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins';
import isEqual from 'lodash-es/isEqual';
import { TransitionEffect } from '../../config/types';
import { dispatchAdvancedCameraCardEvent, getChildrenFromElement } from '../basic.js';
import { getChildrenFromElement } from '../basic.js';
import { fireAdvancedCameraCardEvent } from '../fire-advanced-camera-card-event';
import { TextDirection } from '../text-direction';
export interface CarouselSelected {
@@ -99,7 +100,7 @@ export class CarouselController {
// this is used.
const newSlide = this.getSlide(index);
if (newSlide) {
dispatchAdvancedCameraCardEvent<CarouselSelected>(
fireAdvancedCameraCardEvent<CarouselSelected>(
this._parent,
'carousel:force-select',
{
@@ -172,7 +173,7 @@ export class CarouselController {
const selectSlide = (): void => {
const carouselSelected = getCarouselSelectedObject();
if (carouselSelected) {
dispatchAdvancedCameraCardEvent<CarouselSelected>(
fireAdvancedCameraCardEvent<CarouselSelected>(
this._parent,
'carousel:select',
carouselSelected,
+2 -2
View File
@@ -1,10 +1,10 @@
import { CameraEndpoint } from '../camera-manager/types';
import { ExtendedHomeAssistant } from '../types';
import { HomeAssistant } from '../ha/types';
import { errorToConsole } from './basic';
import { homeAssistantSignPath } from './ha';
export const convertEndpointAddressToSignedWebsocket = async (
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
endpoint: CameraEndpoint,
expires?: number,
): Promise<string | null> => {
@@ -0,0 +1,25 @@
/**
* Dispatch an Advanced Camera Card event.
* @param target The target from which send the event.
* @param type The type of the Advanced Camera Card event to send.
* @param detail An optional detail object to attach.
*/
export function fireAdvancedCameraCardEvent<T>(
target: EventTarget,
type: string,
detail?: T,
options?: {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
},
): void {
target.dispatchEvent(
new CustomEvent<T>(`advanced-camera-card:${type}`, {
bubbles: options?.bubbles ?? true,
composed: options?.composed ?? true,
cancelable: options?.cancelable ?? false,
detail: detail,
}),
);
}
@@ -1,9 +1,9 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { add } from 'date-fns';
import chunk from 'lodash-es/chunk';
import orderBy from 'lodash-es/orderBy';
import { BrowseMediaMetadata } from '../../../camera-manager/browse-media/types';
import { MemoryRequestCache } from '../../../camera-manager/cache';
import { HomeAssistant } from '../../../ha/types';
import { allPromises } from '../../basic';
import { homeAssistantWSRequest } from '../ws-request';
import {
+3 -2
View File
@@ -1,6 +1,7 @@
import { computeDomain, HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HassEntity } from 'home-assistant-js-websocket';
import { Entity } from './registry/entity/types';
import { computeDomain } from '../../ha/compute-domain.js';
import { HomeAssistant } from '../../ha/types.js';
import { Entity } from './registry/entity/types.js';
/**
* Get the translation of an entity state. Inspired by:
+7 -13
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HassEntity } from 'home-assistant-js-websocket';
import { STATES_ON } from '../../ha/const.js';
import { HomeAssistant } from '../../ha/types.js';
import {
CardHelpers,
ExtendedHomeAssistant,
LovelaceCardWithEditor,
SignedPath,
signedPathSchema,
@@ -18,7 +18,7 @@ import { homeAssistantWSRequest } from './ws-request.js';
* @returns The signed URL, or null if the response was malformed.
*/
export async function homeAssistantSignPath(
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
path: string,
expires?: number,
): Promise<string | null> {
@@ -183,7 +183,7 @@ export const sideLoadHomeAssistantElements = async (): Promise<boolean> => {
* @returns `true` if triggered, `false` otherwise.
*/
export const isTriggeredState = (state?: string): boolean => {
return !!state && ['on', 'open'].includes(state);
return !!state && STATES_ON.includes(state);
};
/**
@@ -224,15 +224,9 @@ export function isHARelativeURL(url?: string): boolean {
* location will be the Chromecast receiver, not HA).
* @param url The media URL
*/
export function canonicalizeHAURL(hass: ExtendedHomeAssistant, url: string): string;
export function canonicalizeHAURL(
hass: ExtendedHomeAssistant,
url?: string,
): string | null;
export function canonicalizeHAURL(
hass: ExtendedHomeAssistant,
url?: string,
): string | null {
export function canonicalizeHAURL(hass: HomeAssistant, url: string): string;
export function canonicalizeHAURL(hass: HomeAssistant, url?: string): string | null;
export function canonicalizeHAURL(hass: HomeAssistant, url?: string): string | null {
if (isHARelativeURL(url)) {
return hass.hassUrl(url);
}
+3 -3
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { homeAssistantWSRequest } from '../ws-request';
import { IntegrationManifest, integrationManifestSchema } from './types';
import { HomeAssistant } from '../../../ha/types.js';
import { homeAssistantWSRequest } from '../ws-request.js';
import { IntegrationManifest, integrationManifestSchema } from './types.js';
export const getIntegrationManifest = async (
hass: HomeAssistant,
+2 -2
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { homeAssistantWSRequest } from '../../ws-request';
import { HomeAssistant } from '../../../../ha/types';
import { errorToConsole } from '../../../basic';
import { homeAssistantWSRequest } from '../../ws-request';
import { RegistryCache } from '../cache';
import { Device, DeviceList, deviceListSchema } from './types';
+4 -4
View File
@@ -1,7 +1,7 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { homeAssistantWSRequest } from '../../ws-request';
import { errorToConsole } from '../../../basic';
import { RegistryCache } from '../cache';
import { HomeAssistant } from '../../../../ha/types.js';
import { errorToConsole } from '../../../basic.js';
import { homeAssistantWSRequest } from '../../ws-request.js';
import { RegistryCache } from '../cache.js';
import { Entity, EntityList, entityListSchema, entitySchema } from './types.js';
export const createEntityRegistryCache = (): RegistryCache<Entity> => {
+2 -2
View File
@@ -1,8 +1,8 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import QuickLRU from 'quick-lru';
import { homeAssistantWSRequest } from './ws-request';
import { HomeAssistant } from '../../ha/types';
import { ResolvedMedia, resolvedMediaSchema } from '../../types.js';
import { errorToConsole } from '../basic';
import { homeAssistantWSRequest } from './ws-request';
// It's important the cache size be at least as large as the largest likely
// media query or media items will from a given query will be evicted for other
+2 -3
View File
@@ -1,6 +1,5 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { CameraProxyConfig } from '../../camera-manager/types';
import { ExtendedHomeAssistant } from '../../types';
import { HomeAssistant } from '../../ha/types';
export const HASS_WEB_PROXY_DOMAIN = 'hass_web_proxy';
@@ -29,7 +28,7 @@ export const shouldUseWebProxy = (
* @returns The signed URL, or null if the response was malformed.
*/
export async function addDynamicProxyURL(
hass: ExtendedHomeAssistant,
hass: HomeAssistant,
url_pattern: string,
options?: {
urlID?: string;
+1 -1
View File
@@ -1,6 +1,6 @@
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { MessageBase } from 'home-assistant-js-websocket';
import { ZodSchema } from 'zod';
import { HomeAssistant } from '../../ha/types';
import { localize } from '../../localize/localize';
import { AdvancedCameraCardError } from '../../types';
import { getParseErrorKeys } from '../zod';
+8 -12
View File
@@ -4,7 +4,7 @@ import {
MediaPlayerController,
MediaTechnology,
} from '../types.js';
import { dispatchAdvancedCameraCardEvent } from './basic.js';
import { fireAdvancedCameraCardEvent } from './fire-advanced-camera-card-event.js';
const MEDIA_INFO_HEIGHT_CUTOFF = 50;
const MEDIA_INFO_WIDTH_CUTOFF = MEDIA_INFO_HEIGHT_CUTOFF;
@@ -75,17 +75,13 @@ export function dispatchMediaLoadedEvent(
/**
* Dispatch a pre-existing MediaLoadedInfo object as an event.
* @param element The element to send the event.
* @param MediaLoadedInfo The MediaLoadedInfo object to send.
* @param mediaLoadedInfo The MediaLoadedInfo object to send.
*/
export function dispatchExistingMediaLoadedInfoAsEvent(
target: EventTarget,
MediaLoadedInfo: MediaLoadedInfo,
mediaLoadedInfo: MediaLoadedInfo,
): void {
dispatchAdvancedCameraCardEvent<MediaLoadedInfo>(
target,
'media:loaded',
MediaLoadedInfo,
);
fireAdvancedCameraCardEvent<MediaLoadedInfo>(target, 'media:loaded', mediaLoadedInfo);
}
/**
@@ -93,19 +89,19 @@ export function dispatchExistingMediaLoadedInfoAsEvent(
* @param element The element to send the event.
*/
export function dispatchMediaUnloadedEvent(element: HTMLElement): void {
dispatchAdvancedCameraCardEvent(element, 'media:unloaded');
fireAdvancedCameraCardEvent(element, 'media:unloaded');
}
export function dispatchMediaVolumeChangeEvent(target: HTMLElement): void {
dispatchAdvancedCameraCardEvent(target, 'media:volumechange');
fireAdvancedCameraCardEvent(target, 'media:volumechange');
}
export function dispatchMediaPlayEvent(target: HTMLElement): void {
dispatchAdvancedCameraCardEvent(target, 'media:play');
fireAdvancedCameraCardEvent(target, 'media:play');
}
export function dispatchMediaPauseEvent(target: HTMLElement): void {
dispatchAdvancedCameraCardEvent(target, 'media:pause');
fireAdvancedCameraCardEvent(target, 'media:pause');
}
/**
+1 -1
View File
@@ -1,6 +1,6 @@
import { Task } from '@lit-labs/task';
import { ReactiveControllerHost } from '@lit/reactive-element';
import { HomeAssistant } from '@dermotduffy/custom-card-helpers';
import { HomeAssistant } from '../ha/types';
// See: https://github.com/sindresorhus/is-absolute-url
// Scheme: https://tools.ietf.org/html/rfc3986#section-3.1