mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add Text entity (#14447)
This commit is contained in:
parent
0aa2c9044a
commit
a9d44fcb61
@ -138,7 +138,7 @@ if (!window.cardTools) {
|
||||
return cardTools.createThing("row", config);
|
||||
|
||||
const domain = config.entity.split(".", 1)[0];
|
||||
Object.assign(config, { type: DEFAULT_ROWS[domain] || "text" });
|
||||
Object.assign(config, { type: DEFAULT_ROWS[domain] || "simple" });
|
||||
return cardTools.createThing("entity-row", config);
|
||||
};
|
||||
|
||||
|
@ -98,6 +98,9 @@ const ENTITIES = [
|
||||
minimum: 0,
|
||||
maximum: 10,
|
||||
}),
|
||||
getEntity("text", "message", "Hello!", {
|
||||
friendly_name: "Message",
|
||||
}),
|
||||
|
||||
getEntity("light", "unavailable", "unavailable", {
|
||||
friendly_name: "Bed Light",
|
||||
@ -129,6 +132,9 @@ const ENTITIES = [
|
||||
friendly_name: "Who cooks",
|
||||
icon: "mdi:cheff",
|
||||
}),
|
||||
getEntity("text", "unavailable", "unavailable", {
|
||||
friendly_name: "Message",
|
||||
}),
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
@ -147,6 +153,7 @@ const CONFIGS = [
|
||||
- climate.ecobee
|
||||
- input_number.number
|
||||
- sensor.humidity
|
||||
- text.message
|
||||
`,
|
||||
},
|
||||
{
|
||||
@ -219,6 +226,7 @@ const CONFIGS = [
|
||||
- climate.unavailable
|
||||
- input_number.unavailable
|
||||
- input_select.unavailable
|
||||
- text.unavailable
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
@ -114,6 +114,7 @@ export const FIXED_DOMAIN_ICONS = {
|
||||
siren: mdiBullhorn,
|
||||
simple_alarm: mdiBell,
|
||||
sun: mdiWhiteBalanceSunny,
|
||||
text: mdiFormTextbox,
|
||||
timer: mdiTimerOutline,
|
||||
updater: mdiCloudUpload,
|
||||
vacuum: mdiRobotVacuum,
|
||||
@ -182,6 +183,7 @@ export const DOMAINS_WITH_CARD = [
|
||||
"script",
|
||||
"select",
|
||||
"timer",
|
||||
"text",
|
||||
"vacuum",
|
||||
"water_heater",
|
||||
];
|
||||
@ -214,6 +216,7 @@ export const DOMAINS_INPUT_ROW = [
|
||||
"script",
|
||||
"select",
|
||||
"switch",
|
||||
"text",
|
||||
"vacuum",
|
||||
];
|
||||
|
||||
|
19
src/data/text.ts
Normal file
19
src/data/text.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import {
|
||||
HassEntityAttributeBase,
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
interface TextEntityAttributes extends HassEntityAttributeBase {
|
||||
min?: number;
|
||||
max?: number;
|
||||
pattern?: string;
|
||||
mode?: "text" | "password";
|
||||
}
|
||||
|
||||
export interface TextEntity extends HassEntityBase {
|
||||
attributes: TextEntityAttributes;
|
||||
}
|
||||
|
||||
export const setValue = (hass: HomeAssistant, entity: string, value: string) =>
|
||||
hass.callService("text", "set_value", { value }, { entity_id: entity });
|
@ -50,8 +50,9 @@ export const DOMAINS_HIDE_DEFAULT_MORE_INFO = [
|
||||
"input_text",
|
||||
"number",
|
||||
"scene",
|
||||
"update",
|
||||
"select",
|
||||
"text",
|
||||
"update",
|
||||
];
|
||||
|
||||
/** Domains that should have the history hidden in the more info dialog. */
|
||||
|
@ -2,7 +2,7 @@ import "../entity-rows/hui-media-player-entity-row";
|
||||
import "../entity-rows/hui-scene-entity-row";
|
||||
import "../entity-rows/hui-script-entity-row";
|
||||
import "../entity-rows/hui-sensor-entity-row";
|
||||
import "../entity-rows/hui-text-entity-row";
|
||||
import "../entity-rows/hui-simple-entity-row";
|
||||
import "../entity-rows/hui-toggle-entity-row";
|
||||
import { LovelaceRowConfig } from "../entity-rows/types";
|
||||
import "../special-rows/hui-attribute-row";
|
||||
@ -18,7 +18,7 @@ const ALWAYS_LOADED_TYPES = new Set([
|
||||
"scene-entity",
|
||||
"script-entity",
|
||||
"sensor-entity",
|
||||
"text-entity",
|
||||
"simple-entity",
|
||||
"toggle-entity",
|
||||
"button",
|
||||
"call-service",
|
||||
@ -41,6 +41,7 @@ const LAZY_LOAD_TYPES = {
|
||||
"lock-entity": () => import("../entity-rows/hui-lock-entity-row"),
|
||||
"number-entity": () => import("../entity-rows/hui-number-entity-row"),
|
||||
"select-entity": () => import("../entity-rows/hui-select-entity-row"),
|
||||
"text-entity": () => import("../entity-rows/hui-text-entity-row"),
|
||||
"timer-entity": () => import("../entity-rows/hui-timer-entity-row"),
|
||||
conditional: () => import("../special-rows/hui-conditional-row"),
|
||||
"weather-entity": () => import("../entity-rows/hui-weather-entity-row"),
|
||||
@ -53,7 +54,7 @@ const LAZY_LOAD_TYPES = {
|
||||
text: () => import("../special-rows/hui-text-row"),
|
||||
};
|
||||
const DOMAIN_TO_ELEMENT_TYPE = {
|
||||
_domain_not_found: "text",
|
||||
_domain_not_found: "simple",
|
||||
alert: "toggle",
|
||||
automation: "toggle",
|
||||
button: "button",
|
||||
@ -78,6 +79,7 @@ const DOMAIN_TO_ELEMENT_TYPE = {
|
||||
sensor: "sensor",
|
||||
siren: "toggle",
|
||||
switch: "toggle",
|
||||
text: "text",
|
||||
timer: "timer",
|
||||
vacuum: "toggle",
|
||||
// Temporary. Once climate is rewritten,
|
||||
|
73
src/panels/lovelace/entity-rows/hui-simple-entity-row.ts
Normal file
73
src/panels/lovelace/entity-rows/hui-simple-entity-row.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntitiesCardEntityConfig } from "../cards/types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import { LovelaceRow } from "./types";
|
||||
|
||||
@customElement("hui-simple-entity-row")
|
||||
class HuiSimpleEntityRow extends LitElement implements LovelaceRow {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@state() private _config?: EntitiesCardEntityConfig;
|
||||
|
||||
public setConfig(config: EntitiesCardEntityConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
return hasConfigOrEntityChanged(this, changedProps);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity];
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<hui-warning>
|
||||
${createEntityNotFoundWarning(this.hass, this._config.entity)}
|
||||
</hui-warning>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||
${computeStateDisplay(this.hass!.localize, stateObj, this.hass.locale)}
|
||||
</hui-generic-entity-row>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
div {
|
||||
text-align: right;
|
||||
}
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-simple-entity-row": HuiSimpleEntityRow;
|
||||
}
|
||||
}
|
@ -1,27 +1,22 @@
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { UNAVAILABLE, UNAVAILABLE_STATES } from "../../../data/entity";
|
||||
import { TextEntity, setValue } from "../../../data/text";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { EntitiesCardEntityConfig } from "../cards/types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import { LovelaceRow } from "./types";
|
||||
import { EntityConfig, LovelaceRow } from "./types";
|
||||
import "../../../components/ha-textfield";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
|
||||
@customElement("hui-text-entity-row")
|
||||
class HuiTextEntityRow extends LitElement implements LovelaceRow {
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@state() private _config?: EntitiesCardEntityConfig;
|
||||
@state() private _config?: EntityConfig;
|
||||
|
||||
public setConfig(config: EntitiesCardEntityConfig): void {
|
||||
public setConfig(config: EntityConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
@ -37,7 +32,9 @@ class HuiTextEntityRow extends LitElement implements LovelaceRow {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity];
|
||||
const stateObj = this.hass.states[this._config.entity] as
|
||||
| TextEntity
|
||||
| undefined;
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
@ -48,22 +45,53 @@ class HuiTextEntityRow extends LitElement implements LovelaceRow {
|
||||
}
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||
${computeStateDisplay(this.hass!.localize, stateObj, this.hass.locale)}
|
||||
<hui-generic-entity-row
|
||||
.hass=${this.hass}
|
||||
.config=${this._config}
|
||||
hideName
|
||||
>
|
||||
<ha-textfield
|
||||
.label=${this._config.name || computeStateName(stateObj)}
|
||||
.disabled=${stateObj.state === UNAVAILABLE}
|
||||
.value=${stateObj.state}
|
||||
.minlength=${stateObj.attributes.min}
|
||||
.maxlength=${stateObj.attributes.max}
|
||||
.autoValidate=${stateObj.attributes.pattern}
|
||||
.pattern=${stateObj.attributes.pattern}
|
||||
.type=${stateObj.attributes.mode}
|
||||
@change=${this._valueChanged}
|
||||
placeholder=${this.hass!.localize("ui.card.text.emtpy_value")}
|
||||
></ha-textfield>
|
||||
</hui-generic-entity-row>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
div {
|
||||
text-align: right;
|
||||
}
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
private _valueChanged(ev): void {
|
||||
const stateObj = this.hass!.states[this._config!.entity] as TextEntity;
|
||||
const newValue = ev.target.value;
|
||||
|
||||
// Filter out invalid text states
|
||||
if (newValue && UNAVAILABLE_STATES.includes(newValue)) {
|
||||
ev.target.value = stateObj.state;
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue !== stateObj.state) {
|
||||
setValue(this.hass!, stateObj.entity_id, newValue);
|
||||
}
|
||||
|
||||
ev.target.blur();
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
hui-generic-entity-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
ha-textfield {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -17,6 +17,7 @@ import "./state-card-number";
|
||||
import "./state-card-scene";
|
||||
import "./state-card-script";
|
||||
import "./state-card-select";
|
||||
import "./state-card-text";
|
||||
import "./state-card-timer";
|
||||
import "./state-card-toggle";
|
||||
import "./state-card-vacuum";
|
||||
|
73
src/state-summary/state-card-text.ts
Normal file
73
src/state-summary/state-card-text.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import "../components/ha-textfield";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import { stopPropagation } from "../common/dom/stop_propagation";
|
||||
import "../components/entity/state-badge";
|
||||
import { UNAVAILABLE, UNAVAILABLE_STATES } from "../data/entity";
|
||||
import { TextEntity, setValue } from "../data/text";
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
@customElement("state-card-text")
|
||||
class StateCardText extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public stateObj!: TextEntity;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<state-badge .stateObj=${this.stateObj}></state-badge>
|
||||
<ha-textfield
|
||||
.label=${computeStateName(this.stateObj)}
|
||||
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||
.value=${this.stateObj.state}
|
||||
.minlength=${this.stateObj.attributes.min}
|
||||
.maxlength=${this.stateObj.attributes.max}
|
||||
.autoValidate=${this.stateObj.attributes.pattern}
|
||||
.pattern=${this.stateObj.attributes.pattern}
|
||||
.type=${this.stateObj.attributes.mode}
|
||||
@change=${this._valueChanged}
|
||||
@click=${stopPropagation}
|
||||
placeholder=${this.hass.localize("ui.card.text.emtpy_value")}
|
||||
></ha-textfield>
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev): void {
|
||||
const value = ev.target.value;
|
||||
|
||||
// Filter out invalid text states
|
||||
if (value && UNAVAILABLE_STATES.includes(value)) {
|
||||
ev.target.value = this.stateObj.state;
|
||||
return;
|
||||
}
|
||||
|
||||
if (value === this.stateObj.state) {
|
||||
return;
|
||||
}
|
||||
setValue(this.hass!, this.stateObj.entity_id, value);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
:host {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
state-badge {
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
ha-textfield {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"state-card-text": StateCardText;
|
||||
}
|
||||
}
|
@ -235,6 +235,9 @@
|
||||
"installing_with_progress": "Installing ({progress}%)",
|
||||
"up_to_date": "Up-to-date"
|
||||
},
|
||||
"text": {
|
||||
"emtpy_value": "(empty value)"
|
||||
},
|
||||
"timer": {
|
||||
"actions": {
|
||||
"start": "start",
|
||||
|
Loading…
x
Reference in New Issue
Block a user