mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-08 18:06:36 +00:00
Allow managing users (#1436)
* Allow managing users * Address comments * table -> card-content * Don't close dialog on error
This commit is contained in:
parent
c11cf53f96
commit
ed9c73429f
@ -173,6 +173,8 @@ class HomeAssistant extends LocalizeMixin(PolymerElement) {
|
|||||||
moreInfoEntityId: null,
|
moreInfoEntityId: null,
|
||||||
callService: null,
|
callService: null,
|
||||||
callApi: null,
|
callApi: null,
|
||||||
|
sendWS: null,
|
||||||
|
callWS: null,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -243,6 +245,29 @@ class HomeAssistant extends LocalizeMixin(PolymerElement) {
|
|||||||
return await hassCallApi(host, auth, method, path, parameters);
|
return await hassCallApi(host, auth, method, path, parameters);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// For messages that do not get a response
|
||||||
|
sendWS: (msg) => {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
if (__DEV__) console.log('Sending', msg);
|
||||||
|
conn.sendMessage(msg);
|
||||||
|
},
|
||||||
|
// For messages that expect a response
|
||||||
|
callWS: (msg) => {
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
if (__DEV__) console.log('Sending', msg);
|
||||||
|
|
||||||
|
const resp = conn.sendMessagePromise(msg);
|
||||||
|
|
||||||
|
if (__DEV__) {
|
||||||
|
resp.then(
|
||||||
|
result => console.log('Received', result),
|
||||||
|
err => console.log('Error', err),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// In the future we'll do this as a breaking change
|
||||||
|
// inside home-assistant-js-websocket
|
||||||
|
return resp.then(result => result.result);
|
||||||
|
},
|
||||||
}, this.$.storage.getStoredState());
|
}, this.$.storage.getStoredState());
|
||||||
|
|
||||||
var reconnected = () => {
|
var reconnected = () => {
|
||||||
|
@ -9,6 +9,7 @@ import '../../../components/ha-menu-button.js';
|
|||||||
import '../ha-config-section.js';
|
import '../ha-config-section.js';
|
||||||
import './ha-config-cloud-menu.js';
|
import './ha-config-cloud-menu.js';
|
||||||
import './ha-config-entries-menu.js';
|
import './ha-config-entries-menu.js';
|
||||||
|
import './ha-config-users-menu.js';
|
||||||
import './ha-config-navigation.js';
|
import './ha-config-navigation.js';
|
||||||
|
|
||||||
import isComponentLoaded from '../../../common/config/is_component_loaded.js';
|
import isComponentLoaded from '../../../common/config/is_component_loaded.js';
|
||||||
@ -39,14 +40,18 @@ class HaConfigDashboard extends LocalizeMixin(PolymerElement) {
|
|||||||
<span slot="header">[[localize('ui.panel.config.header')]]</span>
|
<span slot="header">[[localize('ui.panel.config.header')]]</span>
|
||||||
<span slot="introduction">[[localize('ui.panel.config.introduction')]]</span>
|
<span slot="introduction">[[localize('ui.panel.config.introduction')]]</span>
|
||||||
|
|
||||||
<template is="dom-if" if="[[computeIsLoaded(hass, "cloud")]]">
|
<template is="dom-if" if="[[computeIsLoaded(hass, 'cloud')]]">
|
||||||
<ha-config-cloud-menu hass="[[hass]]" account="[[account]]"></ha-config-cloud-menu>
|
<ha-config-cloud-menu hass="[[hass]]" account="[[account]]"></ha-config-cloud-menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template is="dom-if" if="[[computeIsLoaded(hass, "config.config_entries")]]">
|
<template is="dom-if" if="[[computeIsLoaded(hass, 'config.config_entries')]]">
|
||||||
<ha-config-entries-menu hass="[[hass]]"></ha-config-entries-menu>
|
<ha-config-entries-menu hass="[[hass]]"></ha-config-entries-menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template is="dom-if" if="[[computeIsLoaded(hass, 'config.auth_provider_homeassistant')]]">
|
||||||
|
<ha-config-users-menu hass="[[hass]]"></ha-config-users-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
<ha-config-navigation hass="[[hass]]"></ha-config-navigation>
|
<ha-config-navigation hass="[[hass]]"></ha-config-navigation>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
</div>
|
</div>
|
||||||
|
47
src/panels/config/dashboard/ha-config-users-menu.js
Normal file
47
src/panels/config/dashboard/ha-config-users-menu.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import '@polymer/iron-icon/iron-icon.js';
|
||||||
|
import '@polymer/paper-card/paper-card.js';
|
||||||
|
import '@polymer/paper-item/paper-item-body.js';
|
||||||
|
import '@polymer/paper-item/paper-item.js';
|
||||||
|
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||||
|
|
||||||
|
import LocalizeMixin from '../../../mixins/localize-mixin.js';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @appliesMixin LocalizeMixin
|
||||||
|
*/
|
||||||
|
class HaConfigUsersMenu extends LocalizeMixin(PolymerElement) {
|
||||||
|
static get template() {
|
||||||
|
return html`
|
||||||
|
<style include="iron-flex">
|
||||||
|
paper-card {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<paper-card>
|
||||||
|
<a href='/config/users'>
|
||||||
|
<paper-item>
|
||||||
|
<paper-item-body two-line>
|
||||||
|
[[localize('ui.panel.config.users.caption')]]
|
||||||
|
<div secondary>
|
||||||
|
[[localize('ui.panel.config.users.description')]]
|
||||||
|
</div>
|
||||||
|
</paper-item-body>
|
||||||
|
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||||
|
</paper-item>
|
||||||
|
</a>
|
||||||
|
</paper-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
hass: Object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('ha-config-users-menu', HaConfigUsersMenu);
|
@ -12,6 +12,7 @@ import './core/ha-config-core.js';
|
|||||||
import './customize/ha-config-customize.js';
|
import './customize/ha-config-customize.js';
|
||||||
import './dashboard/ha-config-dashboard.js';
|
import './dashboard/ha-config-dashboard.js';
|
||||||
import './script/ha-config-script.js';
|
import './script/ha-config-script.js';
|
||||||
|
import './users/ha-config-users.js';
|
||||||
import './zwave/ha-config-zwave.js';
|
import './zwave/ha-config-zwave.js';
|
||||||
|
|
||||||
import isComponentLoaded from '../../common/config/is_component_loaded.js';
|
import isComponentLoaded from '../../common/config/is_component_loaded.js';
|
||||||
@ -104,6 +105,14 @@ class HaPanelConfig extends NavigateMixin(PolymerElement) {
|
|||||||
is-wide='[[isWide]]'
|
is-wide='[[isWide]]'
|
||||||
></ha-config-entries>
|
></ha-config-entries>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template is="dom-if" if='[[_equals(_routeData.page, "users")]]' restamp>
|
||||||
|
<ha-config-users
|
||||||
|
page-name='users'
|
||||||
|
route='[[route]]'
|
||||||
|
hass='[[hass]]'
|
||||||
|
></ha-config-users>
|
||||||
|
</template>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
100
src/panels/config/users/ha-config-users.js
Normal file
100
src/panels/config/users/ha-config-users.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import '@polymer/app-route/app-route.js';
|
||||||
|
import { timeOut } from '@polymer/polymer/lib/utils/async.js';
|
||||||
|
import { Debouncer } from '@polymer/polymer/lib/utils/debounce.js';
|
||||||
|
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||||
|
|
||||||
|
import NavigateMixin from '../../../mixins/navigate-mixin.js';
|
||||||
|
|
||||||
|
import './ha-user-picker.js';
|
||||||
|
import './ha-user-editor.js';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @appliesMixin NavigateMixin
|
||||||
|
*/
|
||||||
|
class HaConfigUsers extends NavigateMixin(PolymerElement) {
|
||||||
|
static get template() {
|
||||||
|
return html`
|
||||||
|
<app-route
|
||||||
|
route='[[route]]'
|
||||||
|
pattern='/users/:user'
|
||||||
|
data="{{_routeData}}"
|
||||||
|
></app-route>
|
||||||
|
|
||||||
|
<template is='dom-if' if='[[_equals(_routeData.user, "picker")]]'>
|
||||||
|
<ha-user-picker
|
||||||
|
hass='[[hass]]'
|
||||||
|
users='[[_users]]'
|
||||||
|
></ha-user-picker>
|
||||||
|
</template>
|
||||||
|
<template is='dom-if' if='[[!_equals(_routeData.user, "picker")]]' restamp>
|
||||||
|
<ha-user-editor
|
||||||
|
hass='[[hass]]'
|
||||||
|
user='[[_computeUser(_users, _routeData.user)]]'
|
||||||
|
></ha-user-editor>
|
||||||
|
</template>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
hass: Object,
|
||||||
|
route: {
|
||||||
|
type: Object,
|
||||||
|
observer: '_checkRoute',
|
||||||
|
},
|
||||||
|
_routeData: Object,
|
||||||
|
_user: {
|
||||||
|
type: Object,
|
||||||
|
value: null,
|
||||||
|
},
|
||||||
|
_users: {
|
||||||
|
type: Array,
|
||||||
|
value: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ready() {
|
||||||
|
super.ready();
|
||||||
|
this._loadData();
|
||||||
|
this.addEventListener('reload-users', () => this._loadData());
|
||||||
|
}
|
||||||
|
|
||||||
|
_handlePickUser(ev) {
|
||||||
|
this._user = ev.detail.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkRoute(route) {
|
||||||
|
if (!route || route.path.substr(0, 6) !== '/users') return;
|
||||||
|
|
||||||
|
// prevent list gettung under toolbar
|
||||||
|
this.fire('iron-resize');
|
||||||
|
|
||||||
|
this._debouncer = Debouncer.debounce(
|
||||||
|
this._debouncer,
|
||||||
|
timeOut.after(0),
|
||||||
|
() => {
|
||||||
|
if (route.path === '/users') {
|
||||||
|
this.navigate('/config/users/picker', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_computeUser(users, userId) {
|
||||||
|
return users && users.filter(u => u.id === userId)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
_equals(a, b) {
|
||||||
|
return a === b;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _loadData() {
|
||||||
|
this._users = await this.hass.callWS({
|
||||||
|
type: 'config/auth/list',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('ha-config-users', HaConfigUsers);
|
169
src/panels/config/users/ha-dialog-add-user.js
Normal file
169
src/panels/config/users/ha-dialog-add-user.js
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import '@polymer/paper-button/paper-button.js';
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js';
|
||||||
|
import '@polymer/paper-spinner/paper-spinner.js';
|
||||||
|
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||||
|
|
||||||
|
import '../../../resources/ha-style.js';
|
||||||
|
|
||||||
|
import LocalizeMixin from '../../../mixins/localize-mixin.js';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @appliesMixin LocalizeMixin
|
||||||
|
*/
|
||||||
|
class HaDialogAddUser extends LocalizeMixin(PolymerElement) {
|
||||||
|
static get template() {
|
||||||
|
return html`
|
||||||
|
<style include="ha-style-dialog">
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
paper-dialog {
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
.username {
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<paper-dialog id="dialog" with-backdrop opened="{{_opened}}" on-opened-changed="_openedChanged">
|
||||||
|
<h2>Add user</h2>
|
||||||
|
<div>
|
||||||
|
<template is="dom-if" if="[[_errorMsg]]">
|
||||||
|
<div class='error'>[[_errorMsg]]</div>
|
||||||
|
</template>
|
||||||
|
<paper-input
|
||||||
|
autofocus
|
||||||
|
class='username'
|
||||||
|
label='Username'
|
||||||
|
value='{{_username}}'
|
||||||
|
required
|
||||||
|
auto-validate
|
||||||
|
error-message='Required'
|
||||||
|
></paper-input>
|
||||||
|
<paper-input
|
||||||
|
label='Password'
|
||||||
|
type='password'
|
||||||
|
value='{{_password}}'
|
||||||
|
required
|
||||||
|
auto-validate
|
||||||
|
error-message='Required'
|
||||||
|
></paper-input>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<template is="dom-if" if="[[_loading]]">
|
||||||
|
<div class='submit-spinner'><paper-spinner active></paper-spinner></div>
|
||||||
|
</template>
|
||||||
|
<template is="dom-if" if="[[!_loading]]">
|
||||||
|
<paper-button on-click="_createUser">Create</paper-button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
_hass: Object,
|
||||||
|
_dialogClosedCallback: Function,
|
||||||
|
|
||||||
|
_loading: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Error message when can't talk to server etc
|
||||||
|
_errorMsg: String,
|
||||||
|
|
||||||
|
_opened: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
_username: String,
|
||||||
|
_password: String,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ready() {
|
||||||
|
super.ready();
|
||||||
|
this.addEventListener('keypress', (ev) => {
|
||||||
|
if (ev.keyCode === 13) {
|
||||||
|
this._createUser();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
showDialog({ hass, dialogClosedCallback }) {
|
||||||
|
this.hass = hass;
|
||||||
|
this._dialogClosedCallback = dialogClosedCallback;
|
||||||
|
this._loading = false;
|
||||||
|
this._opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _createUser() {
|
||||||
|
if (!this._username || !this._password) return;
|
||||||
|
|
||||||
|
this._loading = true;
|
||||||
|
this._errorMsg = null;
|
||||||
|
|
||||||
|
let userId;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const userResponse = await this.hass.callWS({
|
||||||
|
type: 'config/auth/create',
|
||||||
|
name: this._username,
|
||||||
|
});
|
||||||
|
userId = userResponse.user.id;
|
||||||
|
} catch (err) {
|
||||||
|
this._loading = false;
|
||||||
|
this._errorMsg = err.code;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.hass.callWS({
|
||||||
|
type: 'config/auth_provider/homeassistant/create',
|
||||||
|
user_id: userId,
|
||||||
|
username: this._username,
|
||||||
|
password: this._password,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
this._loading = false;
|
||||||
|
this._errorMsg = err.code;
|
||||||
|
await this.hass.callWS({
|
||||||
|
type: 'config/auth/delete',
|
||||||
|
user_id: userId,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dialogDone(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dialogDone(userId) {
|
||||||
|
this._dialogClosedCallback({ userId });
|
||||||
|
|
||||||
|
this.setProperties({
|
||||||
|
_errorMsg: null,
|
||||||
|
_username: '',
|
||||||
|
_password: '',
|
||||||
|
_dialogClosedCallback: null,
|
||||||
|
_opened: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_equals(a, b) {
|
||||||
|
return a === b;
|
||||||
|
}
|
||||||
|
|
||||||
|
_openedChanged(ev) {
|
||||||
|
// Closed dialog by clicking on the overlay
|
||||||
|
// Check against dialogClosedCallback to make sure we didn't change
|
||||||
|
// programmatically
|
||||||
|
if (this._dialogClosedCallback && !ev.detail.value) {
|
||||||
|
this._dialogDone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('ha-dialog-add-user', HaDialogAddUser);
|
99
src/panels/config/users/ha-user-editor.js
Normal file
99
src/panels/config/users/ha-user-editor.js
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import '@polymer/paper-button/paper-button.js';
|
||||||
|
import '@polymer/paper-card/paper-card.js';
|
||||||
|
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||||
|
|
||||||
|
import '../../../layouts/hass-subpage.js';
|
||||||
|
import LocalizeMixin from '../../../mixins/localize-mixin.js';
|
||||||
|
import NavigateMixin from '../../../mixins/navigate-mixin.js';
|
||||||
|
import EventsMixin from '../../../mixins/events-mixin.js';
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @appliesMixin LocalizeMixin
|
||||||
|
* @appliesMixin NavigateMixin
|
||||||
|
* @appliesMixin EventsMixin
|
||||||
|
*/
|
||||||
|
class HaUserEditor extends EventsMixin(NavigateMixin(LocalizeMixin(PolymerElement))) {
|
||||||
|
static get template() {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
paper-card {
|
||||||
|
display: block;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
}
|
||||||
|
paper-card:first-child {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
paper-card:last-child {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
paper-button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<hass-subpage header="View user">
|
||||||
|
<paper-card heading="[[_computeName(user)]]">
|
||||||
|
<table class='card-content'>
|
||||||
|
<tr>
|
||||||
|
<td>ID</td>
|
||||||
|
<td>[[user.id]]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Owner</td>
|
||||||
|
<td>[[user.is_owner]]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Active</td>
|
||||||
|
<td>[[user.is_active]]</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>System generated</td>
|
||||||
|
<td>[[user.system_generated]]</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</paper-card>
|
||||||
|
<paper-card>
|
||||||
|
<div class='card-actions'>
|
||||||
|
<paper-button on-click='_deleteUser'>
|
||||||
|
[[localize('ui.panel.config.users.editor.delete_user')]]
|
||||||
|
</paper-button>
|
||||||
|
</div>
|
||||||
|
</paper-card>
|
||||||
|
</hass-subpage>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
hass: Object,
|
||||||
|
user: Object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_computeName(user) {
|
||||||
|
return user && (user.name || 'Unnamed user');
|
||||||
|
}
|
||||||
|
|
||||||
|
async _deleteUser(ev) {
|
||||||
|
if (!confirm(`Are you sure you want to delete ${this._computeName(this.user)}`)) {
|
||||||
|
ev.target.blur();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.hass.callWS({
|
||||||
|
type: 'config/auth/delete',
|
||||||
|
user_id: this.user.id,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
alert(err.code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.fire('reload-users');
|
||||||
|
this.navigate('/config/users');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('ha-user-editor', HaUserEditor);
|
110
src/panels/config/users/ha-user-picker.js
Normal file
110
src/panels/config/users/ha-user-picker.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import '@polymer/paper-fab/paper-fab.js';
|
||||||
|
import '@polymer/paper-item/paper-item.js';
|
||||||
|
import '@polymer/paper-card/paper-card.js';
|
||||||
|
import '@polymer/paper-item/paper-item-body.js';
|
||||||
|
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||||
|
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||||
|
|
||||||
|
import '../../../layouts/hass-subpage.js';
|
||||||
|
|
||||||
|
import LocalizeMixin from '../../../mixins/localize-mixin.js';
|
||||||
|
import NavigateMixin from '../../../mixins/navigate-mixin.js';
|
||||||
|
import EventsMixin from '../../../mixins/events-mixin.js';
|
||||||
|
|
||||||
|
let registeredDialog = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @appliesMixin LocalizeMixin
|
||||||
|
* @appliesMixin NavigateMixin
|
||||||
|
* @appliesMixin EventsMixin
|
||||||
|
*/
|
||||||
|
class HaUserPicker extends EventsMixin(NavigateMixin(LocalizeMixin(PolymerElement))) {
|
||||||
|
static get template() {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
paper-fab {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 16px;
|
||||||
|
right: 16px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
paper-fab[is-wide] {
|
||||||
|
bottom: 24px;
|
||||||
|
right: 24px;
|
||||||
|
}
|
||||||
|
paper-card {
|
||||||
|
display: block;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 16px auto;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<hass-subpage header="[[localize('ui.panel.config.users.picker.title')]]">
|
||||||
|
<paper-card>
|
||||||
|
<template is="dom-repeat" items="[[users]]" as="user">
|
||||||
|
<a href='[[_computeUrl(user)]]'>
|
||||||
|
<paper-item>
|
||||||
|
<paper-item-body two-line>
|
||||||
|
<div>[[_withDefault(user.name, 'Unnamed User')]]</div>
|
||||||
|
<div secondary="">[[user.id]]</div>
|
||||||
|
</paper-item-body>
|
||||||
|
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||||
|
</paper-item>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</paper-card>
|
||||||
|
|
||||||
|
<paper-fab
|
||||||
|
is-wide$="[[isWide]]"
|
||||||
|
icon="hass:plus"
|
||||||
|
title="[[localize('ui.panel.config.users.picker.add_user')]]"
|
||||||
|
on-click="_addUser"
|
||||||
|
></paper-fab>
|
||||||
|
</hass-subpage>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
hass: Object,
|
||||||
|
users: Array,
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
|
||||||
|
if (!registeredDialog) {
|
||||||
|
registeredDialog = true;
|
||||||
|
this.fire('register-dialog', {
|
||||||
|
dialogShowEvent: 'show-add-user',
|
||||||
|
dialogTag: 'ha-dialog-add-user',
|
||||||
|
dialogImport: () => import('./ha-dialog-add-user.js'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_withDefault(value, defaultValue) {
|
||||||
|
return value || defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_computeUrl(user) {
|
||||||
|
return `/config/users/${user.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_addUser() {
|
||||||
|
this.fire('show-add-user', {
|
||||||
|
hass: this.hass,
|
||||||
|
dialogClosedCallback: async ({ userId }) => {
|
||||||
|
this.fire('reload-users');
|
||||||
|
if (userId) this.navigate(`/config/users/${userId}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('ha-user-picker', HaUserPicker);
|
@ -672,6 +672,20 @@
|
|||||||
"caption": "Script",
|
"caption": "Script",
|
||||||
"description": "Create and edit scripts"
|
"description": "Create and edit scripts"
|
||||||
},
|
},
|
||||||
|
"users": {
|
||||||
|
"caption": "Users",
|
||||||
|
"description": "Manage users",
|
||||||
|
"picker": {
|
||||||
|
"title": "Users"
|
||||||
|
},
|
||||||
|
"editor": {
|
||||||
|
"rename_user": "Rename user",
|
||||||
|
"change_password": "Change password",
|
||||||
|
"activate_user": "Activate user",
|
||||||
|
"deactivate_user": "Deactivate user",
|
||||||
|
"delete_user": "Delete user"
|
||||||
|
}
|
||||||
|
},
|
||||||
"zwave": {
|
"zwave": {
|
||||||
"caption": "Z-Wave",
|
"caption": "Z-Wave",
|
||||||
"description": "Manage your Z-Wave network"
|
"description": "Manage your Z-Wave network"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user