mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-18 14:56:37 +00:00
Rename tile extras to tile features (#14483)
This commit is contained in:
parent
92d022747b
commit
d4cda0c106
@ -29,10 +29,14 @@ import { actionHandler } from "../common/directives/action-handler-directive";
|
|||||||
import { findEntities } from "../common/find-entities";
|
import { findEntities } from "../common/find-entities";
|
||||||
import { handleAction } from "../common/handle-action";
|
import { handleAction } from "../common/handle-action";
|
||||||
import "../components/hui-timestamp-display";
|
import "../components/hui-timestamp-display";
|
||||||
import { createTileExtraElement } from "../create-element/create-tile-extra-element";
|
import { createTileFeatureElement } from "../create-element/create-tile-feature-element";
|
||||||
import { supportsTileExtra } from "../tile-extra/tile-extras";
|
import { supportsTileFeature } from "../tile-features/tile-features";
|
||||||
import { LovelaceTileExtraConfig } from "../tile-extra/types";
|
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||||
import { LovelaceCard, LovelaceCardEditor, LovelaceTileExtra } from "../types";
|
import {
|
||||||
|
LovelaceCard,
|
||||||
|
LovelaceCardEditor,
|
||||||
|
LovelaceTileFeature,
|
||||||
|
} from "../types";
|
||||||
import { HuiErrorCard } from "./hui-error-card";
|
import { HuiErrorCard } from "./hui-error-card";
|
||||||
import { computeTileBadge } from "./tile/badges/tile-badge";
|
import { computeTileBadge } from "./tile/badges/tile-badge";
|
||||||
import { ThermostatCardConfig, TileCardConfig } from "./types";
|
import { ThermostatCardConfig, TileCardConfig } from "./types";
|
||||||
@ -242,8 +246,8 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
: undefined;
|
: undefined;
|
||||||
const badge = computeTileBadge(stateObj, this.hass);
|
const badge = computeTileBadge(stateObj, this.hass);
|
||||||
|
|
||||||
const supportedExtras = this._config.extras?.filter((extra) =>
|
const supportedFeatures = this._config.features?.filter((feature) =>
|
||||||
supportsTileExtra(stateObj, extra.type)
|
supportsTileFeature(stateObj, feature.type)
|
||||||
);
|
);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
@ -292,11 +296,11 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
.actionHandler=${actionHandler()}
|
.actionHandler=${actionHandler()}
|
||||||
></ha-tile-info>
|
></ha-tile-info>
|
||||||
</div>
|
</div>
|
||||||
${supportedExtras?.length
|
${supportedFeatures?.length
|
||||||
? html`
|
? html`
|
||||||
<div class="extras">
|
<div class="features">
|
||||||
${supportedExtras.map((extraConf) =>
|
${supportedFeatures.map((featureConf) =>
|
||||||
this.renderExtra(extraConf, stateObj)
|
this.renderFeature(featureConf, stateObj)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@ -305,33 +309,33 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _extrasElements = new WeakMap<
|
private _featuresElements = new WeakMap<
|
||||||
LovelaceTileExtraConfig,
|
LovelaceTileFeatureConfig,
|
||||||
LovelaceTileExtra | HuiErrorCard
|
LovelaceTileFeature | HuiErrorCard
|
||||||
>();
|
>();
|
||||||
|
|
||||||
private _getExtraElement(extra: LovelaceTileExtraConfig) {
|
private _getFeatureElement(feature: LovelaceTileFeatureConfig) {
|
||||||
if (!this._extrasElements.has(extra)) {
|
if (!this._featuresElements.has(feature)) {
|
||||||
const element = createTileExtraElement(extra);
|
const element = createTileFeatureElement(feature);
|
||||||
this._extrasElements.set(extra, element);
|
this._featuresElements.set(feature, element);
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._extrasElements.get(extra)!;
|
return this._featuresElements.get(feature)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderExtra(
|
private renderFeature(
|
||||||
extraConf: LovelaceTileExtraConfig,
|
featureConf: LovelaceTileFeatureConfig,
|
||||||
stateObj: HassEntity
|
stateObj: HassEntity
|
||||||
): TemplateResult {
|
): TemplateResult {
|
||||||
const element = this._getExtraElement(extraConf);
|
const element = this._getFeatureElement(featureConf);
|
||||||
|
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
element.hass = this.hass;
|
element.hass = this.hass;
|
||||||
(element as LovelaceTileExtra).stateObj = stateObj;
|
(element as LovelaceTileFeature).stateObj = stateObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`<div class="extra">${element}</div>`;
|
return html`<div class="feature">${element}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
} from "../entity-rows/types";
|
} from "../entity-rows/types";
|
||||||
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
||||||
import { HaDurationData } from "../../../components/ha-duration-input";
|
import { HaDurationData } from "../../../components/ha-duration-input";
|
||||||
import { LovelaceTileExtraConfig } from "../tile-extra/types";
|
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||||
|
|
||||||
export interface AlarmPanelCardConfig extends LovelaceCardConfig {
|
export interface AlarmPanelCardConfig extends LovelaceCardConfig {
|
||||||
entity: string;
|
entity: string;
|
||||||
@ -502,5 +502,5 @@ export interface TileCardConfig extends LovelaceCardConfig {
|
|||||||
show_entity_picture?: string;
|
show_entity_picture?: string;
|
||||||
tap_action?: ActionConfig;
|
tap_action?: ActionConfig;
|
||||||
icon_tap_action?: ActionConfig;
|
icon_tap_action?: ActionConfig;
|
||||||
extras?: LovelaceTileExtraConfig[];
|
features?: LovelaceTileFeatureConfig[];
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import type { ErrorCardConfig } from "../cards/types";
|
|||||||
import { LovelaceElement, LovelaceElementConfig } from "../elements/types";
|
import { LovelaceElement, LovelaceElementConfig } from "../elements/types";
|
||||||
import { LovelaceRow, LovelaceRowConfig } from "../entity-rows/types";
|
import { LovelaceRow, LovelaceRowConfig } from "../entity-rows/types";
|
||||||
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
||||||
import { LovelaceTileExtraConfig } from "../tile-extra/types";
|
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||||
import {
|
import {
|
||||||
LovelaceBadge,
|
LovelaceBadge,
|
||||||
LovelaceCard,
|
LovelaceCard,
|
||||||
@ -19,8 +19,8 @@ import {
|
|||||||
LovelaceHeaderFooter,
|
LovelaceHeaderFooter,
|
||||||
LovelaceHeaderFooterConstructor,
|
LovelaceHeaderFooterConstructor,
|
||||||
LovelaceRowConstructor,
|
LovelaceRowConstructor,
|
||||||
LovelaceTileExtra,
|
LovelaceTileFeature,
|
||||||
LovelaceTileExtraConstructor,
|
LovelaceTileFeatureConstructor,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
|
|
||||||
const TIMEOUT = 2000;
|
const TIMEOUT = 2000;
|
||||||
@ -56,10 +56,10 @@ interface CreateElementConfigTypes {
|
|||||||
element: LovelaceViewElement;
|
element: LovelaceViewElement;
|
||||||
constructor: unknown;
|
constructor: unknown;
|
||||||
};
|
};
|
||||||
"tile-extra": {
|
"tile-feature": {
|
||||||
config: LovelaceTileExtraConfig;
|
config: LovelaceTileFeatureConfig;
|
||||||
element: LovelaceTileExtra;
|
element: LovelaceTileFeature;
|
||||||
constructor: LovelaceTileExtraConstructor;
|
constructor: LovelaceTileFeatureConstructor;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import { LovelaceTileExtraConfig } from "../tile-extra/types";
|
|
||||||
import {
|
|
||||||
createLovelaceElement,
|
|
||||||
getLovelaceElementClass,
|
|
||||||
} from "./create-element-base";
|
|
||||||
import "../tile-extra/hui-cover-open-close-tile-extra";
|
|
||||||
import "../tile-extra/hui-cover-tilt-tile-extra";
|
|
||||||
import "../tile-extra/hui-light-brightness-tile-extra";
|
|
||||||
import "../tile-extra/hui-vacuum-commands-tile-extra";
|
|
||||||
|
|
||||||
const TYPES: Set<LovelaceTileExtraConfig["type"]> = new Set([
|
|
||||||
"cover-open-close",
|
|
||||||
"cover-tilt",
|
|
||||||
"light-brightness",
|
|
||||||
"vacuum-commands",
|
|
||||||
]);
|
|
||||||
|
|
||||||
export const createTileExtraElement = (config: LovelaceTileExtraConfig) =>
|
|
||||||
createLovelaceElement("tile-extra", config, TYPES);
|
|
||||||
|
|
||||||
export const getTileExtraElementClass = (type: string) =>
|
|
||||||
getLovelaceElementClass(type, "tile-extra", TYPES);
|
|
@ -0,0 +1,22 @@
|
|||||||
|
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||||
|
import {
|
||||||
|
createLovelaceElement,
|
||||||
|
getLovelaceElementClass,
|
||||||
|
} from "./create-element-base";
|
||||||
|
import "../tile-features/hui-cover-open-close-tile-feature";
|
||||||
|
import "../tile-features/hui-cover-tilt-tile-feature";
|
||||||
|
import "../tile-features/hui-light-brightness-tile-feature";
|
||||||
|
import "../tile-features/hui-vacuum-commands-tile-feature";
|
||||||
|
|
||||||
|
const TYPES: Set<LovelaceTileFeatureConfig["type"]> = new Set([
|
||||||
|
"cover-open-close",
|
||||||
|
"cover-tilt",
|
||||||
|
"light-brightness",
|
||||||
|
"vacuum-commands",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const createTileFeatureElement = (config: LovelaceTileFeatureConfig) =>
|
||||||
|
createLovelaceElement("tile-feature", config, TYPES);
|
||||||
|
|
||||||
|
export const getTileFeatureElementClass = (type: string) =>
|
||||||
|
getLovelaceElementClass(type, "tile-feature", TYPES);
|
@ -21,16 +21,16 @@ import type { SchemaUnion } from "../../../../components/ha-form/types";
|
|||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import type { TileCardConfig } from "../../cards/types";
|
import type { TileCardConfig } from "../../cards/types";
|
||||||
import {
|
import {
|
||||||
LovelaceTileExtraConfig,
|
LovelaceTileFeatureConfig,
|
||||||
LovelaceTileExtraContext,
|
LovelaceTileFeatureContext,
|
||||||
} from "../../tile-extra/types";
|
} from "../../tile-features/types";
|
||||||
import type { LovelaceCardEditor } from "../../types";
|
import type { LovelaceCardEditor } from "../../types";
|
||||||
import "../hui-sub-element-editor";
|
import "../hui-sub-element-editor";
|
||||||
import { actionConfigStruct } from "../structs/action-struct";
|
import { actionConfigStruct } from "../structs/action-struct";
|
||||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||||
import { EditSubElementEvent, SubElementEditorConfig } from "../types";
|
import { EditSubElementEvent, SubElementEditorConfig } from "../types";
|
||||||
import { configElementStyle } from "./config-elements-style";
|
import { configElementStyle } from "./config-elements-style";
|
||||||
import "./hui-tile-card-extras-editor";
|
import "./hui-tile-card-features-editor";
|
||||||
|
|
||||||
const cardConfigStruct = assign(
|
const cardConfigStruct = assign(
|
||||||
baseLovelaceCardConfig,
|
baseLovelaceCardConfig,
|
||||||
@ -42,7 +42,7 @@ const cardConfigStruct = assign(
|
|||||||
show_entity_picture: optional(boolean()),
|
show_entity_picture: optional(boolean()),
|
||||||
tap_action: optional(actionConfigStruct),
|
tap_action: optional(actionConfigStruct),
|
||||||
icon_tap_action: optional(actionConfigStruct),
|
icon_tap_action: optional(actionConfigStruct),
|
||||||
extras: optional(array(any())),
|
features: optional(array(any())),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ export class HuiTileCardEditor
|
|||||||
);
|
);
|
||||||
|
|
||||||
private _context = memoizeOne(
|
private _context = memoizeOne(
|
||||||
(entity_id?: string): LovelaceTileExtraContext => ({ entity_id })
|
(entity_id?: string): LovelaceTileFeatureContext => ({ entity_id })
|
||||||
);
|
);
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@ -172,13 +172,13 @@ export class HuiTileCardEditor
|
|||||||
.computeLabel=${this._computeLabelCallback}
|
.computeLabel=${this._computeLabelCallback}
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
></ha-form>
|
></ha-form>
|
||||||
<hui-tile-card-extras-editor
|
<hui-tile-card-features-editor
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.stateObj=${stateObj}
|
.stateObj=${stateObj}
|
||||||
.extras=${this._config!.extras ?? []}
|
.features=${this._config!.features ?? []}
|
||||||
@extras-changed=${this._extrasChanged}
|
@features-changed=${this._featuresChanged}
|
||||||
@edit-detail-element=${this._editDetailElement}
|
@edit-detail-element=${this._editDetailElement}
|
||||||
></hui-tile-card-extras-editor>
|
></hui-tile-card-features-editor>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,26 +189,26 @@ export class HuiTileCardEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config: TileCardConfig = {
|
const config: TileCardConfig = {
|
||||||
extras: this._config.extras,
|
features: this._config.features,
|
||||||
...ev.detail.value,
|
...ev.detail.value,
|
||||||
};
|
};
|
||||||
fireEvent(this, "config-changed", { config });
|
fireEvent(this, "config-changed", { config });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _extrasChanged(ev: CustomEvent) {
|
private _featuresChanged(ev: CustomEvent) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
if (!this._config || !this.hass) {
|
if (!this._config || !this.hass) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const extras = ev.detail.extras as LovelaceTileExtraConfig[];
|
const features = ev.detail.features as LovelaceTileFeatureConfig[];
|
||||||
const config: TileCardConfig = {
|
const config: TileCardConfig = {
|
||||||
...this._config,
|
...this._config,
|
||||||
extras,
|
features,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (extras.length === 0) {
|
if (features.length === 0) {
|
||||||
delete config.extras;
|
delete config.features;
|
||||||
}
|
}
|
||||||
|
|
||||||
fireEvent(this, "config-changed", { config });
|
fireEvent(this, "config-changed", { config });
|
||||||
@ -222,18 +222,18 @@ export class HuiTileCardEditor
|
|||||||
|
|
||||||
const value = ev.detail.config;
|
const value = ev.detail.config;
|
||||||
|
|
||||||
const newConfigExtras = this._config!.extras
|
const newConfigFeatures = this._config!.features
|
||||||
? [...this._config!.extras]
|
? [...this._config!.features]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
newConfigExtras.splice(this._subElementEditorConfig!.index!, 1);
|
newConfigFeatures.splice(this._subElementEditorConfig!.index!, 1);
|
||||||
this._goBack();
|
this._goBack();
|
||||||
} else {
|
} else {
|
||||||
newConfigExtras[this._subElementEditorConfig!.index!] = value;
|
newConfigFeatures[this._subElementEditorConfig!.index!] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._config = { ...this._config!, extras: newConfigExtras };
|
this._config = { ...this._config!, features: newConfigFeatures };
|
||||||
|
|
||||||
this._subElementEditorConfig = {
|
this._subElementEditorConfig = {
|
||||||
...this._subElementEditorConfig!,
|
...this._subElementEditorConfig!,
|
||||||
|
@ -22,14 +22,14 @@ import {
|
|||||||
SortableInstance,
|
SortableInstance,
|
||||||
} from "../../../../resources/sortable.ondemand";
|
} from "../../../../resources/sortable.ondemand";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
import { getTileExtraElementClass } from "../../create-element/create-tile-extra-element";
|
import { getTileFeatureElementClass } from "../../create-element/create-tile-feature-element";
|
||||||
import {
|
import {
|
||||||
isTileExtraEditable,
|
isTileFeatureEditable,
|
||||||
supportsTileExtra,
|
supportsTileFeature,
|
||||||
} from "../../tile-extra/tile-extras";
|
} from "../../tile-features/tile-features";
|
||||||
import { LovelaceTileExtraConfig } from "../../tile-extra/types";
|
import { LovelaceTileFeatureConfig } from "../../tile-features/types";
|
||||||
|
|
||||||
const EXTRAS_TYPE: LovelaceTileExtraConfig["type"][] = [
|
const FEATURES_TYPE: LovelaceTileFeatureConfig["type"][] = [
|
||||||
"cover-open-close",
|
"cover-open-close",
|
||||||
"cover-tilt",
|
"cover-tilt",
|
||||||
"light-brightness",
|
"light-brightness",
|
||||||
@ -38,24 +38,24 @@ const EXTRAS_TYPE: LovelaceTileExtraConfig["type"][] = [
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HASSDomEvents {
|
interface HASSDomEvents {
|
||||||
"extras-changed": {
|
"features-changed": {
|
||||||
extras: LovelaceTileExtraConfig[];
|
features: LovelaceTileFeatureConfig[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("hui-tile-card-extras-editor")
|
@customElement("hui-tile-card-features-editor")
|
||||||
export class HuiTileCardExtrasEditor extends LitElement {
|
export class HuiTileCardFeaturesEditor extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public stateObj?: HassEntity;
|
@property({ attribute: false }) public stateObj?: HassEntity;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public extras?: LovelaceTileExtraConfig[];
|
public features?: LovelaceTileFeatureConfig[];
|
||||||
|
|
||||||
@property() public label?: string;
|
@property() public label?: string;
|
||||||
|
|
||||||
private _extraKeys = new WeakMap<LovelaceTileExtraConfig, string>();
|
private _featuresKeys = new WeakMap<LovelaceTileFeatureConfig, string>();
|
||||||
|
|
||||||
private _sortable?: SortableInstance;
|
private _sortable?: SortableInstance;
|
||||||
|
|
||||||
@ -63,24 +63,24 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||||||
this._destroySortable();
|
this._destroySortable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getKey(extra: LovelaceTileExtraConfig) {
|
private _getKey(feature: LovelaceTileFeatureConfig) {
|
||||||
if (!this._extraKeys.has(extra)) {
|
if (!this._featuresKeys.has(feature)) {
|
||||||
this._extraKeys.set(extra, Math.random().toString());
|
this._featuresKeys.set(feature, Math.random().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._extraKeys.get(extra)!;
|
return this._featuresKeys.get(feature)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _supportedExtraTypes() {
|
private get _supportedFeatureTypes() {
|
||||||
if (!this.stateObj) return [];
|
if (!this.stateObj) return [];
|
||||||
|
|
||||||
return EXTRAS_TYPE.filter((type) =>
|
return FEATURES_TYPE.filter((type) =>
|
||||||
supportsTileExtra(this.stateObj!, type)
|
supportsTileFeature(this.stateObj!, type)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.extras || !this.hass) {
|
if (!this.features || !this.hass) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,93 +89,94 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||||||
<h3 slot="header">
|
<h3 slot="header">
|
||||||
<ha-svg-icon .path=${mdiListBox}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiListBox}></ha-svg-icon>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.lovelace.editor.card.tile.extras.name"
|
"ui.panel.lovelace.editor.card.tile.features.name"
|
||||||
)}
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${this._supportedExtraTypes.length === 0 && this.extras.length === 0
|
${this._supportedFeatureTypes.length === 0 &&
|
||||||
|
this.features.length === 0
|
||||||
? html`
|
? html`
|
||||||
<ha-alert type="info">
|
<ha-alert type="info">
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.lovelace.editor.card.tile.extras.no_compatible_available"
|
"ui.panel.lovelace.editor.card.tile.features.no_compatible_available"
|
||||||
)}
|
)}
|
||||||
</ha-alert>
|
</ha-alert>
|
||||||
`
|
`
|
||||||
: null}
|
: null}
|
||||||
<div class="extras">
|
<div class="features">
|
||||||
${repeat(
|
${repeat(
|
||||||
this.extras,
|
this.features,
|
||||||
(extraConf) => this._getKey(extraConf),
|
(featureConf) => this._getKey(featureConf),
|
||||||
(extraConf, index) => html`
|
(featureConf, index) => html`
|
||||||
<div class="extra">
|
<div class="feature">
|
||||||
<div class="handle">
|
<div class="handle">
|
||||||
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDrag}></ha-svg-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="extra-content">
|
<div class="feature-content">
|
||||||
<div>
|
<div>
|
||||||
<span>
|
<span>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.tile.extras.types.${extraConf.type}.label`
|
`ui.panel.lovelace.editor.card.tile.features.types.${featureConf.type}.label`
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
${this.stateObj &&
|
${this.stateObj &&
|
||||||
!supportsTileExtra(this.stateObj, extraConf.type)
|
!supportsTileFeature(this.stateObj, featureConf.type)
|
||||||
? html`<span class="secondary">
|
? html`<span class="secondary">
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.lovelace.editor.card.tile.extras.not_compatible"
|
"ui.panel.lovelace.editor.card.tile.features.not_compatible"
|
||||||
)}
|
)}
|
||||||
</span>`
|
</span>`
|
||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${isTileExtraEditable(extraConf.type)
|
${isTileFeatureEditable(featureConf.type)
|
||||||
? html`<ha-icon-button
|
? html`<ha-icon-button
|
||||||
.label=${this.hass!.localize(
|
.label=${this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.tile.extras.edit`
|
`ui.panel.lovelace.editor.card.tile.features.edit`
|
||||||
)}
|
)}
|
||||||
.path=${mdiPencil}
|
.path=${mdiPencil}
|
||||||
class="edit-icon"
|
class="edit-icon"
|
||||||
.index=${index}
|
.index=${index}
|
||||||
@click=${this._editExtra}
|
@click=${this._editFeature}
|
||||||
></ha-icon-button>`
|
></ha-icon-button>`
|
||||||
: null}
|
: null}
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
.label=${this.hass!.localize(
|
.label=${this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.tile.extras.remove`
|
`ui.panel.lovelace.editor.card.tile.features.remove`
|
||||||
)}
|
)}
|
||||||
.path=${mdiDelete}
|
.path=${mdiDelete}
|
||||||
class="remove-icon"
|
class="remove-icon"
|
||||||
.index=${index}
|
.index=${index}
|
||||||
@click=${this._removeExtra}
|
@click=${this._removeFeature}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
${this._supportedExtraTypes.length > 0
|
${this._supportedFeatureTypes.length > 0
|
||||||
? html`
|
? html`
|
||||||
<ha-button-menu
|
<ha-button-menu
|
||||||
fixed
|
fixed
|
||||||
@action=${this._addExtra}
|
@action=${this._addFeature}
|
||||||
@closed=${stopPropagation}
|
@closed=${stopPropagation}
|
||||||
>
|
>
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
outlined
|
outlined
|
||||||
.label=${this.hass!.localize(
|
.label=${this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.tile.extras.add`
|
`ui.panel.lovelace.editor.card.tile.features.add`
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
${this._supportedExtraTypes.map(
|
${this._supportedFeatureTypes.map(
|
||||||
(extraType) => html`<mwc-list-item .value=${extraType}>
|
(featureType) => html`<mwc-list-item .value=${featureType}>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
slot="graphic"
|
slot="graphic"
|
||||||
.path=${mdiWindowShutter}
|
.path=${mdiWindowShutter}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.tile.extras.types.${extraType}.label`
|
`ui.panel.lovelace.editor.card.tile.features.types.${featureType}.label`
|
||||||
)}
|
)}
|
||||||
</mwc-list-item>`
|
</mwc-list-item>`
|
||||||
)}
|
)}
|
||||||
@ -193,24 +194,27 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||||||
|
|
||||||
private async _createSortable() {
|
private async _createSortable() {
|
||||||
const Sortable = await loadSortable();
|
const Sortable = await loadSortable();
|
||||||
this._sortable = new Sortable(this.shadowRoot!.querySelector(".extras")!, {
|
this._sortable = new Sortable(
|
||||||
animation: 150,
|
this.shadowRoot!.querySelector(".features")!,
|
||||||
fallbackClass: "sortable-fallback",
|
{
|
||||||
handle: ".handle",
|
animation: 150,
|
||||||
onChoose: (evt: SortableEvent) => {
|
fallbackClass: "sortable-fallback",
|
||||||
(evt.item as any).placeholder =
|
handle: ".handle",
|
||||||
document.createComment("sort-placeholder");
|
onChoose: (evt: SortableEvent) => {
|
||||||
evt.item.after((evt.item as any).placeholder);
|
(evt.item as any).placeholder =
|
||||||
},
|
document.createComment("sort-placeholder");
|
||||||
onEnd: (evt: SortableEvent) => {
|
evt.item.after((evt.item as any).placeholder);
|
||||||
// put back in original location
|
},
|
||||||
if ((evt.item as any).placeholder) {
|
onEnd: (evt: SortableEvent) => {
|
||||||
(evt.item as any).placeholder.replaceWith(evt.item);
|
// put back in original location
|
||||||
delete (evt.item as any).placeholder;
|
if ((evt.item as any).placeholder) {
|
||||||
}
|
(evt.item as any).placeholder.replaceWith(evt.item);
|
||||||
this._rowMoved(evt);
|
delete (evt.item as any).placeholder;
|
||||||
},
|
}
|
||||||
});
|
this._rowMoved(evt);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _destroySortable() {
|
private _destroySortable() {
|
||||||
@ -218,22 +222,22 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||||||
this._sortable = undefined;
|
this._sortable = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _addExtra(ev: CustomEvent): Promise<void> {
|
private async _addFeature(ev: CustomEvent): Promise<void> {
|
||||||
const index = ev.detail.index as number;
|
const index = ev.detail.index as number;
|
||||||
|
|
||||||
if (index == null) return;
|
if (index == null) return;
|
||||||
|
|
||||||
const value = this._supportedExtraTypes[index];
|
const value = this._supportedFeatureTypes[index];
|
||||||
const elClass = await getTileExtraElementClass(value);
|
const elClass = await getTileFeatureElementClass(value);
|
||||||
|
|
||||||
let newExtra: LovelaceTileExtraConfig;
|
let newFeature: LovelaceTileFeatureConfig;
|
||||||
if (elClass && elClass.getStubConfig) {
|
if (elClass && elClass.getStubConfig) {
|
||||||
newExtra = await elClass.getStubConfig(this.hass!, this.stateObj);
|
newFeature = await elClass.getStubConfig(this.hass!, this.stateObj);
|
||||||
} else {
|
} else {
|
||||||
newExtra = { type: value } as LovelaceTileExtraConfig;
|
newFeature = { type: value } as LovelaceTileFeatureConfig;
|
||||||
}
|
}
|
||||||
const newConfigExtra = this.extras!.concat(newExtra);
|
const newConfigFeature = this.features!.concat(newFeature);
|
||||||
fireEvent(this, "extras-changed", { extras: newConfigExtra });
|
fireEvent(this, "features-changed", { features: newConfigFeature });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _rowMoved(ev: SortableEvent): void {
|
private _rowMoved(ev: SortableEvent): void {
|
||||||
@ -241,29 +245,29 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newExtras = this.extras!.concat();
|
const newFeatures = this.features!.concat();
|
||||||
|
|
||||||
newExtras.splice(ev.newIndex!, 0, newExtras.splice(ev.oldIndex!, 1)[0]);
|
newFeatures.splice(ev.newIndex!, 0, newFeatures.splice(ev.oldIndex!, 1)[0]);
|
||||||
|
|
||||||
fireEvent(this, "extras-changed", { extras: newExtras });
|
fireEvent(this, "features-changed", { features: newFeatures });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _removeExtra(ev: CustomEvent): void {
|
private _removeFeature(ev: CustomEvent): void {
|
||||||
const index = (ev.currentTarget as any).index;
|
const index = (ev.currentTarget as any).index;
|
||||||
const newExtras = this.extras!.concat();
|
const newfeatures = this.features!.concat();
|
||||||
|
|
||||||
newExtras.splice(index, 1);
|
newfeatures.splice(index, 1);
|
||||||
|
|
||||||
fireEvent(this, "extras-changed", { extras: newExtras });
|
fireEvent(this, "features-changed", { features: newfeatures });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _editExtra(ev: CustomEvent): void {
|
private _editFeature(ev: CustomEvent): void {
|
||||||
const index = (ev.currentTarget as any).index;
|
const index = (ev.currentTarget as any).index;
|
||||||
fireEvent(this, "edit-detail-element", {
|
fireEvent(this, "edit-detail-element", {
|
||||||
subElementConfig: {
|
subElementConfig: {
|
||||||
index,
|
index,
|
||||||
type: "tile-extra",
|
type: "tile-feature",
|
||||||
elementConfig: this.extras![index],
|
elementConfig: this.features![index],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -296,22 +300,22 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||||||
ha-button-menu {
|
ha-button-menu {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.extra {
|
.feature {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.extra .handle {
|
.feature .handle {
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
cursor: move;
|
cursor: move;
|
||||||
padding-inline-end: 8px;
|
padding-inline-end: 8px;
|
||||||
padding-inline-start: initial;
|
padding-inline-start: initial;
|
||||||
direction: var(--direction);
|
direction: var(--direction);
|
||||||
}
|
}
|
||||||
.extra .handle > * {
|
.feature .handle > * {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extra-content {
|
.feature-content {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -320,7 +324,7 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.extra-content div {
|
.feature-content div {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@ -342,6 +346,6 @@ export class HuiTileCardExtrasEditor extends LitElement {
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hui-tile-card-extras-editor": HuiTileCardExtrasEditor;
|
"hui-tile-card-features-editor": HuiTileCardFeaturesEditor;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,26 +6,26 @@ import { fireEvent } from "../../../../common/dom/fire_event";
|
|||||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||||
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
import type { SchemaUnion } from "../../../../components/ha-form/types";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import { supportsVacuumCommand } from "../../tile-extra/hui-vacuum-commands-tile-extra";
|
import { supportsVacuumCommand } from "../../tile-features/hui-vacuum-commands-tile-feature";
|
||||||
import {
|
import {
|
||||||
LovelaceTileExtraContext,
|
LovelaceTileFeatureContext,
|
||||||
VacuumCommandsTileExtraConfig,
|
VacuumCommandsTileFeatureConfig,
|
||||||
VACUUM_COMMANDS,
|
VACUUM_COMMANDS,
|
||||||
} from "../../tile-extra/types";
|
} from "../../tile-features/types";
|
||||||
import type { LovelaceTileExtraEditor } from "../../types";
|
import type { LovelaceTileFeatureEditor } from "../../types";
|
||||||
|
|
||||||
@customElement("hui-vacuum-commands-tile-extra-editor")
|
@customElement("hui-vacuum-commands-tile-feature-editor")
|
||||||
export class HuiVacuumCommandsTileExtraEditor
|
export class HuiVacuumCommandsTileFeatureEditor
|
||||||
extends LitElement
|
extends LitElement
|
||||||
implements LovelaceTileExtraEditor
|
implements LovelaceTileFeatureEditor
|
||||||
{
|
{
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public context?: LovelaceTileExtraContext;
|
@property({ attribute: false }) public context?: LovelaceTileFeatureContext;
|
||||||
|
|
||||||
@state() private _config?: VacuumCommandsTileExtraConfig;
|
@state() private _config?: VacuumCommandsTileFeatureConfig;
|
||||||
|
|
||||||
public setConfig(config: VacuumCommandsTileExtraConfig): void {
|
public setConfig(config: VacuumCommandsTileFeatureConfig): void {
|
||||||
this._config = config;
|
this._config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ export class HuiVacuumCommandsTileExtraEditor
|
|||||||
).map((command) => ({
|
).map((command) => ({
|
||||||
value: command,
|
value: command,
|
||||||
label: `${localize(
|
label: `${localize(
|
||||||
`ui.panel.lovelace.editor.card.tile.extras.types.vacuum-commands.commands_list.${command}`
|
`ui.panel.lovelace.editor.card.tile.features.types.vacuum-commands.commands_list.${command}`
|
||||||
)}`,
|
)}`,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
@ -84,7 +84,7 @@ export class HuiVacuumCommandsTileExtraEditor
|
|||||||
switch (schema.name) {
|
switch (schema.name) {
|
||||||
case "commands":
|
case "commands":
|
||||||
return this.hass!.localize(
|
return this.hass!.localize(
|
||||||
`ui.panel.lovelace.editor.card.tile.extras.types.vacuum-commands.${schema.name}`
|
`ui.panel.lovelace.editor.card.tile.features.types.vacuum-commands.${schema.name}`
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return this.hass!.localize(
|
return this.hass!.localize(
|
||||||
@ -96,6 +96,6 @@ export class HuiVacuumCommandsTileExtraEditor
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hui-vacuum-commands-tile-extra-editor": HuiVacuumCommandsTileExtraEditor;
|
"hui-vacuum-commands-tile-feature-editor": HuiVacuumCommandsTileFeatureEditor;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,14 +27,14 @@ import type { LovelaceGenericElementEditor } from "../types";
|
|||||||
import "./config-elements/hui-generic-entity-row-editor";
|
import "./config-elements/hui-generic-entity-row-editor";
|
||||||
import { GUISupportError } from "./gui-support-error";
|
import { GUISupportError } from "./gui-support-error";
|
||||||
import { EditSubElementEvent, GUIModeChangedEvent } from "./types";
|
import { EditSubElementEvent, GUIModeChangedEvent } from "./types";
|
||||||
import { LovelaceTileExtraConfig } from "../tile-extra/types";
|
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||||
|
|
||||||
export interface ConfigChangedEvent {
|
export interface ConfigChangedEvent {
|
||||||
config:
|
config:
|
||||||
| LovelaceCardConfig
|
| LovelaceCardConfig
|
||||||
| LovelaceRowConfig
|
| LovelaceRowConfig
|
||||||
| LovelaceHeaderFooterConfig
|
| LovelaceHeaderFooterConfig
|
||||||
| LovelaceTileExtraConfig;
|
| LovelaceTileFeatureConfig;
|
||||||
error?: string;
|
error?: string;
|
||||||
guiModeAvailable?: boolean;
|
guiModeAvailable?: boolean;
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ export interface UIConfigChangedEvent extends Event {
|
|||||||
| LovelaceCardConfig
|
| LovelaceCardConfig
|
||||||
| LovelaceRowConfig
|
| LovelaceRowConfig
|
||||||
| LovelaceHeaderFooterConfig
|
| LovelaceHeaderFooterConfig
|
||||||
| LovelaceTileExtraConfig;
|
| LovelaceTileFeatureConfig;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import type { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
|||||||
import "./entity-row-editor/hui-row-element-editor";
|
import "./entity-row-editor/hui-row-element-editor";
|
||||||
import "./header-footer-editor/hui-header-footer-element-editor";
|
import "./header-footer-editor/hui-header-footer-element-editor";
|
||||||
import type { HuiElementEditor } from "./hui-element-editor";
|
import type { HuiElementEditor } from "./hui-element-editor";
|
||||||
import "./tile-extra/hui-tile-extra-element-editor";
|
import "./tile-feature-editor/hui-tile-feature-element-editor";
|
||||||
import type { GUIModeChangedEvent, SubElementEditorConfig } from "./types";
|
import type { GUIModeChangedEvent, SubElementEditorConfig } from "./types";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -84,16 +84,16 @@ export class HuiSubElementEditor extends LitElement {
|
|||||||
@GUImode-changed=${this._handleGUIModeChanged}
|
@GUImode-changed=${this._handleGUIModeChanged}
|
||||||
></hui-headerfooter-element-editor>
|
></hui-headerfooter-element-editor>
|
||||||
`
|
`
|
||||||
: this.config.type === "tile-extra"
|
: this.config.type === "tile-feature"
|
||||||
? html`
|
? html`
|
||||||
<hui-tile-extra-element-editor
|
<hui-tile-feature-element-editor
|
||||||
class="editor"
|
class="editor"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.value=${this.config.elementConfig}
|
.value=${this.config.elementConfig}
|
||||||
.context=${this.context}
|
.context=${this.context}
|
||||||
@config-changed=${this._handleConfigChanged}
|
@config-changed=${this._handleConfigChanged}
|
||||||
@GUImode-changed=${this._handleGUIModeChanged}
|
@GUImode-changed=${this._handleGUIModeChanged}
|
||||||
></hui-tile-extra-element-editor>
|
></hui-tile-feature-element-editor>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
`;
|
`;
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
import { customElement } from "lit/decorators";
|
|
||||||
import { getTileExtraElementClass } from "../../create-element/create-tile-extra-element";
|
|
||||||
import {
|
|
||||||
LovelaceTileExtraConfig,
|
|
||||||
LovelaceTileExtraContext,
|
|
||||||
} from "../../tile-extra/types";
|
|
||||||
import type { LovelaceTileExtraEditor } from "../../types";
|
|
||||||
import { HuiElementEditor } from "../hui-element-editor";
|
|
||||||
|
|
||||||
@customElement("hui-tile-extra-element-editor")
|
|
||||||
export class HuiTileExtraElementEditor extends HuiElementEditor<
|
|
||||||
LovelaceTileExtraConfig,
|
|
||||||
LovelaceTileExtraContext
|
|
||||||
> {
|
|
||||||
protected async getConfigElement(): Promise<
|
|
||||||
LovelaceTileExtraEditor | undefined
|
|
||||||
> {
|
|
||||||
const elClass = await getTileExtraElementClass(this.configElementType!);
|
|
||||||
|
|
||||||
// Check if a GUI editor exists
|
|
||||||
if (elClass && elClass.getConfigElement) {
|
|
||||||
return elClass.getConfigElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"hui-tile-extra-element-editor": HuiTileExtraElementEditor;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,33 @@
|
|||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import { getTileFeatureElementClass } from "../../create-element/create-tile-feature-element";
|
||||||
|
import {
|
||||||
|
LovelaceTileFeatureConfig,
|
||||||
|
LovelaceTileFeatureContext,
|
||||||
|
} from "../../tile-features/types";
|
||||||
|
import type { LovelaceTileFeatureEditor } from "../../types";
|
||||||
|
import { HuiElementEditor } from "../hui-element-editor";
|
||||||
|
|
||||||
|
@customElement("hui-tile-feature-element-editor")
|
||||||
|
export class HuiTileFeatureElementEditor extends HuiElementEditor<
|
||||||
|
LovelaceTileFeatureConfig,
|
||||||
|
LovelaceTileFeatureContext
|
||||||
|
> {
|
||||||
|
protected async getConfigElement(): Promise<
|
||||||
|
LovelaceTileFeatureEditor | undefined
|
||||||
|
> {
|
||||||
|
const elClass = await getTileFeatureElementClass(this.configElementType!);
|
||||||
|
|
||||||
|
// Check if a GUI editor exists
|
||||||
|
if (elClass && elClass.getConfigElement) {
|
||||||
|
return elClass.getConfigElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-tile-feature-element-editor": HuiTileFeatureElementEditor;
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ import {
|
|||||||
} from "../../../data/lovelace";
|
} from "../../../data/lovelace";
|
||||||
import { EntityConfig, LovelaceRowConfig } from "../entity-rows/types";
|
import { EntityConfig, LovelaceRowConfig } from "../entity-rows/types";
|
||||||
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
import { LovelaceHeaderFooterConfig } from "../header-footer/types";
|
||||||
import { LovelaceTileExtraConfig } from "../tile-extra/types";
|
import { LovelaceTileFeatureConfig } from "../tile-features/types";
|
||||||
|
|
||||||
export interface YamlChangedEvent extends Event {
|
export interface YamlChangedEvent extends Event {
|
||||||
detail: {
|
detail: {
|
||||||
@ -78,8 +78,8 @@ export interface SubElementEditorConfig {
|
|||||||
elementConfig?:
|
elementConfig?:
|
||||||
| LovelaceRowConfig
|
| LovelaceRowConfig
|
||||||
| LovelaceHeaderFooterConfig
|
| LovelaceHeaderFooterConfig
|
||||||
| LovelaceTileExtraConfig;
|
| LovelaceTileFeatureConfig;
|
||||||
type: "header" | "footer" | "row" | "tile-extra";
|
type: "header" | "footer" | "row" | "tile-feature";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EditSubElementEvent {
|
export interface EditSubElementEvent {
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
export interface CoverOpenCloseTileExtraConfig {
|
|
||||||
type: "cover-open-close";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CoverTiltTileExtraConfig {
|
|
||||||
type: "cover-tilt";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LightBrightnessTileExtraConfig {
|
|
||||||
type: "light-brightness";
|
|
||||||
}
|
|
||||||
|
|
||||||
export const VACUUM_COMMANDS = [
|
|
||||||
"start_pause",
|
|
||||||
"stop",
|
|
||||||
"clean_spot",
|
|
||||||
"locate",
|
|
||||||
"return_home",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export type VacuumCommand = typeof VACUUM_COMMANDS[number];
|
|
||||||
|
|
||||||
export interface VacuumCommandsTileExtraConfig {
|
|
||||||
type: "vacuum-commands";
|
|
||||||
commands?: VacuumCommand[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LovelaceTileExtraConfig =
|
|
||||||
| CoverOpenCloseTileExtraConfig
|
|
||||||
| CoverTiltTileExtraConfig
|
|
||||||
| LightBrightnessTileExtraConfig
|
|
||||||
| VacuumCommandsTileExtraConfig;
|
|
||||||
|
|
||||||
export type LovelaceTileExtraContext = {
|
|
||||||
entity_id?: string;
|
|
||||||
};
|
|
@ -15,27 +15,27 @@ import {
|
|||||||
CoverEntityFeature,
|
CoverEntityFeature,
|
||||||
} from "../../../data/cover";
|
} from "../../../data/cover";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { LovelaceTileExtra } from "../types";
|
import { LovelaceTileFeature } from "../types";
|
||||||
import { CoverOpenCloseTileExtraConfig } from "./types";
|
import { CoverOpenCloseTileFeatureConfig } from "./types";
|
||||||
|
|
||||||
@customElement("hui-cover-open-close-tile-extra")
|
@customElement("hui-cover-open-close-tile-feature")
|
||||||
class HuiCoverOpenCloseTileExtra
|
class HuiCoverOpenCloseTileFeature
|
||||||
extends LitElement
|
extends LitElement
|
||||||
implements LovelaceTileExtra
|
implements LovelaceTileFeature
|
||||||
{
|
{
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public stateObj?: HassEntity;
|
@property({ attribute: false }) public stateObj?: HassEntity;
|
||||||
|
|
||||||
@state() private _config?: CoverOpenCloseTileExtraConfig;
|
@state() private _config?: CoverOpenCloseTileFeatureConfig;
|
||||||
|
|
||||||
static getStubConfig(): CoverOpenCloseTileExtraConfig {
|
static getStubConfig(): CoverOpenCloseTileFeatureConfig {
|
||||||
return {
|
return {
|
||||||
type: "cover-open-close",
|
type: "cover-open-close",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(config: CoverOpenCloseTileExtraConfig): void {
|
public setConfig(config: CoverOpenCloseTileFeatureConfig): void {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Invalid configuration");
|
throw new Error("Invalid configuration");
|
||||||
}
|
}
|
||||||
@ -138,6 +138,6 @@ class HuiCoverOpenCloseTileExtra
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hui-cover-open-close-tile-extra": HuiCoverOpenCloseTileExtra;
|
"hui-cover-open-close-tile-feature": HuiCoverOpenCloseTileFeature;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,24 +11,27 @@ import {
|
|||||||
CoverEntityFeature,
|
CoverEntityFeature,
|
||||||
} from "../../../data/cover";
|
} from "../../../data/cover";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { LovelaceTileExtra } from "../types";
|
import { LovelaceTileFeature } from "../types";
|
||||||
import { CoverTiltTileExtraConfig } from "./types";
|
import { CoverTiltTileFeatureConfig } from "./types";
|
||||||
|
|
||||||
@customElement("hui-cover-tilt-tile-extra")
|
@customElement("hui-cover-tilt-tile-feature")
|
||||||
class HuiCoverTiltTileExtra extends LitElement implements LovelaceTileExtra {
|
class HuiCoverTiltTileFeature
|
||||||
|
extends LitElement
|
||||||
|
implements LovelaceTileFeature
|
||||||
|
{
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public stateObj?: HassEntity;
|
@property({ attribute: false }) public stateObj?: HassEntity;
|
||||||
|
|
||||||
@state() private _config?: CoverTiltTileExtraConfig;
|
@state() private _config?: CoverTiltTileFeatureConfig;
|
||||||
|
|
||||||
static getStubConfig(): CoverTiltTileExtraConfig {
|
static getStubConfig(): CoverTiltTileFeatureConfig {
|
||||||
return {
|
return {
|
||||||
type: "cover-tilt",
|
type: "cover-tilt",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(config: CoverTiltTileExtraConfig): void {
|
public setConfig(config: CoverTiltTileFeatureConfig): void {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Invalid configuration");
|
throw new Error("Invalid configuration");
|
||||||
}
|
}
|
||||||
@ -127,6 +130,6 @@ class HuiCoverTiltTileExtra extends LitElement implements LovelaceTileExtra {
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hui-cover-tilt-tile-extra": HuiCoverTiltTileExtra;
|
"hui-cover-tilt-tile-feature": HuiCoverTiltTileFeature;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,27 +4,27 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import "../../../components/tile/ha-tile-slider";
|
import "../../../components/tile/ha-tile-slider";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { LovelaceTileExtra } from "../types";
|
import { LovelaceTileFeature } from "../types";
|
||||||
import { LightBrightnessTileExtraConfig } from "./types";
|
import { LightBrightnessTileFeatureConfig } from "./types";
|
||||||
|
|
||||||
@customElement("hui-light-brightness-tile-extra")
|
@customElement("hui-light-brightness-tile-feature")
|
||||||
class HuiLightBrightnessTileExtra
|
class HuiLightBrightnessTileFeature
|
||||||
extends LitElement
|
extends LitElement
|
||||||
implements LovelaceTileExtra
|
implements LovelaceTileFeature
|
||||||
{
|
{
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public stateObj?: HassEntity;
|
@property({ attribute: false }) public stateObj?: HassEntity;
|
||||||
|
|
||||||
@state() private _config?: LightBrightnessTileExtraConfig;
|
@state() private _config?: LightBrightnessTileFeatureConfig;
|
||||||
|
|
||||||
static getStubConfig(): LightBrightnessTileExtraConfig {
|
static getStubConfig(): LightBrightnessTileFeatureConfig {
|
||||||
return {
|
return {
|
||||||
type: "light-brightness",
|
type: "light-brightness",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(config: LightBrightnessTileExtraConfig): void {
|
public setConfig(config: LightBrightnessTileFeatureConfig): void {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Invalid configuration");
|
throw new Error("Invalid configuration");
|
||||||
}
|
}
|
||||||
@ -84,6 +84,6 @@ class HuiLightBrightnessTileExtra
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hui-light-brightness-tile-extra": HuiLightBrightnessTileExtra;
|
"hui-light-brightness-tile-feature": HuiLightBrightnessTileFeature;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,10 +22,10 @@ import {
|
|||||||
VacuumEntityFeature,
|
VacuumEntityFeature,
|
||||||
} from "../../../data/vacuum";
|
} from "../../../data/vacuum";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { LovelaceTileExtra, LovelaceTileExtraEditor } from "../types";
|
import { LovelaceTileFeature, LovelaceTileFeatureEditor } from "../types";
|
||||||
import {
|
import {
|
||||||
VacuumCommand,
|
VacuumCommand,
|
||||||
VacuumCommandsTileExtraConfig,
|
VacuumCommandsTileFeatureConfig,
|
||||||
VACUUM_COMMANDS,
|
VACUUM_COMMANDS,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
@ -112,21 +112,21 @@ export const VACUUM_COMMANDS_BUTTONS: Record<
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@customElement("hui-vacuum-commands-tile-extra")
|
@customElement("hui-vacuum-commands-tile-feature")
|
||||||
class HuiVacuumCommandTileExtra
|
class HuiVacuumCommandTileFeature
|
||||||
extends LitElement
|
extends LitElement
|
||||||
implements LovelaceTileExtra
|
implements LovelaceTileFeature
|
||||||
{
|
{
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public stateObj?: HassEntity;
|
@property({ attribute: false }) public stateObj?: HassEntity;
|
||||||
|
|
||||||
@state() private _config?: VacuumCommandsTileExtraConfig;
|
@state() private _config?: VacuumCommandsTileFeatureConfig;
|
||||||
|
|
||||||
static getStubConfig(
|
static getStubConfig(
|
||||||
_,
|
_,
|
||||||
stateObj?: HassEntity
|
stateObj?: HassEntity
|
||||||
): VacuumCommandsTileExtraConfig {
|
): VacuumCommandsTileFeatureConfig {
|
||||||
return {
|
return {
|
||||||
type: "vacuum-commands",
|
type: "vacuum-commands",
|
||||||
commands: stateObj
|
commands: stateObj
|
||||||
@ -137,14 +137,14 @@ class HuiVacuumCommandTileExtra
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async getConfigElement(): Promise<LovelaceTileExtraEditor> {
|
public static async getConfigElement(): Promise<LovelaceTileFeatureEditor> {
|
||||||
await import(
|
await import(
|
||||||
"../editor/config-elements/hui-vacuum-commands-tile-extra-editor"
|
"../editor/config-elements/hui-vacuum-commands-tile-feature-editor"
|
||||||
);
|
);
|
||||||
return document.createElement("hui-vacuum-commands-tile-extra-editor");
|
return document.createElement("hui-vacuum-commands-tile-feature-editor");
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(config: VacuumCommandsTileExtraConfig): void {
|
public setConfig(config: VacuumCommandsTileFeatureConfig): void {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Invalid configuration");
|
throw new Error("Invalid configuration");
|
||||||
}
|
}
|
||||||
@ -215,6 +215,6 @@ class HuiVacuumCommandTileExtra
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hui-vacuum-commands-tile-extra": HuiVacuumCommandTileExtra;
|
"hui-vacuum-commands-tile-feature": HuiVacuumCommandTileFeature;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,13 +3,13 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
|||||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
import { CoverEntityFeature } from "../../../data/cover";
|
import { CoverEntityFeature } from "../../../data/cover";
|
||||||
import { lightSupportsBrightness } from "../../../data/light";
|
import { lightSupportsBrightness } from "../../../data/light";
|
||||||
import { supportsVacuumCommand } from "./hui-vacuum-commands-tile-extra";
|
import { supportsVacuumCommand } from "./hui-vacuum-commands-tile-feature";
|
||||||
import { LovelaceTileExtraConfig, VACUUM_COMMANDS } from "./types";
|
import { LovelaceTileFeatureConfig, VACUUM_COMMANDS } from "./types";
|
||||||
|
|
||||||
type TileExtraType = LovelaceTileExtraConfig["type"];
|
type TileFeatureType = LovelaceTileFeatureConfig["type"];
|
||||||
export type SupportsTileExtra = (stateObj: HassEntity) => boolean;
|
export type SupportsTileFeature = (stateObj: HassEntity) => boolean;
|
||||||
|
|
||||||
const TILE_EXTRAS_SUPPORT: Record<TileExtraType, SupportsTileExtra> = {
|
const TILE_FEATURES_SUPPORT: Record<TileFeatureType, SupportsTileFeature> = {
|
||||||
"cover-open-close": (stateObj) =>
|
"cover-open-close": (stateObj) =>
|
||||||
computeDomain(stateObj.entity_id) === "cover" &&
|
computeDomain(stateObj.entity_id) === "cover" &&
|
||||||
(supportsFeature(stateObj, CoverEntityFeature.OPEN) ||
|
(supportsFeature(stateObj, CoverEntityFeature.OPEN) ||
|
||||||
@ -26,17 +26,19 @@ const TILE_EXTRAS_SUPPORT: Record<TileExtraType, SupportsTileExtra> = {
|
|||||||
VACUUM_COMMANDS.some((c) => supportsVacuumCommand(stateObj, c)),
|
VACUUM_COMMANDS.some((c) => supportsVacuumCommand(stateObj, c)),
|
||||||
};
|
};
|
||||||
|
|
||||||
const TILE_EXTRAS_EDITABLE: Set<TileExtraType> = new Set(["vacuum-commands"]);
|
const TILE_FEATURE_EDITABLE: Set<TileFeatureType> = new Set([
|
||||||
|
"vacuum-commands",
|
||||||
|
]);
|
||||||
|
|
||||||
export const supportsTileExtra = (
|
export const supportsTileFeature = (
|
||||||
stateObj: HassEntity,
|
stateObj: HassEntity,
|
||||||
extra: TileExtraType
|
feature: TileFeatureType
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const supportFunction = TILE_EXTRAS_SUPPORT[extra] as
|
const supportFunction = TILE_FEATURES_SUPPORT[feature] as
|
||||||
| SupportsTileExtra
|
| SupportsTileFeature
|
||||||
| undefined;
|
| undefined;
|
||||||
return !supportFunction || supportFunction(stateObj);
|
return !supportFunction || supportFunction(stateObj);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isTileExtraEditable = (extra: TileExtraType): boolean =>
|
export const isTileFeatureEditable = (feature: TileFeatureType): boolean =>
|
||||||
TILE_EXTRAS_EDITABLE.has(extra);
|
TILE_FEATURE_EDITABLE.has(feature);
|
36
src/panels/lovelace/tile-features/types.ts
Normal file
36
src/panels/lovelace/tile-features/types.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
export interface CoverOpenCloseTileFeatureConfig {
|
||||||
|
type: "cover-open-close";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CoverTiltTileFeatureConfig {
|
||||||
|
type: "cover-tilt";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LightBrightnessTileFeatureConfig {
|
||||||
|
type: "light-brightness";
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VACUUM_COMMANDS = [
|
||||||
|
"start_pause",
|
||||||
|
"stop",
|
||||||
|
"clean_spot",
|
||||||
|
"locate",
|
||||||
|
"return_home",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type VacuumCommand = typeof VACUUM_COMMANDS[number];
|
||||||
|
|
||||||
|
export interface VacuumCommandsTileFeatureConfig {
|
||||||
|
type: "vacuum-commands";
|
||||||
|
commands?: VacuumCommand[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LovelaceTileFeatureConfig =
|
||||||
|
| CoverOpenCloseTileFeatureConfig
|
||||||
|
| CoverTiltTileFeatureConfig
|
||||||
|
| LightBrightnessTileFeatureConfig
|
||||||
|
| VacuumCommandsTileFeatureConfig;
|
||||||
|
|
||||||
|
export type LovelaceTileFeatureContext = {
|
||||||
|
entity_id?: string;
|
||||||
|
};
|
@ -8,7 +8,7 @@ import { FrontendLocaleData } from "../../data/translation";
|
|||||||
import { Constructor, HomeAssistant } from "../../types";
|
import { Constructor, HomeAssistant } from "../../types";
|
||||||
import { LovelaceRow, LovelaceRowConfig } from "./entity-rows/types";
|
import { LovelaceRow, LovelaceRowConfig } from "./entity-rows/types";
|
||||||
import { LovelaceHeaderFooterConfig } from "./header-footer/types";
|
import { LovelaceHeaderFooterConfig } from "./header-footer/types";
|
||||||
import { LovelaceTileExtraConfig } from "./tile-extra/types";
|
import { LovelaceTileFeatureConfig } from "./tile-features/types";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@ -96,21 +96,22 @@ export interface LovelaceGenericElementEditor<C = any> extends HTMLElement {
|
|||||||
focusYamlEditor?: () => void;
|
focusYamlEditor?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LovelaceTileExtra extends HTMLElement {
|
export interface LovelaceTileFeature extends HTMLElement {
|
||||||
hass?: HomeAssistant;
|
hass?: HomeAssistant;
|
||||||
stateObj?: HassEntity;
|
stateObj?: HassEntity;
|
||||||
setConfig(config: LovelaceTileExtraConfig);
|
setConfig(config: LovelaceTileFeatureConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LovelaceTileExtraConstructor
|
export interface LovelaceTileFeatureConstructor
|
||||||
extends Constructor<LovelaceTileExtra> {
|
extends Constructor<LovelaceTileFeature> {
|
||||||
getConfigElement?: () => LovelaceTileExtraEditor;
|
getConfigElement?: () => LovelaceTileFeatureEditor;
|
||||||
getStubConfig?: (
|
getStubConfig?: (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
stateObj?: HassEntity
|
stateObj?: HassEntity
|
||||||
) => LovelaceTileExtraConfig;
|
) => LovelaceTileFeatureConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LovelaceTileExtraEditor extends LovelaceGenericElementEditor {
|
export interface LovelaceTileFeatureEditor
|
||||||
setConfig(config: LovelaceTileExtraConfig): void;
|
extends LovelaceGenericElementEditor {
|
||||||
|
setConfig(config: LovelaceTileFeatureConfig): void;
|
||||||
}
|
}
|
||||||
|
@ -4224,13 +4224,13 @@
|
|||||||
"appearance": "Appearance",
|
"appearance": "Appearance",
|
||||||
"default_color": "Default color (state)",
|
"default_color": "Default color (state)",
|
||||||
"show_entity_picture": "Show entity picture",
|
"show_entity_picture": "Show entity picture",
|
||||||
"extras": {
|
"features": {
|
||||||
"name": "Extras",
|
"name": "Features",
|
||||||
"not_compatible": "Not compatible",
|
"not_compatible": "Not compatible",
|
||||||
"no_compatible_available": "No compatible extras available for this entity",
|
"no_compatible_available": "No compatible features available for this entity",
|
||||||
"add": "Add extra",
|
"add": "Add feature",
|
||||||
"edit": "Edit extra",
|
"edit": "Edit feature",
|
||||||
"remove": "Remove extra",
|
"remove": "Remove feature",
|
||||||
"types": {
|
"types": {
|
||||||
"cover-open-close": {
|
"cover-open-close": {
|
||||||
"label": "Cover open/close"
|
"label": "Cover open/close"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user