Improve user and person dialogs (#21162)

* Improve user dialog

* Update person dialog

* Improve add user dialog

* Fix secondary option
This commit is contained in:
Paul Bottein 2024-06-26 10:03:43 +02:00 committed by GitHub
parent 128dbbcfef
commit 1acada625f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 317 additions and 233 deletions

View File

@ -1,12 +1,15 @@
import "@material/mwc-button";
import { mdiPencil } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import "../../../components/entity/ha-entities-picker";
import "../../../components/ha-button";
import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-formfield";
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-textfield";
import { adminChangeUsername } from "../../../data/auth";
import { PersonMutableParams } from "../../../data/person";
@ -137,11 +140,17 @@ class DialogPersonDetail extends LitElement {
@change=${this._pictureChanged}
></ha-picture-upload>
<ha-formfield
.label=${`${this.hass!.localize(
"ui.panel.config.person.detail.allow_login"
)}${this._user ? ` (${this._user.username})` : ""}`}
>
<ha-settings-row>
<span slot="heading">
${this.hass!.localize(
"ui.panel.config.person.detail.allow_login"
)}
</span>
<span slot="description">
${this.hass!.localize(
"ui.panel.config.person.detail.allow_login_description"
)}
</span>
<ha-switch
@change=${this._allowLoginChanged}
.disabled=${this._user &&
@ -150,34 +159,9 @@ class DialogPersonDetail extends LitElement {
this._user.is_owner)}
.checked=${this._userId}
></ha-switch>
</ha-formfield>
</ha-settings-row>
${this._user
? html`<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.person.detail.local_only"
)}
>
<ha-switch
.checked=${this._localOnly}
@change=${this._localOnlyChanged}
>
</ha-switch>
</ha-formfield>
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.person.detail.admin"
)}
>
<ha-switch
.disabled=${this._user.system_generated ||
this._user.is_owner}
.checked=${this._isAdmin}
@change=${this._adminChanged}
>
</ha-switch>
</ha-formfield>`
: ""}
${this._renderUserFields()}
${this._deviceTrackersAvailable(this.hass)
? html`
<p>
@ -235,7 +219,7 @@ class DialogPersonDetail extends LitElement {
</div>
${this._params.entry
? html`
<mwc-button
<ha-button
slot="secondaryAction"
class="warning"
@click=${this._deleteEntry}
@ -243,28 +227,10 @@ class DialogPersonDetail extends LitElement {
this._submitting}
>
${this.hass!.localize("ui.panel.config.person.detail.delete")}
</mwc-button>
${this._user && this.hass.user?.is_owner
? html`<mwc-button
slot="secondaryAction"
@click=${this._changeUsername}
>
${this.hass.localize(
"ui.panel.config.users.editor.change_username"
)}
</mwc-button>
<mwc-button
slot="secondaryAction"
@click=${this._changePassword}
>
${this.hass.localize(
"ui.panel.config.users.editor.change_password"
)}
</mwc-button>`
: ""}
</ha-button>
`
: nothing}
<mwc-button
<ha-button
slot="primaryAction"
@click=${this._updateEntry}
.disabled=${nameInvalid || this._submitting}
@ -272,11 +238,96 @@ class DialogPersonDetail extends LitElement {
${this._params.entry
? this.hass!.localize("ui.panel.config.person.detail.update")
: this.hass!.localize("ui.panel.config.person.detail.create")}
</mwc-button>
</ha-button>
</ha-dialog>
`;
}
private _renderUserFields() {
const user = this._user;
if (!user) return nothing;
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>
${this.hass.user?.is_owner
? html`
<ha-icon-button
.path=${mdiPencil}
@click=${this._changeUsername}
.label=${this.hass.localize(
"ui.panel.config.person.detail.change_username"
)}
>
</ha-icon-button>
`
: nothing}
</ha-settings-row>
`
: 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>
${this.hass.user?.is_owner
? html`
<ha-icon-button
.path=${mdiPencil}
@click=${this._changePassword}
.label=${this.hass.localize(
"ui.panel.config.person.detail.change_password"
)}
>
</ha-icon-button>
`
: nothing}
</ha-settings-row>
`
: nothing}
<ha-settings-row>
<span slot="heading">
${this.hass.localize(
"ui.panel.config.person.detail.local_access_only"
)}
</span>
<span slot="description">
${this.hass.localize(
"ui.panel.config.person.detail.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.person.detail.admin")}
</span>
<span slot="description">
${this.hass.localize(
"ui.panel.config.person.detail.admin_description"
)}
</span>
<ha-switch
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isAdmin}
@change=${this._adminChanged}
>
</ha-switch>
</ha-settings-row>
`;
}
private _closeDialog() {
this._params = undefined;
}
@ -317,14 +368,16 @@ class DialogPersonDetail extends LitElement {
} else if (this._userId) {
if (
!(await showConfirmationDialog(this, {
title: this.hass!.localize(
"ui.panel.config.person.detail.confirm_delete_user_title"
),
text: this.hass!.localize(
"ui.panel.config.person.detail.confirm_delete_user",
"ui.panel.config.person.detail.confirm_delete_user_text",
{ name: this._name }
),
confirmText: this.hass!.localize(
"ui.panel.config.person.detail.delete"
),
confirmText: this.hass!.localize("ui.common.delete"),
dismissText: this.hass!.localize("ui.common.cancel"),
destructive: true,
}))
) {
target.checked = true;
@ -488,9 +541,8 @@ class DialogPersonDetail extends LitElement {
margin-bottom: 16px;
--file-upload-image-border-radius: 50%;
}
ha-formfield {
display: block;
padding: 16px 0;
ha-settings-row {
padding: 0;
}
a {
color: var(--primary-color);

View File

@ -1,31 +1,34 @@
import "@material/mwc-button";
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
css,
html,
nothing,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-alert";
import "../../../components/ha-button";
import "../../../components/ha-circular-progress";
import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-formfield";
import "../../../components/ha-icon-button";
import "../../../components/ha-settings-row";
import "../../../components/ha-switch";
import type { HaSwitch } from "../../../components/ha-switch";
import "../../../components/ha-textfield";
import type { HaTextField } from "../../../components/ha-textfield";
import { createAuthForUser } from "../../../data/auth";
import {
createUser,
deleteUser,
SYSTEM_GROUP_ID_ADMIN,
SYSTEM_GROUP_ID_USER,
User,
createUser,
deleteUser,
} from "../../../data/user";
import { ValueChangedEvent, HomeAssistant } from "../../../types";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant, ValueChangedEvent } from "../../../types";
import { AddUserDialogParams } from "./show-dialog-add-user";
import "../../../components/ha-textfield";
import type { HaTextField } from "../../../components/ha-textfield";
@customElement("dialog-add-user")
export class DialogAddUser extends LitElement {
@ -155,38 +158,44 @@ export class DialogAddUser extends LitElement {
"ui.panel.config.users.add_user.password_not_match"
)}
></ha-textfield>
<div class="row">
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.users.editor.local_only"
<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
.checked=${this._localOnly}
@change=${this._localOnlyChanged}
>
<ha-switch
.checked=${this._localOnly}
@change=${this._localOnlyChanged}
>
</ha-switch>
</ha-formfield>
</div>
<div class="row">
<ha-formfield
.label=${this.hass.localize("ui.panel.config.users.editor.admin")}
>
<ha-switch
.checked=${this._isAdmin}
@change=${this._adminChanged}
>
</ha-switch>
</ha-formfield>
</div>
</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 .checked=${this._isAdmin} @change=${this._adminChanged}>
</ha-switch>
</ha-settings-row>
${!this._isAdmin
? html`
<br />
${this.hass.localize(
"ui.panel.config.users.users_privileges_note"
)}
<ha-alert alert-type="info">
${this.hass.localize(
"ui.panel.config.users.users_privileges_note"
)}
</ha-alert>
`
: ""}
: nothing}
</div>
${this._loading
? html`
@ -195,7 +204,7 @@ export class DialogAddUser extends LitElement {
</div>
`
: html`
<mwc-button
<ha-button
slot="primaryAction"
.disabled=${!this._name ||
!this._username ||
@ -204,7 +213,7 @@ export class DialogAddUser extends LitElement {
@click=${this._createUser}
>
${this.hass.localize("ui.panel.config.users.add_user.create")}
</mwc-button>
</ha-button>
`}
</ha-dialog>
`;
@ -299,7 +308,10 @@ export class DialogAddUser extends LitElement {
}
ha-textfield {
display: block;
margin-bottom: 16px;
margin-bottom: 8px;
}
ha-settings-row {
padding: 0;
}
`,
];

View File

@ -132,7 +132,7 @@ class DialogAdminChangePassword extends LitElement {
@value-changed=${this._valueChanged}
.disabled=${this._submitting}
></ha-form>
<mwc-button slot="primaryAction" @click=${this.closeDialog}>
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
${this.hass.localize("ui.common.cancel")}
</mwc-button>
<mwc-button

View File

@ -1,12 +1,13 @@
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import "@material/mwc-button";
import { mdiPencil } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-alert";
import "../../../components/ha-button";
import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-formfield";
import "../../../components/ha-help-tooltip";
import "../../../components/ha-icon-button";
import "../../../components/ha-label";
import "../../../components/ha-settings-row";
import "../../../components/ha-svg-icon";
import "../../../components/ha-switch";
import "../../../components/ha-textfield";
@ -68,15 +69,15 @@ class DialogUserDetail extends LitElement {
.heading=${createCloseHeading(this.hass, user.name)}
>
<div>
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
${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 />
${this.hass.localize("ui.panel.config.users.editor.username")}:
${user.username}
</div>
${badges.length === 0
? ""
? nothing
: html`
<div class="badge-container">
${badges.map(
@ -90,74 +91,136 @@ class DialogUserDetail extends LitElement {
</div>
`}
<div class="form">
<ha-textfield
dialogInitialFocus
.value=${this._name}
.disabled=${user.system_generated}
@input=${this._nameChanged}
.label=${this.hass!.localize("ui.panel.config.users.editor.name")}
></ha-textfield>
<div class="row">
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.users.editor.local_only"
)}
>
<ha-switch
.disabled=${user.system_generated}
.checked=${this._localOnly}
@change=${this._localOnlyChanged}
>
</ha-switch>
</ha-formfield>
</div>
<div class="row">
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.users.editor.admin"
)}
>
<ha-switch
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isAdmin}
@change=${this._adminChanged}
>
</ha-switch>
</ha-formfield>
</div>
${!this._isAdmin
${!user.system_generated
? html`
<br />
${this.hass.localize(
"ui.panel.config.users.users_privileges_note"
)}
<ha-textfield
dialogInitialFocus
.value=${this._name}
@input=${this._nameChanged}
.label=${this.hass!.localize(
"ui.panel.config.users.editor.name"
)}
></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 class="row">
<ha-formfield
.label=${this.hass.localize(
"ui.panel.config.users.editor.active"
: 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"
)}
</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
.disabled=${user.system_generated || user.is_owner}
.checked=${this._isActive}
@change=${this._activeChanged}
>
</ha-switch>
</ha-formfield>
<ha-help-tooltip
.label=${this.hass.localize(
"ui.panel.config.users.editor.active_tooltip"
</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-help-tooltip>
</div>
</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
? 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.editor.system_generated_read_only_users"
)}
</ha-alert>
`
: nothing}
</div>
<div slot="secondaryAction">
<mwc-button
<ha-button
class="warning"
@click=${this._deleteEntry}
.disabled=${this._submitting ||
@ -165,47 +228,18 @@ class DialogUserDetail extends LitElement {
user.is_owner}
>
${this.hass!.localize("ui.panel.config.users.editor.delete_user")}
</mwc-button>
${user.system_generated
? html`
<simple-tooltip animation-delay="0" position="right">
${this.hass.localize(
"ui.panel.config.users.editor.system_generated_users_not_removable"
)}
</simple-tooltip>
`
: ""}
${!user.system_generated && this.hass.user?.is_owner
? html`<mwc-button @click=${this._changeUsername}>
${this.hass.localize(
"ui.panel.config.users.editor.change_username"
)} </mwc-button
><mwc-button @click=${this._changePassword}>
${this.hass.localize(
"ui.panel.config.users.editor.change_password"
)}
</mwc-button>`
: ""}
</ha-button>
</div>
<div slot="primaryAction">
<mwc-button
<ha-button
@click=${this._updateEntry}
.disabled=${!this._name ||
this._submitting ||
user.system_generated}
>
${this.hass!.localize("ui.panel.config.users.editor.update_user")}
</mwc-button>
${user.system_generated
? html`
<simple-tooltip animation-delay="0" position="left">
${this.hass.localize(
"ui.panel.config.users.editor.system_generated_users_not_editable"
)}
</simple-tooltip>
`
: ""}
</ha-button>
</div>
</ha-dialog>
`;
@ -353,27 +387,8 @@ class DialogUserDetail extends LitElement {
margin-inline-end: 4px;
margin-inline-start: 0;
}
.state {
background-color: rgba(var(--rgb-primary-text-color), 0.15);
border-radius: 16px;
padding: 4px 8px;
margin-top: 8px;
display: inline-block;
}
.state:not(:first-child) {
margin-left: 8px;
margin-inline-start: 8px;
margin-inline-end: initial;
}
.row {
display: flex;
padding: 8px 0;
}
ha-help-tooltip {
margin-left: 4px;
margin-inline-start: 4px;
margin-inline-end: initial;
position: relative;
ha-settings-row {
padding: 0;
}
`,
];

View File

@ -419,11 +419,6 @@
"manual": "Manual Entry"
}
},
"image": {
"select_image": "Select image",
"upload": "Upload picture",
"url": "Local path or web URL"
},
"text": {
"show_password": "Show password",
"hide_password": "Hide password"
@ -4143,10 +4138,18 @@
"delete": "Delete",
"create": "Create",
"update": "Update",
"confirm_delete_user": "Are you sure you want to delete the user account for {name}? You can still track the user, but the person will no longer be able to login.",
"confirm_delete_user_title": "Delete user account",
"confirm_delete_user_text": "The user account for ''{name}'' will be permanently deleted. You can still track the user, but the person will no longer be able to login.",
"allow_login": "Allow login",
"allow_login_description": "Allow access using username and password.",
"username": "[%key:ui::panel::config::users::editor::username%]",
"password": "[%key:ui::panel::config::users::editor::password%]",
"admin": "[%key:ui::panel::config::users::editor::admin%]",
"local_only": "[%key:ui::panel::config::users::editor::local_only%]",
"allow_login": "Allow person to login"
"admin_description": "[%key:ui::panel::config::users::editor::admin_description%]",
"local_access_only": "[%key:ui::panel::config::users::editor::local_access_only%]",
"local_access_only_description": "[%key:ui::panel::config::users::editor::local_access_only_description%]",
"change_username": "[%key:ui::panel::config::users::editor::change_username%]",
"change_password": "[%key:ui::panel::config::users::editor::change_password%]"
}
},
"zone": {
@ -4386,6 +4389,7 @@
"caption": "View user",
"name": "Display name",
"username": "Username",
"password": "Password",
"change_password": "Change password",
"change_username": "Change username",
"activate_user": "Activate user",
@ -4395,16 +4399,17 @@
"id": "ID",
"owner": "Owner",
"admin": "Administrator",
"admin_description": "Administrators can manage users, devices, automations and dashboards.",
"group": "Group",
"active": "Active",
"local_only": "Can only log in from the local network",
"active_description": "Controls if user can login",
"local_access_only": "Local access only",
"local_access_only_description": "Can only log in from the local network",
"system_generated": "System user",
"system_generated_users_not_removable": "Unable to remove system users.",
"system_generated_users_not_editable": "Unable to update system users.",
"system_generated_read_only_users": "System users can not be updated.",
"unnamed_user": "Unnamed User",
"confirm_user_deletion_title": "Delete {name}?",
"confirm_user_deletion_text": "This user will be permanently deleted.",
"active_tooltip": "Controls if user can login"
"confirm_user_deletion_text": "This user will be permanently deleted."
},
"add_user": {
"caption": "Add user",