1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-02-15 07:25:54 +00:00

Migrate more "ha-settings-row" to "ha-md-list-item" (#29508)

Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
Co-authored-by: Wendelin <w@pe8.at>
This commit is contained in:
ildar170975
2026-02-12 11:54:49 +03:00
committed by GitHub
parent 24014116dc
commit a354026780
13 changed files with 553 additions and 521 deletions

View File

@@ -5,7 +5,7 @@ import { fireEvent } from "../common/dom/fire_event";
import type { LocalizeFunc } from "../common/translations/localize";
import type { Analytics, AnalyticsPreferences } from "../data/analytics";
import { haStyle } from "../resources/styles";
import "./ha-settings-row";
import "./ha-md-list-item";
import "./ha-switch";
import "./ha-tooltip";
import type { HaSwitch } from "./ha-switch";
@@ -33,105 +33,80 @@ export class HaAnalytics extends LitElement {
const baseEnabled = !loading && this.analytics!.preferences.base;
return html`
<ha-settings-row>
<span slot="heading" data-for="base">
${this.localize(
<ha-md-list-item>
<span slot="headline"
>${this.localize(
`ui.panel.${this.translationKeyPanel}.analytics.preferences.base.title`
)}
</span>
<span slot="description" data-for="base">
${this.localize(
)}</span
>
<span slot="supporting-text"
>${this.localize(
`ui.panel.${this.translationKeyPanel}.analytics.preferences.base.description`
)}
</span>
)}</span
>
<ha-switch
slot="end"
@change=${this._handleRowClick}
.checked=${!!baseEnabled}
.preference=${"base"}
.disabled=${loading}
name="base"
>
</ha-switch>
</ha-settings-row>
></ha-switch>
</ha-md-list-item>
${ADDITIONAL_PREFERENCES.map(
(preference) => html`
<ha-settings-row>
<span slot="heading" data-for=${preference}>
${this.localize(
<ha-md-list-item>
<span slot="headline"
>${this.localize(
`ui.panel.${this.translationKeyPanel}.analytics.preferences.${preference}.title`
)}
</span>
<span slot="description" data-for=${preference}>
${this.localize(
)}</span
>
<span slot="supporting-text"
>${this.localize(
`ui.panel.${this.translationKeyPanel}.analytics.preferences.${preference}.description`
)}
</span>
<span>
<ha-switch
.id="switch-${preference}"
@change=${this._handleRowClick}
.checked=${!!this.analytics?.preferences[preference]}
.preference=${preference}
name=${preference}
>
</ha-switch>
${baseEnabled
? nothing
: html`<ha-tooltip
.for="switch-${preference}"
placement="right"
>
${this.localize(
`ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled`
)}
</ha-tooltip>`}
</span>
</ha-settings-row>
)}</span
>
<ha-switch
slot="end"
.id="switch-${preference}"
@change=${this._handleRowClick}
.checked=${!!this.analytics?.preferences[preference]}
.preference=${preference}
name=${preference}
></ha-switch>
${baseEnabled
? nothing
: html`<ha-tooltip .for="switch-${preference}" placement="right">
${this.localize(
`ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled`
)}
</ha-tooltip>`}
</ha-md-list-item>
`
)}
<ha-settings-row>
<span slot="heading" data-for="diagnostics">
${this.localize(
<ha-md-list-item>
<span slot="headline"
>${this.localize(
`ui.panel.${this.translationKeyPanel}.analytics.preferences.diagnostics.title`
)}
</span>
<span slot="description" data-for="diagnostics">
${this.localize(
)}</span
>
<span slot="supporting-text"
>${this.localize(
`ui.panel.${this.translationKeyPanel}.analytics.preferences.diagnostics.description`
)}
</span>
)}</span
>
<ha-switch
slot="end"
@change=${this._handleRowClick}
.checked=${!!this.analytics?.preferences.diagnostics}
.preference=${"diagnostics"}
.disabled=${loading}
name="diagnostics"
>
</ha-switch>
</ha-settings-row>
></ha-switch>
</ha-md-list-item>
`;
}
protected updated(changedProps) {
super.updated(changedProps);
this.shadowRoot!.querySelectorAll("*[data-for]").forEach((el) => {
const forEl = (el as HTMLElement).dataset.for;
delete (el as HTMLElement).dataset.for;
el.addEventListener("click", () => {
const toFocus = this.shadowRoot!.querySelector(
`*[name=${forEl}]`
) as HTMLElement | null;
if (toFocus) {
toFocus.focus();
toFocus.click();
}
});
});
}
private _handleRowClick(ev: Event) {
const target = ev.currentTarget as HaSwitch;
const preference = (target as any).preference;
@@ -164,13 +139,10 @@ export class HaAnalytics extends LitElement {
color: var(--error-color);
}
ha-settings-row {
padding: 0;
}
span[slot="heading"],
span[slot="description"] {
cursor: pointer;
ha-md-list-item {
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-item-overflow: visible;
}
`,
];

View File

@@ -229,7 +229,6 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
<cloud-webhooks
.hass=${this.hass}
.narrow=${this.narrow}
.cloudStatus=${this.cloudStatus}
></cloud-webhooks>
</ha-config-section>

View File

@@ -5,7 +5,7 @@ import { isComponentLoaded } from "../../../../common/config/is_component_loaded
import "../../../../components/ha-card";
import "../../../../components/ha-button";
import "../../../../components/ha-spinner";
import "../../../../components/ha-settings-row";
import "../../../../components/ha-md-list-item";
import "../../../../components/ha-switch";
import type { CloudStatusLoggedIn, CloudWebhook } from "../../../../data/cloud";
import { createCloudhook, deleteCloudhook } from "../../../../data/cloud";
@@ -21,8 +21,6 @@ export class CloudWebhooks extends LitElement {
@property({ attribute: false }) public cloudStatus?: CloudStatusLoggedIn;
@property({ type: Boolean }) public narrow = false;
@state() private _cloudHooks?: Record<string, CloudWebhook>;
@state() private _localHooks?: Webhook[];
@@ -78,23 +76,24 @@ export class CloudWebhooks extends LitElement {
`
: this._localHooks.map(
(entry) => html`
<ha-settings-row .narrow=${this.narrow} .entry=${entry}>
<span slot="heading">
${entry.name}
<ha-md-list-item .entry=${entry}>
<span slot="headline"
>${entry.name}
${entry.domain !== entry.name.toLowerCase()
? ` (${entry.domain})`
: ""}
</span>
<span slot="description">${entry.webhook_id}</span>
: ""}</span
>
<span slot="supporting-text">${entry.webhook_id}</span>
${this._progress.includes(entry.webhook_id)
? html`
<div class="progress">
<div class="progress" slot="end">
<ha-spinner></ha-spinner>
</div>
`
: this._cloudHooks![entry.webhook_id]
? html`
<ha-button
slot="end"
appearance="plain"
size="small"
@click=${this._handleManageButton}
@@ -104,9 +103,10 @@ export class CloudWebhooks extends LitElement {
)}
</ha-button>
`
: html`<ha-switch @click=${this._enableWebhook}>
: html`<ha-switch slot="end">
@click=${this._enableWebhook}
</ha-switch>`}
</ha-settings-row>
</ha-md-list-item>
`
)}
<div class="footer">
@@ -235,8 +235,13 @@ export class CloudWebhooks extends LitElement {
.footer a {
color: var(--primary-color);
}
ha-settings-row {
padding: 0;
ha-md-list-item {
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-item-overflow: visible;
}
ha-md-list-item [slot="supporting-text"] {
word-break: break-all;
}
`,
];

View File

@@ -28,10 +28,10 @@ import "../../../components/ha-icon-button-next";
import "../../../components/ha-icon-picker";
import "../../../components/ha-labels-picker";
import "../../../components/ha-list-item";
import "../../../components/ha-md-list-item";
import "../../../components/ha-radio";
import "../../../components/ha-select";
import type { HaSelectSelectEvent } from "../../../components/ha-select";
import "../../../components/ha-settings-row";
import "../../../components/ha-state-icon";
import "../../../components/ha-switch";
import type { HaSwitch } from "../../../components/ha-switch";
@@ -502,22 +502,23 @@ export class EntityRegistrySettingsEditor extends LitElement {
</ha-select>
${SWITCH_AS_DOMAINS_INVERT.includes(this._switchAsDomain)
? html`
<ha-settings-row>
<span slot="heading"
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.invert.label"
)}</span
>
<span slot="description"
<span slot="supporting-text"
>${this.hass.localize(
`ui.dialogs.entity_registry.editor.invert.descriptions.${this._switchAsDomain}`
)}</span
>
<ha-switch
slot="end"
.checked=${!!this.entry.options?.switch_as_x?.invert}
@change=${this._switchAsInvertChanged}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
`
: nothing} `
: nothing}
@@ -781,36 +782,37 @@ export class EntityRegistrySettingsEditor extends LitElement {
></ha-labels-picker>
${this._cameraPrefs
? html`
<ha-settings-row>
<span slot="heading"
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.stream.preload_stream"
)}</span
>
<span slot="description"
<span slot="supporting-text"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.stream.preload_stream_description"
)}</span
>
<ha-switch
slot="end"
.checked=${this._cameraPrefs.preload_stream}
.disabled=${this.disabled}
@change=${this._handleCameraPrefsChanged}
>
</ha-switch>
</ha-settings-row>
<ha-settings-row>
<span slot="heading"
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.stream.stream_orientation"
)}</span
>
<span slot="description"
<span slot="supporting-text"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.stream.stream_orientation_description"
)}</span
>
<ha-select
slot="supporting-text"
.label=${this.hass.localize(
"ui.dialogs.entity_registry.editor.stream.stream_orientation"
)}
@@ -826,7 +828,7 @@ export class EntityRegistrySettingsEditor extends LitElement {
.value=${this._cameraPrefs.orientation.toString()}
>
</ha-select>
</ha-settings-row>
</ha-md-list-item>
`
: nothing}
${this.helperConfigEntry &&
@@ -906,18 +908,19 @@ export class EntityRegistrySettingsEditor extends LitElement {
>`
: nothing}
<ha-settings-row>
<span slot="heading"
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.enabled_label"
)}</span
>
<span slot="description"
<span slot="supporting-text"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.enabled_description"
)}</span
>
<ha-switch
slot="end"
.checked=${!this._disabledBy}
.disabled=${this.disabled ||
this._device?.disabled_by ||
@@ -926,7 +929,7 @@ export class EntityRegistrySettingsEditor extends LitElement {
this._disabledBy !== "integration")}
@change=${this._enabledChanged}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
${this._hiddenBy && this._hiddenBy !== "user"
? html`<ha-alert alert-type="warning"
@@ -941,27 +944,29 @@ export class EntityRegistrySettingsEditor extends LitElement {
>`
: nothing}
<ha-settings-row>
<span slot="heading"
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.visible_label"
)}</span
>
<span slot="description"
<span slot="supporting-text"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.hidden_explanation"
)}</span
>
<ha-switch
slot="end"
.checked=${!this._disabledBy && !this._hiddenBy}
.disabled=${this.disabled || this._disabledBy}
@change=${this._hiddenChanged}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
${this.entry.device_id
? html`<ha-settings-row>
<span slot="heading"
? html`
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.use_device_area"
)}
@@ -973,7 +978,7 @@ export class EntityRegistrySettingsEditor extends LitElement {
})`
: nothing}</span
>
<span slot="description"
<span slot="supporting-text"
>${this.hass.localize(
"ui.dialogs.entity_registry.editor.change_device_settings",
{
@@ -989,12 +994,12 @@ export class EntityRegistrySettingsEditor extends LitElement {
)}</span
>
<ha-switch
slot="end"
.checked=${!this._areaId || this._noDeviceArea}
.disabled=${this.disabled}
@change=${this._useDeviceAreaChanged}
>
</ha-switch
></ha-settings-row>
></ha-switch>
</ha-md-list-item>
${this._areaId || this._noDeviceArea
? html`<ha-area-picker
.hass=${this.hass}
@@ -1002,7 +1007,8 @@ export class EntityRegistrySettingsEditor extends LitElement {
.disabled=${this.disabled}
@value-changed=${this._areaPicked}
></ha-area-picker>`
: nothing} `
: nothing}
`
: nothing}
`;
}
@@ -1563,21 +1569,8 @@ export class EntityRegistrySettingsEditor extends LitElement {
inset-inline-end: calc(var(--ha-space-2) * -1);
direction: var(--direction);
}
ha-switch {
margin-right: var(--ha-space-4);
margin-inline-end: var(--ha-space-4);
margin-inline-start: initial;
}
ha-settings-row ha-switch {
margin-right: 0;
margin-inline-end: 0;
margin-inline-start: initial;
}
ha-settings-row {
display: grid;
grid-template-columns: 1fr auto;
gap: var(--ha-space-4);
align-items: start;
ha-md-list-item ha-select {
width: auto;
}
ha-textfield,
ha-icon-picker,

View File

@@ -6,9 +6,9 @@ import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { isIPAddress } from "../../../common/string/is_ip_address";
import "../../../components/ha-alert";
import "../../../components/ha-card";
import "../../../components/ha-md-list-item";
import "../../../components/ha-switch";
import "../../../components/ha-textfield";
import "../../../components/ha-settings-row";
import "../../../components/ha-button";
import type { HaTextField } from "../../../components/ha-textfield";
import type { CloudStatus } from "../../../data/cloud";
@@ -110,10 +110,10 @@ class ConfigUrlForm extends SubscribeMixin(LitElement) {
)}
</ha-alert>
`
: ""}
: nothing}
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
: nothing}
<div class="description">
${this.hass.localize("ui.panel.config.url.description")}
@@ -126,20 +126,21 @@ class ConfigUrlForm extends SubscribeMixin(LitElement) {
"ui.panel.config.url.external_url_label"
)}
</h4>
<ha-settings-row slim>
<span slot="heading">
${this.hass.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.url.external_use_ha_cloud"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.disabled=${disabled}
.checked=${this._cloudChecked}
@change=${this._toggleCloud}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
`
: ""}
: nothing}
<div class="url-container">
<div class="textfield-container">
<ha-textfield
@@ -181,7 +182,7 @@ class ConfigUrlForm extends SubscribeMixin(LitElement) {
</ha-button>
</div>
${hasCloud || !isComponentLoaded(this.hass, "cloud")
? ""
? nothing
: html`
<div class="row">
<div class="flex"></div>
@@ -223,28 +224,29 @@ class ConfigUrlForm extends SubscribeMixin(LitElement) {
</ha-alert>
`}
`
: ""}
: nothing}
<h4>
${this.hass.localize("ui.panel.config.url.internal_url_label")}
</h4>
<ha-settings-row slim>
<span slot="heading">
${this.hass.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.url.internal_url_automatic"
)}
</span>
<span slot="description">
${this.hass.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.url.internal_url_automatic_description"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.disabled=${disabled}
.checked=${!this._showCustomInternalUrl}
@change=${this._toggleInternalAutomatic}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
<div class="url-container">
<div class="textfield-container">
@@ -310,7 +312,7 @@ class ConfigUrlForm extends SubscribeMixin(LitElement) {
)}
</ha-alert>
`
: ""
: nothing
}
</div>
<div class="card-actions">
@@ -465,6 +467,14 @@ class ConfigUrlForm extends SubscribeMixin(LitElement) {
color: var(--secondary-text-color);
direction: var(--direction);
}
ha-md-list-item {
--md-list-item-top-space: 0;
--md-list-item-bottom-space: 0;
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-list-item-two-line-container-height: 48px;
}
`;
}

View File

@@ -10,7 +10,7 @@ import "../../../components/ha-dialog-footer";
import "../../../components/ha-icon-button";
import "../../../components/ha-picture-upload";
import type { HaPictureUpload } from "../../../components/ha-picture-upload";
import "../../../components/ha-settings-row";
import "../../../components/ha-md-list-item";
import "../../../components/ha-textfield";
import "../../../components/ha-wa-dialog";
import { adminChangeUsername } from "../../../data/auth";
@@ -164,18 +164,19 @@ class DialogPersonDetail extends LitElement implements HassDialog {
@change=${this._pictureChanged}
></ha-picture-upload>
<ha-settings-row>
<span slot="heading">
${this.hass!.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass!.localize(
"ui.panel.config.person.detail.allow_login"
)}
</span>
<span slot="description">
${this.hass!.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass!.localize(
"ui.panel.config.person.detail.allow_login_description"
)}
</span>
)}</span
>
<ha-switch
slot="end"
@change=${this._allowLoginChanged}
.disabled=${this._user &&
(this._user.id === this.hass.user?.id ||
@@ -183,7 +184,7 @@ class DialogPersonDetail extends LitElement implements HassDialog {
this._user.is_owner)}
.checked=${this._userId}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
${this._renderUserFields()}
${this._deviceTrackersAvailable(this.hass)
@@ -280,14 +281,17 @@ class DialogPersonDetail extends LitElement implements HassDialog {
return html`
${!user.system_generated
? html`
<ha-settings-row>
<span slot="heading">
${this.hass.localize("ui.panel.config.person.detail.username")}
</span>
<span slot="description">${user.username}</span>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.person.detail.username"
)}</span
>
<span slot="supporting-text">${user.username}</span>
${this.hass.user?.is_owner
? html`
<ha-icon-button
slot="end"
.path=${mdiPencil}
@click=${this._changeUsername}
.label=${this.hass.localize(
@@ -297,19 +301,22 @@ class DialogPersonDetail extends LitElement implements HassDialog {
</ha-icon-button>
`
: nothing}
</ha-settings-row>
</ha-md-list-item>
`
: nothing}
${!user.system_generated && this.hass.user?.is_owner
? html`
<ha-settings-row>
<span slot="heading">
${this.hass.localize("ui.panel.config.person.detail.password")}
</span>
<span slot="description">************</span>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.person.detail.password"
)}</span
>
<span slot="supporting-text">************</span>
${this.hass.user?.is_owner
? html`
<ha-icon-button
slot="end"
.path=${mdiPencil}
@click=${this._changePassword}
.label=${this.hass.localize(
@@ -319,43 +326,43 @@ class DialogPersonDetail extends LitElement implements HassDialog {
</ha-icon-button>
`
: nothing}
</ha-settings-row>
</ha-md-list-item>
`
: nothing}
<ha-settings-row>
<span slot="heading">
${this.hass.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.person.detail.local_access_only"
)}
</span>
<span slot="description">
${this.hass.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.person.detail.local_access_only_description"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.disabled=${user.system_generated}
.checked=${this._localOnly}
@change=${this._localOnlyChanged}
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize("ui.panel.config.person.detail.admin")}</span
>
</ha-switch>
</ha-settings-row>
<ha-settings-row>
<span slot="heading">
${this.hass.localize("ui.panel.config.person.detail.admin")}
</span>
<span slot="description">
${this.hass.localize(
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.person.detail.admin_description"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isAdmin}
@change=${this._adminChanged}
>
</ha-switch>
</ha-settings-row>
></ha-switch>
</ha-md-list-item>
`;
}
@@ -556,8 +563,10 @@ class DialogPersonDetail extends LitElement implements HassDialog {
margin-bottom: 16px;
--file-upload-image-border-radius: var(--ha-border-radius-circle);
}
ha-settings-row {
padding: 0;
ha-md-list-item {
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-item-overflow: visible;
}
a {
color: var(--primary-color);

View File

@@ -6,7 +6,7 @@ import "../../../components/ha-alert";
import "../../../components/ha-button";
import "../../../components/ha-dialog-footer";
import "../../../components/ha-icon-button";
import "../../../components/ha-settings-row";
import "../../../components/ha-md-list-item";
import "../../../components/ha-switch";
import type { HaSwitch } from "../../../components/ha-switch";
import "../../../components/ha-textfield";
@@ -156,35 +156,38 @@ export class DialogAddUser extends LitElement {
"ui.panel.config.users.add_user.password_not_match"
)}
></ha-password-field>
<ha-settings-row>
<span slot="heading">
${this.hass.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.users.editor.local_access_only"
)}
</span>
<span slot="description">
${this.hass.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.users.editor.local_access_only_description"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.checked=${this._localOnly}
@change=${this._localOnlyChanged}
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize("ui.panel.config.users.editor.admin")}</span
>
</ha-switch>
</ha-settings-row>
<ha-settings-row>
<span slot="heading">
${this.hass.localize("ui.panel.config.users.editor.admin")}
</span>
<span slot="description">
${this.hass.localize(
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.users.editor.admin_description"
)}
</span>
<ha-switch .checked=${this._isAdmin} @change=${this._adminChanged}>
</ha-switch>
</ha-settings-row>
)}</span
>
<ha-switch
slot="end"
.checked=${this._isAdmin}
@change=${this._adminChanged}
></ha-switch>
</ha-md-list-item>
${!this._isAdmin
? html`
<ha-alert alert-type="info">
@@ -321,8 +324,10 @@ export class DialogAddUser extends LitElement {
display: block;
margin-bottom: 8px;
}
ha-settings-row {
padding: 0;
ha-md-list-item {
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-item-overflow: visible;
}
`,
];

View File

@@ -8,7 +8,7 @@ import "../../../components/ha-button";
import "../../../components/ha-dialog-footer";
import "../../../components/ha-icon-button";
import "../../../components/ha-label";
import "../../../components/ha-settings-row";
import "../../../components/ha-md-list-item";
import "../../../components/ha-svg-icon";
import "../../../components/ha-switch";
import "../../../components/ha-textfield";
@@ -75,184 +75,202 @@ class DialogUserDetail extends LitElement {
@closed=${this._dialogClosed}
>
<div>
${this._error
? html`<div class="error">${this._error}</div>`
: nothing}
${
this._error
? html`<div class="error">${this._error}</div>`
: nothing
}
<div class="secondary">
${this.hass.localize("ui.panel.config.users.editor.id")}:
${user.id}<br />
</div>
${badges.length === 0
? nothing
: html`
<div class="badge-container">
${badges.map(
([icon, label]) => html`
<ha-label>
<ha-svg-icon slot="icon" .path=${icon}></ha-svg-icon>
${label}
</ha-label>
`
)}
</div>
`}
<div class="form">
${!user.system_generated
? html`
<ha-textfield
autofocus
.value=${this._name}
@input=${this._nameChanged}
.label=${this.hass!.localize(
"ui.panel.config.users.editor.name"
${
badges.length === 0
? nothing
: html`
<div class="badge-container">
${badges.map(
([icon, label]) => html`
<ha-label>
<ha-svg-icon slot="icon" .path=${icon}></ha-svg-icon>
${label}
</ha-label>
`
)}
></ha-textfield>
<ha-settings-row>
<span slot="heading">
${this.hass.localize(
"ui.panel.config.users.editor.username"
)}
</span>
<span slot="description">${user.username}</span>
${this.hass.user?.is_owner
? html`
<ha-icon-button
.path=${mdiPencil}
@click=${this._changeUsername}
.label=${this.hass.localize(
"ui.panel.config.users.editor.change_username"
)}
>
</ha-icon-button>
`
: nothing}
</ha-settings-row>
</div>
`
: nothing}
${!user.system_generated && this.hass.user?.is_owner
? html`
<ha-settings-row>
<span slot="heading">
${this.hass.localize(
"ui.panel.config.users.editor.password"
}
<div class="form">
${
!user.system_generated
? html`
<ha-textfield
autofocus
.value=${this._name}
@input=${this._nameChanged}
.label=${this.hass!.localize(
"ui.panel.config.users.editor.name"
)}
</span>
<span slot="description">************</span>
${this.hass.user?.is_owner
? html`
<ha-icon-button
.path=${mdiPencil}
@click=${this._changePassword}
.label=${this.hass.localize(
"ui.panel.config.users.editor.change_password"
)}
>
</ha-icon-button>
`
: nothing}
</ha-settings-row>
`
: nothing}
<ha-settings-row>
<span slot="heading">
${this.hass.localize("ui.panel.config.users.editor.active")}
</span>
<span slot="description">
${this.hass.localize(
"ui.panel.config.users.editor.active_description"
)}
</span>
<ha-switch
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isActive}
@change=${this._activeChanged}
>
</ha-switch>
</ha-settings-row>
<ha-settings-row>
<span slot="heading">
${this.hass.localize(
"ui.panel.config.users.editor.local_access_only"
)}
</span>
<span slot="description">
${this.hass.localize(
"ui.panel.config.users.editor.local_access_only_description"
)}
</span>
<ha-switch
.disabled=${user.system_generated}
.checked=${this._localOnly}
@change=${this._localOnlyChanged}
>
</ha-switch>
</ha-settings-row>
<ha-settings-row>
<span slot="heading">
${this.hass.localize("ui.panel.config.users.editor.admin")}
</span>
<span slot="description">
${this.hass.localize(
"ui.panel.config.users.editor.admin_description"
)}
</span>
<ha-switch
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isAdmin}
@change=${this._adminChanged}
>
</ha-switch>
</ha-settings-row>
${!this._isAdmin && !user.system_generated
></ha-textfield>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.users.editor.username"
)}</span
>
<span slot="supporting-text">${user.username}</span>
${this.hass.user?.is_owner
? html`
<ha-icon-button
slot="end"
.path=${mdiPencil}
@click=${this._changeUsername}
.label=${this.hass.localize(
"ui.panel.config.users.editor.change_username"
)}
>
</ha-icon-button>
`
: nothing}
</ha-md-list-item>
`
: nothing
}
${
!user.system_generated && this.hass.user?.is_owner
? html`
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.users.editor.password"
)}</span
>
<span slot="supporting-text">************</span>
${this.hass.user?.is_owner
? html`
<ha-icon-button
slot="end"
.path=${mdiPencil}
@click=${this._changePassword}
.label=${this.hass.localize(
"ui.panel.config.users.editor.change_password"
)}
>
</ha-icon-button>
`
: nothing}
</ha-md-list-item>
`
: nothing
}
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.users.editor.active"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.users.editor.active_description"
)}</span
>
<ha-switch
slot="end"
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isActive}
@change=${this._activeChanged}
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.users.editor.local_access_only"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.users.editor.local_access_only_description"
)}</span
>
<ha-switch
slot="end"
.disabled=${user.system_generated}
.checked=${this._localOnly}
@change=${this._localOnlyChanged}
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.users.editor.admin"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.users.editor.admin_description"
)}</span
>
<ha-switch
slot="end"
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isAdmin}
@change=${this._adminChanged}
></ha-switch>
</ha-switch>
</ha-md-list-item>
${
!this._isAdmin && !user.system_generated
? html`
<ha-alert alert-type="info">
${this.hass.localize(
"ui.panel.config.users.users_privileges_note"
)}
</ha-alert>
`
: nothing
}
</div>
${
user.system_generated
? html`
<ha-alert alert-type="info">
${this.hass.localize(
"ui.panel.config.users.users_privileges_note"
"ui.panel.config.users.editor.system_generated_read_only_users"
)}
</ha-alert>
`
: nothing}
</div>
${user.system_generated
? html`
<ha-alert alert-type="info">
${this.hass.localize(
"ui.panel.config.users.editor.system_generated_read_only_users"
)}
</ha-alert>
`
: nothing}
: nothing
}
</div>
<ha-dialog-footer slot="footer">
<ha-button
<ha-button
slot="secondaryAction"
variant="danger"
appearance="plain"
@click=${this._deleteEntry}
.disabled=${
this._submitting || user.system_generated || user.is_owner
}
>
${this.hass!.localize("ui.panel.config.users.editor.delete_user")}
</ha-button>
<ha-button
slot="secondaryAction"
variant="danger"
appearance="plain"
@click=${this._deleteEntry}
.disabled=${this._submitting ||
user.system_generated ||
user.is_owner}
>
${this.hass!.localize("ui.panel.config.users.editor.delete_user")}
</ha-button>
<ha-button
slot="secondaryAction"
appearance="plain"
@click=${this._close}
>
${this.hass!.localize("ui.common.cancel")}
</ha-button>
<ha-button
slot="primaryAction"
@click=${this._updateEntry}
.disabled=${!this._name ||
this._submitting ||
user.system_generated}
>
${this.hass!.localize("ui.common.save")}
</ha-button>
appearance="plain"
@click=${this._close}
>
${this.hass!.localize("ui.common.cancel")}
</ha-button>
<ha-button
slot="primaryAction"
@click=${this._updateEntry}
.disabled=${
!this._name || this._submitting || user.system_generated
}
>
${this.hass!.localize("ui.common.save")}
</ha-button>
</ha-dialog-footer>
</ha-wa-dialog>
`;
@@ -391,6 +409,11 @@ class DialogUserDetail extends LitElement {
ha-textfield {
display: block;
}
ha-md-list-item {
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-item-overflow: visible;
}
.badge-container {
margin-top: 4px;
}
@@ -402,9 +425,6 @@ class DialogUserDetail extends LitElement {
margin-inline-end: 4px;
margin-inline-start: 0;
}
ha-settings-row {
padding: 0;
}
`,
];
}

