Compare commits

..

1 Commits

Author SHA1 Message Date
Aidan Timson bda25622ab Add "picker" option to dropdown select selectors 2026-01-06 16:21:04 +00:00
15 changed files with 68 additions and 75 deletions
+2 -25
View File
@@ -251,34 +251,11 @@ export class HaEntityPicker extends LitElement {
}
);
private _getEntitiesMemoized = memoizeOne(
(
_entities: HomeAssistant["entities"],
includeDomains?: string[],
excludeDomains?: string[],
entityFilter?: HaEntityPickerEntityFilterFunc,
includeDeviceClasses?: string[],
includeUnitOfMeasurement?: string[],
includeEntities?: string[],
excludeEntities?: string[],
value?: string
) =>
getEntities(
this.hass,
includeDomains,
excludeDomains,
entityFilter,
includeDeviceClasses,
includeUnitOfMeasurement,
includeEntities,
excludeEntities,
value
)
);
private _getEntitiesMemoized = memoizeOne(getEntities);
private _getItems = () =>
this._getEntitiesMemoized(
this.hass.entities,
this.hass,
this.includeDomains,
this.excludeDomains,
this.entityFilter,
+2 -3
View File
@@ -141,7 +141,6 @@ export class HaStatisticPicker extends LitElement {
private async _getStatisticIds() {
this.statisticIds = await getStatisticIds(this.hass, this.statisticTypes);
this._picker?.requestUpdate();
}
private _getItems = () =>
@@ -178,9 +177,9 @@ export class HaStatisticPicker extends LitElement {
entitiesOnly?: boolean,
excludeStatistics?: string[],
value?: string
): StatisticComboBoxItem[] | undefined => {
): StatisticComboBoxItem[] => {
if (!statisticIds) {
return undefined;
return [];
}
if (includeStatisticsUnitOfMeasurement) {
+1 -1
View File
@@ -39,7 +39,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
public getItems!: (
searchString?: string,
section?: string
) => (PickerComboBoxItem | string)[] | undefined;
) => (PickerComboBoxItem | string)[];
@property({ attribute: false, type: Array })
public getAdditionalItems?: (searchString?: string) => PickerComboBoxItem[];
+3 -3
View File
@@ -109,7 +109,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
public getItems!: (
searchString?: string,
section?: string
) => PickerComboBoxItem[] | undefined;
) => PickerComboBoxItem[];
@property({ attribute: false, type: Array })
public getAdditionalItems?: (searchString?: string) => PickerComboBoxItem[];
@@ -295,7 +295,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
this.getAdditionalItems?.(searchString) || [];
private _getItems = () => {
let items = [...(this.getItems(this._search, this.selectedSection) || [])];
let items = [...this.getItems(this._search, this.selectedSection)];
if (!this.sections?.length) {
items = items.sort((entityA, entityB) => {
@@ -787,7 +787,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
.section-title,
.title {
background-color: var(--ha-color-fill-neutral-quiet-resting);
padding: var(--ha-space-2) var(--ha-space-3);
padding: var(--ha-space-1) var(--ha-space-2);
font-weight: var(--ha-font-weight-bold);
color: var(--secondary-text-color);
min-height: var(--ha-space-6);
+1 -1
View File
@@ -10,7 +10,7 @@ class HaSectionTitle extends LitElement {
static styles = css`
:host {
background-color: var(--ha-color-fill-neutral-quiet-resting);
padding: var(--ha-space-2) var(--ha-space-3);
padding: var(--ha-space-1) var(--ha-space-2);
font-weight: var(--ha-font-weight-bold);
color: var(--secondary-text-color);
min-height: var(--ha-space-6);
@@ -9,6 +9,7 @@ import { stopPropagation } from "../../common/dom/stop_propagation";
import { caseInsensitiveStringCompare } from "../../common/string/compare";
import type { SelectOption, SelectSelector } from "../../data/selector";
import type { HomeAssistant } from "../../types";
import type { PickerValueRenderer } from "../ha-picker-field";
import "../chips/ha-chip-set";
import "../chips/ha-input-chip";
import "../ha-checkbox";
@@ -223,12 +224,30 @@ export class HaSelectSelector extends LitElement {
.required=${this.required}
.getItems=${this._getItems(options)}
.value=${this.value as string | undefined}
.valueRenderer=${this._getValueRenderer(options)}
@value-changed=${this._comboBoxValueChanged}
allow-custom-value
></ha-generic-picker>
`;
}
if (this._mode === "dropdown" && this.selector.select?.picker) {
return html`
<ha-generic-picker
.hass=${this.hass}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
.getItems=${this._getItems(options)}
.value=${this.value as string | undefined}
.valueRenderer=${this._getValueRenderer(options)}
@value-changed=${this._comboBoxValueChanged}
.allowCustomValue=${this.selector.select?.custom_value ?? false}
></ha-generic-picker>
`;
}
return html`
<ha-select
fixedMenuPosition
@@ -285,6 +304,15 @@ export class HaSelectSelector extends LitElement {
}
);
private _getValueRenderer = memoizeOne(
(options: SelectOption[]): PickerValueRenderer =>
(value: string) => {
const option = options.find((opt) => opt.value === value);
const label = option?.label || value;
return html`<span slot="headline">${label}</span>`;
}
);
private get _mode(): "list" | "dropdown" | "box" {
return (
this.selector.select?.mode ||
+12 -24
View File
@@ -449,9 +449,16 @@ const getEnergyData = async (
const allStatIDs = [...energyStatIds, ...waterStatIds, ...powerStatIds];
const dayDifference = differenceInDays(end || new Date(), start);
const period = getSuggestedPeriod(start, end);
const finePeriod = getSuggestedPeriod(start, end, true);
const period =
isFirstDayOfMonth(start) &&
(!end || isLastDayOfMonth(end)) &&
dayDifference > 35
? "month"
: dayDifference > 2
? "day"
: "hour";
const finePeriod =
dayDifference > 64 ? "day" : dayDifference > 8 ? "hour" : "5minute";
const statsMetadata: Record<string, StatisticsMetaData> = {};
const statsMetadataArray = allStatIDs.length
@@ -582,7 +589,7 @@ const getEnergyData = async (
consumptionStatIDs,
co2SignalEntity,
end,
period
dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour"
);
if (compare) {
_fossilEnergyConsumptionCompare = getFossilEnergyConsumption(
@@ -591,7 +598,7 @@ const getEnergyData = async (
consumptionStatIDs,
co2SignalEntity,
endCompare,
period
dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour"
);
}
}
@@ -1420,22 +1427,3 @@ export const formatPowerShort = (
units[unitIndex]
);
};
export function getSuggestedPeriod(
start: Date,
end?: Date,
fine = false
): "5minute" | "hour" | "day" | "month" {
const dayDifference = differenceInDays(end || new Date(), start);
if (fine) {
return dayDifference > 64 ? "day" : dayDifference > 8 ? "hour" : "5minute";
}
return isFirstDayOfMonth(start) &&
(!end || isLastDayOfMonth(end)) &&
dayDifference > 35
? "month"
: dayDifference > 2
? "day"
: "hour";
}
+1
View File
@@ -388,6 +388,7 @@ export interface SelectSelector {
multiple?: boolean;
custom_value?: boolean;
mode?: "list" | "dropdown" | "box";
picker?: boolean;
options: readonly string[] | readonly SelectOption[];
translation_key?: string;
sort?: boolean;
@@ -2062,7 +2062,6 @@ class DialogAddAutomationElement
.content.column {
flex-direction: column;
gap: var(--ha-space-3);
}
ha-md-list {
@@ -285,8 +285,6 @@ export class HaAutomationAddItems extends LitElement {
border-radius: var(--ha-border-radius-md);
background: var(--ha-color-fill-neutral-normal-resting);
padding: 0 var(--ha-space-2) 0 var(--ha-space-1);
border: var(--ha-border-width-sm) solid
var(--ha-color-border-neutral-quiet);
color: var(--ha-color-on-neutral-normal);
overflow: hidden;
}
@@ -223,8 +223,6 @@ export class HaAutomationRowTargets extends LitElement {
background: var(--ha-color-fill-neutral-normal-resting);
padding: 0 var(--ha-space-2) 0 var(--ha-space-1);
color: var(--ha-color-on-neutral-normal);
border: var(--ha-border-width-sm) solid
var(--ha-color-border-neutral-quiet);
overflow: hidden;
height: 32px;
}
@@ -31,7 +31,6 @@ import { formatTime } from "../../../../../common/datetime/format_time";
import type { ECOption } from "../../../../../resources/echarts/echarts";
import { filterXSS } from "../../../../../common/util/xss";
import type { StatisticPeriod } from "../../../../../data/recorder";
import { getSuggestedPeriod } from "../../../../../data/energy";
export function getSuggestedMax(period: StatisticPeriod, end: Date): number {
let suggestedMax = new Date(end);
@@ -57,6 +56,10 @@ export function getSuggestedMax(period: StatisticPeriod, end: Date): number {
return suggestedMax.getTime();
}
export function getSuggestedPeriod(dayDifference: number): StatisticPeriod {
return dayDifference > 35 ? "month" : dayDifference > 2 ? "day" : "hour";
}
function createYAxisLabelFormatter(locale: FrontendLocaleData) {
let previousValue: number | undefined;
@@ -92,7 +95,7 @@ export function getCommonOptions(
type: "time",
min: start,
max: getSuggestedMax(
getSuggestedPeriod(start, end, detailedDailyData),
detailedDailyData ? "5minute" : getSuggestedPeriod(dayDifference),
end
),
},
@@ -1,4 +1,4 @@
import { endOfToday, isToday, startOfToday } from "date-fns";
import { differenceInDays, endOfToday, isToday, startOfToday } from "date-fns";
import type { HassConfig, UnsubscribeFunc } from "home-assistant-js-websocket";
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
@@ -18,7 +18,6 @@ import type {
import {
getEnergyDataCollection,
getEnergySolarForecasts,
getSuggestedPeriod,
} from "../../../../data/energy";
import type { Statistics, StatisticsMetaData } from "../../../../data/recorder";
import { getStatisticLabel } from "../../../../data/recorder";
@@ -355,7 +354,7 @@ export class HuiEnergySolarGraphCard
) {
const data: LineSeriesOption[] = [];
const period = getSuggestedPeriod(start, end);
const dayDifference = differenceInDays(end || new Date(), start);
// Process solar forecast data.
solarSources.forEach((source) => {
@@ -371,10 +370,10 @@ export class HuiEnergySolarGraphCard
if (dateObj < start || (end && dateObj > end)) {
return;
}
if (period === "month") {
if (dayDifference > 35) {
dateObj.setDate(1);
}
if (period === "month" || period === "day") {
if (dayDifference > 2) {
dateObj.setHours(0, 0, 0, 0);
} else {
dateObj.setMinutes(0, 0, 0);
@@ -8,10 +8,7 @@ import { createSearchParam } from "../../../common/url/search-params";
import "../../../components/ha-card";
import "../../../components/ha-icon-next";
import "../../../components/ha-tooltip";
import {
getEnergyDataCollection,
getSuggestedPeriod,
} from "../../../data/energy";
import { getEnergyDataCollection } from "../../../data/energy";
import type {
Statistics,
StatisticsMetaData,
@@ -29,7 +26,10 @@ import { hasConfigOrEntitiesChanged } from "../common/has-changed";
import { processConfigEntities } from "../common/process-config-entities";
import type { EntityConfig } from "../entity-rows/types";
import type { LovelaceCard, LovelaceGridOptions } from "../types";
import { getSuggestedMax } from "./energy/common/energy-chart-options";
import {
getSuggestedMax,
getSuggestedPeriod,
} from "./energy/common/energy-chart-options";
import type { StatisticsGraphCardConfig } from "./types";
export const DEFAULT_DAYS_TO_SHOW = 30;
@@ -268,7 +268,9 @@ export class HuiStatisticsGraphCard extends LitElement implements LovelaceCard {
return (
this._config?.period ??
(this._energyStart && this._energyEnd
? getSuggestedPeriod(this._energyStart, this._energyEnd)
? getSuggestedPeriod(
differenceInDays(this._energyEnd, this._energyStart)
)
: undefined)
);
}
@@ -242,6 +242,7 @@ export class HuiClockCardEditor
selector: {
select: {
mode: "dropdown",
picker: true,
options: [
[
"auto",