mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Make time inputs the same through the UI (#9766)
This commit is contained in:
parent
19e4c0657a
commit
5dad18c85f
31
src/common/datetime/create_duration_data.ts
Normal file
31
src/common/datetime/create_duration_data.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { HaDurationData } from "../../components/ha-duration-input";
|
||||
import { ForDict } from "../../data/automation";
|
||||
|
||||
export const createDurationData = (
|
||||
duration: string | number | ForDict | undefined
|
||||
): HaDurationData => {
|
||||
if (duration === undefined) {
|
||||
return {};
|
||||
}
|
||||
if (typeof duration !== "object") {
|
||||
if (typeof duration === "string" || isNaN(duration)) {
|
||||
const parts = duration?.toString().split(":") || [];
|
||||
return {
|
||||
hours: Number(parts[0]) || 0,
|
||||
minutes: Number(parts[1]) || 0,
|
||||
seconds: Number(parts[2]) || 0,
|
||||
milliseconds: Number(parts[3]) || 0,
|
||||
};
|
||||
}
|
||||
return { seconds: duration };
|
||||
}
|
||||
const { days, minutes, seconds, milliseconds } = duration;
|
||||
let hours = duration.hours || 0;
|
||||
hours = (hours || 0) + (days || 0) * 24;
|
||||
return {
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
milliseconds,
|
||||
};
|
||||
};
|
140
src/components/ha-duration-input.ts
Normal file
140
src/components/ha-duration-input.ts
Normal file
@ -0,0 +1,140 @@
|
||||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import "./paper-time-input";
|
||||
|
||||
export interface HaDurationData {
|
||||
hours?: number;
|
||||
minutes?: number;
|
||||
seconds?: number;
|
||||
milliseconds?: number;
|
||||
}
|
||||
|
||||
@customElement("ha-duration-input")
|
||||
class HaDurationInput extends LitElement {
|
||||
@property({ attribute: false }) public data!: HaDurationData;
|
||||
|
||||
@property() public label?: string;
|
||||
|
||||
@property() public suffix?: string;
|
||||
|
||||
@property({ type: Boolean }) public required?: boolean;
|
||||
|
||||
@property({ type: Boolean }) public enableMillisecond?: boolean;
|
||||
|
||||
@query("paper-time-input", true) private _input?: HTMLElement;
|
||||
|
||||
public focus() {
|
||||
if (this._input) {
|
||||
this._input.focus();
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<paper-time-input
|
||||
.label=${this.label}
|
||||
.required=${this.required}
|
||||
.autoValidate=${this.required}
|
||||
error-message="Required"
|
||||
enable-second
|
||||
.enableMillisecond=${this.enableMillisecond}
|
||||
format="24"
|
||||
.hour=${this._parseDuration(this._hours)}
|
||||
.min=${this._parseDuration(this._minutes)}
|
||||
.sec=${this._parseDuration(this._seconds)}
|
||||
.millisec=${this._parseDurationMillisec(this._milliseconds)}
|
||||
@hour-changed=${this._hourChanged}
|
||||
@min-changed=${this._minChanged}
|
||||
@sec-changed=${this._secChanged}
|
||||
@millisec-changed=${this._millisecChanged}
|
||||
float-input-labels
|
||||
no-hours-limit
|
||||
always-float-input-labels
|
||||
hour-label="hh"
|
||||
min-label="mm"
|
||||
sec-label="ss"
|
||||
millisec-label="ms"
|
||||
></paper-time-input>
|
||||
`;
|
||||
}
|
||||
|
||||
private get _hours() {
|
||||
return this.data && this.data.hours ? Number(this.data.hours) : 0;
|
||||
}
|
||||
|
||||
private get _minutes() {
|
||||
return this.data && this.data.minutes ? Number(this.data.minutes) : 0;
|
||||
}
|
||||
|
||||
private get _seconds() {
|
||||
return this.data && this.data.seconds ? Number(this.data.seconds) : 0;
|
||||
}
|
||||
|
||||
private get _milliseconds() {
|
||||
return this.data && this.data.milliseconds
|
||||
? Number(this.data.milliseconds)
|
||||
: 0;
|
||||
}
|
||||
|
||||
private _parseDuration(value) {
|
||||
return value.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
private _parseDurationMillisec(value) {
|
||||
return value.toString().padStart(3, "0");
|
||||
}
|
||||
|
||||
private _hourChanged(ev) {
|
||||
this._durationChanged(ev, "hours");
|
||||
}
|
||||
|
||||
private _minChanged(ev) {
|
||||
this._durationChanged(ev, "minutes");
|
||||
}
|
||||
|
||||
private _secChanged(ev) {
|
||||
this._durationChanged(ev, "seconds");
|
||||
}
|
||||
|
||||
private _millisecChanged(ev) {
|
||||
this._durationChanged(ev, "milliseconds");
|
||||
}
|
||||
|
||||
private _durationChanged(ev, unit) {
|
||||
let value = Number(ev.detail.value);
|
||||
|
||||
if (value === this[`_${unit}`]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hours = this._hours;
|
||||
let minutes = this._minutes;
|
||||
|
||||
if (unit === "seconds" && value > 59) {
|
||||
minutes += Math.floor(value / 60);
|
||||
value %= 60;
|
||||
}
|
||||
|
||||
if (unit === "minutes" && value > 59) {
|
||||
hours += Math.floor(value / 60);
|
||||
value %= 60;
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
hours,
|
||||
minutes,
|
||||
seconds: this._seconds,
|
||||
milliseconds: this._milliseconds,
|
||||
...{ [unit]: value },
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-duration-input": HaDurationInput;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import "../ha-time-input";
|
||||
import "../ha-duration-input";
|
||||
import { HaFormElement, HaFormTimeData, HaFormTimeSchema } from "./ha-form";
|
||||
|
||||
@customElement("ha-form-positive_time_period_dict")
|
||||
@ -23,11 +23,11 @@ export class HaFormTimePeriod extends LitElement implements HaFormElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-time-input
|
||||
<ha-duration-input
|
||||
.label=${this.label}
|
||||
.required=${this.schema.required}
|
||||
.data=${this.data}
|
||||
></ha-time-input>
|
||||
></ha-duration-input>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { dynamicElement } from "../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { HaTimeData } from "../ha-time-input";
|
||||
import { HaDurationData } from "../ha-duration-input";
|
||||
import "./ha-form-boolean";
|
||||
import "./ha-form-constant";
|
||||
import "./ha-form-float";
|
||||
@ -88,7 +88,7 @@ export type HaFormFloatData = number;
|
||||
export type HaFormBooleanData = boolean;
|
||||
export type HaFormSelectData = string;
|
||||
export type HaFormMultiSelectData = string[];
|
||||
export type HaFormTimeData = HaTimeData;
|
||||
export type HaFormTimeData = HaDurationData;
|
||||
|
||||
export interface HaFormElement extends LitElement {
|
||||
schema: HaFormSchema | HaFormSchema[];
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { useAmPm } from "../../common/datetime/use_am_pm";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { TimeSelector } from "../../data/selector";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "../paper-time-input";
|
||||
import "../ha-time-input";
|
||||
|
||||
@customElement("ha-selector-time")
|
||||
export class HaTimeSelector extends LitElement {
|
||||
@ -19,46 +17,16 @@ export class HaTimeSelector extends LitElement {
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
||||
protected render() {
|
||||
const useAMPM = useAmPm(this.hass.locale);
|
||||
|
||||
const parts = this.value?.split(":") || [];
|
||||
const hours = parts[0];
|
||||
|
||||
return html`
|
||||
<paper-time-input
|
||||
.label=${this.label}
|
||||
.hour=${hours &&
|
||||
(useAMPM && Number(hours) > 12 ? Number(hours) - 12 : hours)}
|
||||
.min=${parts[1]}
|
||||
.sec=${parts[2]}
|
||||
.format=${useAMPM ? 12 : 24}
|
||||
.amPm=${useAMPM && (Number(hours) > 12 ? "PM" : "AM")}
|
||||
<ha-time-input
|
||||
.value=${this.value}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${this.disabled}
|
||||
@change=${this._timeChanged}
|
||||
@am-pm-changed=${this._timeChanged}
|
||||
hide-label
|
||||
enable-second
|
||||
></paper-time-input>
|
||||
></ha-time-input>
|
||||
`;
|
||||
}
|
||||
|
||||
private _timeChanged(ev) {
|
||||
let value = ev.target.value;
|
||||
const useAMPM = useAmPm(this.hass.locale);
|
||||
let hours = Number(ev.target.hour || 0);
|
||||
if (value && useAMPM) {
|
||||
if (ev.target.amPm === "PM") {
|
||||
hours += 12;
|
||||
}
|
||||
value = `${hours}:${ev.target.min || "00"}:${ev.target.sec || "00"}`;
|
||||
}
|
||||
if (value === this.value) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -1,134 +1,78 @@
|
||||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { useAmPm } from "../common/datetime/use_am_pm";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import "./paper-time-input";
|
||||
|
||||
export interface HaTimeData {
|
||||
hours?: number;
|
||||
minutes?: number;
|
||||
seconds?: number;
|
||||
milliseconds?: number;
|
||||
}
|
||||
import { FrontendLocaleData } from "../data/translation";
|
||||
|
||||
@customElement("ha-time-input")
|
||||
class HaTimeInput extends LitElement {
|
||||
@property() public data!: HaTimeData;
|
||||
export class HaTimeInput extends LitElement {
|
||||
@property() public locale!: FrontendLocaleData;
|
||||
|
||||
@property() public value?: string;
|
||||
|
||||
@property() public label?: string;
|
||||
|
||||
@property() public suffix?: string;
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
||||
@property({ type: Boolean }) public required?: boolean;
|
||||
@property({ type: Boolean, attribute: "hide-label" }) public hideLabel =
|
||||
false;
|
||||
|
||||
@property({ type: Boolean }) public enableMillisecond?: boolean;
|
||||
@property({ type: Boolean, attribute: "enable-second" })
|
||||
public enableSecond = false;
|
||||
|
||||
@query("paper-time-input", true) private _input?: HTMLElement;
|
||||
protected render() {
|
||||
const useAMPM = useAmPm(this.locale);
|
||||
|
||||
public focus() {
|
||||
if (this._input) {
|
||||
this._input.focus();
|
||||
const parts = this.value?.split(":") || [];
|
||||
let hours = parts[0];
|
||||
const numberHours = Number(parts[0]);
|
||||
if (numberHours && useAMPM && numberHours > 12) {
|
||||
hours = String(numberHours - 12).padStart(2, "0");
|
||||
}
|
||||
if (useAMPM && numberHours === 0) {
|
||||
hours = "12";
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<paper-time-input
|
||||
.label=${this.label}
|
||||
.required=${this.required}
|
||||
.autoValidate=${this.required}
|
||||
error-message="Required"
|
||||
enable-second
|
||||
.enableMillisecond=${this.enableMillisecond}
|
||||
format="24"
|
||||
.hour=${this._parseDuration(this._hours)}
|
||||
.min=${this._parseDuration(this._minutes)}
|
||||
.sec=${this._parseDuration(this._seconds)}
|
||||
.millisec=${this._parseDurationMillisec(this._milliseconds)}
|
||||
@hour-changed=${this._hourChanged}
|
||||
@min-changed=${this._minChanged}
|
||||
@sec-changed=${this._secChanged}
|
||||
@millisec-changed=${this._millisecChanged}
|
||||
float-input-labels
|
||||
no-hours-limit
|
||||
always-float-input-labels
|
||||
hour-label="hh"
|
||||
min-label="mm"
|
||||
sec-label="ss"
|
||||
millisec-label="ms"
|
||||
.hour=${hours}
|
||||
.min=${parts[1]}
|
||||
.sec=${parts[2]}
|
||||
.format=${useAMPM ? 12 : 24}
|
||||
.amPm=${useAMPM && (numberHours >= 12 ? "PM" : "AM")}
|
||||
.disabled=${this.disabled}
|
||||
@change=${this._timeChanged}
|
||||
@am-pm-changed=${this._timeChanged}
|
||||
.hideLabel=${this.hideLabel}
|
||||
.enableSecond=${this.enableSecond}
|
||||
></paper-time-input>
|
||||
`;
|
||||
}
|
||||
|
||||
private get _hours() {
|
||||
return this.data && this.data.hours ? Number(this.data.hours) : 0;
|
||||
}
|
||||
|
||||
private get _minutes() {
|
||||
return this.data && this.data.minutes ? Number(this.data.minutes) : 0;
|
||||
}
|
||||
|
||||
private get _seconds() {
|
||||
return this.data && this.data.seconds ? Number(this.data.seconds) : 0;
|
||||
}
|
||||
|
||||
private get _milliseconds() {
|
||||
return this.data && this.data.milliseconds
|
||||
? Number(this.data.milliseconds)
|
||||
: 0;
|
||||
}
|
||||
|
||||
private _parseDuration(value) {
|
||||
return value.toString().padStart(2, "0");
|
||||
}
|
||||
|
||||
private _parseDurationMillisec(value) {
|
||||
return value.toString().padStart(3, "0");
|
||||
}
|
||||
|
||||
private _hourChanged(ev) {
|
||||
this._durationChanged(ev, "hours");
|
||||
}
|
||||
|
||||
private _minChanged(ev) {
|
||||
this._durationChanged(ev, "minutes");
|
||||
}
|
||||
|
||||
private _secChanged(ev) {
|
||||
this._durationChanged(ev, "seconds");
|
||||
}
|
||||
|
||||
private _millisecChanged(ev) {
|
||||
this._durationChanged(ev, "milliseconds");
|
||||
}
|
||||
|
||||
private _durationChanged(ev, unit) {
|
||||
let value = Number(ev.detail.value);
|
||||
|
||||
if (value === this[`_${unit}`]) {
|
||||
private _timeChanged(ev) {
|
||||
let value = ev.target.value;
|
||||
const useAMPM = useAmPm(this.locale);
|
||||
let hours = Number(ev.target.hour || 0);
|
||||
if (value && useAMPM) {
|
||||
if (ev.target.amPm === "PM" && hours < 12) {
|
||||
hours += 12;
|
||||
}
|
||||
if (ev.target.amPm === "AM" && hours === 12) {
|
||||
hours = 0;
|
||||
}
|
||||
value = `${hours.toString().padStart(2, "0")}:${ev.target.min || "00"}:${
|
||||
ev.target.sec || "00"
|
||||
}`;
|
||||
}
|
||||
if (value === this.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hours = this._hours;
|
||||
let minutes = this._minutes;
|
||||
|
||||
if (unit === "seconds" && value > 59) {
|
||||
minutes += Math.floor(value / 60);
|
||||
value %= 60;
|
||||
}
|
||||
|
||||
if (unit === "minutes" && value > 59) {
|
||||
hours += Math.floor(value / 60);
|
||||
value %= 60;
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
fireEvent(this, "change");
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
hours,
|
||||
minutes,
|
||||
seconds: this._seconds,
|
||||
milliseconds: this._milliseconds,
|
||||
...{ [unit]: value },
|
||||
},
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -46,9 +46,11 @@ export interface BlueprintAutomationConfig extends ManualAutomationConfig {
|
||||
}
|
||||
|
||||
export interface ForDict {
|
||||
hours?: number | string;
|
||||
minutes?: number | string;
|
||||
seconds?: number | string;
|
||||
days?: number;
|
||||
hours?: number;
|
||||
minutes?: number;
|
||||
seconds?: number;
|
||||
milliseconds?: number;
|
||||
}
|
||||
|
||||
export interface ContextConstraint {
|
||||
|
@ -1,191 +0,0 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
/* eslint-plugin-disable lit */
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { attributeClassNames } from "../../../common/entity/attribute_class_names";
|
||||
import "../../../components/ha-date-input";
|
||||
import "../../../components/ha-relative-time";
|
||||
import "../../../components/paper-time-input";
|
||||
|
||||
class DatetimeInput extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
<div class$="[[computeClassNames(stateObj)]]">
|
||||
<template is="dom-if" if="[[doesHaveDate(stateObj)]]" restamp="">
|
||||
<div>
|
||||
<ha-date-input
|
||||
id="dateInput"
|
||||
label="Date"
|
||||
value="{{selectedDate}}"
|
||||
></ha-date-input>
|
||||
</div>
|
||||
</template>
|
||||
<template is="dom-if" if="[[doesHaveTime(stateObj)]]" restamp="">
|
||||
<div>
|
||||
<paper-time-input
|
||||
hour="{{selectedHour}}"
|
||||
min="{{selectedMinute}}"
|
||||
format="24"
|
||||
></paper-time-input>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.is_ready = false;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {
|
||||
type: Object,
|
||||
},
|
||||
|
||||
stateObj: {
|
||||
type: Object,
|
||||
observer: "stateObjChanged",
|
||||
},
|
||||
|
||||
selectedDate: {
|
||||
type: String,
|
||||
observer: "dateTimeChanged",
|
||||
},
|
||||
|
||||
selectedHour: {
|
||||
type: Number,
|
||||
observer: "dateTimeChanged",
|
||||
},
|
||||
|
||||
selectedMinute: {
|
||||
type: Number,
|
||||
observer: "dateTimeChanged",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.is_ready = true;
|
||||
}
|
||||
|
||||
/* Convert the date in the stateObj into a string useable by vaadin-date-picker */
|
||||
getDateString(stateObj) {
|
||||
if (stateObj.state === "unknown") {
|
||||
return "";
|
||||
}
|
||||
let monthFiller;
|
||||
if (stateObj.attributes.month < 10) {
|
||||
monthFiller = "0";
|
||||
} else {
|
||||
monthFiller = "";
|
||||
}
|
||||
|
||||
let dayFiller;
|
||||
if (stateObj.attributes.day < 10) {
|
||||
dayFiller = "0";
|
||||
} else {
|
||||
dayFiller = "";
|
||||
}
|
||||
|
||||
return (
|
||||
stateObj.attributes.year +
|
||||
"-" +
|
||||
monthFiller +
|
||||
stateObj.attributes.month +
|
||||
"-" +
|
||||
dayFiller +
|
||||
stateObj.attributes.day
|
||||
);
|
||||
}
|
||||
|
||||
/* Should fire when any value was changed *by the user*, not b/c of setting
|
||||
* initial values. */
|
||||
dateTimeChanged() {
|
||||
// Check if the change is really coming from the user
|
||||
if (!this.is_ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
let changed = false;
|
||||
let minuteFiller;
|
||||
|
||||
const serviceData = {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
};
|
||||
|
||||
if (this.stateObj.attributes.has_time) {
|
||||
changed =
|
||||
changed ||
|
||||
parseInt(this.selectedMinute) !== this.stateObj.attributes.minute;
|
||||
changed =
|
||||
changed ||
|
||||
parseInt(this.selectedHour) !== this.stateObj.attributes.hour;
|
||||
if (this.selectedMinute < 10) {
|
||||
minuteFiller = "0";
|
||||
} else {
|
||||
minuteFiller = "";
|
||||
}
|
||||
const timeStr =
|
||||
this.selectedHour + ":" + minuteFiller + this.selectedMinute;
|
||||
serviceData.time = timeStr;
|
||||
}
|
||||
|
||||
if (this.stateObj.attributes.has_date) {
|
||||
if (this.selectedDate.length === 0) {
|
||||
return; // Date was not set
|
||||
}
|
||||
|
||||
const dateValInput = new Date(this.selectedDate);
|
||||
const dateValState = new Date(
|
||||
this.stateObj.attributes.year,
|
||||
this.stateObj.attributes.month - 1,
|
||||
this.stateObj.attributes.day
|
||||
);
|
||||
|
||||
changed = changed || dateValState !== dateValInput;
|
||||
|
||||
serviceData.date = this.selectedDate;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this.hass.callService("input_datetime", "set_datetime", serviceData);
|
||||
}
|
||||
}
|
||||
|
||||
stateObjChanged(newVal) {
|
||||
// Set to non-ready s.t. dateTimeChanged does not fire
|
||||
this.is_ready = false;
|
||||
|
||||
if (newVal.attributes.has_time) {
|
||||
this.selectedHour = newVal.attributes.hour;
|
||||
this.selectedMinute = newVal.attributes.minute;
|
||||
}
|
||||
|
||||
if (newVal.attributes.has_date) {
|
||||
this.selectedDate = this.getDateString(newVal);
|
||||
}
|
||||
|
||||
this.is_ready = true;
|
||||
}
|
||||
|
||||
doesHaveDate(stateObj) {
|
||||
return stateObj.attributes.has_date;
|
||||
}
|
||||
|
||||
doesHaveTime(stateObj) {
|
||||
return stateObj.attributes.has_time;
|
||||
}
|
||||
|
||||
computeClassNames(stateObj) {
|
||||
return (
|
||||
"more-info-input_datetime " +
|
||||
attributeClassNames(stateObj, ["has_time", "has_date"])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("more-info-input_datetime", DatetimeInput);
|
103
src/dialogs/more-info/controls/more-info-input_datetime.ts
Normal file
103
src/dialogs/more-info/controls/more-info-input_datetime.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-date-input";
|
||||
import "../../../components/ha-time-input";
|
||||
import { UNAVAILABLE_STATES, UNKNOWN } from "../../../data/entity";
|
||||
import { setInputDateTimeValue } from "../../../data/input_datetime";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@customElement("more-info-input_datetime")
|
||||
class MoreInfoInputDatetime extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public stateObj?: HassEntity;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.stateObj) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
return html`
|
||||
${
|
||||
this.stateObj.attributes.has_date
|
||||
? html`
|
||||
<ha-date-input
|
||||
.value=${`${this.stateObj.attributes.year}-${this.stateObj.attributes.month}-${this.stateObj.attributes.day}`}
|
||||
.disabled=${UNAVAILABLE_STATES.includes(this.stateObj.state)}
|
||||
@value-changed=${this._dateChanged}
|
||||
>
|
||||
</ha-date-input>
|
||||
`
|
||||
: ``
|
||||
}
|
||||
${
|
||||
this.stateObj.attributes.has_time
|
||||
? html`
|
||||
<ha-time-input
|
||||
.value=${this.stateObj.state === UNKNOWN
|
||||
? ""
|
||||
: this.stateObj.attributes.has_date
|
||||
? this.stateObj.state.split(" ")[1]
|
||||
: this.stateObj.state}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${UNAVAILABLE_STATES.includes(this.stateObj.state)}
|
||||
hide-label
|
||||
@value-changed=${this._timeChanged}
|
||||
@click=${this._stopEventPropagation}
|
||||
></ha-time-input>
|
||||
`
|
||||
: ``
|
||||
}
|
||||
</hui-generic-entity-row>
|
||||
`;
|
||||
}
|
||||
|
||||
private _stopEventPropagation(ev: Event): void {
|
||||
ev.stopPropagation();
|
||||
}
|
||||
|
||||
private _timeChanged(ev): void {
|
||||
setInputDateTimeValue(
|
||||
this.hass!,
|
||||
this.stateObj!.entity_id,
|
||||
ev.detail.value,
|
||||
this.stateObj!.attributes.has_date
|
||||
? this.stateObj!.state.split(" ")[0]
|
||||
: undefined
|
||||
);
|
||||
ev.target.blur();
|
||||
}
|
||||
|
||||
private _dateChanged(ev): void {
|
||||
setInputDateTimeValue(
|
||||
this.hass!,
|
||||
this.stateObj!.entity_id,
|
||||
this.stateObj!.attributes.has_time
|
||||
? this.stateObj!.state.split(" ")[1]
|
||||
: undefined,
|
||||
ev.detail.value
|
||||
);
|
||||
|
||||
ev.target.blur();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
ha-date-input + ha-time-input {
|
||||
margin-left: 4px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"more-info-input_datetime": MoreInfoInputDatetime;
|
||||
}
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { html, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { hasTemplate } from "../../../../../common/string/has-template";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { HaFormTimeData } from "../../../../../components/ha-form/ha-form";
|
||||
import "../../../../../components/ha-service-picker";
|
||||
import type { HaDurationData } from "../../../../../components/ha-duration-input";
|
||||
import "../../../../../components/ha-duration-input";
|
||||
import { DelayAction } from "../../../../../data/script";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { ActionElement } from "../ha-automation-action-row";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
|
||||
@customElement("ha-automation-action-delay")
|
||||
export class HaDelayAction extends LitElement implements ActionElement {
|
||||
@ -16,13 +15,13 @@ export class HaDelayAction extends LitElement implements ActionElement {
|
||||
|
||||
@property() public action!: DelayAction;
|
||||
|
||||
@property() public _timeData!: HaFormTimeData;
|
||||
@property() public _timeData!: HaDurationData;
|
||||
|
||||
public static get defaultConfig() {
|
||||
return { delay: "" };
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues) {
|
||||
public willUpdate(changedProperties: PropertyValues) {
|
||||
if (!changedProperties.has("action")) {
|
||||
return;
|
||||
}
|
||||
@ -36,37 +35,15 @@ export class HaDelayAction extends LitElement implements ActionElement {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof this.action.delay !== "object") {
|
||||
if (typeof this.action.delay === "string" || isNaN(this.action.delay)) {
|
||||
const parts = this.action.delay?.toString().split(":") || [];
|
||||
this._timeData = {
|
||||
hours: Number(parts[0]) || 0,
|
||||
minutes: Number(parts[1]) || 0,
|
||||
seconds: Number(parts[2]) || 0,
|
||||
milliseconds: Number(parts[3]) || 0,
|
||||
};
|
||||
} else {
|
||||
this._timeData = { seconds: this.action.delay };
|
||||
}
|
||||
return;
|
||||
}
|
||||
const { days, minutes, seconds, milliseconds } = this.action.delay;
|
||||
let { hours } = this.action.delay || 0;
|
||||
hours = (hours || 0) + (days || 0) * 24;
|
||||
this._timeData = {
|
||||
hours: hours,
|
||||
minutes: minutes,
|
||||
seconds: seconds,
|
||||
milliseconds: milliseconds,
|
||||
};
|
||||
this._timeData = createDurationData(this.action.delay);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
return html`<ha-time-input
|
||||
return html`<ha-duration-input
|
||||
.data=${this._timeData}
|
||||
enableMillisecond
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-time-input>`;
|
||||
></ha-duration-input>`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
|
@ -1,14 +1,16 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import "../../../../../components/entity/ha-entity-attribute-picker";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { ForDict, StateCondition } from "../../../../../data/automation";
|
||||
import { StateCondition } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import {
|
||||
ConditionElement,
|
||||
handleChangeEvent,
|
||||
} from "../ha-automation-condition-row";
|
||||
import "../../../../../components/ha-duration-input";
|
||||
|
||||
@customElement("ha-automation-condition-state")
|
||||
export class HaStateCondition extends LitElement implements ConditionElement {
|
||||
@ -22,23 +24,7 @@ export class HaStateCondition extends LitElement implements ConditionElement {
|
||||
|
||||
protected render() {
|
||||
const { entity_id, attribute, state } = this.condition;
|
||||
let forTime = this.condition.for;
|
||||
|
||||
if (
|
||||
forTime &&
|
||||
((forTime as ForDict).hours ||
|
||||
(forTime as ForDict).minutes ||
|
||||
(forTime as ForDict).seconds)
|
||||
) {
|
||||
// If the trigger was defined using the yaml dict syntax, convert it to
|
||||
// the equivalent string format
|
||||
let { hours = 0, minutes = 0, seconds = 0 } = forTime as ForDict;
|
||||
hours = hours.toString().padStart(2, "0");
|
||||
minutes = minutes.toString().padStart(2, "0");
|
||||
seconds = seconds.toString().padStart(2, "0");
|
||||
|
||||
forTime = `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
const forTime = createDurationData(this.condition.for);
|
||||
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
@ -67,14 +53,14 @@ export class HaStateCondition extends LitElement implements ConditionElement {
|
||||
.value=${state}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
<paper-input
|
||||
<ha-duration-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.state.for"
|
||||
)}
|
||||
.name=${"for"}
|
||||
.value=${forTime}
|
||||
.data=${forTime}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
></ha-duration-input>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Radio } from "@material/mwc-radio";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
@ -13,6 +12,7 @@ import {
|
||||
ConditionElement,
|
||||
handleChangeEvent,
|
||||
} from "../ha-automation-condition-row";
|
||||
import "../../../../../components/ha-time-input";
|
||||
|
||||
const includeDomains = ["input_datetime"];
|
||||
|
||||
@ -89,14 +89,15 @@ export class HaTimeCondition extends LitElement implements ConditionElement {
|
||||
.hass=${this.hass}
|
||||
allow-custom-entity
|
||||
></ha-entity-picker>`
|
||||
: html`<paper-input
|
||||
: html`<ha-time-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.time.after"
|
||||
)}
|
||||
name="after"
|
||||
.locale=${this.hass.locale}
|
||||
.name=${"after"}
|
||||
.value=${after?.startsWith("input_datetime.") ? "" : after}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>`}
|
||||
></ha-time-input>`}
|
||||
|
||||
<ha-formfield
|
||||
.label=${this.hass!.localize(
|
||||
@ -134,14 +135,15 @@ export class HaTimeCondition extends LitElement implements ConditionElement {
|
||||
.hass=${this.hass}
|
||||
allow-custom-entity
|
||||
></ha-entity-picker>`
|
||||
: html`<paper-input
|
||||
: html`<ha-time-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.time.before"
|
||||
)}
|
||||
name="before"
|
||||
.name=${"before"}
|
||||
.locale=${this.hass.locale}
|
||||
.value=${before?.startsWith("input_datetime.") ? "" : before}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>`}
|
||||
></ha-time-input>`}
|
||||
${Object.keys(DAYS).map(
|
||||
(day) => html`
|
||||
<ha-formfield
|
||||
|
@ -9,6 +9,7 @@ import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon-button";
|
||||
@ -80,6 +81,8 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
|
||||
@property() public trigger!: Trigger;
|
||||
|
||||
@state() private _warnings?: string[];
|
||||
|
||||
@state() private _yamlMode = false;
|
||||
|
||||
protected render() {
|
||||
@ -118,6 +121,20 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
${this._warnings
|
||||
? html`<div class="warning">
|
||||
${this.hass.localize("ui.errors.config.editor_not_supported")}:
|
||||
<br />
|
||||
${this._warnings.length && this._warnings[0] !== undefined
|
||||
? html` <ul>
|
||||
${this._warnings.map(
|
||||
(warning) => html`<li>${warning}</li>`
|
||||
)}
|
||||
</ul>`
|
||||
: ""}
|
||||
${this.hass.localize("ui.errors.config.edit_in_yaml_supported")}
|
||||
</div>`
|
||||
: ""}
|
||||
${yamlMode
|
||||
? html`
|
||||
${selected === -1
|
||||
@ -170,7 +187,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
@value-changed=${this._idChanged}
|
||||
>
|
||||
</paper-input>
|
||||
<div>
|
||||
<div @ui-mode-not-available=${this._handleUiModeNotAvailable}>
|
||||
${dynamicElement(
|
||||
`ha-automation-trigger-${this.trigger.platform}`,
|
||||
{ hass: this.hass, trigger: this.trigger }
|
||||
@ -182,6 +199,13 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleUiModeNotAvailable(ev: CustomEvent) {
|
||||
this._warnings = handleStructError(this.hass, ev.detail).warnings;
|
||||
if (!this._yamlMode) {
|
||||
this._yamlMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
@ -258,6 +282,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
}
|
||||
|
||||
private _switchYamlMode() {
|
||||
this._warnings = undefined;
|
||||
this._yamlMode = !this._yamlMode;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { html, LitElement } from "lit";
|
||||
import { html, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { hasTemplate } from "../../../../../common/string/has-template";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { ForDict, NumericStateTrigger } from "../../../../../data/automation";
|
||||
import { NumericStateTrigger } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { handleChangeEvent } from "../ha-automation-trigger-row";
|
||||
import "../../../../../components/ha-duration-input";
|
||||
|
||||
@customElement("ha-automation-trigger-numeric_state")
|
||||
export default class HaNumericStateTrigger extends LitElement {
|
||||
@ -13,6 +17,20 @@ export default class HaNumericStateTrigger extends LitElement {
|
||||
|
||||
@property() public trigger!: NumericStateTrigger;
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues) {
|
||||
if (!changedProperties.has("trigger")) {
|
||||
return;
|
||||
}
|
||||
// Check for templates in trigger. If found, revert to YAML mode.
|
||||
if (this.trigger && hasTemplate(this.trigger)) {
|
||||
fireEvent(
|
||||
this,
|
||||
"ui-mode-not-available",
|
||||
Error(this.hass.localize("ui.errors.config.no_template_editor_support"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static get defaultConfig() {
|
||||
return {
|
||||
entity_id: "",
|
||||
@ -21,23 +39,8 @@ export default class HaNumericStateTrigger extends LitElement {
|
||||
|
||||
public render() {
|
||||
const { value_template, entity_id, attribute, below, above } = this.trigger;
|
||||
let trgFor = this.trigger.for;
|
||||
const trgFor = createDurationData(this.trigger.for);
|
||||
|
||||
if (
|
||||
trgFor &&
|
||||
((trgFor as ForDict).hours ||
|
||||
(trgFor as ForDict).minutes ||
|
||||
(trgFor as ForDict).seconds)
|
||||
) {
|
||||
// If the trigger was defined using the yaml dict syntax, convert it to
|
||||
// the equivalent string format
|
||||
let { hours = 0, minutes = 0, seconds = 0 } = trgFor as ForDict;
|
||||
hours = hours.toString();
|
||||
minutes = minutes.toString().padStart(2, "0");
|
||||
seconds = seconds.toString().padStart(2, "0");
|
||||
|
||||
trgFor = `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
.value="${entity_id}"
|
||||
@ -82,14 +85,14 @@ export default class HaNumericStateTrigger extends LitElement {
|
||||
@value-changed=${this._valueChanged}
|
||||
dir="ltr"
|
||||
></paper-textarea>
|
||||
<paper-input
|
||||
<ha-duration-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.state.for"
|
||||
)}
|
||||
name="for"
|
||||
.value=${trgFor}
|
||||
.name=${"for"}
|
||||
.data=${trgFor}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
></ha-duration-input>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,14 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { html, LitElement } from "lit";
|
||||
import { html, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { hasTemplate } from "../../../../../common/string/has-template";
|
||||
import "../../../../../components/entity/ha-entity-attribute-picker";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import { ForDict, StateTrigger } from "../../../../../data/automation";
|
||||
import { StateTrigger } from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../../../components/ha-duration-input";
|
||||
import {
|
||||
handleChangeEvent,
|
||||
TriggerElement,
|
||||
@ -20,25 +24,23 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
|
||||
return { entity_id: "" };
|
||||
}
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues) {
|
||||
if (!changedProperties.has("trigger")) {
|
||||
return;
|
||||
}
|
||||
// Check for templates in trigger. If found, revert to YAML mode.
|
||||
if (this.trigger && hasTemplate(this.trigger)) {
|
||||
fireEvent(
|
||||
this,
|
||||
"ui-mode-not-available",
|
||||
Error(this.hass.localize("ui.errors.config.no_template_editor_support"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { entity_id, attribute, to, from } = this.trigger;
|
||||
let trgFor = this.trigger.for;
|
||||
|
||||
if (
|
||||
trgFor &&
|
||||
((trgFor as ForDict).hours ||
|
||||
(trgFor as ForDict).minutes ||
|
||||
(trgFor as ForDict).seconds)
|
||||
) {
|
||||
// If the trigger was defined using the yaml dict syntax, convert it to
|
||||
// the equivalent string format
|
||||
let { hours = 0, minutes = 0, seconds = 0 } = trgFor as ForDict;
|
||||
hours = hours.toString();
|
||||
minutes = minutes.toString().padStart(2, "0");
|
||||
seconds = seconds.toString().padStart(2, "0");
|
||||
|
||||
trgFor = `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
const trgFor = createDurationData(this.trigger.for);
|
||||
|
||||
return html`
|
||||
<ha-entity-picker
|
||||
@ -75,14 +77,14 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
|
||||
.value=${to}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
<paper-input
|
||||
<ha-duration-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.state.for"
|
||||
)}
|
||||
.name=${"for"}
|
||||
.value=${trgFor}
|
||||
.data=${trgFor}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>
|
||||
></ha-duration-input>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import { html, LitElement } from "lit";
|
||||
import { html, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../../components/ha-formfield";
|
||||
@ -10,9 +9,10 @@ import {
|
||||
handleChangeEvent,
|
||||
TriggerElement,
|
||||
} from "../ha-automation-trigger-row";
|
||||
import "../../../../../components/ha-time-input";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
|
||||
const includeDomains = ["input_datetime"];
|
||||
|
||||
@customElement("ha-automation-trigger-time")
|
||||
export class HaTimeTrigger extends LitElement implements TriggerElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -25,11 +25,32 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
|
||||
return { at: "" };
|
||||
}
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues) {
|
||||
if (!changedProperties.has("trigger")) {
|
||||
return;
|
||||
}
|
||||
// We dont support multiple times atm.
|
||||
if (this.trigger && Array.isArray(this.trigger.at)) {
|
||||
fireEvent(
|
||||
this,
|
||||
"ui-mode-not-available",
|
||||
Error(this.hass.localize("ui.errors.config.editor_not_supported"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { at } = this.trigger;
|
||||
const inputMode = this._inputMode ?? at?.startsWith("input_datetime.");
|
||||
return html`
|
||||
<ha-formfield
|
||||
const at = this.trigger.at;
|
||||
|
||||
if (Array.isArray(at)) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const inputMode =
|
||||
this._inputMode ??
|
||||
(at?.startsWith("input_datetime.") || at?.startsWith("sensor."));
|
||||
|
||||
return html`<ha-formfield
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time.type_value"
|
||||
)}
|
||||
@ -53,6 +74,7 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
|
||||
?checked=${inputMode}
|
||||
></ha-radio>
|
||||
</ha-formfield>
|
||||
|
||||
${inputMode
|
||||
? html`<ha-entity-picker
|
||||
.label=${this.hass.localize(
|
||||
@ -60,20 +82,26 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
|
||||
)}
|
||||
.includeDomains=${includeDomains}
|
||||
.name=${"at"}
|
||||
.value=${at?.startsWith("input_datetime.") ? at : ""}
|
||||
.value=${at?.startsWith("input_datetime.") ||
|
||||
at?.startsWith("sensor.")
|
||||
? at
|
||||
: ""}
|
||||
@value-changed=${this._valueChanged}
|
||||
.hass=${this.hass}
|
||||
allow-custom-entity
|
||||
></ha-entity-picker>`
|
||||
: html`<paper-input
|
||||
: html`<ha-time-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time.at"
|
||||
)}
|
||||
name="at"
|
||||
.value=${at?.startsWith("input_datetime.") ? "" : at}
|
||||
.name=${"at"}
|
||||
.value=${at?.startsWith("input_datetime.") ||
|
||||
at?.startsWith("sensor.")
|
||||
? ""
|
||||
: at}
|
||||
.locale=${this.hass.locale}
|
||||
@value-changed=${this._valueChanged}
|
||||
></paper-input>`}
|
||||
`;
|
||||
></ha-time-input>`} `;
|
||||
}
|
||||
|
||||
private _handleModeChanged(ev: Event) {
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, state, query } from "lit/decorators";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../../components/ha-date-input";
|
||||
import type { HaDateInput } from "../../../components/ha-date-input";
|
||||
import "../../../components/paper-time-input";
|
||||
import type { PaperTimeInput } from "../../../components/paper-time-input";
|
||||
import { UNAVAILABLE_STATES, UNKNOWN } from "../../../data/entity";
|
||||
import { setInputDateTimeValue } from "../../../data/input_datetime";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
@ -11,6 +15,7 @@ import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import type { EntityConfig, LovelaceRow } from "./types";
|
||||
import "../../../components/ha-time-input";
|
||||
|
||||
@customElement("hui-input-datetime-entity-row")
|
||||
class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
||||
@ -18,10 +23,6 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
||||
|
||||
@state() private _config?: EntityConfig;
|
||||
|
||||
@query("paper-time-input") private _timeInputEl?: PaperTimeInput;
|
||||
|
||||
@query("ha-date-input") private _dateInputEl?: HaDateInput;
|
||||
|
||||
public setConfig(config: EntityConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Invalid configuration");
|
||||
@ -55,27 +56,25 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
||||
<ha-date-input
|
||||
.disabled=${UNAVAILABLE_STATES.includes(stateObj.state)}
|
||||
.value=${`${stateObj.attributes.year}-${stateObj.attributes.month}-${stateObj.attributes.day}`}
|
||||
@value-changed=${this._selectedValueChanged}
|
||||
@value-changed=${this._dateChanged}
|
||||
>
|
||||
</ha-date-input>
|
||||
${stateObj.attributes.has_time ? "," : ""}
|
||||
`
|
||||
: ``}
|
||||
${stateObj.attributes.has_time
|
||||
? html`
|
||||
<paper-time-input
|
||||
<ha-time-input
|
||||
.value=${stateObj.state === UNKNOWN
|
||||
? ""
|
||||
: stateObj.attributes.has_date
|
||||
? stateObj.state.split(" ")[1]
|
||||
: stateObj.state}
|
||||
.locale=${this.hass.locale}
|
||||
.disabled=${UNAVAILABLE_STATES.includes(stateObj.state)}
|
||||
.hour=${stateObj.state === UNKNOWN
|
||||
? ""
|
||||
: ("0" + stateObj.attributes.hour).slice(-2)}
|
||||
.min=${stateObj.state === UNKNOWN
|
||||
? ""
|
||||
: ("0" + stateObj.attributes.minute).slice(-2)}
|
||||
@change=${this._selectedValueChanged}
|
||||
@click=${this._stopEventPropagation}
|
||||
hide-label
|
||||
.format=${24}
|
||||
></paper-time-input>
|
||||
@value-changed=${this._timeChanged}
|
||||
@click=${this._stopEventPropagation}
|
||||
></ha-time-input>
|
||||
`
|
||||
: ``}
|
||||
</hui-generic-entity-row>
|
||||
@ -86,19 +85,37 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
||||
ev.stopPropagation();
|
||||
}
|
||||
|
||||
private _selectedValueChanged(ev): void {
|
||||
private _timeChanged(ev): void {
|
||||
const stateObj = this.hass!.states[this._config!.entity];
|
||||
setInputDateTimeValue(
|
||||
this.hass!,
|
||||
stateObj.entity_id,
|
||||
ev.detail.value,
|
||||
stateObj.attributes.has_date ? stateObj.state.split(" ")[0] : undefined
|
||||
);
|
||||
ev.target.blur();
|
||||
}
|
||||
|
||||
private _dateChanged(ev): void {
|
||||
const stateObj = this.hass!.states[this._config!.entity];
|
||||
|
||||
const time = this._timeInputEl
|
||||
? this._timeInputEl.value?.trim()
|
||||
: undefined;
|
||||
|
||||
const date = this._dateInputEl ? this._dateInputEl.value : undefined;
|
||||
|
||||
setInputDateTimeValue(this.hass!, stateObj.entity_id, time, date);
|
||||
setInputDateTimeValue(
|
||||
this.hass!,
|
||||
stateObj.entity_id,
|
||||
stateObj.attributes.has_time ? stateObj.state.split(" ")[1] : undefined,
|
||||
ev.detail.value
|
||||
);
|
||||
|
||||
ev.target.blur();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
ha-date-input + ha-time-input {
|
||||
margin-left: 4px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
Loading…
x
Reference in New Issue
Block a user