mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add date range picker to energy period selector (#14337)
This commit is contained in:
parent
f8966a2114
commit
607175706b
@ -260,7 +260,6 @@ export class HcMain extends HassElement {
|
||||
{
|
||||
strategy: {
|
||||
type: "energy",
|
||||
show_date_selection: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -5,12 +5,15 @@ import { FrontendLocaleData, TimeZone } from "../../data/translation";
|
||||
const calcZonedDate = (
|
||||
date: Date,
|
||||
tz: string,
|
||||
fn: (date: Date, options?: any) => Date,
|
||||
fn: (date: Date, options?: any) => Date | number | boolean,
|
||||
options?
|
||||
) => {
|
||||
const inputZoned = utcToZonedTime(date, tz);
|
||||
const fnZoned = fn(inputZoned, options);
|
||||
return zonedTimeToUtc(fnZoned, tz);
|
||||
if (fnZoned instanceof Date) {
|
||||
return zonedTimeToUtc(fnZoned, tz) as Date;
|
||||
}
|
||||
return fnZoned;
|
||||
};
|
||||
|
||||
export const calcDate = (
|
||||
@ -21,5 +24,16 @@ export const calcDate = (
|
||||
options?
|
||||
) =>
|
||||
locale.time_zone === TimeZone.server
|
||||
? calcZonedDate(date, config.time_zone, fn, options)
|
||||
? (calcZonedDate(date, config.time_zone, fn, options) as Date)
|
||||
: fn(date, options);
|
||||
|
||||
export const calcDateProperty = (
|
||||
date: Date,
|
||||
fn: (date: Date, options?: any) => boolean | number,
|
||||
locale: FrontendLocaleData,
|
||||
config: HassConfig,
|
||||
options?
|
||||
) =>
|
||||
locale.time_zone === TimeZone.server
|
||||
? (calcZonedDate(date, config.time_zone, fn, options) as number | boolean)
|
||||
: fn(date, options);
|
||||
|
@ -37,6 +37,23 @@ const formatDateMem = memoizeOne(
|
||||
})
|
||||
);
|
||||
|
||||
// Aug 10, 2021
|
||||
export const formatDateShort = (
|
||||
dateObj: Date,
|
||||
locale: FrontendLocaleData,
|
||||
config: HassConfig
|
||||
) => formatDateShortMem(locale, config.time_zone).format(dateObj);
|
||||
|
||||
const formatDateShortMem = memoizeOne(
|
||||
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||
new Intl.DateTimeFormat(locale.language, {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
})
|
||||
);
|
||||
|
||||
// 10/08/2021
|
||||
export const formatDateNumeric = (
|
||||
dateObj: Date,
|
||||
@ -102,13 +119,13 @@ const formatDateNumericMem = memoizeOne(
|
||||
);
|
||||
|
||||
// Aug 10
|
||||
export const formatDateShort = (
|
||||
export const formatDateVeryShort = (
|
||||
dateObj: Date,
|
||||
locale: FrontendLocaleData,
|
||||
config: HassConfig
|
||||
) => formatDateShortMem(locale, config.time_zone).format(dateObj);
|
||||
) => formatDateVeryShortMem(locale, config.time_zone).format(dateObj);
|
||||
|
||||
const formatDateShortMem = memoizeOne(
|
||||
const formatDateVeryShortMem = memoizeOne(
|
||||
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||
new Intl.DateTimeFormat(locale.language, {
|
||||
day: "numeric",
|
||||
|
@ -39,7 +39,7 @@ import {
|
||||
formatDate,
|
||||
formatDateMonth,
|
||||
formatDateMonthYear,
|
||||
formatDateShort,
|
||||
formatDateVeryShort,
|
||||
formatDateWeekdayDay,
|
||||
formatDateYear,
|
||||
} from "../../common/datetime/format_date";
|
||||
@ -128,7 +128,7 @@ _adapters._date.override({
|
||||
this.options.config
|
||||
);
|
||||
case "day":
|
||||
return formatDateShort(
|
||||
return formatDateVeryShort(
|
||||
new Date(time),
|
||||
this.options.locale,
|
||||
this.options.config
|
||||
|
@ -31,6 +31,10 @@ const Component = Vue.extend({
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
openingDirection: {
|
||||
type: String,
|
||||
default: "right",
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@ -66,7 +70,7 @@ const Component = Vue.extend({
|
||||
props: {
|
||||
"time-picker": this.timePicker,
|
||||
"auto-apply": this.autoApply,
|
||||
opens: "right",
|
||||
opens: this.openingDirection,
|
||||
"show-dropdowns": false,
|
||||
"time-picker24-hour": this.twentyfourHours,
|
||||
disabled: this.disabled,
|
||||
@ -126,9 +130,9 @@ class DateRangePickerElement extends WrappedElement {
|
||||
${dateRangePickerStyles}
|
||||
.calendars {
|
||||
display: flex;
|
||||
flex-wrap: nowrap !important;
|
||||
}
|
||||
.daterangepicker {
|
||||
left: 0px !important;
|
||||
top: auto;
|
||||
box-shadow: var(--ha-card-box-shadow, none);
|
||||
background-color: var(--card-background-color);
|
||||
@ -252,6 +256,10 @@ class DateRangePickerElement extends WrappedElement {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
.vue-daterange-picker{
|
||||
min-width: unset !important;
|
||||
display: block !important;
|
||||
}
|
||||
`;
|
||||
const shadowRoot = this.shadowRoot!;
|
||||
shadowRoot.appendChild(style);
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
nothing,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
@ -29,6 +30,7 @@ import { HomeAssistant } from "../types";
|
||||
import "./date-range-picker";
|
||||
import "./ha-svg-icon";
|
||||
import "./ha-textfield";
|
||||
import "./ha-icon-button";
|
||||
|
||||
export interface DateRangePickerRanges {
|
||||
[key: string]: [Date, Date];
|
||||
@ -54,7 +56,21 @@ export class HaDateRangePicker extends LitElement {
|
||||
|
||||
@property({ type: String }) private _rtlDirection = "ltr";
|
||||
|
||||
@property({ type: Boolean }) private minimal = false;
|
||||
|
||||
@property() private _openingDirection = "right";
|
||||
|
||||
protected willUpdate() {
|
||||
// set dialog opening direction based on position
|
||||
const datePickerPosition = this.getBoundingClientRect().x;
|
||||
if (datePickerPosition > (2 * window.innerWidth) / 3) {
|
||||
this._openingDirection = "left";
|
||||
} else if (datePickerPosition < window.innerWidth / 3) {
|
||||
this._openingDirection = "right";
|
||||
} else {
|
||||
this._openingDirection = "center";
|
||||
}
|
||||
|
||||
if (!this.hasUpdated && this.ranges === undefined) {
|
||||
const today = new Date();
|
||||
const weekStartsOn = firstWeekdayIndex(this.hass.locale);
|
||||
@ -133,41 +149,61 @@ export class HaDateRangePicker extends LitElement {
|
||||
<date-range-picker
|
||||
?disabled=${this.disabled}
|
||||
?auto-apply=${this.autoApply}
|
||||
?time-picker=${this.timePicker}
|
||||
time-picker=${this.timePicker}
|
||||
twentyfour-hours=${this._hour24format}
|
||||
start-date=${this.startDate}
|
||||
end-date=${this.endDate}
|
||||
?ranges=${this.ranges !== false}
|
||||
opening-direction=${this._openingDirection}
|
||||
first-day=${firstWeekdayIndex(this.hass.locale)}
|
||||
>
|
||||
<div slot="input" class="date-range-inputs">
|
||||
<ha-svg-icon .path=${mdiCalendar}></ha-svg-icon>
|
||||
<ha-textfield
|
||||
.value=${this.timePicker
|
||||
? formatDateTime(
|
||||
this.startDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)
|
||||
: formatDate(this.startDate, this.hass.locale, this.hass.config)}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.date-range-picker.start_date"
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@click=${this._handleInputClick}
|
||||
readonly
|
||||
></ha-textfield>
|
||||
<ha-textfield
|
||||
.value=${this.timePicker
|
||||
? formatDateTime(this.endDate, this.hass.locale, this.hass.config)
|
||||
: formatDate(this.endDate, this.hass.locale, this.hass.config)}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.date-range-picker.end_date"
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@click=${this._handleInputClick}
|
||||
readonly
|
||||
></ha-textfield>
|
||||
${!this.minimal
|
||||
? html`<ha-svg-icon .path=${mdiCalendar}></ha-svg-icon>
|
||||
<ha-textfield
|
||||
.value=${this.timePicker
|
||||
? formatDateTime(
|
||||
this.startDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)
|
||||
: formatDate(
|
||||
this.startDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.date-range-picker.start_date"
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@click=${this._handleInputClick}
|
||||
readonly
|
||||
></ha-textfield>
|
||||
<ha-textfield
|
||||
.value=${this.timePicker
|
||||
? formatDateTime(
|
||||
this.endDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)
|
||||
: formatDate(
|
||||
this.endDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)}
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.date-range-picker.end_date"
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@click=${this._handleInputClick}
|
||||
readonly
|
||||
></ha-textfield>`
|
||||
: html`<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.date-range-picker.select_date_range"
|
||||
)}
|
||||
.path=${mdiCalendar}
|
||||
></ha-icon-button>`}
|
||||
</div>
|
||||
${this.ranges
|
||||
? html`<div
|
||||
@ -181,7 +217,7 @@ export class HaDateRangePicker extends LitElement {
|
||||
)}
|
||||
</mwc-list>
|
||||
</div>`
|
||||
: ""}
|
||||
: nothing}
|
||||
<div slot="footer" class="date-range-footer">
|
||||
<mwc-button @click=${this._cancelDateRange}
|
||||
>${this.hass.localize("ui.common.cancel")}</mwc-button
|
||||
@ -234,6 +270,10 @@ export class HaDateRangePicker extends LitElement {
|
||||
direction: var(--direction);
|
||||
}
|
||||
|
||||
ha-icon-button {
|
||||
direction: var(--direction);
|
||||
}
|
||||
|
||||
.date-range-inputs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -4,11 +4,14 @@ import {
|
||||
addMilliseconds,
|
||||
addMonths,
|
||||
differenceInDays,
|
||||
differenceInMonths,
|
||||
endOfDay,
|
||||
startOfDay,
|
||||
isFirstDayOfMonth,
|
||||
isLastDayOfMonth,
|
||||
} from "date-fns/esm";
|
||||
import { Collection, getCollection } from "home-assistant-js-websocket";
|
||||
import { calcDate } from "../common/datetime/calc_date";
|
||||
import { calcDate, calcDateProperty } from "../common/datetime/calc_date";
|
||||
import { formatTime24h } from "../common/datetime/format_time";
|
||||
import { groupBy } from "../common/util/group-by";
|
||||
import { HomeAssistant } from "../types";
|
||||
@ -416,11 +419,42 @@ const getEnergyData = async (
|
||||
let _waterStatsCompare: Statistics | Promise<Statistics> = {};
|
||||
|
||||
if (compare) {
|
||||
if (dayDifference > 27 && dayDifference < 32) {
|
||||
// When comparing a month, we want to start at the begining of the month
|
||||
startCompare = addMonths(start, -1);
|
||||
if (
|
||||
(calcDateProperty(
|
||||
start,
|
||||
isFirstDayOfMonth,
|
||||
hass.locale,
|
||||
hass.config
|
||||
) as boolean) &&
|
||||
(calcDateProperty(
|
||||
end || new Date(),
|
||||
isLastDayOfMonth,
|
||||
hass.locale,
|
||||
hass.config
|
||||
) as boolean)
|
||||
) {
|
||||
// When comparing a month (or multiple), we want to start at the begining of the month
|
||||
startCompare = calcDate(
|
||||
start,
|
||||
addMonths,
|
||||
hass.locale,
|
||||
hass.config,
|
||||
-(calcDateProperty(
|
||||
end || new Date(),
|
||||
differenceInMonths,
|
||||
hass.locale,
|
||||
hass.config,
|
||||
start
|
||||
) as number) - 1
|
||||
);
|
||||
} else {
|
||||
startCompare = addDays(start, (dayDifference + 1) * -1);
|
||||
startCompare = calcDate(
|
||||
start,
|
||||
addDays,
|
||||
hass.locale,
|
||||
hass.config,
|
||||
(dayDifference + 1) * -1
|
||||
);
|
||||
}
|
||||
endCompare = addMilliseconds(start, -1);
|
||||
if (energyStatIds.length) {
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
nothing,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import "../../components/ha-menu-button";
|
||||
@ -60,31 +61,33 @@ class PanelEnergy extends LitElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-top-app-bar-fixed>
|
||||
<ha-menu-button
|
||||
slot="navigationIcon"
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
></ha-menu-button>
|
||||
<div slot="title">${this.hass.localize("panel.energy")}</div>
|
||||
${this.narrow
|
||||
? ""
|
||||
: html`
|
||||
<hui-energy-period-selector
|
||||
slot="actionItems"
|
||||
.hass=${this.hass}
|
||||
collectionKey="energy_dashboard"
|
||||
.narrow=${false}
|
||||
></hui-energy-period-selector>
|
||||
`}
|
||||
<hui-view
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.lovelace=${this._lovelace}
|
||||
.index=${this._viewIndex}
|
||||
@reload-energy-panel=${this._reloadView}
|
||||
></hui-view>
|
||||
</ha-top-app-bar-fixed>
|
||||
<div class="header">
|
||||
<div class="toolbar">
|
||||
<ha-menu-button
|
||||
slot="navigationIcon"
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
></ha-menu-button>
|
||||
${!this.narrow
|
||||
? html`<div class="main-title">
|
||||
${this.hass.localize("panel.energy")}
|
||||
</div>`
|
||||
: nothing}
|
||||
|
||||
<hui-energy-period-selector
|
||||
.hass=${this.hass}
|
||||
collectionKey="energy_dashboard"
|
||||
></hui-energy-period-selector>
|
||||
</div>
|
||||
</div>
|
||||
<hui-view
|
||||
id="view"
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.lovelace=${this._lovelace}
|
||||
.index=${this._viewIndex}
|
||||
@reload-energy-panel=${this._reloadView}
|
||||
></hui-view>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -116,13 +119,83 @@ class PanelEnergy extends LitElement {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
hui-energy-period-selector {
|
||||
:host hui-energy-period-selector {
|
||||
width: 100%;
|
||||
padding-left: 16px;
|
||||
padding-inline-start: 16px;
|
||||
padding-left: 32px;
|
||||
padding-inline-start: 32px;
|
||||
--disabled-text-color: rgba(var(--rgb-text-primary-color), 0.5);
|
||||
direction: var(--direction);
|
||||
}
|
||||
:host([narrow]) hui-energy-period-selector {
|
||||
padding-left: 0px;
|
||||
padding-inline-start: 0px;
|
||||
}
|
||||
:host {
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
.header {
|
||||
background-color: var(--app-header-background-color);
|
||||
color: var(--app-header-text-color, white);
|
||||
border-bottom: var(--app-header-border-bottom, none);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: var(--mdc-top-app-bar-width, 100%);
|
||||
padding-top: env(safe-area-inset-top);
|
||||
z-index: 4;
|
||||
transition: box-shadow 200ms linear;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
:host([scrolled]) .header {
|
||||
box-shadow: var(
|
||||
--mdc-top-app-bar-fixed-box-shadow,
|
||||
0px 2px 4px -1px rgba(0, 0, 0, 0.2),
|
||||
0px 4px 5px 0px rgba(0, 0, 0, 0.14),
|
||||
0px 1px 10px 0px rgba(0, 0, 0, 0.12)
|
||||
);
|
||||
}
|
||||
.toolbar {
|
||||
height: var(--header-height);
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
font-size: 20px;
|
||||
padding: 0px 12px;
|
||||
font-weight: 400;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@media (max-width: 599px) {
|
||||
.toolbar {
|
||||
padding: 0 4px;
|
||||
}
|
||||
}
|
||||
.main-title {
|
||||
margin: 0 0 0 24px;
|
||||
line-height: 20px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
#view {
|
||||
position: relative;
|
||||
display: flex;
|
||||
padding-top: calc(var(--header-height) + env(safe-area-inset-top));
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
hui-view {
|
||||
background: var(
|
||||
--lovelace-background,
|
||||
var(--primary-background-color)
|
||||
);
|
||||
}
|
||||
#view > * {
|
||||
flex: 1 1 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import {
|
||||
LovelaceViewConfig,
|
||||
} from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceStrategyParams } from "../../lovelace/strategies/types";
|
||||
|
||||
const setupWizard = async (): Promise<LovelaceViewConfig> => {
|
||||
await import("../cards/energy-setup-wizard-card");
|
||||
@ -24,16 +23,11 @@ const setupWizard = async (): Promise<LovelaceViewConfig> => {
|
||||
};
|
||||
};
|
||||
|
||||
export interface EnergeryViewStrategyConfig extends LovelaceStrategyConfig {
|
||||
show_date_selection?: boolean;
|
||||
}
|
||||
|
||||
@customElement("energy-view-strategy")
|
||||
export class EnergyViewStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
config: EnergeryViewStrategyConfig,
|
||||
hass: HomeAssistant,
|
||||
params: LovelaceStrategyParams
|
||||
_config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const view: LovelaceViewConfig = { cards: [] };
|
||||
|
||||
@ -67,14 +61,6 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
(source) => source.type === "water"
|
||||
);
|
||||
|
||||
if (params.narrow || config.show_date_selection) {
|
||||
view.cards!.push({
|
||||
type: "energy-date-selection",
|
||||
collection_key: "energy_dashboard",
|
||||
view_layout: { position: "sidebar" },
|
||||
});
|
||||
}
|
||||
|
||||
view.cards!.push({
|
||||
type: "energy-compare",
|
||||
collection_key: "energy_dashboard",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { html, LitElement, nothing, css, CSSResultGroup } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "../../components/hui-energy-period-selector";
|
||||
@ -28,10 +28,22 @@ export class HuiEnergyDateSelectionCard
|
||||
}
|
||||
|
||||
return html`
|
||||
<hui-energy-period-selector
|
||||
.hass=${this.hass}
|
||||
.collectionKey=${this._config.collection_key}
|
||||
></hui-energy-period-selector>
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<hui-energy-period-selector
|
||||
.hass=${this.hass}
|
||||
.collectionKey=${this._config.collection_key}
|
||||
></hui-energy-period-selector>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
.padded {
|
||||
padding-left: 16px !important;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
rgb2lab,
|
||||
} from "../../../../common/color/convert-color";
|
||||
import { labBrighten, labDarken } from "../../../../common/color/lab";
|
||||
import { formatDateShort } from "../../../../common/datetime/format_date";
|
||||
import { formatDateVeryShort } from "../../../../common/datetime/format_date";
|
||||
import { formatTime } from "../../../../common/datetime/format_time";
|
||||
import {
|
||||
formatNumber,
|
||||
@ -228,7 +228,9 @@ export class HuiEnergyGasGraphCard
|
||||
}
|
||||
const date = new Date(datasets[0].parsed.x);
|
||||
return `${
|
||||
compare ? `${formatDateShort(date, locale, config)}: ` : ""
|
||||
compare
|
||||
? `${formatDateVeryShort(date, locale, config)}: `
|
||||
: ""
|
||||
}${formatTime(date, locale, config)} – ${formatTime(
|
||||
addHours(date, 1),
|
||||
locale,
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
rgb2lab,
|
||||
} from "../../../../common/color/convert-color";
|
||||
import { labBrighten, labDarken } from "../../../../common/color/lab";
|
||||
import { formatDateShort } from "../../../../common/datetime/format_date";
|
||||
import { formatDateVeryShort } from "../../../../common/datetime/format_date";
|
||||
import { formatTime } from "../../../../common/datetime/format_time";
|
||||
import {
|
||||
formatNumber,
|
||||
@ -224,7 +224,9 @@ export class HuiEnergySolarGraphCard
|
||||
}
|
||||
const date = new Date(datasets[0].parsed.x);
|
||||
return `${
|
||||
compare ? `${formatDateShort(date, locale, config)}: ` : ""
|
||||
compare
|
||||
? `${formatDateVeryShort(date, locale, config)}: `
|
||||
: ""
|
||||
}${formatTime(date, locale, config)} – ${formatTime(
|
||||
addHours(date, 1),
|
||||
locale,
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
rgb2lab,
|
||||
} from "../../../../common/color/convert-color";
|
||||
import { labBrighten, labDarken } from "../../../../common/color/lab";
|
||||
import { formatDateShort } from "../../../../common/datetime/format_date";
|
||||
import { formatDateVeryShort } from "../../../../common/datetime/format_date";
|
||||
import { formatTime } from "../../../../common/datetime/format_time";
|
||||
import {
|
||||
formatNumber,
|
||||
@ -233,7 +233,9 @@ export class HuiEnergyUsageGraphCard
|
||||
}
|
||||
const date = new Date(datasets[0].parsed.x);
|
||||
return `${
|
||||
compare ? `${formatDateShort(date, locale, config)}: ` : ""
|
||||
compare
|
||||
? `${formatDateVeryShort(date, locale, config)}: `
|
||||
: ""
|
||||
}${formatTime(date, locale, config)} – ${formatTime(
|
||||
addHours(date, 1),
|
||||
locale,
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
rgb2lab,
|
||||
} from "../../../../common/color/convert-color";
|
||||
import { labBrighten, labDarken } from "../../../../common/color/lab";
|
||||
import { formatDateShort } from "../../../../common/datetime/format_date";
|
||||
import { formatDateVeryShort } from "../../../../common/datetime/format_date";
|
||||
import { formatTime } from "../../../../common/datetime/format_time";
|
||||
import {
|
||||
formatNumber,
|
||||
@ -228,7 +228,9 @@ export class HuiEnergyWaterGraphCard
|
||||
}
|
||||
const date = new Date(datasets[0].parsed.x);
|
||||
return `${
|
||||
compare ? `${formatDateShort(date, locale, config)}: ` : ""
|
||||
compare
|
||||
? `${formatDateVeryShort(date, locale, config)}: `
|
||||
: ""
|
||||
}${formatTime(date, locale, config)} – ${formatTime(
|
||||
addHours(date, 1),
|
||||
locale,
|
||||
|
@ -1,43 +1,56 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { mdiCompare, mdiCompareRemove } from "@mdi/js";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import {
|
||||
addDays,
|
||||
subDays,
|
||||
addMonths,
|
||||
addWeeks,
|
||||
addYears,
|
||||
differenceInDays,
|
||||
endOfDay,
|
||||
endOfMonth,
|
||||
endOfToday,
|
||||
endOfWeek,
|
||||
endOfQuarter,
|
||||
endOfYear,
|
||||
isWithinInterval,
|
||||
isFirstDayOfMonth,
|
||||
isLastDayOfMonth,
|
||||
differenceInMonths,
|
||||
startOfDay,
|
||||
startOfMonth,
|
||||
startOfToday,
|
||||
startOfWeek,
|
||||
startOfQuarter,
|
||||
startOfYear,
|
||||
} from "date-fns/esm";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
nothing,
|
||||
PropertyValues,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { calcDate } from "../../../common/datetime/calc_date";
|
||||
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||
import { calcDate, calcDateProperty } from "../../../common/datetime/calc_date";
|
||||
import { firstWeekdayIndex } from "../../../common/datetime/first_weekday";
|
||||
import {
|
||||
formatDate,
|
||||
formatDateMonthYear,
|
||||
formatDateShort,
|
||||
formatDateVeryShort,
|
||||
formatDateMonthYear,
|
||||
formatDateYear,
|
||||
} from "../../../common/datetime/format_date";
|
||||
import { toggleAttribute } from "../../../common/dom/toggle_attribute";
|
||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||
import "../../../components/ha-button-toggle-group";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon-button-next";
|
||||
import "../../../components/ha-icon-button-prev";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-check-list-item";
|
||||
import { EnergyData, getEnergyDataCollection } from "../../../data/energy";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { HomeAssistant, ToggleButton } from "../../../types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../../../components/ha-date-range-picker";
|
||||
import type { DateRangePickerRanges } from "../../../components/ha-date-range-picker";
|
||||
import { loadPolyfillIfNeeded } from "../../../resources/resize-observer.polyfill";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
|
||||
@customElement("hui-energy-period-selector")
|
||||
export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
|
||||
@ -51,16 +64,11 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() _endDate?: Date;
|
||||
|
||||
@state() private _period?: "day" | "week" | "month" | "year";
|
||||
@state() private _ranges?: DateRangePickerRanges;
|
||||
|
||||
@state() private _compare = false;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (this.narrow !== false) {
|
||||
toggleAttribute(this, "narrow", this.offsetWidth < 600);
|
||||
}
|
||||
}
|
||||
private _resizeObserver?: ResizeObserver;
|
||||
|
||||
public hassSubscribe(): UnsubscribeFunc[] {
|
||||
return [
|
||||
@ -70,64 +78,143 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
|
||||
];
|
||||
}
|
||||
|
||||
private _measure() {
|
||||
this.narrow = this.offsetWidth < 450;
|
||||
}
|
||||
|
||||
private async _attachObserver(): Promise<void> {
|
||||
if (!this._resizeObserver) {
|
||||
await loadPolyfillIfNeeded();
|
||||
this._resizeObserver = new ResizeObserver(
|
||||
debounce(() => this._measure(), 250, false)
|
||||
);
|
||||
}
|
||||
this._resizeObserver.observe(this);
|
||||
}
|
||||
|
||||
protected firstUpdated(): void {
|
||||
this._attachObserver();
|
||||
}
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this.updateComplete.then(() => this._attachObserver());
|
||||
}
|
||||
|
||||
public disconnectedCallback(): void {
|
||||
if (this._resizeObserver) {
|
||||
this._resizeObserver.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public willUpdate(changedProps: PropertyValues) {
|
||||
super.willUpdate(changedProps);
|
||||
if (!this.hasUpdated) {
|
||||
this._measure();
|
||||
}
|
||||
const today = new Date();
|
||||
const weekStartsOn = firstWeekdayIndex(this.hass.locale);
|
||||
|
||||
// pre defined date ranges
|
||||
this._ranges = {
|
||||
[this.hass.localize("ui.components.date-range-picker.ranges.today")]: [
|
||||
calcDate(today, startOfDay, this.hass.locale, this.hass.config, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
calcDate(today, endOfDay, this.hass.locale, this.hass.config, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
],
|
||||
[this.hass.localize("ui.components.date-range-picker.ranges.yesterday")]:
|
||||
[
|
||||
calcDate(
|
||||
calcDate(today, subDays, this.hass.locale, this.hass.config, 1),
|
||||
startOfDay,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
),
|
||||
calcDate(
|
||||
calcDate(today, subDays, this.hass.locale, this.hass.config, 1),
|
||||
endOfDay,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
),
|
||||
],
|
||||
[this.hass.localize("ui.components.date-range-picker.ranges.this_week")]:
|
||||
[
|
||||
calcDate(today, startOfWeek, this.hass.locale, this.hass.config, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
calcDate(today, endOfWeek, this.hass.locale, this.hass.config, {
|
||||
weekStartsOn,
|
||||
}),
|
||||
],
|
||||
[this.hass.localize("ui.components.date-range-picker.ranges.this_month")]:
|
||||
[
|
||||
calcDate(today, startOfMonth, this.hass.locale, this.hass.config),
|
||||
calcDate(today, endOfMonth, this.hass.locale, this.hass.config),
|
||||
],
|
||||
[this.hass.localize(
|
||||
"ui.components.date-range-picker.ranges.this_quarter"
|
||||
)]: [
|
||||
calcDate(today, startOfQuarter, this.hass.locale, this.hass.config),
|
||||
calcDate(today, endOfQuarter, this.hass.locale, this.hass.config),
|
||||
],
|
||||
[this.hass.localize("ui.components.date-range-picker.ranges.this_year")]:
|
||||
[
|
||||
calcDate(today, startOfYear, this.hass.locale, this.hass.config),
|
||||
calcDate(today, endOfYear, this.hass.locale, this.hass.config),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this.hass || !this._startDate) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const viewButtons: ToggleButton[] = [
|
||||
{
|
||||
label: this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.day"
|
||||
),
|
||||
value: "day",
|
||||
},
|
||||
{
|
||||
label: this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.week"
|
||||
),
|
||||
value: "week",
|
||||
},
|
||||
{
|
||||
label: this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.month"
|
||||
),
|
||||
value: "month",
|
||||
},
|
||||
{
|
||||
label: this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.year"
|
||||
),
|
||||
value: "year",
|
||||
},
|
||||
];
|
||||
const simpleRange = this._simpleRange();
|
||||
|
||||
return html`
|
||||
<div class="row">
|
||||
<div class="label">
|
||||
${this._period === "day"
|
||||
? formatDate(this._startDate, this.hass.locale, this.hass.config)
|
||||
: this._period === "month"
|
||||
${simpleRange === "day"
|
||||
? this.narrow
|
||||
? formatDateShort(
|
||||
this._startDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)
|
||||
: formatDate(this._startDate, this.hass.locale, this.hass.config)
|
||||
: simpleRange === "month"
|
||||
? formatDateMonthYear(
|
||||
this._startDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)
|
||||
: this._period === "year"
|
||||
: simpleRange === "year"
|
||||
? formatDateYear(
|
||||
this._startDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)
|
||||
: `${formatDateShort(
|
||||
: `${formatDateVeryShort(
|
||||
this._startDate,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)} – ${formatDateShort(
|
||||
)} – ${formatDateVeryShort(
|
||||
this._endDate || new Date(),
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)}`}
|
||||
</div>
|
||||
<div class="time-handle">
|
||||
<ha-icon-button-prev
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.previous"
|
||||
@ -140,160 +227,375 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
|
||||
)}
|
||||
@click=${this._pickNext}
|
||||
></ha-icon-button-next>
|
||||
<mwc-button dense outlined @click=${this._pickToday}>
|
||||
<ha-date-range-picker
|
||||
.hass=${this.hass}
|
||||
.startDate=${this._startDate}
|
||||
.endDate=${this._endDate || new Date()}
|
||||
.ranges=${this._ranges}
|
||||
@change=${this._dateRangeChanged}
|
||||
.timePicker=${false}
|
||||
minimal
|
||||
></ha-date-range-picker>
|
||||
</div>
|
||||
|
||||
${!this.narrow
|
||||
? html`<mwc-button dense outlined @click=${this._pickToday}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.today"
|
||||
)}
|
||||
</mwc-button>`
|
||||
: nothing}
|
||||
|
||||
<ha-button-menu>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-check-list-item
|
||||
left
|
||||
@request-selected=${this._toggleCompare}
|
||||
.selected=${this._compare}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.today"
|
||||
"ui.panel.lovelace.components.energy_period_selector.compare"
|
||||
)}
|
||||
</mwc-button>
|
||||
</div>
|
||||
<div class="period">
|
||||
<ha-button-toggle-group
|
||||
.buttons=${viewButtons}
|
||||
.active=${this._period}
|
||||
dense
|
||||
@value-changed=${this._handleView}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
></ha-button-toggle-group>
|
||||
${this.narrow
|
||||
? html`<ha-icon-button
|
||||
class="compare ${this._compare ? "active" : ""}"
|
||||
.path=${this._compare ? mdiCompareRemove : mdiCompare}
|
||||
@click=${this._toggleCompare}
|
||||
dense
|
||||
outlined
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.compare"
|
||||
)}
|
||||
</ha-icon-button>`
|
||||
: html`<mwc-button
|
||||
class="compare ${this._compare ? "active" : ""}"
|
||||
@click=${this._toggleCompare}
|
||||
dense
|
||||
outlined
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.components.energy_period_selector.compare"
|
||||
)}
|
||||
</mwc-button>`}
|
||||
</div>
|
||||
</ha-check-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleView(ev: CustomEvent): void {
|
||||
this._period = ev.detail.value;
|
||||
const today = startOfToday();
|
||||
const start =
|
||||
!this._startDate ||
|
||||
isWithinInterval(today, {
|
||||
start: this._startDate,
|
||||
end: this._endDate || endOfToday(),
|
||||
})
|
||||
? today
|
||||
: this._startDate;
|
||||
|
||||
const weekStartsOn = firstWeekdayIndex(this.hass.locale);
|
||||
|
||||
this._setDate(
|
||||
this._period === "day"
|
||||
? calcDate(start, startOfDay, this.hass.locale, this.hass.config)
|
||||
: this._period === "week"
|
||||
? calcDate(start, startOfWeek, this.hass.locale, this.hass.config, {
|
||||
weekStartsOn,
|
||||
})
|
||||
: this._period === "month"
|
||||
? calcDate(start, startOfMonth, this.hass.locale, this.hass.config)
|
||||
: calcDate(start, startOfYear, this.hass.locale, this.hass.config)
|
||||
);
|
||||
private _simpleRange(): string {
|
||||
if (differenceInDays(this._endDate!, this._startDate!) === 0) {
|
||||
return "day";
|
||||
}
|
||||
if (
|
||||
(calcDateProperty(
|
||||
this._startDate!,
|
||||
isFirstDayOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
) as boolean) &&
|
||||
(calcDateProperty(
|
||||
this._endDate!,
|
||||
isLastDayOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
) as boolean)
|
||||
) {
|
||||
if (
|
||||
(calcDateProperty(
|
||||
this._endDate!,
|
||||
differenceInMonths,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this._startDate!
|
||||
) as number) === 0
|
||||
) {
|
||||
return "month";
|
||||
}
|
||||
if (
|
||||
(calcDateProperty(
|
||||
this._endDate!,
|
||||
differenceInMonths,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this._startDate!
|
||||
) as number) === 2 &&
|
||||
this._startDate!.getMonth() % 3 === 0
|
||||
) {
|
||||
return "quarter";
|
||||
}
|
||||
}
|
||||
if (
|
||||
calcDateProperty(
|
||||
this._startDate!,
|
||||
isFirstDayOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
) &&
|
||||
calcDateProperty(
|
||||
this._endDate!,
|
||||
isLastDayOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
) &&
|
||||
calcDateProperty(
|
||||
this._endDate!,
|
||||
differenceInMonths,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this._startDate!
|
||||
) === 11
|
||||
) {
|
||||
return "year";
|
||||
}
|
||||
return "other";
|
||||
}
|
||||
|
||||
private _pickToday() {
|
||||
const weekStartsOn = firstWeekdayIndex(this.hass.locale);
|
||||
|
||||
this._setDate(
|
||||
this._period === "day"
|
||||
? calcDate(new Date(), startOfDay, this.hass.locale, this.hass.config)
|
||||
: this._period === "week"
|
||||
? calcDate(
|
||||
new Date(),
|
||||
startOfWeek,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
)
|
||||
: this._period === "month"
|
||||
? calcDate(new Date(), startOfMonth, this.hass.locale, this.hass.config)
|
||||
: calcDate(new Date(), startOfYear, this.hass.locale, this.hass.config)
|
||||
);
|
||||
}
|
||||
|
||||
private _pickPrevious() {
|
||||
const newStart =
|
||||
this._period === "day"
|
||||
? addDays(this._startDate!, -1)
|
||||
: this._period === "week"
|
||||
? addWeeks(this._startDate!, -1)
|
||||
: this._period === "month"
|
||||
? addMonths(this._startDate!, -1)
|
||||
: addYears(this._startDate!, -1);
|
||||
this._setDate(newStart);
|
||||
}
|
||||
|
||||
private _pickNext() {
|
||||
const newStart =
|
||||
this._period === "day"
|
||||
? addDays(this._startDate!, 1)
|
||||
: this._period === "week"
|
||||
? addWeeks(this._startDate!, 1)
|
||||
: this._period === "month"
|
||||
? addMonths(this._startDate!, 1)
|
||||
: addYears(this._startDate!, 1);
|
||||
this._setDate(newStart);
|
||||
}
|
||||
|
||||
private _setDate(startDate: Date) {
|
||||
const weekStartsOn = firstWeekdayIndex(this.hass.locale);
|
||||
|
||||
const endDate =
|
||||
this._period === "day"
|
||||
? calcDate(startDate, endOfDay, this.hass.locale, this.hass.config)
|
||||
: this._period === "week"
|
||||
? calcDate(startDate, endOfWeek, this.hass.locale, this.hass.config, {
|
||||
weekStartsOn,
|
||||
})
|
||||
: this._period === "month"
|
||||
? calcDate(startDate, endOfMonth, this.hass.locale, this.hass.config)
|
||||
: calcDate(startDate, endOfYear, this.hass.locale, this.hass.config);
|
||||
|
||||
private _updateCollectionPeriod() {
|
||||
const energyCollection = getEnergyDataCollection(this.hass, {
|
||||
key: this.collectionKey,
|
||||
});
|
||||
energyCollection.setPeriod(startDate, endDate);
|
||||
energyCollection.setPeriod(this._startDate!, this._endDate!);
|
||||
energyCollection.refresh();
|
||||
}
|
||||
|
||||
private _dateRangeChanged(ev) {
|
||||
const weekStartsOn = firstWeekdayIndex(this.hass.locale);
|
||||
this._startDate = calcDate(
|
||||
ev.detail.startDate,
|
||||
startOfDay,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
);
|
||||
this._endDate = calcDate(
|
||||
ev.detail.endDate,
|
||||
endOfDay,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
);
|
||||
|
||||
this._updateCollectionPeriod();
|
||||
}
|
||||
|
||||
private _pickToday() {
|
||||
if (!this._startDate) return;
|
||||
|
||||
const range = this._simpleRange();
|
||||
const today = new Date();
|
||||
if (range === "month") {
|
||||
this._startDate = calcDate(
|
||||
today,
|
||||
startOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
this._endDate = calcDate(
|
||||
today,
|
||||
endOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
} else if (range === "quarter") {
|
||||
this._startDate = calcDate(
|
||||
today,
|
||||
startOfQuarter,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
this._endDate = calcDate(
|
||||
today,
|
||||
endOfQuarter,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
} else if (range === "year") {
|
||||
this._startDate = calcDate(
|
||||
today,
|
||||
startOfYear,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
this._endDate = calcDate(
|
||||
today,
|
||||
endOfYear,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
} else {
|
||||
const weekStartsOn = firstWeekdayIndex(this.hass.locale);
|
||||
const weekStart = calcDate(
|
||||
this._endDate!,
|
||||
startOfWeek,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
);
|
||||
const weekEnd = calcDate(
|
||||
this._endDate!,
|
||||
endOfWeek,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
);
|
||||
|
||||
// Check if a single week is selected
|
||||
if (
|
||||
this._startDate.getTime() === weekStart.getTime() &&
|
||||
this._endDate!.getTime() === weekEnd.getTime()
|
||||
) {
|
||||
// Pick current week
|
||||
this._startDate = calcDate(
|
||||
today,
|
||||
startOfWeek,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
);
|
||||
this._endDate = calcDate(
|
||||
today,
|
||||
endOfWeek,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// Custom date range
|
||||
const difference = calcDateProperty(
|
||||
this._endDate!,
|
||||
differenceInDays,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this._startDate
|
||||
) as number;
|
||||
this._startDate = calcDate(
|
||||
calcDate(
|
||||
today,
|
||||
subDays,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
difference
|
||||
),
|
||||
startOfDay,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
);
|
||||
this._endDate = calcDate(
|
||||
today,
|
||||
endOfDay,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
{
|
||||
weekStartsOn,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this._updateCollectionPeriod();
|
||||
}
|
||||
|
||||
private _pickPrevious() {
|
||||
this._shift(false);
|
||||
}
|
||||
|
||||
private _pickNext() {
|
||||
this._shift(true);
|
||||
}
|
||||
|
||||
private _shift(forward: boolean) {
|
||||
if (!this._startDate) return;
|
||||
|
||||
let start: Date;
|
||||
let end: Date;
|
||||
if (
|
||||
(calcDateProperty(
|
||||
this._startDate,
|
||||
isFirstDayOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
) as boolean) &&
|
||||
(calcDateProperty(
|
||||
this._endDate!,
|
||||
isLastDayOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
) as boolean)
|
||||
) {
|
||||
// Shift date range with respect to month/year selection
|
||||
const difference =
|
||||
((calcDateProperty(
|
||||
this._endDate!,
|
||||
differenceInMonths,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this._startDate
|
||||
) as number) +
|
||||
1) *
|
||||
(forward ? 1 : -1);
|
||||
start = calcDate(
|
||||
this._startDate,
|
||||
addMonths,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
difference
|
||||
);
|
||||
end = calcDate(
|
||||
calcDate(
|
||||
this._endDate!,
|
||||
addMonths,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
difference
|
||||
),
|
||||
endOfMonth,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
} else {
|
||||
// Shift date range by period length
|
||||
const difference =
|
||||
((calcDateProperty(
|
||||
this._endDate!,
|
||||
differenceInDays,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
this._startDate
|
||||
) as number) +
|
||||
1) *
|
||||
(forward ? 1 : -1);
|
||||
start = calcDate(
|
||||
this._startDate,
|
||||
addDays,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
difference
|
||||
);
|
||||
end = calcDate(
|
||||
this._endDate!,
|
||||
addDays,
|
||||
this.hass.locale,
|
||||
this.hass.config,
|
||||
difference
|
||||
);
|
||||
}
|
||||
|
||||
this._startDate = start;
|
||||
this._endDate = end;
|
||||
|
||||
this._updateCollectionPeriod();
|
||||
}
|
||||
|
||||
private _updateDates(energyData: EnergyData): void {
|
||||
this._compare = energyData.startCompare !== undefined;
|
||||
this._startDate = energyData.start;
|
||||
this._endDate = energyData.end || endOfToday();
|
||||
const dayDifference = differenceInDays(this._endDate, this._startDate);
|
||||
this._period =
|
||||
dayDifference < 1
|
||||
? "day"
|
||||
: dayDifference === 6
|
||||
? "week"
|
||||
: dayDifference > 26 && dayDifference < 31 // 28, 29, 30 or 31 days in a month
|
||||
? "month"
|
||||
: dayDifference === 364 || dayDifference === 365 // Leap year
|
||||
? "year"
|
||||
: undefined;
|
||||
}
|
||||
|
||||
private _toggleCompare() {
|
||||
this._compare = !this._compare;
|
||||
private _toggleCompare(ev: CustomEvent<RequestSelectedDetail>) {
|
||||
if (ev.detail.source !== "interaction") {
|
||||
return;
|
||||
}
|
||||
this._compare = ev.detail.selected;
|
||||
const energyCollection = getEnergyDataCollection(this.hass, {
|
||||
key: this.collectionKey,
|
||||
});
|
||||
@ -305,74 +607,35 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
|
||||
return css`
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
:host([narrow]) .row {
|
||||
flex-direction: column-reverse;
|
||||
:host .time-handle {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
:host([narrow]) .time-handle {
|
||||
margin-left: auto;
|
||||
}
|
||||
.label {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
font-size: 20px;
|
||||
margin-left: auto;
|
||||
}
|
||||
.period {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
:host([narrow]) .period {
|
||||
margin-bottom: 8px;
|
||||
:host([narrow]) .label {
|
||||
margin-left: unset;
|
||||
}
|
||||
mwc-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
ha-icon-button {
|
||||
margin-left: 4px;
|
||||
--mdc-icon-size: 20px;
|
||||
}
|
||||
ha-icon-button.active::before,
|
||||
mwc-button.active::before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
background-color: currentColor;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
content: "";
|
||||
transition:
|
||||
opacity 15ms linear,
|
||||
background-color 15ms linear;
|
||||
opacity: var(--mdc-icon-button-ripple-opacity, 0.12);
|
||||
}
|
||||
ha-icon-button.active::before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.compare {
|
||||
position: relative;
|
||||
}
|
||||
:host {
|
||||
flex-shrink: 0;
|
||||
--mdc-button-outline-color: currentColor;
|
||||
--primary-color: currentColor;
|
||||
--mdc-theme-primary: currentColor;
|
||||
--mdc-theme-on-primary: currentColor;
|
||||
--mdc-button-disabled-outline-color: var(--disabled-text-color);
|
||||
--mdc-button-disabled-ink-color: var(--disabled-text-color);
|
||||
--mdc-icon-button-ripple-opacity: 0.2;
|
||||
}
|
||||
ha-icon-button {
|
||||
--mdc-icon-button-size: 28px;
|
||||
}
|
||||
ha-button-toggle-group {
|
||||
padding-left: 8px;
|
||||
padding-inline-start: 8px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
mwc-button {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -528,11 +528,15 @@
|
||||
"start_date": "Start date",
|
||||
"end_date": "End date",
|
||||
"select": "Select",
|
||||
"select_date_range": "Select time period",
|
||||
"ranges": {
|
||||
"today": "Today",
|
||||
"yesterday": "Yesterday",
|
||||
"this_week": "This week",
|
||||
"last_week": "Last week"
|
||||
"last_week": "Last week",
|
||||
"this_quarter": "This quarter",
|
||||
"this_month": "This month",
|
||||
"this_year": "This year"
|
||||
}
|
||||
},
|
||||
"relative_time": {
|
||||
@ -5232,10 +5236,6 @@
|
||||
},
|
||||
"energy_period_selector": {
|
||||
"today": "Today",
|
||||
"day": "Day",
|
||||
"week": "Week",
|
||||
"month": "Month",
|
||||
"year": "Year",
|
||||
"previous": "Previous",
|
||||
"next": "Next",
|
||||
"compare": "Compare data"
|
||||
|
Loading…
x
Reference in New Issue
Block a user