mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-25 22:07:20 +00:00
Add support for timestamp device class (#2087)
This commit is contained in:
parent
d41a4cf78b
commit
a7ab652dd3
@ -10,31 +10,43 @@ const langKey = ["second", "minute", "hour", "day"];
|
|||||||
|
|
||||||
export default function relativeTime(
|
export default function relativeTime(
|
||||||
dateObj: Date,
|
dateObj: Date,
|
||||||
localize: LocalizeFunc
|
localize: LocalizeFunc,
|
||||||
|
options: {
|
||||||
|
compareTime?: Date;
|
||||||
|
includeTense?: boolean;
|
||||||
|
} = {}
|
||||||
): string {
|
): string {
|
||||||
let delta = (new Date().getTime() - dateObj.getTime()) / 1000;
|
const compareTime = options.compareTime || new Date();
|
||||||
|
let delta = (compareTime.getTime() - dateObj.getTime()) / 1000;
|
||||||
const tense = delta >= 0 ? "past" : "future";
|
const tense = delta >= 0 ? "past" : "future";
|
||||||
delta = Math.abs(delta);
|
delta = Math.abs(delta);
|
||||||
|
|
||||||
|
let timeDesc;
|
||||||
|
|
||||||
for (let i = 0; i < tests.length; i++) {
|
for (let i = 0; i < tests.length; i++) {
|
||||||
if (delta < tests[i]) {
|
if (delta < tests[i]) {
|
||||||
delta = Math.floor(delta);
|
delta = Math.floor(delta);
|
||||||
const timeDesc = localize(
|
timeDesc = localize(
|
||||||
`ui.components.relative_time.duration.${langKey[i]}`,
|
`ui.components.relative_time.duration.${langKey[i]}`,
|
||||||
"count",
|
"count",
|
||||||
delta
|
delta
|
||||||
);
|
);
|
||||||
return localize(`ui.components.relative_time.${tense}`, "time", timeDesc);
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
delta /= tests[i];
|
delta /= tests[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
delta = Math.floor(delta);
|
if (timeDesc === undefined) {
|
||||||
const time = localize(
|
delta = Math.floor(delta);
|
||||||
"ui.components.relative_time.duration.week",
|
timeDesc = localize(
|
||||||
"count",
|
"ui.components.relative_time.duration.week",
|
||||||
delta
|
"count",
|
||||||
);
|
delta
|
||||||
return localize(`ui.components.relative_time.${tense}`, "time", time);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return options.includeTense === false
|
||||||
|
? timeDesc
|
||||||
|
: localize(`ui.components.relative_time.${tense}`, "time", timeDesc);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import "../entity-rows/hui-lock-entity-row";
|
|||||||
import "../entity-rows/hui-media-player-entity-row";
|
import "../entity-rows/hui-media-player-entity-row";
|
||||||
import "../entity-rows/hui-scene-entity-row";
|
import "../entity-rows/hui-scene-entity-row";
|
||||||
import "../entity-rows/hui-script-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-text-entity-row";
|
||||||
import "../entity-rows/hui-timer-entity-row";
|
import "../entity-rows/hui-timer-entity-row";
|
||||||
import "../entity-rows/hui-toggle-entity-row";
|
import "../entity-rows/hui-toggle-entity-row";
|
||||||
@ -42,6 +43,7 @@ const DOMAIN_TO_ELEMENT_TYPE = {
|
|||||||
lock: "lock",
|
lock: "lock",
|
||||||
scene: "scene",
|
scene: "scene",
|
||||||
script: "script",
|
script: "script",
|
||||||
|
sensor: "sensor",
|
||||||
timer: "timer",
|
timer: "timer",
|
||||||
switch: "toggle",
|
switch: "toggle",
|
||||||
vacuum: "toggle",
|
vacuum: "toggle",
|
||||||
|
130
src/panels/lovelace/components/hui-timestamp-display.ts
Normal file
130
src/panels/lovelace/components/hui-timestamp-display.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import {
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyDeclarations,
|
||||||
|
PropertyValues,
|
||||||
|
} from "@polymer/lit-element";
|
||||||
|
import { TemplateResult } from "lit-html";
|
||||||
|
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import format_date from "../../../common/datetime/format_date";
|
||||||
|
import format_date_time from "../../../common/datetime/format_date_time";
|
||||||
|
import format_time from "../../../common/datetime/format_time";
|
||||||
|
import relativeTime from "../../../common/datetime/relative_time";
|
||||||
|
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||||
|
|
||||||
|
const FORMATS: { [key: string]: (ts: Date, lang: string) => string } = {
|
||||||
|
date: format_date,
|
||||||
|
datetime: format_date_time,
|
||||||
|
time: format_time,
|
||||||
|
};
|
||||||
|
const INTERVAL_FORMAT = ["relative", "total"];
|
||||||
|
|
||||||
|
class HuiTimestampDisplay extends hassLocalizeLitMixin(LitElement) {
|
||||||
|
public hass?: HomeAssistant;
|
||||||
|
public ts?: Date;
|
||||||
|
public format?: "relative" | "total" | "date" | "datetime" | "time";
|
||||||
|
private _relative?: string;
|
||||||
|
private _connected?: boolean;
|
||||||
|
private _interval?: number;
|
||||||
|
|
||||||
|
static get properties(): PropertyDeclarations {
|
||||||
|
return {
|
||||||
|
ts: {},
|
||||||
|
hass: {},
|
||||||
|
format: {},
|
||||||
|
_relative: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
this._connected = true;
|
||||||
|
this._startInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this._connected = false;
|
||||||
|
this._clearInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.ts || !this.hass) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(this.ts.getTime())) {
|
||||||
|
return html`
|
||||||
|
Invalid date
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const format = this._format;
|
||||||
|
|
||||||
|
if (INTERVAL_FORMAT.includes(format)) {
|
||||||
|
return html`
|
||||||
|
${this._relative}
|
||||||
|
`;
|
||||||
|
} else if (format in FORMATS) {
|
||||||
|
return html`
|
||||||
|
${FORMATS[format](this.ts, this.hass.language)}
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
return html`
|
||||||
|
Invalid format
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues) {
|
||||||
|
if (!changedProperties.has("format") || !this._connected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INTERVAL_FORMAT.includes("relative")) {
|
||||||
|
this._startInterval();
|
||||||
|
} else {
|
||||||
|
this._clearInterval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _format() {
|
||||||
|
return this.format || "relative";
|
||||||
|
}
|
||||||
|
|
||||||
|
private _startInterval() {
|
||||||
|
this._clearInterval();
|
||||||
|
if (this._connected && INTERVAL_FORMAT.includes(this._format)) {
|
||||||
|
this._updateRelative();
|
||||||
|
this._interval = window.setInterval(() => this._updateRelative(), 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _clearInterval() {
|
||||||
|
if (this._interval) {
|
||||||
|
clearInterval(this._interval);
|
||||||
|
this._interval = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateRelative() {
|
||||||
|
if (this.ts && this.localize) {
|
||||||
|
this._relative =
|
||||||
|
this._format === "relative"
|
||||||
|
? relativeTime(this.ts, this.localize)
|
||||||
|
: (this._relative = relativeTime(new Date(), this.localize, {
|
||||||
|
compareTime: this.ts,
|
||||||
|
includeTense: false,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-timestamp-display": HuiTimestampDisplay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("hui-timestamp-display", HuiTimestampDisplay);
|
@ -3,16 +3,19 @@ import { TemplateResult } from "lit-html";
|
|||||||
|
|
||||||
class HuiErrorEntityRow extends LitElement {
|
class HuiErrorEntityRow extends LitElement {
|
||||||
public entity?: string;
|
public entity?: string;
|
||||||
|
public error?: string;
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
|
error: {},
|
||||||
entity: {},
|
entity: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
${this.renderStyle()} Entity not available: ${this.entity || ""}
|
${this.renderStyle()} ${this.error || "Entity not available"}:
|
||||||
|
${this.entity || ""}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
85
src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts
Normal file
85
src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||||
|
import { TemplateResult } from "lit-html";
|
||||||
|
|
||||||
|
import "../components/hui-generic-entity-row";
|
||||||
|
import "../components/hui-timestamp-display";
|
||||||
|
import "./hui-error-entity-row";
|
||||||
|
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { EntityRow, EntityConfig } from "./types";
|
||||||
|
|
||||||
|
interface SensorEntityConfig extends EntityConfig {
|
||||||
|
format?: "relative" | "date" | "time" | "datetime";
|
||||||
|
}
|
||||||
|
|
||||||
|
class HuiSensorEntityRow extends LitElement implements EntityRow {
|
||||||
|
public hass?: HomeAssistant;
|
||||||
|
private _config?: SensorEntityConfig;
|
||||||
|
|
||||||
|
static get properties(): PropertyDeclarations {
|
||||||
|
return {
|
||||||
|
hass: {},
|
||||||
|
_config: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public setConfig(config: SensorEntityConfig): void {
|
||||||
|
if (!config) {
|
||||||
|
throw new Error("Configuration error");
|
||||||
|
}
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateObj = this.hass.states[this._config.entity];
|
||||||
|
|
||||||
|
if (!stateObj) {
|
||||||
|
return html`
|
||||||
|
<hui-error-entity-row
|
||||||
|
.entity="${this._config.entity}"
|
||||||
|
></hui-error-entity-row>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
${this.renderStyle()}
|
||||||
|
<hui-generic-entity-row .hass="${this.hass}" .config="${this._config}">
|
||||||
|
<div>
|
||||||
|
${
|
||||||
|
stateObj.attributes.device_class === "timestamp"
|
||||||
|
? html`
|
||||||
|
<hui-timestamp-display
|
||||||
|
.hass="${this.hass}"
|
||||||
|
.ts="${new Date(stateObj.state)}"
|
||||||
|
.format="${this._config.format}"
|
||||||
|
></hui-timestamp-display>
|
||||||
|
`
|
||||||
|
: stateObj.state
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</hui-generic-entity-row>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderStyle(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-sensor-entity-row": HuiSensorEntityRow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("hui-sensor-entity-row", HuiSensorEntityRow);
|
Loading…
x
Reference in New Issue
Block a user