mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-24 13:27:22 +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(
|
||||
dateObj: Date,
|
||||
localize: LocalizeFunc
|
||||
localize: LocalizeFunc,
|
||||
options: {
|
||||
compareTime?: Date;
|
||||
includeTense?: boolean;
|
||||
} = {}
|
||||
): 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";
|
||||
delta = Math.abs(delta);
|
||||
|
||||
let timeDesc;
|
||||
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
if (delta < tests[i]) {
|
||||
delta = Math.floor(delta);
|
||||
const timeDesc = localize(
|
||||
timeDesc = localize(
|
||||
`ui.components.relative_time.duration.${langKey[i]}`,
|
||||
"count",
|
||||
delta
|
||||
);
|
||||
return localize(`ui.components.relative_time.${tense}`, "time", timeDesc);
|
||||
break;
|
||||
}
|
||||
|
||||
delta /= tests[i];
|
||||
}
|
||||
|
||||
delta = Math.floor(delta);
|
||||
const time = localize(
|
||||
"ui.components.relative_time.duration.week",
|
||||
"count",
|
||||
delta
|
||||
);
|
||||
return localize(`ui.components.relative_time.${tense}`, "time", time);
|
||||
if (timeDesc === undefined) {
|
||||
delta = Math.floor(delta);
|
||||
timeDesc = localize(
|
||||
"ui.components.relative_time.duration.week",
|
||||
"count",
|
||||
delta
|
||||
);
|
||||
}
|
||||
|
||||
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-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-timer-entity-row";
|
||||
import "../entity-rows/hui-toggle-entity-row";
|
||||
@ -42,6 +43,7 @@ const DOMAIN_TO_ELEMENT_TYPE = {
|
||||
lock: "lock",
|
||||
scene: "scene",
|
||||
script: "script",
|
||||
sensor: "sensor",
|
||||
timer: "timer",
|
||||
switch: "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 {
|
||||
public entity?: string;
|
||||
public error?: string;
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
error: {},
|
||||
entity: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
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