Hassio updates (#335)

* Fetch addons from /hassio/addons

* Fetch snapshots from /hassio/snapshots

* Hass.io cleanup

* Hass.io limit data fetches until visible

* Upgrade hass addon view

* lint
This commit is contained in:
Paulus Schoutsen 2017-07-11 23:35:34 -07:00 committed by GitHub
parent c8c8b6aaab
commit 8a2f881684
9 changed files with 281 additions and 242 deletions

View File

@ -47,6 +47,11 @@ Polymer({
type: Object, type: Object,
}, },
visible: {
type: Boolean,
observer: '_visibleChanged',
},
route: Object, route: Object,
_routeData: Object, _routeData: Object,
_routeMatches: Boolean, _routeMatches: Boolean,
@ -78,16 +83,18 @@ Polymer({
apiCalled: function (ev) { apiCalled: function (ev) {
if (ev.detail.success) { if (ev.detail.success) {
this.loadData(); this._loadData();
} }
}, },
attached: function () { _visibleChanged: function (visible) {
this.loadData(); if (visible) {
this._loadData();
}
}, },
loadData: function () { _loadData: function () {
this.hass.callApi('get', 'hassio/supervisor/addons') this.hass.callApi('get', 'hassio/addons')
.then(function (info) { .then(function (info) {
this.addons = info.data.addons; this.addons = info.data.addons;
this.repos = info.data.repositories; this.repos = info.data.repositories;
@ -120,7 +127,7 @@ Polymer({
refreshData: function () { refreshData: function () {
this.hass.callApi('post', 'hassio/supervisor/reload') this.hass.callApi('post', 'hassio/supervisor/reload')
.then(function () { .then(function () {
this.loadData(); this._loadData();
}.bind(this)); }.bind(this));
}, },
}); });

View File

@ -3,14 +3,13 @@
<link rel="import" href="../../../bower_components/app-layout/app-header/app-header.html"> <link rel="import" href="../../../bower_components/app-layout/app-header/app-header.html">
<link rel="import" href="../../../bower_components/app-layout/app-toolbar/app-toolbar.html"> <link rel="import" href="../../../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../../../bower_components/paper-icon-button/paper-icon-button.html"> <link rel="import" href="../../../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> <link rel="import" href="../../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../../bower_components/paper-item/paper-item.html"> <link rel="import" href="../../../bower_components/paper-checkbox/paper-checkbox.html">
<link rel="import" href="../../../bower_components/paper-button/paper-button.html"> <link rel="import" href="../../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../../../bower_components/paper-item/paper-item-body.html">
<link rel="import" href="../../../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
<link rel="import" href="../../../src/components/ha-menu-button.html">
<link rel="import" href="../../../src/components/ha-icon-check.html">
<dom-module id="hassio-addon-info"> <dom-module id="hassio-addon-info">
<template> <template>
@ -21,25 +20,131 @@
paper-card { paper-card {
display: block; display: block;
} }
td {
padding-top: 5px;
}
td ha-call-api-button {
color: var(--primary-color);
}
a.help {
--iron-icon-height: 16px;
--iron-icon-width: 16px;
color: var(--primary-color);
}
</style> </style>
<paper-card heading='Info'> <paper-card heading='Info'>
<div class="card-content"> <div class="card-content">
<p>[[addonInfo.description]]</p> <table class='info' cellspacing="0">
<table class='info'>
<tr> <tr>
<td>Installed</td> <td>Description</td>
<td>[[computeInstallStatus(addonInfo)]]</td> <td>[[addonInfo.description]]</td>
</tr> </tr>
<tr> <tr>
<td>Version</td> <td>Version</td>
<td>[[addonInfo.version]]</td> <td>
[[addonState.version]]
<template is='dom-if' if='[[_computeUpdateAvailable(addonState)]]'>
<ha-call-api-button
hass='[[hass]]'
path="[[_pathUpdate(addonInfo.slug)]]"
>Update</ha-call-api-button>
</template>
</td>
</tr>
<tr>
<td>State</td>
<td>[[addonState.state]]</td>
</tr>
<tr>
<td>Boot</td>
<td>
[[addonState.boot]]
<ha-call-api-button
hass='[[hass]]'
path="[[_pathAddonOptions(addonInfo.slug)]]"
data="[[_dataToggleBoot(addonInfo.slug, addonState)]]"
>Toggle</ha-call-api-button>
</td>
</tr>
<tr>
<td>Auto update</td>
<td>
<ha-icon-check
checked='[[addonState.auto_update]]'
></ha-icon-check>
<ha-call-api-button
hass='[[hass]]'
path="[[_pathAddonOptions(addonInfo.slug)]]"
data="[[_dataToggleAutoUpdate(addonInfo.slug, addonState)]]"
>Toggle</ha-call-api-button>
</td>
</tr>
<tr>
<td>Uses host network</td>
<td>
<ha-icon-check
checked='[[addonState.host_network]]'
></ha-icon-check>
</td>
</tr>
<tr>
<td>
Builds locally
<a
class='help'
href="https://home-assistant.io/hassio/addon_publishing/#locally-build-containers"
target="_blank"
>
<iron-icon
icon="mdi:help-circle"
label="Learn more about locally build containers"
></iron-icon>
</a>
</td>
<td>
<ha-icon-check
checked='[[addonState.build]]'
></ha-icon-check>
</td>
</tr> </tr>
<tr> <tr>
<td>Detached</td> <td>Detached</td>
<td>[[addonInfo.detached]]</td> <td>
<ha-icon-check
checked='[[addonState.detached]]'
></ha-icon-check>
</td>
</tr> </tr>
</table> </table>
</div> </div>
<div class="card-actions">
<template is='dom-if' if='[[!_isRunning]]'>
<ha-call-api-button
hass='[[hass]]'
path="[[_pathStart(addonInfo.slug)]]"
>Start</ha-call-api-button>
</template>
<template is='dom-if' if='[[_isRunning]]'>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path="[[_pathRestart(addonInfo.slug)]]"
>Restart</ha-call-api-button>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path="[[_pathStop(addonInfo.slug)]]"
>Stop</ha-call-api-button>
</template>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path="[[_pathUninstall(addonInfo.slug)]]"
>Uninstall</ha-call-api-button>
</div>
</paper-card> </paper-card>
</template> </template>
</dom-module> </dom-module>
@ -49,17 +154,54 @@ Polymer({
is: 'hassio-addon-info', is: 'hassio-addon-info',
properties: { properties: {
hass: { hass: Object,
type: Object, addonInfo: Object,
}, addonState: Object,
addonInfo: { _isRunning: {
type: Object, type: Boolean,
computed: '_computeIsRunning(addonState)',
}, },
}, },
computeInstallStatus: function (addon) { _computeIsRunning: function (addonState) {
return (addon && addon.installed) || 'Not installed'; return addonState && addonState.state === 'started';
}, },
_computeUpdateAvailable: function (data) {
return data && !data.detached && data.version !== data.last_version;
},
_pathStart: function (addon) {
return 'hassio/addons/' + addon + '/start';
},
_pathStop: function (addon) {
return 'hassio/addons/' + addon + '/stop';
},
_pathRestart: function (addon) {
return 'hassio/addons/' + addon + '/restart';
},
_pathUninstall: function (addon) {
return 'hassio/addons/' + addon + '/uninstall';
},
_pathUpdate: function (addon) {
return 'hassio/addons/' + addon + '/update';
},
_pathAddonOptions: function (addon) {
return 'hassio/addons/' + addon + '/options';
},
_dataToggleAutoUpdate: function (addon, addonState) {
return addonState && { auto_update: !addonState.auto_update };
},
_dataToggleBoot: function (addon, addonState) {
return addonState && { boot: addonState.boot === 'manual' ? 'auto' : 'manual' };
}
}); });
</script> </script>

View File

@ -1,125 +0,0 @@
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../../src/components/buttons/ha-call-api-button.html">
<dom-module id="hassio-addon-state">
<template>
<style include="ha-style">
:host {
display: block;
}
paper-card {
display: block;
}
</style>
<paper-card heading='Installed'>
<div class="card-content">
<table class='info'>
<tr>
<td>Version</td>
<td>[[addonState.version]]</td>
</tr>
<tr>
<td>State</td>
<td>[[addonState.state]]</td>
</tr>
<tr>
<td>Boot</td>
<td>[[addonState.boot]]</td>
</tr>
</table>
</div>
<div class="card-actions">
<template is='dom-if' if='[[!isRunning]]'>
<ha-call-api-button
hass='[[hass]]'
path="[[pathStart(addon)]]"
>Start</ha-call-api-button>
</template>
<template is='dom-if' if='[[isRunning]]'>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path="[[pathRestart(addon)]]"
>Restart</ha-call-api-button>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path="[[pathStop(addon)]]"
>Stop</ha-call-api-button>
</template>
<template is='dom-if' if='[[computeUpdateAvailable(addonState)]]'>
<ha-call-api-button
hass='[[hass]]'
path="[[pathUpdate(addon)]]"
>Update</ha-call-api-button>
</template>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path="[[pathUninstall(addon)]]"
>Uninstall</ha-call-api-button>
</div>
</paper-card>
</template>
</dom-module>
<script>
Polymer({
is: 'hassio-addon-state',
properties: {
hass: {
type: Object,
},
addon: {
type: String,
},
isRunning: {
type: Boolean,
computed: 'computeIsRunning(addonState)',
},
addonInfo: {
type: Object,
value: null,
},
addonState: {
type: Object,
value: null,
},
},
computeIsRunning: function (addonState) {
return addonState && addonState.state === 'started';
},
computeUpdateAvailable: function (data) {
return data && !data.detached && data.version !== data.last_version;
},
pathStart: function (addon) {
return 'hassio/addons/' + addon + '/start';
},
pathStop: function (addon) {
return 'hassio/addons/' + addon + '/stop';
},
pathRestart: function (addon) {
return 'hassio/addons/' + addon + '/restart';
},
pathUninstall: function (addon) {
return 'hassio/addons/' + addon + '/uninstall';
},
pathUpdate: function (addon) {
return 'hassio/addons/' + addon + '/update';
},
});
</script>

View File

@ -7,17 +7,13 @@
<link rel="import" href="../../../src/components/ha-menu-button.html"> <link rel="import" href="../../../src/components/ha-menu-button.html">
<link rel="import" href="./hassio-addon-info.html"> <link rel="import" href="./hassio-addon-info.html">
<link rel="import" href="./hassio-addon-state.html">
<link rel="import" href="./hassio-addon-options.html"> <link rel="import" href="./hassio-addon-options.html">
<link rel="import" href="./hassio-addon-logs.html"> <link rel="import" href="./hassio-addon-logs.html">
<dom-module id="hassio-addon-view"> <dom-module id="hassio-addon-view">
<template> <template>
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
paper-card { hassio-addon-info,
display: block;
}
.controls paper-card,
hassio-addon-options { hassio-addon-options {
margin-bottom: 24px; margin-bottom: 24px;
} }
@ -26,16 +22,6 @@
max-width: 600px; max-width: 600px;
margin: 0 auto; margin: 0 auto;
} }
.status {
@apply(--layout-horizontal);
margin-bottom: 24px;
}
.status > * {
@apply(--layout-flex);
}
.status > *:first-child {
margin-right: 24px;
}
</style> </style>
<app-route <app-route
route='[[route]]' route='[[route]]'
@ -54,22 +40,12 @@
</app-header> </app-header>
<div class='content'> <div class='content'>
<div class='status'>
<hassio-addon-info <hassio-addon-info
hass='[[hass]]' hass='[[hass]]'
addon-info='[[addonInfo]]' addon-info='[[addonInfo]]'
addon-state='[[addonState]]'
></hassio-addon-info> ></hassio-addon-info>
<hassio-addon-state
hass='[[hass]]'
addon='[[_routeData.addon]]'
addon-info='[[addonInfo]]'
addon-state='[[addonState]]'
></hassio-addon-state>
</div>
<template is='dom-if' if='[[addonState]]'>
<div class='controls'>
<hassio-addon-options <hassio-addon-options
hass='[[hass]]' hass='[[hass]]'
addon='[[_routeData.addon]]' addon='[[_routeData.addon]]'
@ -81,8 +57,6 @@
addon='[[_routeData.addon]]' addon='[[_routeData.addon]]'
></hassio-addon-logs> ></hassio-addon-logs>
</div> </div>
</template>
</div>
</app-header-layout> </app-header-layout>
</template> </template>
</dom-module> </dom-module>
@ -96,15 +70,6 @@ Polymer({
type: Object, type: Object,
}, },
narrow: {
type: Boolean,
},
showMenu: {
type: Boolean,
value: false,
},
route: Object, route: Object,
_routeData: { _routeData: {
type: Object, type: Object,
@ -138,6 +103,8 @@ Polymer({
apiCalled: function (ev) { apiCalled: function (ev) {
var path = ev.detail.path; var path = ev.detail.path;
if (!path) return;
if (path.substr(path.lastIndexOf('/') + 1) === 'uninstall') { if (path.substr(path.lastIndexOf('/') + 1) === 'uninstall') {
this.backTapped(); this.backTapped();
} else { } else {

View File

@ -75,15 +75,6 @@ Polymer({
type: Object, type: Object,
}, },
narrow: {
type: Boolean,
},
showMenu: {
type: Boolean,
value: false,
},
supervisorInfo: { supervisorInfo: {
type: Object, type: Object,
value: {}, value: {},

View File

@ -81,8 +81,6 @@
<hassio-advanced <hassio-advanced
page-name='advanced' page-name='advanced'
hass='[[hass]]' hass='[[hass]]'
narrow='[[narrow]]'
show-menu='[[showMenu]]'
supervisor-info='[[supervisorInfo]]' supervisor-info='[[supervisorInfo]]'
host-info='[[hostInfo]]' host-info='[[hostInfo]]'
hass-info='[[hassInfo]]' hass-info='[[hassInfo]]'
@ -91,9 +89,6 @@
<hassio-snapshot <hassio-snapshot
page-name='snapshot' page-name='snapshot'
hass='[[hass]]' hass='[[hass]]'
narrow='[[narrow]]'
show-menu='[[showMenu]]'
supervisor-info='[[supervisorInfo]]'
></hassio-snapshot> ></hassio-snapshot>
<hass-error-screen <hass-error-screen

View File

@ -17,7 +17,7 @@
display: block; display: block;
} }
paper-card:first-child { paper-card {
margin-bottom: 32px; margin-bottom: 32px;
} }
@ -75,7 +75,7 @@
<p>Looks like you don't have any snapshots yet.</p> <p>Looks like you don't have any snapshots yet.</p>
</template> </template>
</div> </div>
<template is='dom-repeat' items='[[data]]' as='snapshot'> <template is='dom-repeat' items='[[_data]]' as='snapshot'>
<paper-item> <paper-item>
<paper-item-body two-line> <paper-item-body two-line>
<div>[[snapshot.name]]</div> <div>[[snapshot.name]]</div>
@ -99,18 +99,44 @@ Polymer({
properties: { properties: {
hass: Object, hass: Object,
narrow: Boolean, visible: {
showMenu: Boolean, type: Boolean,
supervisorInfo: Object, observer: '_visibleChanged',
},
_snapshotName: String, _snapshotName: String,
_creatingSnapshot: Boolean, _creatingSnapshot: Boolean,
_error: Object, _error: Object,
data: { _data: {
type: Array, type: Array,
computed: '_computeData(supervisorInfo)' value: [],
},
},
listeners: {
'hass-api-called': '_apiCalled',
},
_visibleChanged: function (visible) {
if (visible) {
this._updateData();
} }
}, },
_apiCalled: function (ev) {
if (ev.detail.success) {
this._updateData();
}
},
_updateData: function () {
this.hass.callApi('get', 'hassio/snapshots')
.then(function (result) {
this._data = result.data.snapshots;
}.bind(this), function (error) {
this._error = error.message;
}.bind(this));
},
_createSnapshot: function () { _createSnapshot: function () {
this._creatingSnapshot = true; this._creatingSnapshot = true;
this.hass.callApi('post', 'hassio/snapshots/new/full', { this.hass.callApi('post', 'hassio/snapshots/new/full', {
@ -128,10 +154,6 @@ Polymer({
}.bind(this)); }.bind(this));
}, },
_computeData: function (supervisorInfo) {
return supervisorInfo.snapshots;
},
_computeRestorePath: function (snapshot) { _computeRestorePath: function (snapshot) {
return 'hassio/snapshots/' + snapshot.slug + '/restore/full'; return 'hassio/snapshots/' + snapshot.slug + '/restore/full';
}, },

View File

@ -20,12 +20,12 @@
<app-toolbar> <app-toolbar>
<paper-icon-button <paper-icon-button
icon='mdi:arrow-left' icon='mdi:arrow-left'
on-tap='backTapped' on-tap='_backTapped'
></paper-icon-button> ></paper-icon-button>
<div main-title>Supervisor Logs</div> <div main-title>Supervisor Logs</div>
<paper-icon-button <paper-icon-button
icon="mdi:refresh" icon="mdi:refresh"
on-tap="refreshTapped" on-tap="_refreshTapped"
></paper-icon-button> ></paper-icon-button>
</app-toolbar> </app-toolbar>
</app-header> </app-header>
@ -44,17 +44,9 @@ Polymer({
type: Object, type: Object,
}, },
narrow: { visible: {
type: Boolean, type: Boolean,
}, observer: '_visibleChanged',
showMenu: {
type: Boolean,
value: false,
},
supervisorInfo: {
type: Object,
}, },
logs: { logs: {
@ -63,11 +55,13 @@ Polymer({
}, },
}, },
attached: function () { _visibleChanged: function (visible) {
this.loadData(); if (visible) {
this._loadData();
}
}, },
loadData: function () { _loadData: function () {
this.hass.callApi('get', 'hassio/supervisor/logs') this.hass.callApi('get', 'hassio/supervisor/logs')
.then(function (info) { .then(function (info) {
this.logs = info; this.logs = info;
@ -76,11 +70,11 @@ Polymer({
}.bind(this)); }.bind(this));
}, },
refreshTapped: function () { _refreshTapped: function () {
this.loadData(); this._loadData();
}, },
backTapped: function () { _backTapped: function () {
history.back(); history.back();
}, },
}); });

View File

@ -0,0 +1,46 @@
<link rel='import' href='../../bower_components/polymer/polymer.html'>
<link rel='import' href='../../bower_components/iron-icon/iron-icon.html'>
<dom-module id='ha-icon-check'>
<template>
<style>
:host {
--ha-label-badge-color: #dac90d;
}
.pos {
color: var(--google-green-500);
}
.neg {
color: var(--google-red-500);
}
[hidden]: {
display: none;
}
</style>
<iron-icon
class='pos'
hidden='[[!checked]]'
icon='mdi:check'
label='True'
></iron-icon>
<iron-icon
class='neg'
hidden='[[checked]]'
icon='mdi:window-close'
label='False'
></iron-icon>
</template>
</dom-module>
<script>
Polymer({
is: 'ha-icon-check',
properties: {
checked: Boolean,
}
});
</script>