mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-24 13:27:22 +00:00
Add UI for tokens (#1656)
* Add UI for tokens * Update strings * Update text * Update text
This commit is contained in:
parent
494e3dc62c
commit
34567d451f
127
src/panels/profile/ha-long-lived-access-tokens-card.js
Normal file
127
src/panels/profile/ha-long-lived-access-tokens-card.js
Normal file
@ -0,0 +1,127 @@
|
||||
import '@polymer/paper-button/paper-button.js';
|
||||
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import EventsMixin from '../../mixins/events-mixin.js';
|
||||
import LocalizeMixin from '../../mixins/localize-mixin.js';
|
||||
import formatDateTime from '../../common/datetime/format_date_time.js';
|
||||
|
||||
import '../../resources/ha-style.js';
|
||||
|
||||
import './ha-settings-row.js';
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class HaLongLivedTokens extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="ha-style">
|
||||
paper-card {
|
||||
display: block;
|
||||
}
|
||||
.card-content {
|
||||
margin: -1em 0;
|
||||
}
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
paper-icon-button {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
</style>
|
||||
<paper-card heading="[[localize('ui.panel.profile.long_lived_access_tokens.header')]]">
|
||||
<div class="card-content">
|
||||
<p>
|
||||
[[localize('ui.panel.profile.long_lived_access_tokens.description')]]
|
||||
<a href='https://developers.home-assistant.io/docs/en/auth_api.html#making-authenticated-requests' target='_blank'>
|
||||
[[localize('ui.panel.profile.long_lived_access_tokens.learn_auth_requests')]]
|
||||
</a>
|
||||
</p>
|
||||
<template is='dom-if' if='[[!_tokens.length]]'>
|
||||
<p>[[localize('ui.panel.profile.long_lived_access_tokens.empty_state')]]</p>
|
||||
</template>
|
||||
</div>
|
||||
<template is='dom-repeat' items='[[_tokens]]'>
|
||||
<ha-settings-row>
|
||||
<span slot='heading'>[[item.client_name]]</span>
|
||||
<span slot='description'>[[_formatCreatedAt(item.created_at)]]</span>
|
||||
<paper-icon-button icon="hass:delete" on-click='_handleDelete'></paper-icon-button>
|
||||
</ha-settings-row>
|
||||
</template>
|
||||
<div class='card-actions'>
|
||||
<paper-button on-click='_handleCreate'>
|
||||
[[localize('ui.panel.profile.long_lived_access_tokens.create')]]
|
||||
</paper-button>
|
||||
</div>
|
||||
</paper-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
refreshTokens: Array,
|
||||
_tokens: {
|
||||
type: Array,
|
||||
computed: '_computeTokens(refreshTokens)'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_computeTokens(refreshTokens) {
|
||||
return refreshTokens.filter(tkn => tkn.type === 'long_lived_access_token').reverse();
|
||||
}
|
||||
|
||||
_formatTitle(name) {
|
||||
return this.localize(
|
||||
'ui.panel.profile.long_lived_access_tokens.token_title',
|
||||
'name', name
|
||||
);
|
||||
}
|
||||
|
||||
_formatCreatedAt(created) {
|
||||
return this.localize(
|
||||
'ui.panel.profile.long_lived_access_tokens.created_at',
|
||||
'date', formatDateTime(new Date(created))
|
||||
);
|
||||
}
|
||||
|
||||
async _handleCreate() {
|
||||
const name = prompt(this.localize('ui.panel.profile.long_lived_access_tokens.prompt_name'));
|
||||
if (!name) return;
|
||||
try {
|
||||
const token = await this.hass.callWS({
|
||||
type: 'auth/long_lived_access_token',
|
||||
lifespan: 3650,
|
||||
client_name: name,
|
||||
});
|
||||
prompt(this.localize('ui.panel.profile.long_lived_access_tokens.prompt_copy_token'), token);
|
||||
this.fire('hass-refresh-tokens');
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.error(err);
|
||||
alert(this.localize('ui.panel.profile.long_lived_access_tokens.create_failed'));
|
||||
}
|
||||
}
|
||||
|
||||
async _handleDelete(ev) {
|
||||
if (!confirm(this.localize('ui.panel.profile.long_lived_access_tokens.confirm_delete', 'name', ev.model.item.client_name))) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.hass.callWS({
|
||||
type: 'auth/delete_refresh_token',
|
||||
refresh_token_id: ev.model.item.id,
|
||||
});
|
||||
this.fire('hass-refresh-tokens');
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.error(err);
|
||||
alert(this.localize('ui.panel.profile.long_lived_access_tokens.delete_failed'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-long-lived-access-tokens-card', HaLongLivedTokens);
|
@ -15,6 +15,9 @@ import EventsMixin from '../../mixins/events-mixin.js';
|
||||
|
||||
import './ha-change-password-card.js';
|
||||
import './ha-mfa-modules-card.js';
|
||||
import './ha-refresh-tokens-card.js';
|
||||
import './ha-long-lived-access-tokens-card.js';
|
||||
|
||||
import './ha-pick-language-row.js';
|
||||
import './ha-pick-theme-row.js';
|
||||
import './ha-push-notifications-row.js';
|
||||
@ -84,7 +87,22 @@ class HaPanelProfile extends EventsMixin(PolymerElement) {
|
||||
<ha-change-password-card hass="[[hass]]"></ha-change-password-card>
|
||||
</template>
|
||||
|
||||
<ha-mfa-modules-card hass='[[hass]]' mfa-modules='[[hass.user.mfa_modules]]'></ha-mfa-modules-card>
|
||||
<ha-mfa-modules-card
|
||||
hass='[[hass]]'
|
||||
mfa-modules='[[hass.user.mfa_modules]]'
|
||||
></ha-mfa-modules-card>
|
||||
|
||||
<ha-refresh-tokens-card
|
||||
hass='[[hass]]'
|
||||
refresh-tokens='[[_refreshTokens]]'
|
||||
on-hass-refresh-tokens='_refreshRefreshTokens'
|
||||
></ha-refresh-tokens-card>
|
||||
|
||||
<ha-long-lived-access-tokens-card
|
||||
hass='[[hass]]'
|
||||
refresh-tokens='[[_refreshTokens]]'
|
||||
on-hass-refresh-tokens='_refreshRefreshTokens'
|
||||
></ha-long-lived-access-tokens-card>
|
||||
</div>
|
||||
</app-header-layout>
|
||||
`;
|
||||
@ -95,9 +113,21 @@ class HaPanelProfile extends EventsMixin(PolymerElement) {
|
||||
hass: Object,
|
||||
narrow: Boolean,
|
||||
showMenu: Boolean,
|
||||
_refreshTokens: Array,
|
||||
};
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._refreshRefreshTokens();
|
||||
}
|
||||
|
||||
async _refreshRefreshTokens() {
|
||||
this._refreshTokens = await this.hass.callWS({
|
||||
type: 'auth/refresh_tokens'
|
||||
});
|
||||
}
|
||||
|
||||
_handleLogOut() {
|
||||
this.fire('hass-logout');
|
||||
}
|
||||
|
82
src/panels/profile/ha-refresh-tokens-card.js
Normal file
82
src/panels/profile/ha-refresh-tokens-card.js
Normal file
@ -0,0 +1,82 @@
|
||||
import '@polymer/paper-icon-button/paper-icon-button.js';
|
||||
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import EventsMixin from '../../mixins/events-mixin.js';
|
||||
import LocalizeMixin from '../../mixins/localize-mixin.js';
|
||||
import formatDateTime from '../../common/datetime/format_date_time.js';
|
||||
|
||||
import './ha-settings-row.js';
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class HaRefreshTokens extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
paper-card {
|
||||
display: block;
|
||||
}
|
||||
paper-icon-button {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
</style>
|
||||
<paper-card heading="[[localize('ui.panel.profile.refresh_tokens.header')]]">
|
||||
<div class="card-content">[[localize('ui.panel.profile.refresh_tokens.description')]]</div>
|
||||
<template is='dom-repeat' items='[[_computeTokens(refreshTokens)]]'>
|
||||
<ha-settings-row>
|
||||
<span slot='heading'>[[_formatTitle(item.client_id)]]</span>
|
||||
<span slot='description'>[[_formatCreatedAt(item.created_at)]]</span>
|
||||
<paper-icon-button icon="hass:delete" on-click='_handleDelete'></paper-icon-button>
|
||||
</ha-settings-row>
|
||||
</template>
|
||||
</paper-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
refreshTokens: Array,
|
||||
};
|
||||
}
|
||||
|
||||
_computeTokens(refreshTokens) {
|
||||
return refreshTokens.filter(tkn => tkn.type === 'normal').reverse();
|
||||
}
|
||||
|
||||
_formatTitle(clientId) {
|
||||
return this.localize(
|
||||
'ui.panel.profile.refresh_tokens.token_title',
|
||||
'clientId', clientId
|
||||
);
|
||||
}
|
||||
|
||||
_formatCreatedAt(created) {
|
||||
return this.localize(
|
||||
'ui.panel.profile.refresh_tokens.created_at',
|
||||
'date', formatDateTime(new Date(created))
|
||||
);
|
||||
}
|
||||
|
||||
async _handleDelete(ev) {
|
||||
if (!confirm(this.localize('ui.panel.profile.refresh_tokens.confirm_delete', 'name', ev.model.item.client_id))) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.hass.callWS({
|
||||
type: 'auth/delete_refresh_token',
|
||||
refresh_token_id: ev.model.item.id,
|
||||
});
|
||||
this.fire('hass-refresh-tokens');
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.error(err);
|
||||
alert(this.localize('ui.panel.profile.refresh_tokens.delete_failed'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-refresh-tokens-card', HaRefreshTokens);
|
@ -746,6 +746,27 @@
|
||||
"error_no_theme": "No themes available.",
|
||||
"link_promo": "Learn about themes",
|
||||
"dropdown_label": "Theme"
|
||||
},
|
||||
"refresh_tokens": {
|
||||
"header": "Refresh Tokens",
|
||||
"description": "Each refresh token represents a login session. Refresh tokens will be automatically removed when you click log out. Below a list of refresh tokens that are currently active for your account.",
|
||||
"token_title": "Refresh token for {clientId}",
|
||||
"created_at": "Created at {date}",
|
||||
"confirm_delete": "Are you sure you want to delete the refresh token for {name}?",
|
||||
"delete_failed": "Failed to delete the refresh token."
|
||||
},
|
||||
"long_lived_access_tokens": {
|
||||
"header": "Long-Lived Access Tokens",
|
||||
"description": "Create long-lived access tokens to allow your scripts to interact with your Home Assistant instance. Each token will be valid for 10 years from creation. The following long-lived access tokens are currently active.",
|
||||
"learn_auth_requests": "Learn how to make authenticated requests.",
|
||||
"created_at": "Created at {date}",
|
||||
"confirm_delete": "Are you sure you want to delete the access token for {name}?",
|
||||
"delete_failed": "Failed to delete the access token.",
|
||||
"create": "Create Token",
|
||||
"create_failed": "Failed to create the access token.",
|
||||
"prompt_name": "Name?",
|
||||
"prompt_copy_token": "Copy your access token. It will not be shown again.",
|
||||
"empty_state": "You have no long-lived access tokens yet."
|
||||
}
|
||||
},
|
||||
"shopping-list": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user