241 lines
6.4 KiB
TypeScript
241 lines
6.4 KiB
TypeScript
import {
|
|
LitElement,
|
|
TemplateResult,
|
|
html,
|
|
customElement,
|
|
CSSResultArray,
|
|
css,
|
|
property,
|
|
} from "lit-element";
|
|
import { until } from "lit-html/directives/until";
|
|
import "@material/mwc-button";
|
|
|
|
import "../../../layouts/hass-subpage";
|
|
import { haStyle } from "../../../resources/styles";
|
|
import "../../../components/ha-card";
|
|
import { HomeAssistant } from "../../../types";
|
|
import { fireEvent } from "../../../common/dom/fire_event";
|
|
import { navigate } from "../../../common/navigate";
|
|
import {
|
|
User,
|
|
deleteUser,
|
|
updateUser,
|
|
SYSTEM_GROUP_ID_USER,
|
|
SYSTEM_GROUP_ID_ADMIN,
|
|
} from "../../../data/user";
|
|
import { showSaveSuccessToast } from "../../../util/toast-saved-success";
|
|
|
|
declare global {
|
|
interface HASSDomEvents {
|
|
"reload-users": undefined;
|
|
}
|
|
}
|
|
|
|
const GROUPS = [SYSTEM_GROUP_ID_USER, SYSTEM_GROUP_ID_ADMIN];
|
|
|
|
@customElement("ha-user-editor")
|
|
class HaUserEditor extends LitElement {
|
|
@property() public hass?: HomeAssistant;
|
|
@property() public user?: User;
|
|
|
|
protected render(): TemplateResult | void {
|
|
const hass = this.hass;
|
|
const user = this.user;
|
|
if (!hass || !user) {
|
|
return html``;
|
|
}
|
|
|
|
return html`
|
|
<hass-subpage
|
|
.header=${hass.localize("ui.panel.config.users.editor.caption")}
|
|
>
|
|
<ha-card .header=${this._name}>
|
|
<table class="card-content">
|
|
<tr>
|
|
<td>${hass.localize("ui.panel.config.users.editor.id")}</td>
|
|
<td>${user.id}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>${hass.localize("ui.panel.config.users.editor.owner")}</td>
|
|
<td>${user.is_owner}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>${hass.localize("ui.panel.config.users.editor.group")}</td>
|
|
<td>
|
|
<select
|
|
@change=${this._handleGroupChange}
|
|
.value=${until(
|
|
this.updateComplete.then(() => user.group_ids[0])
|
|
)}
|
|
>
|
|
${GROUPS.map(
|
|
(groupId) => html`
|
|
<option value=${groupId}>
|
|
${hass.localize(`groups.${groupId}`)}
|
|
</option>
|
|
`
|
|
)}
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
${user.group_ids[0] === SYSTEM_GROUP_ID_USER
|
|
? html`
|
|
<tr>
|
|
<td colspan="2" class="user-experiment">
|
|
The users group is a work in progress. The user will be
|
|
unable to administer the instance via the UI. We're still
|
|
auditing all management API endpoints to ensure that they
|
|
correctly limit access to administrators.
|
|
</td>
|
|
</tr>
|
|
`
|
|
: ""}
|
|
|
|
<tr>
|
|
<td>${hass.localize("ui.panel.config.users.editor.active")}</td>
|
|
<td>${user.is_active}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
${hass.localize(
|
|
"ui.panel.config.users.editor.system_generated"
|
|
)}
|
|
</td>
|
|
<td>${user.system_generated}</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<div class="card-actions">
|
|
<mwc-button @click=${this._handleRenameUser}>
|
|
${hass.localize("ui.panel.config.users.editor.rename_user")}
|
|
</mwc-button>
|
|
<mwc-button
|
|
class="warning"
|
|
@click=${this._deleteUser}
|
|
.disabled=${user.system_generated}
|
|
>
|
|
${hass.localize("ui.panel.config.users.editor.delete_user")}
|
|
</mwc-button>
|
|
${user.system_generated
|
|
? html`
|
|
${hass.localize(
|
|
"ui.panel.config.users.editor.system_generated_users_not_removable"
|
|
)}
|
|
`
|
|
: ""}
|
|
</div>
|
|
</ha-card>
|
|
</hass-subpage>
|
|
`;
|
|
}
|
|
|
|
private get _name() {
|
|
return (
|
|
this.user &&
|
|
(this.user.name ||
|
|
this.hass!.localize("ui.panel.config.users.editor.unnamed_user"))
|
|
);
|
|
}
|
|
|
|
private async _handleRenameUser(ev): Promise<void> {
|
|
ev.currentTarget.blur();
|
|
const newName = prompt(
|
|
this.hass!.localize("ui.panel.config.users.editor.enter_new_name"),
|
|
this.user!.name
|
|
);
|
|
if (newName === null || newName === this.user!.name) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await updateUser(this.hass!, this.user!.id, {
|
|
name: newName,
|
|
});
|
|
fireEvent(this, "reload-users");
|
|
} catch (err) {
|
|
alert(
|
|
`${this.hass!.localize(
|
|
"ui.panel.config.users.editor.user_rename_failed"
|
|
)} ${err.message}`
|
|
);
|
|
}
|
|
}
|
|
|
|
private async _handleGroupChange(ev): Promise<void> {
|
|
const selectEl = ev.currentTarget as HTMLSelectElement;
|
|
const newGroup = selectEl.value;
|
|
try {
|
|
await updateUser(this.hass!, this.user!.id, {
|
|
group_ids: [newGroup],
|
|
});
|
|
showSaveSuccessToast(this, this.hass!);
|
|
fireEvent(this, "reload-users");
|
|
} catch (err) {
|
|
alert(
|
|
`${this.hass!.localize(
|
|
"ui.panel.config.users.editor.group_update_failed"
|
|
)} ${err.message}`
|
|
);
|
|
selectEl.value = this.user!.group_ids[0];
|
|
}
|
|
}
|
|
|
|
private async _deleteUser(ev): Promise<void> {
|
|
if (
|
|
!confirm(
|
|
this.hass!.localize(
|
|
"ui.panel.config.users.editor.confirm_user_deletion",
|
|
"name",
|
|
this._name
|
|
)
|
|
)
|
|
) {
|
|
ev.target.blur();
|
|
return;
|
|
}
|
|
try {
|
|
await deleteUser(this.hass!, this.user!.id);
|
|
} catch (err) {
|
|
alert(err.code);
|
|
return;
|
|
}
|
|
fireEvent(this, "reload-users");
|
|
navigate(this, "/config/users");
|
|
}
|
|
|
|
static get styles(): CSSResultArray {
|
|
return [
|
|
haStyle,
|
|
css`
|
|
.card-actions {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
ha-card {
|
|
max-width: 600px;
|
|
margin: 0 auto 16px;
|
|
}
|
|
hass-subpage ha-card:first-of-type {
|
|
direction: ltr;
|
|
}
|
|
table {
|
|
width: 100%;
|
|
}
|
|
td {
|
|
vertical-align: top;
|
|
}
|
|
.user-experiment {
|
|
padding: 8px 0;
|
|
}
|
|
`,
|
|
];
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
"ha-user-editor": HaUserEditor;
|
|
}
|
|
}
|