- ${["form", "menu", "external"].includes(
- this._step?.type as any
- )
+ ${([
+ "form",
+ "menu",
+ "external",
+ "progress",
+ "data_entry_flow_progressed",
+ ].includes(this._step?.type as any) &&
+ this._params.manifest?.is_built_in) ||
+ this._params.manifest?.documentation
? html`
+
+
`
: ""}
@@ -427,6 +438,17 @@ class DataEntryFlowDialog extends LitElement {
this._handler = undefined;
}
this._processStep(step);
+ if (this._params!.manifest === undefined) {
+ try {
+ this._params!.manifest = await fetchIntegrationManifest(
+ this.hass,
+ this._params?.domain || step.handler
+ );
+ } catch (_) {
+ // No manifest
+ this._params!.manifest = null;
+ }
+ }
} else {
this._step = null;
this._flowsInProgress = flowsInProgress;
diff --git a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts
index 35f6630216..ca57038f8b 100644
--- a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts
+++ b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts
@@ -10,6 +10,7 @@ import {
DataEntryFlowStepMenu,
DataEntryFlowStepProgress,
} from "../../data/data_entry_flow";
+import { IntegrationManifest } from "../../data/integration";
import { HomeAssistant } from "../../types";
export interface FlowHandlers {
@@ -122,6 +123,8 @@ export interface DataEntryFlowDialogParams {
startFlowHandler?: string;
searchQuery?: string;
continueFlowId?: string;
+ manifest?: IntegrationManifest | null;
+ domain?: string;
dialogClosedCallback?: (params: {
flowFinished: boolean;
entryId?: string;
diff --git a/src/dialogs/config-flow/show-dialog-options-flow.ts b/src/dialogs/config-flow/show-dialog-options-flow.ts
index 4a90b08889..14adfcb9e4 100644
--- a/src/dialogs/config-flow/show-dialog-options-flow.ts
+++ b/src/dialogs/config-flow/show-dialog-options-flow.ts
@@ -1,6 +1,6 @@
import { html } from "lit";
import { ConfigEntry } from "../../data/config_entries";
-import { domainToName } from "../../data/integration";
+import { domainToName, IntegrationManifest } from "../../data/integration";
import {
createOptionsFlow,
deleteOptionsFlow,
@@ -16,12 +16,15 @@ export const loadOptionsFlowDialog = loadDataEntryFlowDialog;
export const showOptionsFlowDialog = (
element: HTMLElement,
- configEntry: ConfigEntry
+ configEntry: ConfigEntry,
+ manifest?: IntegrationManifest | null
): void =>
showFlowDialog(
element,
{
startFlowHandler: configEntry.entry_id,
+ domain: configEntry.domain,
+ manifest,
},
{
loadDevicesAndAreas: false,
diff --git a/src/dialogs/config-flow/step-flow-form.ts b/src/dialogs/config-flow/step-flow-form.ts
index e88128b326..5ec2e499d8 100644
--- a/src/dialogs/config-flow/step-flow-form.ts
+++ b/src/dialogs/config-flow/step-flow-form.ts
@@ -190,6 +190,10 @@ class StepFlowForm extends LitElement {
margin-top: 24px;
display: block;
}
+ h2 {
+ word-break: break-word;
+ padding-right: 72px;
+ }
`,
];
}
diff --git a/src/dialogs/more-info/controls/more-info-fan.js b/src/dialogs/more-info/controls/more-info-fan.js
index 5a2f042448..3da9229e1c 100644
--- a/src/dialogs/more-info/controls/more-info-fan.js
+++ b/src/dialogs/more-info/controls/more-info-fan.js
@@ -35,6 +35,7 @@ class MoreInfoFan extends LocalizeMixin(EventsMixin(PolymerElement)) {
.has-direction .container-direction,
.has-oscillating .container-oscillating {
display: block;
+ margin-top: 8px;
}
ha-select {
diff --git a/src/dialogs/more-info/controls/more-info-update.ts b/src/dialogs/more-info/controls/more-info-update.ts
index b48dfcf8a9..57c1ba574b 100644
--- a/src/dialogs/more-info/controls/more-info-update.ts
+++ b/src/dialogs/more-info/controls/more-info-update.ts
@@ -243,6 +243,10 @@ class MoreInfoUpdate extends LitElement {
width: 100%;
justify-content: center;
}
+ mwc-linear-progress {
+ margin-bottom: -10px;
+ margin-top: -10px;
+ }
`;
}
}
diff --git a/src/panels/config/automation/action/types/ha-automation-action-choose.ts b/src/panels/config/automation/action/types/ha-automation-action-choose.ts
index 43e360c459..97d97d4e38 100644
--- a/src/panels/config/automation/action/types/ha-automation-action-choose.ts
+++ b/src/panels/config/automation/action/types/ha-automation-action-choose.ts
@@ -165,6 +165,9 @@ export class HaChooseAction extends LitElement implements ActionElement {
right: 0;
padding: 4px;
}
+ ha-form::part(root) {
+ overflow: visible;
+ }
`,
];
}
diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts
index 3060139753..13254779b1 100644
--- a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts
+++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts
@@ -442,6 +442,9 @@ export default class HaAutomationTriggerRow extends LitElement {
z-index: 3;
--mdc-theme-text-primary-on-background: var(--primary-text-color);
}
+ .rtl .card-menu {
+ float: left;
+ }
.triggered {
cursor: pointer;
position: absolute;
@@ -470,9 +473,6 @@ export default class HaAutomationTriggerRow extends LitElement {
background-color: var(--accent-color);
color: var(--text-accent-color, var(--text-primary-color));
}
- .rtl .card-menu {
- float: left;
- }
mwc-list-item[disabled] {
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
}
diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts
index 48ebb5df49..eabbf8fbaf 100644
--- a/src/panels/config/entities/entity-registry-settings.ts
+++ b/src/panels/config/entities/entity-registry-settings.ts
@@ -11,10 +11,13 @@ import {
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
+import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import { computeDomain } from "../../../common/entity/compute_domain";
import { domainIcon } from "../../../common/entity/domain_icon";
+import { stringCompare } from "../../../common/string/compare";
+import { LocalizeFunc } from "../../../common/translations/localize";
import "../../../components/ha-alert";
import "../../../components/ha-area-picker";
import "../../../components/ha-expansion-panel";
@@ -96,7 +99,7 @@ const OVERRIDE_SENSOR_UNITS = {
pressure: ["hPa", "Pa", "kPa", "bar", "cbar", "mbar", "mmHg", "inHg", "psi"],
};
-const SWITCH_AS_DOMAINS = ["light", "lock", "cover", "fan", "siren"];
+const SWITCH_AS_DOMAINS = ["cover", "fan", "light", "lock", "siren"];
@customElement("entity-registry-settings")
export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
@@ -273,22 +276,29 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
@selected=${this._deviceClassChanged}
@closed=${stopPropagation}
>
- ${this._deviceClassOptions[0].map(
- (deviceClass: string) => html`
-
- ${this.hass.localize(
- `ui.dialogs.entity_registry.editor.device_classes.${domain}.${deviceClass}`
- )}
+ ${this._deviceClassesSorted(
+ domain,
+ this._deviceClassOptions[0],
+ this.hass.localize
+ ).map(
+ (entry) => html`
+
+ ${entry.label}
`
)}
-
- ${this._deviceClassOptions[1].map(
- (deviceClass: string) => html`
-
- ${this.hass.localize(
- `ui.dialogs.entity_registry.editor.device_classes.${domain}.${deviceClass}`
- )}
+ ${this._deviceClassOptions[0].length &&
+ this._deviceClassOptions[1].length
+ ? html``
+ : ""}
+ ${this._deviceClassesSorted(
+ domain,
+ this._deviceClassOptions[1],
+ this.hass.localize
+ ).map(
+ (entry) => html`
+
+ ${entry.label}
`
)}
@@ -296,9 +306,9 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
`
: ""}
${this._deviceClass &&
- stateObj.attributes.unit_of_measurement &&
+ stateObj?.attributes.unit_of_measurement &&
OVERRIDE_SENSOR_UNITS[this._deviceClass]?.includes(
- stateObj.attributes.unit_of_measurement
+ stateObj?.attributes.unit_of_measurement
)
? html`
${domainToName(this.hass.localize, "switch")}
- ${SWITCH_AS_DOMAINS.map(
- (as_domain) => html`
-
- ${domainToName(this.hass.localize, as_domain)}
+
+ ${this._switchAsDomainsSorted(
+ SWITCH_AS_DOMAINS,
+ this.hass.localize
+ ).map(
+ (entry) => html`
+
+ ${entry.label}
`
)}
@@ -716,9 +730,31 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
}
private async _showOptionsFlow() {
- showOptionsFlowDialog(this, this._helperConfigEntry!);
+ showOptionsFlowDialog(this, this._helperConfigEntry!, null);
}
+ private _switchAsDomainsSorted = memoizeOne(
+ (domains: string[], localize: LocalizeFunc) =>
+ domains
+ .map((entry) => ({
+ domain: entry,
+ label: domainToName(localize, entry),
+ }))
+ .sort((a, b) => stringCompare(a.label, b.label))
+ );
+
+ private _deviceClassesSorted = memoizeOne(
+ (domain: string, deviceClasses: string[], localize: LocalizeFunc) =>
+ deviceClasses
+ .map((entry) => ({
+ deviceClass: entry,
+ label: localize(
+ `ui.dialogs.entity_registry.editor.device_classes.${domain}.${entry}`
+ ),
+ }))
+ .sort((a, b) => stringCompare(a.label, b.label))
+ );
+
static get styles(): CSSResultGroup {
return [
haStyle,
diff --git a/src/panels/config/integrations/ha-config-integrations.ts b/src/panels/config/integrations/ha-config-integrations.ts
index a78eb0e94b..79cd2d7828 100644
--- a/src/panels/config/integrations/ha-config-integrations.ts
+++ b/src/panels/config/integrations/ha-config-integrations.ts
@@ -700,6 +700,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
this._handleFlowUpdated();
},
startFlowHandler: domain,
+ manifest: this._manifests[domain],
showAdvanced: this.hass.userData?.showAdvanced,
});
}
diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts
index 28154e279c..d2790ec98f 100644
--- a/src/panels/config/integrations/ha-integration-card.ts
+++ b/src/panels/config/integrations/ha-integration-card.ts
@@ -482,7 +482,11 @@ export class HaIntegrationCard extends LitElement {
);
private _showOptions(ev) {
- showOptionsFlowDialog(this, ev.target.closest("ha-card").configEntry);
+ showOptionsFlowDialog(
+ this,
+ ev.target.closest("ha-card").configEntry,
+ this.manifest
+ );
}
private _handleRename(ev: CustomEvent): void {
diff --git a/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts b/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts
index bae0576f9e..b29db5117b 100644
--- a/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts
+++ b/src/panels/developer-tools/statistics/dialog-statistics-adjust-sum.ts
@@ -1,6 +1,7 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list-item";
import { mdiChevronRight } from "@mdi/js";
+import formatISO9075 from "date-fns/formatISO9075";
import {
css,
CSSResultGroup,
@@ -69,12 +70,11 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
public showDialog(params: DialogStatisticsAdjustSumParams): void {
this._params = params;
+ // moment is in format YYYY-MM-DD HH:mm:ss because of selector
+ // Here we create a date with minutes set to %5
const now = new Date();
- this._moment = `${now.getFullYear()}-${
- now.getMonth() + 1
- }-${now.getDate()} ${now.getHours()}:${
- now.getMinutes() - (now.getMinutes() % 5)
- }:00`;
+ now.setMinutes(now.getMinutes() - (now.getMinutes() % 5), 0);
+ this._moment = formatISO9075(now);
this._fetchStats();
}
@@ -167,6 +167,9 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
time. This can mess up your beautiful graphs! Select a time below to
find the bad moment and adjust the data.
+
- ${this._params!.statistic.name || this._params!.statistic.statistic_id}
+ Statistic: ${this._params!.statistic.statistic_id}
@@ -250,7 +253,10 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
this._stats5min = undefined;
this._statsHour = undefined;
const statId = this._params!.statistic.statistic_id;
- const moment = new Date(this._moment!);
+
+ // moment is in format YYYY-MM-DD HH:mm:ss because of selector
+ // Here we convert it to an ISO string.
+ const moment = new Date(this._moment!.replace(" ", "T"));
// Search 3 hours before and 3 hours after chosen time
const hourStatStart = new Date(moment.getTime());
diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts
index 076d2f02db..f47011d22a 100644
--- a/src/panels/history/ha-panel-history.ts
+++ b/src/panels/history/ha-panel-history.ts
@@ -253,6 +253,10 @@ class HaPanelHistory extends LitElement {
padding: 8px 16px 0;
}
+ :host([narrow]) .filters {
+ flex-wrap: wrap;
+ }
+
ha-date-range-picker {
margin-right: 16px;
max-width: 100%;
diff --git a/src/panels/lovelace/common/entity/turn-on-off-entity.ts b/src/panels/lovelace/common/entity/turn-on-off-entity.ts
index 83c675b9dc..701c2c4996 100644
--- a/src/panels/lovelace/common/entity/turn-on-off-entity.ts
+++ b/src/panels/lovelace/common/entity/turn-on-off-entity.ts
@@ -21,6 +21,9 @@ export const turnOnOffEntity = (
case "input_button":
service = "press";
break;
+ case "scene":
+ service = "turn_on";
+ break;
default:
service = turnOn ? "turn_on" : "turn_off";
}
diff --git a/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts b/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts
index e8c524cfdf..ed49622a37 100644
--- a/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-generic-entity-row-editor.ts
@@ -15,6 +15,7 @@ import type { LovelaceRowEditor } from "../../types";
import { entitiesConfigStruct } from "../structs/entities-struct";
const SecondaryInfoValues: { [key: string]: { domains?: string[] } } = {
+ none: {},
"entity-id": {},
"last-changed": {},
"last-updated": {},