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

View File

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

View File

@ -1,12 +1,13 @@
import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import { mdiPencil } from "@mdi/js";
import "@material/mwc-button";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-alert";
import "../../../components/ha-button";
import { createCloseHeading } from "../../../components/ha-dialog"; import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-formfield"; import "../../../components/ha-formfield";
import "../../../components/ha-help-tooltip"; import "../../../components/ha-icon-button";
import "../../../components/ha-label"; import "../../../components/ha-label";
import "../../../components/ha-settings-row";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import "../../../components/ha-switch"; import "../../../components/ha-switch";
import "../../../components/ha-textfield"; import "../../../components/ha-textfield";
@ -68,15 +69,15 @@ class DialogUserDetail extends LitElement {
.heading=${createCloseHeading(this.hass, user.name)} .heading=${createCloseHeading(this.hass, user.name)}
> >
<div> <div>
${this._error ? html` <div class="error">${this._error}</div> ` : ""} ${this._error
? html`<div class="error">${this._error}</div>`
: nothing}
<div class="secondary"> <div class="secondary">
${this.hass.localize("ui.panel.config.users.editor.id")}: ${this.hass.localize("ui.panel.config.users.editor.id")}:
${user.id}<br /> ${user.id}<br />
${this.hass.localize("ui.panel.config.users.editor.username")}:
${user.username}
</div> </div>
${badges.length === 0 ${badges.length === 0
? "" ? nothing
: html` : html`
<div class="badge-container"> <div class="badge-container">
${badges.map( ${badges.map(
@ -90,74 +91,136 @@ class DialogUserDetail extends LitElement {
</div> </div>
`} `}
<div class="form"> <div class="form">
<ha-textfield ${!user.system_generated
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
? html` ? html`
<br /> <ha-textfield
${this.hass.localize( dialogInitialFocus
"ui.panel.config.users.users_privileges_note" .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>
` `
: ""} : nothing}
<div class="row"> ${!user.system_generated && this.hass.user?.is_owner
<ha-formfield ? html`
.label=${this.hass.localize( <ha-settings-row>
"ui.panel.config.users.editor.active" <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 </ha-switch>
.disabled=${user.system_generated || user.is_owner} </ha-settings-row>
.checked=${this._isActive} <ha-settings-row>
@change=${this._activeChanged} <span slot="heading">
> ${this.hass.localize(
</ha-switch> "ui.panel.config.users.editor.local_access_only"
</ha-formfield>
<ha-help-tooltip
.label=${this.hass.localize(
"ui.panel.config.users.editor.active_tooltip"
)} )}
</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> </ha-switch>
</div> </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> </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>
<div slot="secondaryAction"> <div slot="secondaryAction">
<mwc-button <ha-button
class="warning" class="warning"
@click=${this._deleteEntry} @click=${this._deleteEntry}
.disabled=${this._submitting || .disabled=${this._submitting ||
@ -165,47 +228,18 @@ class DialogUserDetail extends LitElement {
user.is_owner} user.is_owner}
> >
${this.hass!.localize("ui.panel.config.users.editor.delete_user")} ${this.hass!.localize("ui.panel.config.users.editor.delete_user")}
</mwc-button> </ha-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>`
: ""}
</div> </div>
<div slot="primaryAction"> <div slot="primaryAction">
<mwc-button <ha-button
@click=${this._updateEntry} @click=${this._updateEntry}
.disabled=${!this._name || .disabled=${!this._name ||
this._submitting || this._submitting ||
user.system_generated} user.system_generated}
> >
${this.hass!.localize("ui.panel.config.users.editor.update_user")} ${this.hass!.localize("ui.panel.config.users.editor.update_user")}
</mwc-button> </ha-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>
`
: ""}
</div> </div>
</ha-dialog> </ha-dialog>
`; `;
@ -353,27 +387,8 @@ class DialogUserDetail extends LitElement {
margin-inline-end: 4px; margin-inline-end: 4px;
margin-inline-start: 0; margin-inline-start: 0;
} }
.state { ha-settings-row {
background-color: rgba(var(--rgb-primary-text-color), 0.15); padding: 0;
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;
} }
`, `,
]; ];

View File

@ -419,11 +419,6 @@
"manual": "Manual Entry" "manual": "Manual Entry"
} }
}, },
"image": {
"select_image": "Select image",
"upload": "Upload picture",
"url": "Local path or web URL"
},
"text": { "text": {
"show_password": "Show password", "show_password": "Show password",
"hide_password": "Hide password" "hide_password": "Hide password"
@ -4143,10 +4138,18 @@
"delete": "Delete", "delete": "Delete",
"create": "Create", "create": "Create",
"update": "Update", "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%]", "admin": "[%key:ui::panel::config::users::editor::admin%]",
"local_only": "[%key:ui::panel::config::users::editor::local_only%]", "admin_description": "[%key:ui::panel::config::users::editor::admin_description%]",
"allow_login": "Allow person to login" "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": { "zone": {
@ -4386,6 +4389,7 @@
"caption": "View user", "caption": "View user",
"name": "Display name", "name": "Display name",
"username": "Username", "username": "Username",
"password": "Password",
"change_password": "Change password", "change_password": "Change password",
"change_username": "Change username", "change_username": "Change username",
"activate_user": "Activate user", "activate_user": "Activate user",
@ -4395,16 +4399,17 @@
"id": "ID", "id": "ID",
"owner": "Owner", "owner": "Owner",
"admin": "Administrator", "admin": "Administrator",
"admin_description": "Administrators can manage users, devices, automations and dashboards.",
"group": "Group", "group": "Group",
"active": "Active", "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": "System user",
"system_generated_users_not_removable": "Unable to remove system users.", "system_generated_read_only_users": "System users can not be updated.",
"system_generated_users_not_editable": "Unable to update system users.",
"unnamed_user": "Unnamed User", "unnamed_user": "Unnamed User",
"confirm_user_deletion_title": "Delete {name}?", "confirm_user_deletion_title": "Delete {name}?",
"confirm_user_deletion_text": "This user will be permanently deleted.", "confirm_user_deletion_text": "This user will be permanently deleted."
"active_tooltip": "Controls if user can login"
}, },
"add_user": { "add_user": {
"caption": "Add user", "caption": "Add user",