mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-31 05:06:38 +00:00
Card Picker with Previews of cards (#4975)
* Card Picker with Previews of cards * Getting Preview Async - Using dialogs entities * Create generic getElement - filter entities before * lint * Add entities back to Picker. Set Qualifier * Style Updates * Move setup of filtered cards to connected * style updates * Dont pull entities if noEntity config * Move all config logic to getConfig * Style Update - Remove Manual process * lint * Accounting for ll-rebuild for async cards * Style Updates - Use GetStubConfig for most * Lint * Filter entities with function - style - no preview * Iframe rename and description * Move getstubconfig to helper - update spinner * Style for themes * Move entities to be calc once * Should update * oops * TSC * Comments
This commit is contained in:
parent
f3445d99cf
commit
aa2e632df3
@ -24,6 +24,8 @@ import {
|
||||
import { AlarmPanelCardConfig } from "./types";
|
||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
|
||||
const ICONS = {
|
||||
armed_away: "hass:shield-lock",
|
||||
@ -46,8 +48,27 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-alarm-panel-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig() {
|
||||
return { states: ["arm_home", "arm_away"], entity: "" };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
) {
|
||||
const includeDomains = ["alarm_control_panel"];
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return {
|
||||
states: ["arm_home", "arm_away"],
|
||||
entity: foundEntities[0] || "",
|
||||
};
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -30,9 +30,10 @@ import { ButtonCardConfig } from "./types";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||
import { ActionHandlerEvent, LovelaceConfig } from "../../../data/lovelace";
|
||||
import { computeActiveState } from "../../../common/entity/compute_active_state";
|
||||
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
@customElement("hui-button-card")
|
||||
export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||
@ -43,13 +44,28 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-button-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig(): object {
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill
|
||||
);
|
||||
|
||||
return {
|
||||
tap_action: { action: "toggle" },
|
||||
hold_action: { action: "more-info" },
|
||||
show_icon: true,
|
||||
show_name: true,
|
||||
state_color: true,
|
||||
entity: foundEntities[0] || "",
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@ import { createHeaderFooterElement } from "../create-element/create-header-foote
|
||||
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
@customElement("hui-entities-card")
|
||||
class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
@ -37,8 +39,22 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-entities-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig(): object {
|
||||
return { entities: [] };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
) {
|
||||
const maxEntities = 3;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill
|
||||
);
|
||||
|
||||
return { entities: foundEntities };
|
||||
}
|
||||
|
||||
@property() private _config?: EntitiesCardConfig;
|
||||
|
@ -22,6 +22,9 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { GaugeCardConfig } from "./types";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
import { HassEntity } from "home-assistant-js-websocket/dist/types";
|
||||
|
||||
export const severityMap = {
|
||||
red: "var(--label-badge-red)",
|
||||
@ -38,8 +41,30 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
return document.createElement("hui-gauge-card-editor");
|
||||
}
|
||||
public static getStubConfig(): object {
|
||||
return { entity: "" };
|
||||
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["sensor"];
|
||||
const maxEntities = 1;
|
||||
const entityFilter = (stateObj: HassEntity): boolean => {
|
||||
return !isNaN(Number(stateObj.state));
|
||||
};
|
||||
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains,
|
||||
entityFilter
|
||||
);
|
||||
|
||||
return { entity: foundEntities[0] || "" };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -27,10 +27,11 @@ import { processConfigEntities } from "../common/process-config-entities";
|
||||
import { GlanceCardConfig, GlanceConfigEntity } from "./types";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||
import { ActionHandlerEvent, LovelaceConfig } from "../../../data/lovelace";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { UNAVAILABLE, UNKNOWN } from "../../../data/entity";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
@customElement("hui-glance-card")
|
||||
export class HuiGlanceCard extends LitElement implements LovelaceCard {
|
||||
@ -41,8 +42,24 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-glance-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig(): object {
|
||||
return { entities: [] };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["sensor"];
|
||||
const maxEntities = 3;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return { entities: foundEntities };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -20,6 +20,8 @@ import { HomeAssistant } from "../../../types";
|
||||
import { HistoryGraphCardConfig } from "./types";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { EntityConfig } from "../entity-rows/types";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
@customElement("hui-history-graph-card")
|
||||
export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
|
||||
@ -30,8 +32,24 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-history-graph-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig() {
|
||||
return { entities: [] };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["sensor"];
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return { entities: foundEntities };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -29,6 +29,8 @@ import { toggleEntity } from "../common/entity/toggle-entity";
|
||||
import { LightCardConfig } from "./types";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { SUPPORT_BRIGHTNESS } from "../../../data/light";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
|
||||
@customElement("hui-light-card")
|
||||
@ -39,8 +41,25 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
return document.createElement("hui-light-card-editor");
|
||||
}
|
||||
public static getStubConfig(): object {
|
||||
return { entity: "" };
|
||||
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["light"];
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return { entity: foundEntities[0] || "" };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -30,6 +30,8 @@ import { EntityConfig } from "../entity-rows/types";
|
||||
import { processConfigEntities } from "../common/process-config-entities";
|
||||
import { MapCardConfig } from "./types";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
@customElement("hui-map-card")
|
||||
class HuiMapCard extends LitElement implements LovelaceCard {
|
||||
@ -40,8 +42,24 @@ class HuiMapCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-map-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig() {
|
||||
return { entities: [] };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["device_tracker"];
|
||||
const maxEntities = 2;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return { entities: foundEntities };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -34,6 +34,8 @@ import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { MediaControlCardConfig } from "./types";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
@customElement("hui-media-control-card")
|
||||
export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
@ -44,8 +46,24 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-media-control-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig(): object {
|
||||
return { entity: "" };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["media_player"];
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return { entity: foundEntities[0] || "" };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -15,9 +15,39 @@ import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceElementConfig, LovelaceElement } from "../elements/types";
|
||||
import { PictureElementsCardConfig } from "./types";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
@customElement("hui-picture-elements-card")
|
||||
class HuiPictureElementsCard extends LitElement implements LovelaceCard {
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill
|
||||
);
|
||||
|
||||
return {
|
||||
elements: [
|
||||
{
|
||||
type: "state-badge",
|
||||
entity: foundEntities[0] || "",
|
||||
style: "position: absolute, transform: translate(-50%, -50%)",
|
||||
},
|
||||
],
|
||||
image:
|
||||
"https://www.home-assistant.io/images/merchandise/shirt-frontpage.png",
|
||||
};
|
||||
}
|
||||
|
||||
@property() private _config?: PictureElementsCardConfig;
|
||||
|
||||
private _hass?: HomeAssistant;
|
||||
|
@ -27,8 +27,9 @@ import { PictureEntityCardConfig } from "./types";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||
import { ActionHandlerEvent, LovelaceConfig } from "../../../data/lovelace";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
@customElement("hui-picture-entity-card")
|
||||
class HuiPictureEntityCard extends LitElement implements LovelaceCard {
|
||||
@ -38,9 +39,24 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
return document.createElement("hui-picture-entity-card-editor");
|
||||
}
|
||||
public static getStubConfig(): object {
|
||||
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill
|
||||
);
|
||||
|
||||
return {
|
||||
entity: "",
|
||||
entity: foundEntities[0] || "",
|
||||
image:
|
||||
"https://www.home-assistant.io/images/merchandise/shirt-frontpage.png",
|
||||
};
|
||||
|
@ -29,8 +29,9 @@ import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||
import { ActionHandlerEvent, LovelaceConfig } from "../../../data/lovelace";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
const STATES_OFF = new Set(["closed", "locked", "not_home", "off"]);
|
||||
|
||||
@ -42,11 +43,26 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
return document.createElement("hui-picture-glance-card-editor");
|
||||
}
|
||||
public static getStubConfig(): object {
|
||||
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const maxEntities = 2;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill
|
||||
);
|
||||
|
||||
return {
|
||||
image:
|
||||
"https://www.home-assistant.io/images/merchandise/shirt-frontpage.png",
|
||||
entities: [],
|
||||
entities: foundEntities,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,8 @@ import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { PlantStatusCardConfig, PlantAttributeTarget } from "./types";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
const SENSORS = {
|
||||
moisture: "hass:water",
|
||||
@ -40,8 +42,24 @@ class HuiPlantStatusCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-plant-status-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig(): object {
|
||||
return { entity: "" };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["plant"];
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return { entity: foundEntities[0] || "" };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -26,6 +26,9 @@ import { fetchRecent } from "../../../data/history";
|
||||
import { SensorCardConfig } from "./types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
import { HassEntity } from "home-assistant-js-websocket/dist/types";
|
||||
|
||||
const strokeWidth = 5;
|
||||
|
||||
@ -174,8 +177,32 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-sensor-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig(): object {
|
||||
return { entity: "" };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["sensor"];
|
||||
const maxEntities = 1;
|
||||
const entityFilter = (stateObj: HassEntity): boolean => {
|
||||
return (
|
||||
!isNaN(Number(stateObj.state)) &&
|
||||
!!stateObj.attributes.unit_of_measurement
|
||||
);
|
||||
};
|
||||
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains,
|
||||
entityFilter
|
||||
);
|
||||
|
||||
return { entity: foundEntities[0] || "", graph: "line" };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -34,6 +34,8 @@ import {
|
||||
} from "../../../data/climate";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
|
||||
const modeIcons: { [mode in HvacMode]: string } = {
|
||||
@ -55,8 +57,24 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
|
||||
return document.createElement("hui-thermostat-card-editor");
|
||||
}
|
||||
|
||||
public static getStubConfig(): object {
|
||||
return { entity: "" };
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["climate"];
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return { entity: foundEntities[0] || "" };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -24,6 +24,8 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { toggleAttribute } from "../../../common/dom/toggle_attribute";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
|
||||
const cardinalDirections = [
|
||||
"N",
|
||||
@ -71,8 +73,25 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
return document.createElement("hui-weather-forecast-card-editor");
|
||||
}
|
||||
public static getStubConfig(): object {
|
||||
return { entity: "" };
|
||||
|
||||
public static getStubConfig(
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): object {
|
||||
const includeDomains = ["weather"];
|
||||
const maxEntities = 1;
|
||||
const foundEntities = findEntities(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
maxEntities,
|
||||
entities,
|
||||
entitiesFill,
|
||||
includeDomains
|
||||
);
|
||||
|
||||
return { entity: foundEntities[0] || "" };
|
||||
}
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { LovelaceConfig, ActionConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
const EXCLUDED_DOMAINS = ["zone", "persistent_notification"];
|
||||
export const EXCLUDED_DOMAINS = ["zone", "persistent_notification"];
|
||||
|
||||
const addFromAction = (entities: Set<string>, actionConfig: ActionConfig) => {
|
||||
if (
|
||||
@ -61,7 +61,7 @@ const addEntities = (entities: Set<string>, obj) => {
|
||||
}
|
||||
};
|
||||
|
||||
const computeUsedEntities = (config) => {
|
||||
export const computeUsedEntities = (config) => {
|
||||
const entities = new Set<string>();
|
||||
config.views.forEach((view) => addEntities(entities, view));
|
||||
return entities;
|
||||
|
59
src/panels/lovelace/common/find-entites.ts
Normal file
59
src/panels/lovelace/common/find-entites.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import {
|
||||
computeUnusedEntities,
|
||||
computeUsedEntities,
|
||||
} from "./compute-unused-entities";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceConfig } from "../../../data/lovelace";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
export const findEntities = (
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
maxEntities: number,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[],
|
||||
includeDomains?: string[],
|
||||
entityFilter?: (stateObj: HassEntity) => boolean
|
||||
) => {
|
||||
let entityIds: string[];
|
||||
|
||||
entityIds = !entities?.length
|
||||
? computeUnusedEntities(hass, lovelaceConfig)
|
||||
: entities;
|
||||
|
||||
if (includeDomains && includeDomains.length) {
|
||||
entityIds = entityIds.filter((eid) =>
|
||||
includeDomains!.includes(computeDomain(eid))
|
||||
);
|
||||
}
|
||||
|
||||
if (entityFilter) {
|
||||
entityIds = entityIds.filter(
|
||||
(eid) => hass.states[eid] && entityFilter(hass.states[eid])
|
||||
);
|
||||
}
|
||||
|
||||
if (entityIds.length < (maxEntities || 1)) {
|
||||
let fillEntityIds =
|
||||
entitiesFill && entitiesFill.length
|
||||
? entitiesFill
|
||||
: [...computeUsedEntities(lovelaceConfig)];
|
||||
|
||||
if (includeDomains && includeDomains.length) {
|
||||
fillEntityIds = fillEntityIds.filter((eid) =>
|
||||
includeDomains!.includes(computeDomain(eid))
|
||||
);
|
||||
}
|
||||
|
||||
if (entityFilter) {
|
||||
fillEntityIds = fillEntityIds.filter(
|
||||
(eid) => hass.states[eid] && entityFilter(hass.states[eid])
|
||||
);
|
||||
}
|
||||
|
||||
entityIds = [...entityIds, ...fillEntityIds];
|
||||
}
|
||||
|
||||
return entityIds.slice(0, maxEntities);
|
||||
};
|
@ -5,26 +5,31 @@ import {
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
customElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import "@material/mwc-button";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardConfig } from "../../../../data/lovelace";
|
||||
import { CardPickTarget } from "../types";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCard } from "../../types";
|
||||
import { LovelaceCardConfig, LovelaceConfig } from "../../../../data/lovelace";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { getCardElementClass } from "../../create-element/create-card-element";
|
||||
import { createCardElement } from "../../create-element/create-card-element";
|
||||
import { getCardStubConfig } from "../get-card-stub-config";
|
||||
import {
|
||||
computeUnusedEntities,
|
||||
computeUsedEntities,
|
||||
} from "../../common/compute-unused-entities";
|
||||
|
||||
const cards: string[] = [
|
||||
const previewCards: string[] = [
|
||||
"alarm-panel",
|
||||
"conditional",
|
||||
"entities",
|
||||
"button",
|
||||
"entity-filter",
|
||||
"gauge",
|
||||
"glance",
|
||||
"history-graph",
|
||||
"horizontal-stack",
|
||||
"iframe",
|
||||
"light",
|
||||
"map",
|
||||
"markdown",
|
||||
@ -35,78 +40,247 @@ const cards: string[] = [
|
||||
"picture-glance",
|
||||
"plant-status",
|
||||
"sensor",
|
||||
"shopping-list",
|
||||
"thermostat",
|
||||
"vertical-stack",
|
||||
"weather-forecast",
|
||||
];
|
||||
|
||||
const nonPreviewCards: string[] = [
|
||||
"conditional",
|
||||
"entity-filter",
|
||||
"horizontal-stack",
|
||||
"iframe",
|
||||
"vertical-stack",
|
||||
"shopping-list",
|
||||
];
|
||||
|
||||
@customElement("hui-card-picker")
|
||||
export class HuiCardPicker extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
|
||||
@property() public hass?: HomeAssistant;
|
||||
public lovelace?: LovelaceConfig;
|
||||
public cardPicked?: (cardConf: LovelaceCardConfig) => void;
|
||||
private _unusedEntities?: string[];
|
||||
private _usedEntities?: string[];
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (
|
||||
!this.hass ||
|
||||
!this.lovelace ||
|
||||
!this._unusedEntities ||
|
||||
!this._usedEntities
|
||||
) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="cards-container">
|
||||
${cards.map((card: string) => {
|
||||
${previewCards.map((type: string) => {
|
||||
return html`
|
||||
<mwc-button @click="${this._cardPicked}" .type="${card}">
|
||||
${this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.${card}.name`
|
||||
)}
|
||||
</mwc-button>
|
||||
${until(
|
||||
this._renderCardElement(type),
|
||||
html`
|
||||
<div class="card spinner">
|
||||
<paper-spinner active alt="Loading"></paper-spinner>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
})}
|
||||
${nonPreviewCards.map((type: string) => {
|
||||
return html`
|
||||
${until(
|
||||
this._renderCardElement(type, true),
|
||||
html`
|
||||
<div class="card spinner">
|
||||
<paper-spinner active alt="Loading"></paper-spinner>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
<div class="cards-container">
|
||||
<mwc-button @click="${this._manualPicked}">MANUAL CARD</mwc-button>
|
||||
<div
|
||||
class="card"
|
||||
@click="${this._cardPicked}"
|
||||
.config="${{ type: "" }}"
|
||||
>
|
||||
<div class="preview description">
|
||||
${this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.generic.manual_description`
|
||||
)}
|
||||
</div>
|
||||
<div class="card-header">
|
||||
${this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.generic.manual`
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (oldHass.language !== this.hass!.language) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected firstUpdated(): void {
|
||||
if (!this.hass || !this.lovelace) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._unusedEntities = computeUnusedEntities(this.hass, this.lovelace);
|
||||
this._usedEntities = [...computeUsedEntities(this.lovelace)];
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
css`
|
||||
.cards-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.cards-container mwc-button {
|
||||
flex: 1 0 25%;
|
||||
margin: 4px;
|
||||
display: grid;
|
||||
grid-gap: 8px 8px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
.cards-container mwc-button {
|
||||
flex: 1 0 33%;
|
||||
}
|
||||
.card {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--divider-color);
|
||||
background: var(--primary-background-color, #fafafa);
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
color: var(--ha-card-header-color, --primary-text-color);
|
||||
font-family: var(--ha-card-header-font-family, inherit);
|
||||
font-size: 16px;
|
||||
letter-spacing: -0.012em;
|
||||
line-height: 20px;
|
||||
padding: 12px 16px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
background: var(
|
||||
--ha-card-background,
|
||||
var(--paper-card-background-color, white)
|
||||
);
|
||||
border-radius: 0 0 4px 4px;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
|
||||
.preview {
|
||||
pointer-events: none;
|
||||
margin: 20px;
|
||||
flex: 1 1 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.preview > :first-child {
|
||||
zoom: 0.6;
|
||||
-moz-transform: scale(0.6); /* Firefox */
|
||||
-moz-transform-origin: 0 0;
|
||||
-o-transform: scale(0.6); /* Opera */
|
||||
-o-transform-origin: 0 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.description {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
private _manualPicked(): void {
|
||||
fireEvent(this, "config-changed", {
|
||||
config: { type: "" },
|
||||
});
|
||||
}
|
||||
|
||||
private async _cardPicked(ev: Event): Promise<void> {
|
||||
const type = (ev.currentTarget! as CardPickTarget).type;
|
||||
|
||||
const elClass = await getCardElementClass(type);
|
||||
let config: LovelaceCardConfig = { type };
|
||||
|
||||
if (elClass && elClass.getStubConfig) {
|
||||
const cardConfig = elClass.getStubConfig(this.hass!);
|
||||
config = { ...config, ...cardConfig };
|
||||
}
|
||||
private _cardPicked(ev: Event): void {
|
||||
const config: LovelaceCardConfig = (ev.currentTarget! as CardPickTarget)
|
||||
.config;
|
||||
|
||||
fireEvent(this, "config-changed", { config });
|
||||
}
|
||||
|
||||
private _createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
const element = createCardElement(cardConfig) as LovelaceCard;
|
||||
element.hass = this.hass;
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev) => {
|
||||
ev.stopPropagation();
|
||||
element.parentElement!.replaceChild(
|
||||
this._createCardElement(cardConfig),
|
||||
element
|
||||
);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
return element;
|
||||
}
|
||||
|
||||
private async _renderCardElement(
|
||||
type: string,
|
||||
noElement: boolean = false
|
||||
): Promise<TemplateResult> {
|
||||
let element: LovelaceCard | undefined;
|
||||
let cardConfig: LovelaceCardConfig = { type };
|
||||
|
||||
if (this.hass && this.lovelace) {
|
||||
cardConfig = await getCardStubConfig(
|
||||
this.hass,
|
||||
this.lovelace,
|
||||
type,
|
||||
this._unusedEntities,
|
||||
this._usedEntities
|
||||
);
|
||||
|
||||
if (!noElement) {
|
||||
element = this._createCardElement(cardConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="card" @click="${this._cardPicked}" .config="${cardConfig}">
|
||||
<div
|
||||
class="preview ${classMap({
|
||||
description: !element || element.tagName === "HUI-ERROR-CARD",
|
||||
})}"
|
||||
>
|
||||
${!element || element.tagName === "HUI-ERROR-CARD"
|
||||
? html`
|
||||
${this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.${cardConfig.type}.description`
|
||||
)}
|
||||
`
|
||||
: html`
|
||||
${element}
|
||||
`}
|
||||
</div>
|
||||
<div class="card-header">
|
||||
${this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.${cardConfig.type}.name`
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -99,6 +99,7 @@ export class HuiDialogEditCard extends LitElement {
|
||||
${this._cardConfig === undefined
|
||||
? html`
|
||||
<hui-card-picker
|
||||
.lovelace="${this._params.lovelaceConfig}"
|
||||
.hass=${this.hass}
|
||||
@config-changed="${this._handleCardPicked}"
|
||||
></hui-card-picker>
|
||||
@ -254,7 +255,7 @@ export class HuiDialogEditCard extends LitElement {
|
||||
|
||||
private _handleCardPicked(ev) {
|
||||
const config = ev.detail.config;
|
||||
if (this._params!.entities && this._params!.entities.length > 0) {
|
||||
if (this._params!.entities && this._params!.entities.length) {
|
||||
if (Object.keys(config).includes("entities")) {
|
||||
config.entities = this._params!.entities;
|
||||
} else if (Object.keys(config).includes("entity")) {
|
||||
|
28
src/panels/lovelace/editor/get-card-stub-config.ts
Normal file
28
src/panels/lovelace/editor/get-card-stub-config.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCardConfig, LovelaceConfig } from "../../../data/lovelace";
|
||||
import { getCardElementClass } from "../create-element/create-card-element";
|
||||
|
||||
export const getCardStubConfig = async (
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
type: string,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
): Promise<LovelaceCardConfig> => {
|
||||
let cardConfig: LovelaceCardConfig = { type };
|
||||
|
||||
const elClass = await getCardElementClass(type);
|
||||
|
||||
if (elClass && elClass.getStubConfig) {
|
||||
const classStubConfig = elClass.getStubConfig(
|
||||
hass,
|
||||
lovelaceConfig,
|
||||
entities,
|
||||
entitiesFill
|
||||
);
|
||||
|
||||
cardConfig = { ...cardConfig, ...classStubConfig };
|
||||
}
|
||||
|
||||
return cardConfig;
|
||||
};
|
@ -46,7 +46,7 @@ export interface EditorTarget extends EventTarget {
|
||||
}
|
||||
|
||||
export interface CardPickTarget extends EventTarget {
|
||||
type: string;
|
||||
config: LovelaceCardConfig;
|
||||
}
|
||||
|
||||
export const actionConfigStruct = struct({
|
||||
|
@ -38,7 +38,12 @@ export interface LovelaceCard extends HTMLElement {
|
||||
}
|
||||
|
||||
export interface LovelaceCardConstructor extends Constructor<LovelaceCard> {
|
||||
getStubConfig?: (hass: HomeAssistant) => LovelaceCardConfig;
|
||||
getStubConfig?: (
|
||||
hass: HomeAssistant,
|
||||
lovelaceConfig: LovelaceConfig,
|
||||
entities?: string[],
|
||||
entitiesFill?: string[]
|
||||
) => LovelaceCardConfig;
|
||||
getConfigElement?: () => LovelaceCardEditor;
|
||||
}
|
||||
|
||||
|
@ -1956,7 +1956,8 @@
|
||||
"available_states": "Available States"
|
||||
},
|
||||
"conditional": {
|
||||
"name": "Conditional"
|
||||
"name": "Conditional",
|
||||
"description": "Displays another card based on entity states."
|
||||
},
|
||||
"config": {
|
||||
"required": "Required",
|
||||
@ -1971,7 +1972,8 @@
|
||||
"name": "Button"
|
||||
},
|
||||
"entity-filter": {
|
||||
"name": "Entity Filter"
|
||||
"name": "Entity Filter",
|
||||
"description": "This card allows you to define a list of entities that you want to track only when in a certain state."
|
||||
},
|
||||
"gauge": {
|
||||
"name": "Gauge",
|
||||
@ -1990,10 +1992,12 @@
|
||||
"name": "History Graph"
|
||||
},
|
||||
"horizontal-stack": {
|
||||
"name": "Horizontal Stack"
|
||||
"name": "Horizontal Stack",
|
||||
"description": "Horizontal stack card allows you to stack together multiple cards, so they always sit next to each other in the space of one column."
|
||||
},
|
||||
"iframe": {
|
||||
"name": "iFrame"
|
||||
"name": "Webpage",
|
||||
"description": "Embed your favorite webpage right into Home Assistant"
|
||||
},
|
||||
"light": {
|
||||
"name": "Light"
|
||||
@ -2010,6 +2014,8 @@
|
||||
"icon_height": "Icon Height",
|
||||
"image": "Image Path",
|
||||
"maximum": "Maximum",
|
||||
"manual": "Manual",
|
||||
"manual_description": "Need to add a custom card or just want to manually write the yaml?",
|
||||
"minimum": "Minimum",
|
||||
"name": "Name",
|
||||
"refresh_interval": "Refresh Interval",
|
||||
@ -2049,7 +2055,8 @@
|
||||
"name": "Picture Glance"
|
||||
},
|
||||
"plant-status": {
|
||||
"name": "Plant Status"
|
||||
"name": "Plant Status",
|
||||
"description": "A card for all the lovely botanists out there."
|
||||
},
|
||||
"sensor": {
|
||||
"name": "Sensor",
|
||||
@ -2058,13 +2065,15 @@
|
||||
},
|
||||
"shopping-list": {
|
||||
"name": "Shopping List",
|
||||
"description": "The Shopping List Card allows you to add, edit, check-off, and clear items from your shopping list.",
|
||||
"integration_not_loaded": "This card requires the `shopping_list` integration to be set up."
|
||||
},
|
||||
"thermostat": {
|
||||
"name": "Thermostat"
|
||||
},
|
||||
"vertical-stack": {
|
||||
"name": "Vertical Stack"
|
||||
"name": "Vertical Stack",
|
||||
"description": "Vertical stack allows you to group multiple cards so they always sit in the same column."
|
||||
},
|
||||
"weather-forecast": {
|
||||
"name": "Weather Forecast"
|
||||
|
Loading…
x
Reference in New Issue
Block a user