View File

@@ -23,6 +23,7 @@ import "../../../components/ha-card";
import "../../../components/ha-dropdown";
import "../../../components/ha-dropdown-item";
import "../../../components/ha-icon-button";
import "../../../components/ha-md-list-item";
import "../../../components/ha-list";
import "../../../components/ha-list-item";
import "../../../components/ha-svg-icon";
@@ -217,23 +218,24 @@ export class AssistPref extends LitElement {
)}
<ha-svg-icon slot="start" .path=${mdiPlus}></ha-svg-icon>
</ha-button>
<ha-settings-row>
<span slot="heading">
${this.hass!.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass!.localize(
"ui.panel.config.voice_assistants.expose.expose_new_entities"
)}
</span>
<span slot="description">
${this.hass!.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass!.localize(
"ui.panel.config.voice_assistants.expose.expose_new_entities_info"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.checked=${this._exposeNew}
.disabled=${this._exposeNew === undefined}
@change=${this._exposeNewToggleChanged}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
<div class="card-actions">
<ha-button
appearance="plain"

View File

@@ -7,7 +7,7 @@ import { isEmptyEntityDomainFilter } from "../../../common/entity/entity_domain_
import "../../../components/ha-alert";
import "../../../components/ha-card";
import "../../../components/ha-button";
import "../../../components/ha-settings-row";
import "../../../components/ha-md-list-item";
import "../../../components/ha-switch";
import type { HaSwitch } from "../../../components/ha-switch";
import type { CloudStatusLoggedIn } from "../../../data/cloud";
@@ -100,10 +100,11 @@ export class CloudAlexaPref extends LitElement {
"ui.panel.config.cloud.account.alexa.manual_config"
)}
</ha-alert>`
: ""}
: nothing}
${!alexa_enabled
? ""
: html`${!alexa_registered
? nothing
: html`
${!alexa_registered
? html`<ha-alert
.title=${this.hass.localize(
"ui.panel.config.cloud.account.alexa.not_configured_title"
@@ -138,42 +139,47 @@ export class CloudAlexaPref extends LitElement {
</li>
</ul>
</ha-alert>`
: ""}<ha-settings-row>
<span slot="heading">
${this.hass!.localize(
: nothing}
<ha-md-list-item>
<span slot="headline"
>${this.hass!.localize(
"ui.panel.config.cloud.account.alexa.expose_new_entities"
)}
</span>
<span slot="description">
${this.hass!.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass!.localize(
"ui.panel.config.cloud.account.alexa.expose_new_entities_info"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.checked=${this._exposeNew}
.disabled=${this._exposeNew === undefined}
@change=${this._exposeNewToggleChanged}
></ha-switch> </ha-settings-row
>${alexa_registered
></ha-switch>
</ha-md-list-item>
${alexa_registered
? html`
<ha-settings-row>
<span slot="heading">
${this.hass!.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass!.localize(
"ui.panel.config.cloud.account.alexa.enable_state_reporting"
)}
</span>
<span slot="description">
${this.hass!.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass!.localize(
"ui.panel.config.cloud.account.alexa.info_state_reporting"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.checked=${alexa_report_state}
@change=${this._reportToggleChanged}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
`
: ""}`}
: nothing}
`}
</div>
${alexa_enabled
? html`<div class="card-actions">
@@ -250,8 +256,10 @@ export class CloudAlexaPref extends LitElement {
a {
color: var(--primary-color);
}
ha-settings-row {
padding: 0;
ha-md-list-item {
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-item-overflow: visible;
}
.header-actions {
position: absolute;

View File

@@ -7,7 +7,7 @@ import { isEmptyEntityDomainFilter } from "../../../common/entity/entity_domain_
import "../../../components/ha-alert";
import "../../../components/ha-card";
import "../../../components/ha-button";
import "../../../components/ha-settings-row";
import "../../../components/ha-md-list-item";
import "../../../components/ha-switch";
import type { HaSwitch } from "../../../components/ha-switch";
import "../../../components/ha-textfield";
@@ -106,10 +106,11 @@ export class CloudGooglePref extends LitElement {
"ui.panel.config.cloud.account.google.manual_config"
)}
</ha-alert>`
: ""}
: nothing}
${!google_enabled
? ""
: html`${!google_registered
? nothing
: html`
${!google_registered
? html`
<ha-alert
.title=${this.hass.localize(
@@ -135,24 +136,26 @@ export class CloudGooglePref extends LitElement {
</ul>
</ha-alert>
`
: ""}
<ha-settings-row>
<span slot="heading">
${this.hass!.localize(
: nothing}
<ha-md-list-item>
<span slot="headline"
>${this.hass!.localize(
"ui.panel.config.cloud.account.google.expose_new_entities"
)}
</span>
<span slot="description">
${this.hass!.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass!.localize(
"ui.panel.config.cloud.account.google.expose_new_entities_info"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.checked=${this._exposeNew}
.disabled=${this._exposeNew === undefined}
@change=${this._exposeNewToggleChanged}
></ha-switch> </ha-settings-row
>${google_registered
></ha-switch>
</ha-md-list-item>
${google_registered
? html`
${this.cloudStatus.http_use_ssl
? html`
@@ -175,37 +178,38 @@ export class CloudGooglePref extends LitElement {
>
</ha-alert>
`
: ""}
<ha-settings-row>
<span slot="heading">
${this.hass!.localize(
: nothing}
<ha-md-list-item>
<span slot="headline"
>${this.hass!.localize(
"ui.panel.config.cloud.account.google.enable_state_reporting"
)}
</span>
<span slot="description">
${this.hass!.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass!.localize(
"ui.panel.config.cloud.account.google.info_state_reporting"
)}
</span>
)}</span
>
<ha-switch
slot="end"
.checked=${google_report_state}
@change=${this._reportToggleChanged}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
<ha-settings-row>
<span slot="heading">
${this.hass.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.cloud.account.google.security_devices"
)}
</span>
<span slot="description">
${this.hass.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.cloud.account.google.enter_pin_info"
)}
</span>
</ha-settings-row>
)}</span
>
<ha-switch slot="end"></ha-switch>
</ha-md-list-item>
<ha-textfield
id="google_secure_devices_pin"
@@ -219,7 +223,8 @@ export class CloudGooglePref extends LitElement {
@change=${this._pinChanged}
></ha-textfield>
`
: ""}`}
: nothing}
`}
</div>
${google_enabled
? html`<div class="card-actions">
@@ -329,8 +334,10 @@ export class CloudGooglePref extends LitElement {
direction: var(--direction);
color: var(--secondary-text-color);
}
ha-settings-row {
padding: 0;
ha-md-list-item {
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-item-overflow: visible;
}
ha-textfield {
width: 250px;

View File

@@ -17,7 +17,7 @@ import "../../../components/ha-alert";
import "../../../components/ha-aliases-editor";
import "../../../components/ha-checkbox";
import "../../../components/ha-formfield";
import "../../../components/ha-settings-row";
import "../../../components/ha-md-list-item";
import "../../../components/ha-switch";
import { fetchCloudAlexaEntity } from "../../../data/alexa";
import type { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud";
@@ -180,16 +180,17 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
const anyExposed = uiExposed || manExposedAlexa || manExposedGoogle;
return html`
<ha-settings-row>
<h3 slot="heading">
<ha-md-list-item>
<h3 slot="headline">
${this.hass.localize("ui.dialogs.voice-settings.expose_header")}
</h3>
<ha-switch
slot="end"
@change=${this._toggleAll}
.assistants=${uiAssistants}
.checked=${anyExposed}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
${anyExposed
? showAssistants.map((key) => {
const supported = !this._unsupported[key];
@@ -212,16 +213,16 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
this._googleEntity?.might_2fa;
return html`
<ha-settings-row .threeLine=${!supported && manualConfig}>
<ha-md-list-item>
<voice-assistant-brand-icon
slot="prefix"
slot="start"
.voiceAssistantId=${key}
.hass=${this.hass}
>
</voice-assistant-brand-icon>
<span slot="heading">${voiceAssistants[key].name}</span>
<span slot="headline">${voiceAssistants[key].name}</span>
${!supported
? html`<div slot="description" class="unsupported">
? html`<div slot="supporting-text" class="unsupported">
<ha-svg-icon .path=${mdiAlertCircle}></ha-svg-icon>
${this.hass.localize(
"ui.dialogs.voice-settings.unsupported"
@@ -230,7 +231,7 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
: nothing}
${manualConfig
? html`
<div slot="description">
<div slot="supporting-text">
${this.hass.localize(
"ui.dialogs.voice-settings.manual_config"
)}
@@ -240,7 +241,7 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
${support2fa
? html`
<ha-formfield
slot="description"
slot="supporting-text"
.label=${this.hass.localize(
"ui.dialogs.voice-settings.ask_pin"
)}
@@ -253,12 +254,13 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
`
: nothing}
<ha-switch
slot="end"
.assistant=${key}
@change=${this._toggleAssistant}
.disabled=${manualConfig || (!exposed && !supported)}
.checked=${exposed}
></ha-switch>
</ha-settings-row>
</ha-md-list-item>
`;
})
: nothing}
@@ -373,11 +375,11 @@ export class EntityVoiceSettings extends SubscribeMixin(LitElement) {
display: block;
margin: 32px;
margin-top: 0;
--settings-row-prefix-display: contents;
--settings-row-content-display: contents;
}
ha-settings-row {
padding: 0;
ha-md-list-item {
--md-list-item-leading-space: 0;
--md-list-item-trailing-space: 0;
--md-item-overflow: visible;
}
img {
height: 32px;

View File

@@ -10,7 +10,7 @@ import "../../../../components/ha-dropdown";
import "../../../../components/ha-dropdown-item";
import "../../../../components/ha-grid-size-picker";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-settings-row";
import "../../../../components/ha-md-list-item";
import "../../../../components/ha-slider";
import "../../../../components/ha-svg-icon";
import "../../../../components/ha-switch";
@@ -138,42 +138,42 @@ export class HuiCardLayoutEditor extends LitElement {
.columnsDisabled=${this._defaultGridOptions?.fixed_columns}
.step=${this._preciseMode ? 1 : GRID_COLUMN_MULTIPLIER}
></ha-grid-size-picker>
<ha-settings-row>
<span slot="heading" data-for="full-width">
${this.hass.localize(
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.lovelace.editor.edit_card.layout.full_width"
)}
</span>
<span slot="description" data-for="full-width">
${this.hass.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.lovelace.editor.edit_card.layout.full_width_helper"
)}
</span>
)}</span
>
<ha-switch
slot="end"
@change=${this._fullWidthChanged}
.checked=${options.columns === "full"}
name="full-width"
>
</ha-switch>
</ha-settings-row>
<ha-settings-row>
<span slot="heading" data-for="precise-mode">
${this.hass.localize(
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.lovelace.editor.edit_card.layout.precise_mode"
)}
</span>
<span slot="description" data-for="precise-mode">
${this.hass.localize(
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.lovelace.editor.edit_card.layout.precise_mode_helper"
)}
</span>
)}</span
>
<ha-switch
slot="end"
@change=${this._preciseModeChanged}
.checked=${this._preciseMode}
name="precise-mode"
>
</ha-switch>
</ha-settings-row>
></ha-switch>
</ha-md-list-item>
`}
`;
}