Polymer 3 modulize (#1154)

* Version bump to 20180510.1

* Fix hass util

* Fix translations

* Bye paper-time-input

* Add webpack config

* Add webpack to package.json

* Fix translation import

* Disable web animations polyfill bad import

* Disable importHref import

* Update webpack config to build authorize.js

* Build translations json

* Build frontend correctly

* Run eslint --fix

* Load markdown JS on demand (#1155)

* Add HTML imports (#1160)

* Fix localize (#1161)

* Fix Roboto in build (#1162)

* Load web animations polyfill (#1163)

* P3: Fix chart js (#1164)

* P3: Fix Chart JS

* Update timeline package

* P3: panel resolver (#1165)

* WIP

* Initial importing of panels

* Fix panel resolver

* Fix automation and script editor (#1166)

* Expose Polymer and Polymer.Element on window (#1167)

* Remove unused import

* eslint --fix

* Es5 build (#1168)

* Build for ES5

* Fix build_frontend

* Remove stale comment

* Migrate to use paper-material-styles (#1170)

* Send parsed date to history/logbook (#1171)

* Fork app storage behavior (#1172)

* Add paper input with type time (#1173)

* Fix authorize

* Lint

* Sort imports

* Lint

* Remove eslint-html

* Do not lint authorize.html

* Fix polymer lint

* Try chrome 62 for wct

* P3: Add patched iconset (#1175)

* Add patched iconset

* Lint

* Test with latest Chrome again

* Use less window.hassUtil

* Teporarily use my fecha fork

* Import correct intl.messageFormat

* Update wct-browser-legacy to 1.0.0

* Include polyfill in right place

* Fix IntlMessageFormat

* Fix test not having a global scope

* Rollup <_<

* Fork app-localize-behavior

* Disable wct tests

* Lint
This commit is contained in:
Paulus Schoutsen 2018-05-15 13:31:47 -04:00 committed by GitHub
parent 205d6a8347
commit a4afc2e37a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
274 changed files with 12972 additions and 10037 deletions

View File

@ -1,12 +1,12 @@
{ {
"extends": "./.eslintrc-hound.json", "extends": "./.eslintrc-hound.json",
"plugins": [ "plugins": [
"html",
"react" "react"
], ],
"env": { "env": {
"browser": true "browser": true
}, },
"parser": "babel-eslint",
"rules": { "rules": {
"import/no-unresolved": 2, "import/no-unresolved": 2,
"linebreak-style": 0 "linebreak-style": 0

View File

@ -3,24 +3,23 @@ language: node_js
cache: cache:
yarn: true yarn: true
directories: directories:
- bower_components - bower_components
install: install: yarn install
- yarn install
- ./node_modules/.bin/bower install
script: script:
- npm run build - npm run build
- npm run test - npm run test
- xvfb-run wct # - xvfb-run wct --module-resolution=node --npm
- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then wct --plugin sauce; fi # - 'if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then wct --module-resolution=node --npm --plugin sauce; fi'
services: services:
- docker - docker
before_deploy: before_deploy:
- docker pull lokalise/lokalise-cli@sha256:2198814ebddfda56ee041a4b427521757dd57f75415ea9693696a64c550cef21 - 'docker pull lokalise/lokalise-cli@sha256:2198814ebddfda56ee041a4b427521757dd57f75415ea9693696a64c550cef21'
deploy: deploy:
provider: script provider: script
script: script/travis_deploy script: script/travis_deploy
on: 'on':
branch: master branch: master
dist: trusty dist: trusty
addons: addons:
sauce_connect: true sauce_connect: true

View File

@ -1,4 +1,5 @@
const gulp = require('gulp'); const gulp = require('gulp');
const path = require('path');
const replace = require('gulp-batch-replace'); const replace = require('gulp-batch-replace');
const rename = require('gulp-rename'); const rename = require('gulp-rename');
@ -11,8 +12,12 @@ const {
const es5Extra = "<script src='/frontend_es5/custom-elements-es5-adapter.js'></script>"; const es5Extra = "<script src='/frontend_es5/custom-elements-es5-adapter.js'></script>";
async function buildAuth(es6) { async function buildAuth(es6) {
let stream = await bundledStreamFromHTML('src/authorize.html'); const frontendPath = es6 ? 'hass_frontend_latest' : 'hass_frontend_es5';
stream = stream.pipe(replace([['<!--EXTRA_SCRIPTS-->', es6 ? '' : es5Extra]])); const stream = gulp.src(path.resolve(config.polymer_dir, 'src/authorize.html'))
.pipe(replace([
['<!--EXTRA_SCRIPTS-->', es6 ? '' : es5Extra],
['/home-assistant-polymer/build/webpack/ha-authorize.js', `/${frontendPath}/authorize.js`],
]));
return minifyStream(stream, /* es6= */ es6) return minifyStream(stream, /* es6= */ es6)
.pipe(rename('authorize.html')) .pipe(rename('authorize.html'))

View File

@ -31,6 +31,7 @@ function renamePanel(path) {
} }
function build(es6) { function build(es6) {
return;
const strategy = composeStrategies([ const strategy = composeStrategies([
generateShellMergeStrategy(polymerConfig.shell), generateShellMergeStrategy(polymerConfig.shell),
stripImportsStrategy([ stripImportsStrategy([

View File

@ -8,8 +8,7 @@ const { minifyStream } = require('../common/transform');
const buildReplaces = { const buildReplaces = {
'/home-assistant-polymer/build/core.js': 'core.js', '/home-assistant-polymer/build/core.js': 'core.js',
'/home-assistant-polymer/src/home-assistant.html': 'frontend.html', '/home-assistant-polymer/build/webpack/app.js': 'app.js',
'/home-assistant-polymer/src/resources/ha-chart-scripts.html': 'ha-chart-scripts.html',
}; };
function generateIndex(es6) { function generateIndex(es6) {

View File

@ -29,22 +29,13 @@ const staticFingerprinted = [
const staticFingerprintedEs6 = [ const staticFingerprintedEs6 = [
'core.js', 'core.js',
'frontend.html', 'app.js',
'ha-chart-scripts.html',
]; ];
const staticFingerprintedEs5 = [ const staticFingerprintedEs5 = [
'compatibility.js', 'compatibility.js',
'core.js', 'core.js',
'frontend.html', 'app.js',
'ha-chart-scripts.html',
];
// These panels will always be registered inside HA and thus can
// be safely assumed to be able to preload.
const panelsFingerprinted = [
'dev-event', 'dev-info', 'dev-service', 'dev-state', 'dev-template',
'dev-mqtt', 'kiosk',
]; ];
function processStatic(fn, rootDir, urlDir) { function processStatic(fn, rootDir, urlDir) {

View File

@ -248,8 +248,7 @@ gulp.task(taskName, ['build-translation-fingerprints'], function () {
fragments: TRANSLATION_FRAGMENTS, fragments: TRANSLATION_FRAGMENTS,
translations: data, translations: data,
}))) })))
.pipe(insert.wrap('<script>\nwindow.translationMetadata = ', ';\n</script>')) .pipe(rename('translationMetadata.json'))
.pipe(rename('translationMetadata.html'))
.pipe(gulp.dest(workDir)); .pipe(gulp.dest(workDir));
}); });
tasks.push(taskName); tasks.push(taskName);

View File

@ -1,13 +1,14 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/util/hass-mixins.html'> import '../../src/components/hassio-card-content.js';
import '../../src/resources/hassio-style.js';
import '../../src/util/hass-mixins.js';
<link rel='import' href='../../src/components/hassio-card-content.html'> class HassioAddonRepository extends window.hassMixins.NavigateMixin(PolymerElement) {
<link rel='import' href='../../src/resources/hassio-style.html'> static get template() {
return html`
<dom-module id="hassio-addon-repository">
<template>
<style include="iron-flex ha-style hassio-style"> <style include="iron-flex ha-style hassio-style">
paper-card { paper-card {
cursor: pointer; cursor: pointer;
@ -17,35 +18,27 @@
color: var(--primary-text-color); color: var(--primary-text-color);
} }
</style> </style>
<template is='dom-if' if='[[addons.length]]'> <template is="dom-if" if="[[addons.length]]">
<div class='card-group'> <div class="card-group">
<div class='title'> <div class="title">
[[repo.name]] [[repo.name]]
<div class='description'> <div class="description">
Maintained by [[repo.maintainer]] Maintained by [[repo.maintainer]]
<a class='repo' href='[[repo.url]]' target='_blank'>[[repo.url]]</a> <a class="repo" href="[[repo.url]]" target="_blank">[[repo.url]]</a>
</div> </div>
</div> </div>
<template is='dom-repeat' items='[[addons]]' as='addon' sort='sortAddons'> <template is="dom-repeat" items="[[addons]]" as="addon" sort="sortAddons">
<paper-card on-click='addonTapped'> <paper-card on-click="addonTapped">
<div class='card-content'> <div class="card-content">
<hassio-card-content <hassio-card-content title="[[addon.name]]" description="[[addon.description]]" icon="[[computeIcon(addon)]]" icon-title="[[computeIconTitle(addon)]]" icon-class="[[computeIconClass(addon)]]"></hassio-card-content>
title='[[addon.name]]'
description='[[addon.description]]'
icon='[[computeIcon(addon)]]'
icon-title='[[computeIconTitle(addon)]]'
icon-class='[[computeIconClass(addon)]]'
></hassio-card-content>
</div> </div>
</paper-card> </paper-card>
</template> </template>
</div> </div>
</template> </template>
</template> `;
</dom-module> }
<script>
class HassioAddonRepository extends window.hassMixins.NavigateMixin(Polymer.Element) {
static get is() { return 'hassio-addon-repository'; } static get is() { return 'hassio-addon-repository'; }
static get properties() { static get properties() {
@ -79,4 +72,3 @@ class HassioAddonRepository extends window.hassMixins.NavigateMixin(Polymer.Elem
} }
customElements.define(HassioAddonRepository.is, HassioAddonRepository); customElements.define(HassioAddonRepository.is, HassioAddonRepository);
</script>

View File

@ -1,33 +1,26 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/util/hass-mixins.html'> import '../../src/util/hass-mixins.js';
import './hassio-addon-repository.js';
import './hassio-repositories-editor.js';
<link rel="import" href="./hassio-repositories-editor.html"> class HassioAddonStore extends PolymerElement {
<link rel="import" href="./hassio-addon-repository.html"> static get template() {
return html`
<dom-module id="hassio-addon-store">
<template>
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
hassio-addon-repository { hassio-addon-repository {
margin-top: 24px; margin-top: 24px;
} }
</style> </style>
<hassio-repositories-editor <hassio-repositories-editor hass="[[hass]]" repos="[[repos]]"></hassio-repositories-editor>
hass='[[hass]]'
repos='[[repos]]'
></hassio-repositories-editor>
<template is='dom-repeat' items='[[repos]]' as='repo' sort='sortRepos'> <template is="dom-repeat" items="[[repos]]" as="repo" sort="sortRepos">
<hassio-addon-repository <hassio-addon-repository repo="[[repo]]" addons="[[computeAddons(repo.slug)]]"></hassio-addon-repository>
repo='[[repo]]'
addons='[[computeAddons(repo.slug)]]'
></hassio-addon-repository>
</template> </template>
</template> `;
</dom-module> }
<script>
class HassioAddonStore extends Polymer.Element {
static get is() { return 'hassio-addon-store'; } static get is() { return 'hassio-addon-store'; }
static get properties() { static get properties() {
@ -90,4 +83,3 @@ class HassioAddonStore extends Polymer.Element {
} }
customElements.define(HassioAddonStore.is, HassioAddonStore); customElements.define(HassioAddonStore.is, HassioAddonStore);
</script>

View File

@ -1,108 +0,0 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/paper-card/paper-card.html">
<link rel='import' href='../../bower_components/paper-input/paper-input.html'>
<link rel='import' href='../../bower_components/iron-icon/iron-icon.html'>
<link rel="import" href="../../src/components/buttons/ha-call-api-button.html">
<link rel='import' href='../../src/components/hassio-card-content.html'>
<link rel='import' href='../../src/resources/hassio-style.html'>
<dom-module id="hassio-repositories-editor">
<template>
<style include="ha-style hassio-style">
.add {
padding: 12px 16px;
}
iron-icon {
color: var(--secondary-text-color);
margin-right: 16px;
display: inline-block;
}
paper-input {
width: calc(100% - 49px);
display: inline-block;
}
</style>
<div class='card-group'>
<div class='title'>
Repositories
<div class='description'>
Configure which add-on repositories to fetch data from:
</div>
</div>
<template id='list' is='dom-repeat' items='[[repoList]]' as='repo' sort='sortRepos'>
<paper-card>
<div class='card-content'>
<hassio-card-content
title='[[repo.name]]'
description='[[repo.url]]'
icon='mdi:github-circle'
></hassio-card-content>
</div>
<div class='card-actions'>
<ha-call-api-button
hass='[[hass]]'
path='hassio/supervisor/options'
data='[[computeRemoveRepoData(repoList, repo.url)]]'
class='warning'
>Remove</ha-call-api-button>
</div>
</paper-card>
</template>
<paper-card>
<div class='card-content add'>
<iron-icon icon='mdi:github-circle'></iron-icon>
<paper-input label='Add new repository by URL' value='{{repoUrl}}'></paper-input>
</div>
<div class='card-actions'>
<ha-call-api-button
hass='[[hass]]'
path='hassio/supervisor/options'
data='[[computeAddRepoData(repoList, repoUrl)]]'
>Add</ha-call-api-button>
</div>
</paper-card>
</div>
</template>
</dom-module>
<script>
class HassioRepositoriesEditor extends Polymer.Element {
static get is() { return 'hassio-repositories-editor'; }
static get properties() {
return {
hass: Object,
repos: {
type: Array,
observer: 'reposChanged',
},
repoList: Array,
repoUrl: String,
};
}
reposChanged(repos) {
this.repoList = repos.filter(repo => repo.slug !== 'core' && repo.slug !== 'local');
this.repoUrl = '';
}
sortRepos(a, b) {
return a.name < b.name ? -1 : 1;
}
computeRemoveRepoData(repoList, url) {
const list = repoList.filter(repo => repo.url !== url).map(repo => repo.url);
return { addons_repositories: list };
}
computeAddRepoData(repoList, url) {
const list = repoList.map(repo => repo.url);
list.push(url);
return { addons_repositories: list };
}
}
customElements.define(HassioRepositoriesEditor.is, HassioRepositoriesEditor);
</script>

View File

@ -0,0 +1,93 @@
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-input/paper-input.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../src/components/buttons/ha-call-api-button.js';
import '../../src/components/hassio-card-content.js';
import '../../src/resources/hassio-style.js';
class HassioRepositoriesEditor extends PolymerElement {
static get template() {
return html`
<style include="ha-style hassio-style">
.add {
padding: 12px 16px;
}
iron-icon {
color: var(--secondary-text-color);
margin-right: 16px;
display: inline-block;
}
paper-input {
width: calc(100% - 49px);
display: inline-block;
}
</style>
<div class="card-group">
<div class="title">
Repositories
<div class="description">
Configure which add-on repositories to fetch data from:
</div>
</div>
<template id="list" is="dom-repeat" items="[[repoList]]" as="repo" sort="sortRepos">
<paper-card>
<div class="card-content">
<hassio-card-content title="[[repo.name]]" description="[[repo.url]]" icon="mdi:github-circle"></hassio-card-content>
</div>
<div class="card-actions">
<ha-call-api-button hass="[[hass]]" path="hassio/supervisor/options" data="[[computeRemoveRepoData(repoList, repo.url)]]" class="warning">Remove</ha-call-api-button>
</div>
</paper-card>
</template>
<paper-card>
<div class="card-content add">
<iron-icon icon="mdi:github-circle"></iron-icon>
<paper-input label="Add new repository by URL" value="{{repoUrl}}"></paper-input>
</div>
<div class="card-actions">
<ha-call-api-button hass="[[hass]]" path="hassio/supervisor/options" data="[[computeAddRepoData(repoList, repoUrl)]]">Add</ha-call-api-button>
</div>
</paper-card>
</div>
`;
}
static get is() { return 'hassio-repositories-editor'; }
static get properties() {
return {
hass: Object,
repos: {
type: Array,
observer: 'reposChanged',
},
repoList: Array,
repoUrl: String,
};
}
reposChanged(repos) {
this.repoList = repos.filter(repo => repo.slug !== 'core' && repo.slug !== 'local');
this.repoUrl = '';
}
sortRepos(a, b) {
return a.name < b.name ? -1 : 1;
}
computeRemoveRepoData(repoList, url) {
const list = repoList.filter(repo => repo.url !== url).map(repo => repo.url);
return { addons_repositories: list };
}
computeAddRepoData(repoList, url) {
const list = repoList.map(repo => repo.url);
list.push(url);
return { addons_repositories: list };
}
}
customElements.define(HassioRepositoriesEditor.is, HassioRepositoriesEditor);

View File

@ -1,16 +1,19 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import 'web-animations-js/web-animations-next-lite.min.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel='import' href='../../bower_components/paper-listbox/paper-listbox.html'>
<link rel='import' href='../../bower_components/paper-item/paper-item.html'>
<link rel='import' href='../../bower_components/neon-animation/web-animations.html'>
<link rel='import' href='../../src/resources/ha-style.html'> import '@polymer/paper-button/paper-button.js';
<link rel='import' href='../../src/util/hass-mixins.html'> import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
import '@polymer/paper-item/paper-item.js';
import '@polymer/paper-listbox/paper-listbox.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<dom-module id="hassio-addon-audio"> import '../../src/resources/ha-style.js';
<template> import '../../src/util/hass-mixins.js';
class HassioAddonAudio extends window.hassMixins.EventsMixin(PolymerElement) {
static get template() {
return html`
<style include="ha-style"> <style include="ha-style">
:host, :host,
paper-card, paper-card,
@ -28,38 +31,34 @@
text-align: right; text-align: right;
} }
</style> </style>
<paper-card heading='Audio'> <paper-card heading="Audio">
<div class="card-content"> <div class="card-content">
<template is='dom-if' if='[[error]]'> <template is="dom-if" if="[[error]]">
<div class='errors'>[[error]]</div> <div class="errors">[[error]]</div>
</template> </template>
<paper-dropdown-menu label="Input"> <paper-dropdown-menu label="Input">
<paper-listbox slot="dropdown-content" attr-for-selected="device" selected="{{selectedInput}}"> <paper-listbox slot="dropdown-content" attr-for-selected="device" selected="{{selectedInput}}">
<template is='dom-repeat' items='[[inputDevices]]'> <template is="dom-repeat" items="[[inputDevices]]">
<paper-item device$="[[item.device]]">[[item.name]]</paper-item> <paper-item device\$="[[item.device]]">[[item.name]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
<paper-dropdown-menu label="Output"> <paper-dropdown-menu label="Output">
<paper-listbox slot="dropdown-content" attr-for-selected="device" selected="{{selectedOutput}}"> <paper-listbox slot="dropdown-content" attr-for-selected="device" selected="{{selectedOutput}}">
<template is='dom-repeat' items='[[outputDevices]]'> <template is="dom-repeat" items="[[outputDevices]]">
<paper-item device$="[[item.device]]">[[item.name]]</paper-item> <paper-item device\$="[[item.device]]">[[item.name]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<div class="card-actions"> <div class="card-actions">
<paper-button <paper-button on-click="_saveSettings">Save</paper-button>
on-click='_saveSettings'
>Save</paper-button>
</div> </div>
</paper-card> </paper-card>
</template> `;
</dom-module> }
<script>
class HassioAddonAudio extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'hassio-addon-audio'; } static get is() { return 'hassio-addon-audio'; }
static get properties() { static get properties() {
@ -116,4 +115,3 @@ class HassioAddonAudio extends window.hassMixins.EventsMixin(Polymer.Element) {
} }
customElements.define(HassioAddonAudio.is, HassioAddonAudio); customElements.define(HassioAddonAudio.is, HassioAddonAudio);
</script>

View File

@ -1,12 +1,14 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../bower_components/paper-button/paper-button.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../src/components/buttons/ha-call-api-button.html"> import '../../src/components/buttons/ha-call-api-button.js';
<dom-module id="hassio-addon-config"> class HassioAddonConfig extends PolymerElement {
<template> static get template() {
return html`
<style include="ha-style"> <style include="ha-style">
:host { :host {
display: block; display: block;
@ -30,31 +32,21 @@
color: var(--google-red-500); color: var(--google-red-500);
} }
</style> </style>
<paper-card heading='Config'> <paper-card heading="Config">
<div class="card-content"> <div class="card-content">
<template is='dom-if' if='[[error]]'> <template is="dom-if" if="[[error]]">
<div class='errors'>[[error]]</div> <div class="errors">[[error]]</div>
</template> </template>
<iron-autogrow-textarea id='config' value="{{config}}"></iron-autogrow-textarea> <iron-autogrow-textarea id="config" value="{{config}}"></iron-autogrow-textarea>
</div> </div>
<div class="card-actions"> <div class="card-actions">
<ha-call-api-button <ha-call-api-button class="warning" hass="[[hass]]" path="hassio/addons/[[addonSlug]]/options" data="[[resetData]]">Reset to defaults</ha-call-api-button>
class='warning' <paper-button on-click="saveTapped" disabled="[[!configParsed]]">Save</paper-button>
hass='[[hass]]'
path="hassio/addons/[[addonSlug]]/options"
data='[[resetData]]'
>Reset to defaults</ha-call-api-button>
<paper-button
on-click='saveTapped'
disabled='[[!configParsed]]'
>Save</paper-button>
</div> </div>
</paper-card> </paper-card>
</template> `;
</dom-module> }
<script>
class HassioAddonConfig extends Polymer.Element {
static get is() { return 'hassio-addon-config'; } static get is() { return 'hassio-addon-config'; }
static get properties() { static get properties() {
@ -106,4 +98,3 @@ class HassioAddonConfig extends Polymer.Element {
} }
customElements.define(HassioAddonConfig.is, HassioAddonConfig); customElements.define(HassioAddonConfig.is, HassioAddonConfig);
</script>

View File

@ -1,275 +0,0 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.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-button/paper-button.html">
<link rel='import' href='../../bower_components/paper-card/paper-card.html'>
<link rel='import' href='../../bower_components/paper-toggle-button/paper-toggle-button.html'>
<link rel="import" href="../../src/components/buttons/ha-call-api-button.html">
<link rel='import' href='../../src/components/ha-markdown.html'>
<link rel='import' href='../../src/resources/ha-style.html'>
<link rel='import' href='../../src/components/hassio-card-content.html'>
<link rel='import' href='../../src/util/hass-mixins.html'>
<dom-module id="hassio-addon-info">
<template>
<style include='ha-style'>
:host {
display: block;
}
paper-card {
display: block;
margin-bottom: 16px;
}
.addon-header {
@apply --paper-font-headline;
}
.light-color {
color: var(--secondary-text-color);
}
.addon-version {
float: right;
font-size: 15px;
vertical-align: middle;
}
.description {
margin-bottom: 16px;
}
.logo img {
max-height: 60px;
margin: 16px 0;
display: block;
}
.state div{
width: 150px;
display: inline-block;
}
paper-toggle-button {
display: inline;
}
iron-icon.running {
color: var(--paper-green-400);
}
iron-icon.stopped {
color: var(--google-red-300);
}
ha-call-api-button {
font-weight: 500;
color: var(--primary-color);
}
.right {
float: right;
}
</style>
<template is='dom-if' if='[[computeUpdateAvailable(addon)]]'>
<paper-card heading='Update available! 🎉'>
<div class='card-content'>
<hassio-card-content
title='[[addon.name]] [[addon.last_version]] is available'
description='You are currently running version [[addon.version]]'
icon='mdi:arrow-up-bold-circle'
icon-class='update'
></hassio-card-content>
</div>
<div class='card-actions'>
<ha-call-api-button
hass='[[hass]]'
path='hassio/addons/[[addonSlug]]/update'
>Update</ha-call-api-button>
<template is='dom-if' if='[[addon.changelog]]'>
<paper-button on-click='openChangelog'>Changelog</paper-button>
</template>
</div>
</paper-card>
</template>
<paper-card>
<div class='card-content'>
<div class='addon-header'>[[addon.name]]
<div class='addon-version light-color'>
<template is='dom-if' if='[[addon.version]]'>
[[addon.version]]
<template is='dom-if' if='[[isRunning]]'>
<iron-icon
title='Add-on is running'
class='running'
icon='mdi:circle'
></iron-icon>
</template>
<template is='dom-if' if='[[!isRunning]]'>
<iron-icon
title='Add-on is stopped'
class='stopped'
icon='mdi:circle'
></iron-icon>
</template>
</template>
<template is='dom-if' if='[[!addon.version]]'>
[[addon.last_version]]
</template>
</div>
</div>
<div class='description light-color'>
[[addon.description]].<br/>
Visit <a href='[[addon.url]]' target='_blank'>[[addon.name]] page</a> for details.
</div>
<template is='dom-if' if='[[addon.logo]]'>
<a href='[[addon.url]]' target='_blank' class='logo'>
<img src='/api/hassio/addons/[[addonSlug]]/logo'/>
</a>
</template>
<template is='dom-if' if='[[addon.version]]'>
<div class='state'>
<div>Start on boot</div>
<paper-toggle-button
on-change='startOnBootToggled'
checked='[[computeStartOnBoot(addon.boot)]]'
></paper-toggle-button>
</div>
<div class='state'>
<div>Auto update</div>
<paper-toggle-button
on-change='autoUpdateToggled'
checked='[[addon.auto_update]]'
></paper-toggle-button>
</div>
</template>
</div>
<div class='card-actions'>
<template is='dom-if' if='[[addon.version]]'>
<paper-button
class='warning'
on-click='_unistallClicked'
>Uninstall</paper-button>
<template is='dom-if' if='[[addon.build]]'>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path='hassio/addons/[[addonSlug]]/rebuild'
>Rebuild</ha-call-api-button>
</template>
<template is='dom-if' if='[[isRunning]]'>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path='hassio/addons/[[addonSlug]]/restart'
>Restart</ha-call-api-button>
<ha-call-api-button
class='warning'
hass='[[hass]]'
path='hassio/addons/[[addonSlug]]/stop'
>Stop</ha-call-api-button>
</template>
<template is='dom-if' if='[[!isRunning]]'>
<ha-call-api-button
hass='[[hass]]'
path='hassio/addons/[[addonSlug]]/start'
>Start</ha-call-api-button>
</template>
<template is='dom-if' if='[[computeShowWebUI(addon.webui, isRunning)]]'>
<a
href='[[pathWebui(addon.webui)]]'
tabindex='-1'
target='_blank'
class='right'
><paper-button>Open web UI</paper-button></a>
</template>
</template>
<template is='dom-if' if='[[!addon.version]]'>
<ha-call-api-button
hass='[[hass]]'
path='hassio/addons/[[addonSlug]]/install'
>Install</ha-call-api-button>
</template>
</div>
</paper-card>
<template is='dom-if' if='[[addon.long_description]]'>
<paper-card>
<div class='card-content'>
<ha-markdown content='[[addon.long_description]]'></ha-markdown>
</div>
</paper-card>
</template>
</template>
</dom-module>
<script>
class HassioAddonInfo extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'hassio-addon-info'; }
static get properties() {
return {
hass: Object,
addon: Object,
addonSlug: String,
isRunning: {
type: Boolean,
computed: 'computeIsRunning(addon)',
},
};
}
computeIsRunning(addon) {
return addon && addon.state === 'started';
}
computeUpdateAvailable(addon) {
return addon && !addon.detached && addon.version && addon.version !== addon.last_version;
}
pathWebui(webui) {
return webui && webui.replace('[HOST]', document.location.hostname);
}
computeShowWebUI(webui, isRunning) {
return webui && isRunning;
}
computeStartOnBoot(state) {
return state === 'auto';
}
startOnBootToggled() {
const data = { boot: this.addon.boot === 'auto' ? 'manual' : 'auto' };
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data);
}
autoUpdateToggled() {
const data = { auto_update: !this.addon.auto_update };
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data);
}
openChangelog() {
this.hass.callApi('get', `hassio/addons/${this.addonSlug}/changelog`)
.then(
resp => resp
, () => 'Error getting changelog'
).then((content) => {
this.fire('hassio-markdown-dialog', {
title: 'Changelog',
content: content,
});
});
}
_unistallClicked() {
if (!confirm('Are you sure you want to uninstall this add-on?')) {
return;
}
const path = `hassio/addons/${this.addonSlug}/uninstall`;
const eventData = {
path: path,
};
this.hass.callApi('post', path).then((resp) => {
eventData.success = true;
eventData.response = resp;
}, (resp) => {
eventData.success = false;
eventData.response = resp;
}).then(() => {
this.fire('hass-api-called', eventData);
});
}
}
customElements.define(HassioAddonInfo.is, HassioAddonInfo);
</script>

View File

@ -0,0 +1,225 @@
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/paper-button/paper-button.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-toggle-button/paper-toggle-button.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../src/components/buttons/ha-call-api-button.js';
import '../../src/components/ha-markdown.js';
import '../../src/components/hassio-card-content.js';
import '../../src/resources/ha-style.js';
import '../../src/util/hass-mixins.js';
class HassioAddonInfo extends window.hassMixins.EventsMixin(PolymerElement) {
static get template() {
return html`
<style include="ha-style">
:host {
display: block;
}
paper-card {
display: block;
margin-bottom: 16px;
}
.addon-header {
@apply --paper-font-headline;
}
.light-color {
color: var(--secondary-text-color);
}
.addon-version {
float: right;
font-size: 15px;
vertical-align: middle;
}
.description {
margin-bottom: 16px;
}
.logo img {
max-height: 60px;
margin: 16px 0;
display: block;
}
.state div{
width: 150px;
display: inline-block;
}
paper-toggle-button {
display: inline;
}
iron-icon.running {
color: var(--paper-green-400);
}
iron-icon.stopped {
color: var(--google-red-300);
}
ha-call-api-button {
font-weight: 500;
color: var(--primary-color);
}
.right {
float: right;
}
</style>
<template is="dom-if" if="[[computeUpdateAvailable(addon)]]">
<paper-card heading="Update available! 🎉">
<div class="card-content">
<hassio-card-content title="[[addon.name]] [[addon.last_version]] is available" description="You are currently running version [[addon.version]]" icon="mdi:arrow-up-bold-circle" icon-class="update"></hassio-card-content>
</div>
<div class="card-actions">
<ha-call-api-button hass="[[hass]]" path="hassio/addons/[[addonSlug]]/update">Update</ha-call-api-button>
<template is="dom-if" if="[[addon.changelog]]">
<paper-button on-click="openChangelog">Changelog</paper-button>
</template>
</div>
</paper-card>
</template>
<paper-card>
<div class="card-content">
<div class="addon-header">[[addon.name]]
<div class="addon-version light-color">
<template is="dom-if" if="[[addon.version]]">
[[addon.version]]
<template is="dom-if" if="[[isRunning]]">
<iron-icon title="Add-on is running" class="running" icon="mdi:circle"></iron-icon>
</template>
<template is="dom-if" if="[[!isRunning]]">
<iron-icon title="Add-on is stopped" class="stopped" icon="mdi:circle"></iron-icon>
</template>
</template>
<template is="dom-if" if="[[!addon.version]]">
[[addon.last_version]]
</template>
</div>
</div>
<div class="description light-color">
[[addon.description]].<br>
Visit <a href="[[addon.url]]" target="_blank">[[addon.name]] page</a> for details.
</div>
<template is="dom-if" if="[[addon.logo]]">
<a href="[[addon.url]]" target="_blank" class="logo">
<img src="/api/hassio/addons/[[addonSlug]]/logo">
</a>
</template>
<template is="dom-if" if="[[addon.version]]">
<div class="state">
<div>Start on boot</div>
<paper-toggle-button on-change="startOnBootToggled" checked="[[computeStartOnBoot(addon.boot)]]"></paper-toggle-button>
</div>
<div class="state">
<div>Auto update</div>
<paper-toggle-button on-change="autoUpdateToggled" checked="[[addon.auto_update]]"></paper-toggle-button>
</div>
</template>
</div>
<div class="card-actions">
<template is="dom-if" if="[[addon.version]]">
<paper-button class="warning" on-click="_unistallClicked">Uninstall</paper-button>
<template is="dom-if" if="[[addon.build]]">
<ha-call-api-button class="warning" hass="[[hass]]" path="hassio/addons/[[addonSlug]]/rebuild">Rebuild</ha-call-api-button>
</template>
<template is="dom-if" if="[[isRunning]]">
<ha-call-api-button class="warning" hass="[[hass]]" path="hassio/addons/[[addonSlug]]/restart">Restart</ha-call-api-button>
<ha-call-api-button class="warning" hass="[[hass]]" path="hassio/addons/[[addonSlug]]/stop">Stop</ha-call-api-button>
</template>
<template is="dom-if" if="[[!isRunning]]">
<ha-call-api-button hass="[[hass]]" path="hassio/addons/[[addonSlug]]/start">Start</ha-call-api-button>
</template>
<template is="dom-if" if="[[computeShowWebUI(addon.webui, isRunning)]]">
<a href="[[pathWebui(addon.webui)]]" tabindex="-1" target="_blank" class="right"><paper-button>Open web UI</paper-button></a>
</template>
</template>
<template is="dom-if" if="[[!addon.version]]">
<ha-call-api-button hass="[[hass]]" path="hassio/addons/[[addonSlug]]/install">Install</ha-call-api-button>
</template>
</div>
</paper-card>
<template is="dom-if" if="[[addon.long_description]]">
<paper-card>
<div class="card-content">
<ha-markdown content="[[addon.long_description]]"></ha-markdown>
</div>
</paper-card>
</template>
`;
}
static get is() { return 'hassio-addon-info'; }
static get properties() {
return {
hass: Object,
addon: Object,
addonSlug: String,
isRunning: {
type: Boolean,
computed: 'computeIsRunning(addon)',
},
};
}
computeIsRunning(addon) {
return addon && addon.state === 'started';
}
computeUpdateAvailable(addon) {
return addon && !addon.detached && addon.version && addon.version !== addon.last_version;
}
pathWebui(webui) {
return webui && webui.replace('[HOST]', document.location.hostname);
}
computeShowWebUI(webui, isRunning) {
return webui && isRunning;
}
computeStartOnBoot(state) {
return state === 'auto';
}
startOnBootToggled() {
const data = { boot: this.addon.boot === 'auto' ? 'manual' : 'auto' };
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data);
}
autoUpdateToggled() {
const data = { auto_update: !this.addon.auto_update };
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data);
}
openChangelog() {
this.hass.callApi('get', `hassio/addons/${this.addonSlug}/changelog`)
.then(
resp => resp
, () => 'Error getting changelog'
).then((content) => {
this.fire('hassio-markdown-dialog', {
title: 'Changelog',
content: content,
});
});
}
_unistallClicked() {
if (!confirm('Are you sure you want to uninstall this add-on?')) {
return;
}
const path = `hassio/addons/${this.addonSlug}/uninstall`;
const eventData = {
path: path,
};
this.hass.callApi('post', path).then((resp) => {
eventData.success = true;
eventData.response = resp;
}, (resp) => {
eventData.success = false;
eventData.response = resp;
}).then(() => {
this.fire('hass-api-called', eventData);
});
}
}
customElements.define(HassioAddonInfo.is, HassioAddonInfo);

View File

@ -1,30 +1,30 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../bower_components/paper-button/paper-button.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/resources/ha-style.html'> import '../../src/resources/ha-style.js';
<dom-module id="hassio-addon-logs"> class HassioAddonLogs extends PolymerElement {
<template> static get template() {
return html`
<style include="ha-style"> <style include="ha-style">
:host, :host,
paper-card { paper-card {
display: block; display: block;
} }
</style> </style>
<paper-card heading='Log'> <paper-card heading="Log">
<div class="card-content"> <div class="card-content">
<pre>[[log]]</pre> <pre>[[log]]</pre>
</div> </div>
<div class="card-actions"> <div class="card-actions">
<paper-button on-click='refresh'>Refresh</paper-button> <paper-button on-click="refresh">Refresh</paper-button>
</div> </div>
</paper-card> </paper-card>
</template> `;
</dom-module> }
<script>
class HassioAddonLogs extends Polymer.Element {
static get is() { return 'hassio-addon-logs'; } static get is() { return 'hassio-addon-logs'; }
static get properties() { static get properties() {
@ -56,4 +56,3 @@ class HassioAddonLogs extends Polymer.Element {
} }
customElements.define(HassioAddonLogs.is, HassioAddonLogs); customElements.define(HassioAddonLogs.is, HassioAddonLogs);
</script>

View File

@ -1,14 +1,15 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-input/paper-input.js';
<link rel="import" href="../../bower_components/paper-input/paper-input.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/util/hass-mixins.html'> import '../../src/components/buttons/ha-call-api-button.js';
<link rel='import' href='../../src/resources/ha-style.html'> import '../../src/resources/ha-style.js';
import '../../src/util/hass-mixins.js';
<link rel="import" href="../../src/components/buttons/ha-call-api-button.html"> class HassioAddonNetwork extends window.hassMixins.EventsMixin(PolymerElement) {
static get template() {
<dom-module id="hassio-addon-network"> return html`
<template>
<style include="ha-style"> <style include="ha-style">
:host { :host {
display: block; display: block;
@ -25,52 +26,37 @@
@apply --layout-justified; @apply --layout-justified;
} }
</style> </style>
<paper-card heading='Network'> <paper-card heading="Network">
<div class="card-content"> <div class="card-content">
<template is='dom-if' if='[[error]]'> <template is="dom-if" if="[[error]]">
<div class='errors'>[[error]]</div> <div class="errors">[[error]]</div>
</template> </template>
<table> <table>
<tr> <tbody><tr>
<th>Container</th> <th>Container</th>
<th>Host</th> <th>Host</th>
</tr> </tr>
<template <template is="dom-repeat" items="[[config]]">
is='dom-repeat'
items='[[config]]'
>
<tr> <tr>
<td> <td>
[[item.container]] [[item.container]]
</td> </td>
<td> <td>
<paper-input <paper-input value="{{item.host}}" no-label-float=""></paper-input>
value='{{item.host}}'
no-label-float
></paper-input>
</td> </td>
</tr> </tr>
</template> </template>
</table> </tbody></table>
</div> </div>
<div class="card-actions"> <div class="card-actions">
<ha-call-api-button <ha-call-api-button class="warning" hass="[[hass]]" path="hassio/addons/[[addonSlug]]/options" data="[[resetData]]">Reset to defaults</ha-call-api-button>
class='warning' <paper-button on-click="saveTapped">Save</paper-button>
hass='[[hass]]'
path="hassio/addons/[[addonSlug]]/options"
data="[[resetData]]"
>Reset to defaults</ha-call-api-button>
<paper-button
on-click='saveTapped'
>Save</paper-button>
</div> </div>
</paper-card> </paper-card>
</template> `;
</dom-module> }
<script>
class HassioAddonNetwork extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'hassio-addon-network'; } static get is() { return 'hassio-addon-network'; }
static get properties() { static get properties() {
@ -122,4 +108,3 @@ class HassioAddonNetwork extends window.hassMixins.EventsMixin(Polymer.Element)
} }
customElements.define(HassioAddonNetwork.is, HassioAddonNetwork); customElements.define(HassioAddonNetwork.is, HassioAddonNetwork);
</script>

View File

@ -1,165 +0,0 @@
<link rel='import' href='../../bower_components/polymer/polymer-element.html'>
<link rel='import' href='../../bower_components/app-route/app-route.html'>
<link rel='import' href='../../bower_components/app-layout/app-header-layout/app-header-layout.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/paper-icon-button/paper-icon-button.html'>
<link rel='import' href='../../src/components/ha-menu-button.html'>
<link rel='import' href='../../src/resources/ha-style.html'>
<link rel="import" href="./hassio-addon-info.html">
<link rel="import" href="./hassio-addon-config.html">
<link rel="import" href="./hassio-addon-audio.html">
<link rel="import" href="./hassio-addon-network.html">
<link rel="import" href="./hassio-addon-logs.html">
<link rel='import' href='../hassio-markdown-dialog.html'>
<dom-module id="hassio-addon-view">
<template>
<style include="iron-flex ha-style">
:host {
color: var(--primary-text-color);
--paper-card-header-color: var(--primary-text-color);
}
.content {
padding: 24px 0 32px;
max-width: 600px;
margin: 0 auto;
}
hassio-addon-info,
hassio-addon-network,
hassio-addon-audio,
hassio-addon-config {
margin-bottom: 24px;
}
</style>
<app-route
route='[[route]]'
pattern='/addon/:slug'
data="{{routeData}}"
active='{{routeMatches}}'
></app-route>
<app-header-layout has-scrolling-region>
<app-header fixed slot='header'>
<app-toolbar>
<ha-menu-button narrow='[[narrow]]' show-menu='[[showMenu]]'></ha-menu-button>
<paper-icon-button
icon='mdi:arrow-left'
on-click='backTapped'
></paper-icon-button>
<div main-title>Hass.io: add-on details</div>
</app-toolbar>
</app-header>
<div class='content'>
<hassio-addon-info
hass='[[hass]]'
addon='[[addon]]'
addon-slug='[[routeData.slug]]'
></hassio-addon-info>
<template is='dom-if' if='[[addon.version]]'>
<hassio-addon-config
hass='[[hass]]'
addon='[[addon]]'
addon-slug='[[routeData.slug]]'
></hassio-addon-config>
<template is='dom-if' if='[[addon.audio]]'>
<hassio-addon-audio
hass='[[hass]]'
addon='[[addon]]'
></hassio-addon-audio>
</template>
<template is='dom-if' if='[[addon.network]]'>
<hassio-addon-network
hass='[[hass]]'
addon='[[addon]]'
addon-slug='[[routeData.slug]]'
></hassio-addon-network>
</template>
<hassio-addon-logs
hass='[[hass]]'
addon-slug='[[routeData.slug]]'
></hassio-addon-logs>
</template>
</div>
</app-header-layout>
<hassio-markdown-dialog
title='[[markdownTitle]]'
content='[[markdownContent]]'
></hassio-markdown-dialog>
</template>
</dom-module>
<script>
class HassioAddonView extends Polymer.Element {
static get is() { return 'hassio-addon-view'; }
static get properties() {
return {
hass: Object,
showMenu: Boolean,
narrow: Boolean,
route: Object,
routeData: {
type: Object,
observer: 'routeDataChanged',
},
routeMatches: Boolean,
addon: Object,
markdownTitle: String,
markdownContent: {
type: String,
value: '',
},
};
}
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev));
}
apiCalled(ev) {
const path = ev.detail.path;
if (!path) return;
if (path.substr(path.lastIndexOf('/') + 1) === 'uninstall') {
this.backTapped();
} else {
this.routeDataChanged(this.routeData);
}
}
routeDataChanged(routeData) {
if (!this.routeMatches || !routeData || !routeData.slug) return;
this.hass.callApi('get', `hassio/addons/${routeData.slug}/info`)
.then((info) => {
this.addon = info.data;
}, () => {
this.addon = null;
});
}
backTapped() {
history.back();
}
openMarkdown(ev) {
this.setProperties({
markdownTitle: ev.detail.title,
markdownContent: ev.detail.content,
});
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog();
}
}
customElements.define(HassioAddonView.is, HassioAddonView);
</script>

View File

@ -0,0 +1,134 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/app-route/app-route.js';
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 '../../src/components/ha-menu-button.js';
import '../../src/resources/ha-style.js';
import '../hassio-markdown-dialog.js';
import './hassio-addon-audio.js';
import './hassio-addon-config.js';
import './hassio-addon-info.js';
import './hassio-addon-logs.js';
import './hassio-addon-network.js';
class HassioAddonView extends PolymerElement {
static get template() {
return html`
<style include="iron-flex ha-style">
:host {
color: var(--primary-text-color);
--paper-card-header-color: var(--primary-text-color);
}
.content {
padding: 24px 0 32px;
max-width: 600px;
margin: 0 auto;
}
hassio-addon-info,
hassio-addon-network,
hassio-addon-audio,
hassio-addon-config {
margin-bottom: 24px;
}
</style>
<app-route route="[[route]]" pattern="/addon/:slug" data="{{routeData}}" active="{{routeMatches}}"></app-route>
<app-header-layout has-scrolling-region="">
<app-header fixed="" slot="header">
<app-toolbar>
<ha-menu-button narrow="[[narrow]]" show-menu="[[showMenu]]"></ha-menu-button>
<paper-icon-button icon="mdi:arrow-left" on-click="backTapped"></paper-icon-button>
<div main-title="">Hass.io: add-on details</div>
</app-toolbar>
</app-header>
<div class="content">
<hassio-addon-info hass="[[hass]]" addon="[[addon]]" addon-slug="[[routeData.slug]]"></hassio-addon-info>
<template is="dom-if" if="[[addon.version]]">
<hassio-addon-config hass="[[hass]]" addon="[[addon]]" addon-slug="[[routeData.slug]]"></hassio-addon-config>
<template is="dom-if" if="[[addon.audio]]">
<hassio-addon-audio hass="[[hass]]" addon="[[addon]]"></hassio-addon-audio>
</template>
<template is="dom-if" if="[[addon.network]]">
<hassio-addon-network hass="[[hass]]" addon="[[addon]]" addon-slug="[[routeData.slug]]"></hassio-addon-network>
</template>
<hassio-addon-logs hass="[[hass]]" addon-slug="[[routeData.slug]]"></hassio-addon-logs>
</template>
</div>
</app-header-layout>
<hassio-markdown-dialog title="[[markdownTitle]]" content="[[markdownContent]]"></hassio-markdown-dialog>
`;
}
static get is() { return 'hassio-addon-view'; }
static get properties() {
return {
hass: Object,
showMenu: Boolean,
narrow: Boolean,
route: Object,
routeData: {
type: Object,
observer: 'routeDataChanged',
},
routeMatches: Boolean,
addon: Object,
markdownTitle: String,
markdownContent: {
type: String,
value: '',
},
};
}
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev));
}
apiCalled(ev) {
const path = ev.detail.path;
if (!path) return;
if (path.substr(path.lastIndexOf('/') + 1) === 'uninstall') {
this.backTapped();
} else {
this.routeDataChanged(this.routeData);
}
}
routeDataChanged(routeData) {
if (!this.routeMatches || !routeData || !routeData.slug) return;
this.hass.callApi('get', `hassio/addons/${routeData.slug}/info`)
.then((info) => {
this.addon = info.data;
}, () => {
this.addon = null;
});
}
backTapped() {
history.back();
}
openMarkdown(ev) {
this.setProperties({
markdownTitle: ev.detail.title,
markdownContent: ev.detail.content,
});
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog();
}
}
customElements.define(HassioAddonView.is, HassioAddonView);

View File

@ -1,45 +1,39 @@
<link rel='import' href='../../bower_components/polymer/polymer-element.html'> import '@polymer/paper-card/paper-card.js';
<link rel='import' href='../../bower_components/paper-card/paper-card.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/util/hass-mixins.html'> import '../../src/components/hassio-card-content.js';
<link rel='import' href='../../src/components/hassio-card-content.html'> import '../../src/resources/hassio-style.js';
<link rel='import' href='../../src/resources/hassio-style.html'> import '../../src/util/hass-mixins.js';
<dom-module id='hassio-addons'> class HassioAddons extends window.hassMixins.NavigateMixin(PolymerElement) {
<template> static get template() {
<style include='ha-style hassio-style'> return html`
<style include="ha-style hassio-style">
paper-card { paper-card {
cursor: pointer; cursor: pointer;
} }
</style> </style>
<div class='content card-group'> <div class="content card-group">
<div class='title'>Add-ons</div> <div class="title">Add-ons</div>
<template is='dom-if' if='[[!addons.length]]'> <template is="dom-if" if="[[!addons.length]]">
<paper-card> <paper-card>
<div class='card-content'> <div class="card-content">
You don't have any add-ons installed yet. Head over to <a href='#' on-click='openStore'>the add-on store</a> to get started! You don't have any add-ons installed yet. Head over to <a href="#" on-click="openStore">the add-on store</a> to get started!
</div> </div>
</paper-card> </paper-card>
</template> </template>
<template is='dom-repeat' items='[[addons]]' as='addon' sort='sortAddons'> <template is="dom-repeat" items="[[addons]]" as="addon" sort="sortAddons">
<paper-card on-click='addonTapped'> <paper-card on-click="addonTapped">
<div class='card-content'> <div class="card-content">
<hassio-card-content <hassio-card-content title="[[addon.name]]" description="[[addon.description]]" icon="[[computeIcon(addon)]]" icon-title="[[computeIconTitle(addon)]]" icon-class="[[computeIconClass(addon)]]"></hassio-card-content>
title='[[addon.name]]'
description='[[addon.description]]'
icon='[[computeIcon(addon)]]'
icon-title='[[computeIconTitle(addon)]]'
icon-class='[[computeIconClass(addon)]]'
></hassio-card-content>
</div> </div>
</paper-card> </paper-card>
</template> </template>
</div> </div>
</template> `;
</dom-module> }
<script>
class HassioAddons extends window.hassMixins.NavigateMixin(Polymer.Element) {
static get is() { return 'hassio-addons'; } static get is() { return 'hassio-addons'; }
static get properties() { static get properties() {
@ -79,4 +73,3 @@ class HassioAddons extends window.hassMixins.NavigateMixin(Polymer.Element) {
} }
customElements.define(HassioAddons.is, HassioAddons); customElements.define(HassioAddons.is, HassioAddons);
</script>

View File

@ -1,40 +0,0 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="./hassio-addons.html">
<link rel="import" href="./hassio-hass-update.html">
<dom-module id="hassio-dashboard">
<template>
<style include="iron-flex ha-style">
.content {
margin: 0 auto;
}
</style>
<div class='content'>
<hassio-hass-update
hass='[[hass]]'
hass-info='[[hassInfo]]'
></hassio-hass-update>
<hassio-addons
hass='[[hass]]'
addons='[[supervisorInfo.addons]]'
></hassio-addons>
</div>
</template>
</dom-module>
<script>
class HassioDashboard extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'hassio-dashboard'; }
static get properties() {
return {
hass: Object,
supervisorInfo: Object,
hassInfo: Object,
};
}
}
customElements.define(HassioDashboard.is, HassioDashboard);
</script>

View File

@ -0,0 +1,33 @@
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import './hassio-addons.js';
import './hassio-hass-update.js';
class HassioDashboard extends window.hassMixins.EventsMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex ha-style">
.content {
margin: 0 auto;
}
</style>
<div class="content">
<hassio-hass-update hass="[[hass]]" hass-info="[[hassInfo]]"></hassio-hass-update>
<hassio-addons hass="[[hass]]" addons="[[supervisorInfo.addons]]"></hassio-addons>
</div>
`;
}
static get is() { return 'hassio-dashboard'; }
static get properties() {
return {
hass: Object,
supervisorInfo: Object,
hassInfo: Object,
};
}
}
customElements.define(HassioDashboard.is, HassioDashboard);

View File

@ -1,93 +0,0 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../../src/components/buttons/ha-call-api-button.html">
<link rel='import' href='../../src/components/hassio-card-content.html'>
<link rel='import' href='../../src/resources/hassio-style.html'>
<dom-module id="hassio-hass-update">
<template>
<style include="ha-style hassio-style">
paper-card {
display: block;
height: 100%;
margin-bottom: 32px;
}
.errors {
color: var(--google-red-500);
margin-top: 16px;
}
</style>
<template is='dom-if' if='[[computeUpdateAvailable(hassInfo)]]'>
<div class='content'>
<div class='card-group'>
<div class='title'>Update available! 🎉</div>
<paper-card>
<div class='card-content'>
<hassio-card-content
title='Home Assistant [[hassInfo.last_version]] is available'
description='You are currently running version [[hassInfo.version]]'
icon='mdi:home-assistant'
icon-class='hassupdate'
></hassio-card-content>
<template is='dom-if' if='[[error]]'>
<div class='error'>Error: [[error]]</div>
</template>
</div>
<div class='card-actions'>
<ha-call-api-button
hass='[[hass]]'
path='hassio/homeassistant/update'
>Update</ha-call-api-button>
<a
href='https://github.com/home-assistant/home-assistant/releases'
target='_blank'
><paper-button>Release notes</paper-button></a>
</div>
</paper-card>
</div>
</div>
</template>
</template>
</dom-module>
<script>
class HassioHassUpdate extends Polymer.Element {
static get is() { return 'hassio-hass-update'; }
static get properties() {
return {
hass: Object,
hassInfo: Object,
error: String,
};
}
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
}
apiCalled(ev) {
if (ev.detail.success) {
this.errors = null;
return;
}
const response = ev.detail.response;
if (typeof response.body === 'object') {
this.errors = response.body.message || 'Unknown error';
} else {
this.errors = response.body;
}
}
computeUpdateAvailable(hassInfo) {
return hassInfo.version !== hassInfo.last_version;
}
}
customElements.define(HassioHassUpdate.is, HassioHassUpdate);
</script>

View File

@ -0,0 +1,81 @@
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 '../../src/components/buttons/ha-call-api-button.js';
import '../../src/components/hassio-card-content.js';
import '../../src/resources/hassio-style.js';
class HassioHassUpdate extends PolymerElement {
static get template() {
return html`
<style include="ha-style hassio-style">
paper-card {
display: block;
height: 100%;
margin-bottom: 32px;
}
.errors {
color: var(--google-red-500);
margin-top: 16px;
}
</style>
<template is="dom-if" if="[[computeUpdateAvailable(hassInfo)]]">
<div class="content">
<div class="card-group">
<div class="title">Update available! 🎉</div>
<paper-card>
<div class="card-content">
<hassio-card-content title="Home Assistant [[hassInfo.last_version]] is available" description="You are currently running version [[hassInfo.version]]" icon="mdi:home-assistant" icon-class="hassupdate"></hassio-card-content>
<template is="dom-if" if="[[error]]">
<div class="error">Error: [[error]]</div>
</template>
</div>
<div class="card-actions">
<ha-call-api-button hass="[[hass]]" path="hassio/homeassistant/update">Update</ha-call-api-button>
<a href="https://github.com/home-assistant/home-assistant/releases" target="_blank"><paper-button>Release notes</paper-button></a>
</div>
</paper-card>
</div>
</div>
</template>
`;
}
static get is() { return 'hassio-hass-update'; }
static get properties() {
return {
hass: Object,
hassInfo: Object,
error: String,
};
}
ready() {
super.ready();
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
}
apiCalled(ev) {
if (ev.detail.success) {
this.errors = null;
return;
}
const response = ev.detail.response;
if (typeof response.body === 'object') {
this.errors = response.body.message || 'Unknown error';
} else {
this.errors = response.body;
}
}
computeUpdateAvailable(hassInfo) {
return hassInfo.version !== hassInfo.last_version;
}
}
customElements.define(HassioHassUpdate.is, HassioHassUpdate);

View File

@ -1,21 +1,17 @@
<link rel="import" href="../bower_components/polymer/polymer-element.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
<link rel="import" href="./hassio-main.html"> import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<dom-module id="hassio-app"> import './hassio-main.js';
<template>
<template is='dom-if' if='[[hass]]'> class HassioApp extends PolymerElement {
<hassio-main static get template() {
hass='[[hass]]' return html`
narrow='[[narrow]]' <template is="dom-if" if="[[hass]]">
show-menu='[[showMenu]]' <hassio-main hass="[[hass]]" narrow="[[narrow]]" show-menu="[[showMenu]]" route="[[route]]"></hassio-main>
route='[[route]]'
></hassio-main>
</template> </template>
</template> `;
</dom-module> }
<script>
class HassioApp extends Polymer.Element {
static get is() { return 'hassio-app'; } static get is() { return 'hassio-app'; }
static get properties() { static get properties() {
@ -49,4 +45,3 @@ class HassioApp extends Polymer.Element {
} }
customElements.define(HassioApp.is, HassioApp); customElements.define(HassioApp.is, HassioApp);
</script>

View File

@ -1,7 +1,6 @@
<link rel="import" href="../bower_components/polymer/polymer-element.html"> import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<script> class HassioData extends PolymerElement {
class HassioData extends Polymer.Element {
static get is() { return 'hassio-data'; } static get is() { return 'hassio-data'; }
static get properties() { static get properties() {
@ -61,4 +60,3 @@ class HassioData extends Polymer.Element {
} }
customElements.define(HassioData.is, HassioData); customElements.define(HassioData.is, HassioData);
</script>

View File

@ -1,132 +0,0 @@
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="../bower_components/app-route/app-route.html">
<link rel="import" href="../src/layouts/hass-loading-screen.html">
<link rel='import' href='../src/util/hass-util.html'>
<link rel='import' href='./hassio-data.html'>
<link rel='import' href='./hassio-pages-with-tabs.html'>
<link rel='import' href='./addon-view/hassio-addon-view.html'>
<dom-module id="hassio-main">
<template>
<app-route
route='[[route]]'
pattern='/:page'
data="{{routeData}}"
></app-route>
<hassio-data
id='data'
hass='[[hass]]'
supervisor='{{supervisorInfo}}'
homeassistant='{{hassInfo}}'
host='{{hostInfo}}'
></hassio-data>
<template is='dom-if' if='[[!loaded]]'>
<hass-loading-screen
narrow='[[narrow]]'
show-menu='[[showMenu]]'
></hass-loading-screen>
</template>
<template is='dom-if' if='[[loaded]]'>
<template is='dom-if' if='[[!equalsAddon(routeData.page)]]'>
<hassio-pages-with-tabs
hass='[[hass]]'
narrow='[[narrow]]'
show-menu='[[showMenu]]'
page='[[routeData.page]]'
supervisor-info='[[supervisorInfo]]'
hass-info='[[hassInfo]]'
host-info='[[hostInfo]]'
></hassio-pages-with-tabs>
</template>
<template is='dom-if' if='[[equalsAddon(routeData.page)]]'>
<hassio-addon-view
hass='[[hass]]'
narrow='[[narrow]]'
show-menu='[[showMenu]]'
route='[[route]]'
></hassio-addon-view>
</template>
</template>
</template>
</dom-module>
<script>
class HassioMain extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'hassio-main'; }
static get properties() {
return {
hass: Object,
narrow: Boolean,
showMenu: Boolean,
route: {
type: Object,
// Fake route object
value: {
prefix: '/hassio',
path: '/dashboard',
__queryParams: {}
},
observer: 'routeChanged',
},
routeData: Object,
supervisorInfo: Object,
hostInfo: Object,
hassInfo: Object,
loaded: {
type: Boolean,
computed: 'computeIsLoaded(supervisorInfo, hostInfo, hassInfo)',
},
};
}
ready() {
super.ready();
window.hassUtil.applyThemesOnElement(this, this.hass.themes, this.hass.selectedTheme, true);
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
}
connectedCallback() {
super.connectedCallback();
this.routeChanged(this.route);
}
apiCalled(ev) {
if (ev.detail.success) {
let tries = 1;
const tryUpdate = () => {
this.$.data.refresh().catch(function () {
tries += 1;
setTimeout(tryUpdate, Math.min(tries, 5) * 1000);
});
};
tryUpdate();
}
}
computeIsLoaded(supervisorInfo, hostInfo, hassInfo) {
return (supervisorInfo !== null &&
hostInfo !== null &&
hassInfo !== null);
}
routeChanged(route) {
if (route.path === '' && route.prefix === '/hassio') {
history.replaceState(null, null, '/hassio/dashboard');
this.fire('location-changed');
}
}
equalsAddon(page) {
return page && page === 'addon';
}
}
customElements.define(HassioMain.is, HassioMain);
</script>

104
hassio/hassio-main.js Normal file
View File

@ -0,0 +1,104 @@
import '@polymer/app-route/app-route.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../src/layouts/hass-loading-screen.js';
import '../src/util/hass-util.js';
import './addon-view/hassio-addon-view.js';
import './hassio-data.js';
import './hassio-pages-with-tabs.js';
class HassioMain extends window.hassMixins.EventsMixin(PolymerElement) {
static get template() {
return html`
<app-route route="[[route]]" pattern="/:page" data="{{routeData}}"></app-route>
<hassio-data id="data" hass="[[hass]]" supervisor="{{supervisorInfo}}" homeassistant="{{hassInfo}}" host="{{hostInfo}}"></hassio-data>
<template is="dom-if" if="[[!loaded]]">
<hass-loading-screen narrow="[[narrow]]" show-menu="[[showMenu]]"></hass-loading-screen>
</template>
<template is="dom-if" if="[[loaded]]">
<template is="dom-if" if="[[!equalsAddon(routeData.page)]]">
<hassio-pages-with-tabs hass="[[hass]]" narrow="[[narrow]]" show-menu="[[showMenu]]" page="[[routeData.page]]" supervisor-info="[[supervisorInfo]]" hass-info="[[hassInfo]]" host-info="[[hostInfo]]"></hassio-pages-with-tabs>
</template>
<template is="dom-if" if="[[equalsAddon(routeData.page)]]">
<hassio-addon-view hass="[[hass]]" narrow="[[narrow]]" show-menu="[[showMenu]]" route="[[route]]"></hassio-addon-view>
</template>
</template>
`;
}
static get is() { return 'hassio-main'; }
static get properties() {
return {
hass: Object,
narrow: Boolean,
showMenu: Boolean,
route: {
type: Object,
// Fake route object
value: {
prefix: '/hassio',
path: '/dashboard',
__queryParams: {}
},
observer: 'routeChanged',
},
routeData: Object,
supervisorInfo: Object,
hostInfo: Object,
hassInfo: Object,
loaded: {
type: Boolean,
computed: 'computeIsLoaded(supervisorInfo, hostInfo, hassInfo)',
},
};
}
ready() {
super.ready();
window.hassUtil.applyThemesOnElement(this, this.hass.themes, this.hass.selectedTheme, true);
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
}
connectedCallback() {
super.connectedCallback();
this.routeChanged(this.route);
}
apiCalled(ev) {
if (ev.detail.success) {
let tries = 1;
const tryUpdate = () => {
this.$.data.refresh().catch(function () {
tries += 1;
setTimeout(tryUpdate, Math.min(tries, 5) * 1000);
});
};
tryUpdate();
}
}
computeIsLoaded(supervisorInfo, hostInfo, hassInfo) {
return (supervisorInfo !== null &&
hostInfo !== null &&
hassInfo !== null);
}
routeChanged(route) {
if (route.path === '' && route.prefix === '/hassio') {
history.replaceState(null, null, '/hassio/dashboard');
this.fire('location-changed');
}
}
equalsAddon(page) {
return page && page === 'addon';
}
}
customElements.define(HassioMain.is, HassioMain);

View File

@ -1,15 +1,17 @@
<link rel='import' href='../bower_components/polymer/polymer-element.html'> import '@polymer/app-layout/app-toolbar/app-toolbar.js';
<link rel='import' href='../bower_components/paper-dialog/paper-dialog.html'> import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
<link rel='import' href='../bower_components/app-layout/app-toolbar/app-toolbar.html'> import '@polymer/paper-dialog/paper-dialog.js';
<link rel='import' href='../bower_components/paper-icon-button/paper-icon-button.html'> import '@polymer/paper-icon-button/paper-icon-button.js';
<link rel='import' href='../bower_components/paper-dialog-scrollable/paper-dialog-scrollable.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../src/components/ha-markdown.html'> import '../src/components/ha-markdown.js';
<link rel='import' href='../src/resources/ha-style.html'> import '../src/resources/ha-style.js';
<dom-module id='hassio-markdown-dialog'> class HassioMarkdownDialog extends PolymerElement {
<template> static get template() {
<style include='ha-style-dialog'> return html`
<style include="ha-style-dialog">
paper-dialog { paper-dialog {
min-width: 350px; min-width: 350px;
font-size: 14px; font-size: 14px;
@ -48,26 +50,18 @@
} }
} }
</style> </style>
<paper-dialog <paper-dialog id="dialog" with-backdrop="">
id='dialog'
with-backdrop
>
<app-toolbar> <app-toolbar>
<paper-icon-button <paper-icon-button icon="mdi:close" dialog-dismiss=""></paper-icon-button>
icon='mdi:close' <div main-title="">[[title]]</div>
dialog-dismiss
></paper-icon-button>
<div main-title>[[title]]</div>
</app-toolbar> </app-toolbar>
<paper-dialog-scrollable> <paper-dialog-scrollable>
<ha-markdown content='[[content]]'></ha-markdown> <ha-markdown content="[[content]]"></ha-markdown>
</paper-dialog-scrollable> </paper-dialog-scrollable>
</paper-dialog> </paper-dialog>
</template> `;
</dom-module> }
<script>
class HassioMarkdownDialog extends Polymer.Element {
static get is() { return 'hassio-markdown-dialog'; } static get is() { return 'hassio-markdown-dialog'; }
static get properties() { static get properties() {
@ -82,4 +76,3 @@ class HassioMarkdownDialog extends Polymer.Element {
} }
} }
customElements.define(HassioMarkdownDialog.is, HassioMarkdownDialog); customElements.define(HassioMarkdownDialog.is, HassioMarkdownDialog);
</script>

View File

@ -1,163 +0,0 @@
<link rel='import' href='../bower_components/polymer/polymer-element.html'>
<link rel='import' href='../bower_components/app-layout/app-header-layout/app-header-layout.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/paper-tabs/paper-tabs.html'>
<link rel='import' href='../bower_components/paper-tabs/paper-tab.html'>
<link rel='import' href='../bower_components/paper-icon-button/paper-icon-button.html'>
<link rel='import' href='../src/components/ha-menu-button.html'>
<link rel='import' href='../src/util/hass-mixins.html'>
<link rel='import' href='../src/resources/ha-style.html'>
<link rel='import' href='./dashboard/hassio-dashboard.html'>
<link rel='import' href='./snapshots/hassio-snapshots.html'>
<link rel='import' href='./snapshots/hassio-snapshot.html'>
<link rel='import' href='./addon-store/hassio-addon-store.html'>
<link rel='import' href='./system/hassio-system.html'>
<link rel='import' href='./hassio-markdown-dialog.html'>
<dom-module id='hassio-pages-with-tabs'>
<template>
<style include='iron-flex iron-positioning ha-style'>
:host {
color: var(--primary-text-color);
--paper-card-header-color: var(--primary-text-color);
}
paper-tabs {
margin-left: 12px;
--paper-tabs-selection-bar-color: #FFF;
text-transform: uppercase;
}
</style>
<app-header-layout has-scrolling-region>
<app-header fixed slot='header'>
<app-toolbar>
<ha-menu-button narrow='[[narrow]]' show-menu='[[showMenu]]'></ha-menu-button>
<div main-title>Hass.io</div>
<template is='dom-if' if='[[showRefreshButton(page)]]'>
<paper-icon-button
icon='mdi:refresh'
on-click='refreshClicked'
></paper-icon-button>
</template>
</app-toolbar>
<paper-tabs
scrollable
selected='[[page]]'
attr-for-selected='page-name'
on-iron-activate='handlePageSelected'
>
<paper-tab page-name='dashboard'>Dashboard</paper-tab>
<paper-tab page-name='snapshots'>Snapshots</paper-tab>
<paper-tab page-name='store'>Add-on store</paper-tab>
<paper-tab page-name='system'>System</paper-tab>
</paper-tabs>
</app-header>
<template is='dom-if' if='[[equals(page, "dashboard")]]'>
<hassio-dashboard
hass='[[hass]]'
supervisor-info='[[supervisorInfo]]'
hass-info='[[hassInfo]]'
></hassio-dashboard>
</template>
<template is='dom-if' if='[[equals(page, "snapshots")]]'>
<hassio-snapshots
hass='[[hass]]'
installed-addons='[[supervisorInfo.addons]]'
snapshot-slug='{{snapshotSlug}}'
snapshot-deleted='{{snapshotDeleted}}'
></hassio-snapshots>
</template>
<template is='dom-if' if='[[equals(page, "store")]]'>
<hassio-addon-store
hass='[[hass]]'
></hassio-addon-store>
</template>
<template is='dom-if' if='[[equals(page, "system")]]'>
<hassio-system
hass='[[hass]]'
supervisor-info='[[supervisorInfo]]'
host-info='[[hostInfo]]'
></hassio-system>
</template>
</app-header-layout>
<hassio-markdown-dialog
title='[[markdownTitle]]'
content='[[markdownContent]]'
></hassio-markdown-dialog>
<template is='dom-if' if='[[equals(page, "snapshots")]]'>
<hassio-snapshot
hass='[[hass]]'
snapshot-slug='{{snapshotSlug}}'
snapshot-deleted='{{snapshotDeleted}}'
></hassio-snapshot>
</template>
</template>
</dom-module>
<script>
class HassioPagesWithTabs extends window.hassMixins.NavigateMixin(Polymer.Element) {
static get is() { return 'hassio-pages-with-tabs'; }
static get properties() {
return {
hass: Object,
showMenu: Boolean,
narrow: Boolean,
page: String,
supervisorInfo: Object,
hostInfo: Object,
hassInfo: Object,
snapshotSlug: String,
snapshotDeleted: Boolean,
markdownTitle: String,
markdownContent: {
type: String,
value: '',
},
};
}
ready() {
super.ready();
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev));
}
handlePageSelected(ev) {
const newPage = ev.detail.item.getAttribute('page-name');
if (newPage !== this.page) {
this.navigate(`/hassio/${newPage}`);
}
}
equals(a, b) {
return a === b;
}
showRefreshButton(page) {
return page === 'store' || page === 'snapshots';
}
refreshClicked() {
if (this.page === 'snapshots') {
this.shadowRoot.querySelector('hassio-snapshots').refreshData();
} else {
this.shadowRoot.querySelector('hassio-addon-store').refreshData();
}
}
openMarkdown(ev) {
this.setProperties({
markdownTitle: ev.detail.title,
markdownContent: ev.detail.content,
});
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog();
}
}
customElements.define(HassioPagesWithTabs.is, HassioPagesWithTabs);
</script>

View File

@ -0,0 +1,131 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import '@polymer/paper-tabs/paper-tab.js';
import '@polymer/paper-tabs/paper-tabs.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../src/components/ha-menu-button.js';
import '../src/resources/ha-style.js';
import '../src/util/hass-mixins.js';
import './addon-store/hassio-addon-store.js';
import './dashboard/hassio-dashboard.js';
import './hassio-markdown-dialog.js';
import './snapshots/hassio-snapshot.js';
import './snapshots/hassio-snapshots.js';
import './system/hassio-system.js';
class HassioPagesWithTabs extends window.hassMixins.NavigateMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex iron-positioning ha-style">
:host {
color: var(--primary-text-color);
--paper-card-header-color: var(--primary-text-color);
}
paper-tabs {
margin-left: 12px;
--paper-tabs-selection-bar-color: #FFF;
text-transform: uppercase;
}
</style>
<app-header-layout has-scrolling-region="">
<app-header fixed="" slot="header">
<app-toolbar>
<ha-menu-button narrow="[[narrow]]" show-menu="[[showMenu]]"></ha-menu-button>
<div main-title="">Hass.io</div>
<template is="dom-if" if="[[showRefreshButton(page)]]">
<paper-icon-button icon="mdi:refresh" on-click="refreshClicked"></paper-icon-button>
</template>
</app-toolbar>
<paper-tabs scrollable="" selected="[[page]]" attr-for-selected="page-name" on-iron-activate="handlePageSelected">
<paper-tab page-name="dashboard">Dashboard</paper-tab>
<paper-tab page-name="snapshots">Snapshots</paper-tab>
<paper-tab page-name="store">Add-on store</paper-tab>
<paper-tab page-name="system">System</paper-tab>
</paper-tabs>
</app-header>
<template is="dom-if" if="[[equals(page, &quot;dashboard&quot;)]]">
<hassio-dashboard hass="[[hass]]" supervisor-info="[[supervisorInfo]]" hass-info="[[hassInfo]]"></hassio-dashboard>
</template>
<template is="dom-if" if="[[equals(page, &quot;snapshots&quot;)]]">
<hassio-snapshots hass="[[hass]]" installed-addons="[[supervisorInfo.addons]]" snapshot-slug="{{snapshotSlug}}" snapshot-deleted="{{snapshotDeleted}}"></hassio-snapshots>
</template>
<template is="dom-if" if="[[equals(page, &quot;store&quot;)]]">
<hassio-addon-store hass="[[hass]]"></hassio-addon-store>
</template>
<template is="dom-if" if="[[equals(page, &quot;system&quot;)]]">
<hassio-system hass="[[hass]]" supervisor-info="[[supervisorInfo]]" host-info="[[hostInfo]]"></hassio-system>
</template>
</app-header-layout>
<hassio-markdown-dialog title="[[markdownTitle]]" content="[[markdownContent]]"></hassio-markdown-dialog>
<template is="dom-if" if="[[equals(page, &quot;snapshots&quot;)]]">
<hassio-snapshot hass="[[hass]]" snapshot-slug="{{snapshotSlug}}" snapshot-deleted="{{snapshotDeleted}}"></hassio-snapshot>
</template>
`;
}
static get is() { return 'hassio-pages-with-tabs'; }
static get properties() {
return {
hass: Object,
showMenu: Boolean,
narrow: Boolean,
page: String,
supervisorInfo: Object,
hostInfo: Object,
hassInfo: Object,
snapshotSlug: String,
snapshotDeleted: Boolean,
markdownTitle: String,
markdownContent: {
type: String,
value: '',
},
};
}
ready() {
super.ready();
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev));
}
handlePageSelected(ev) {
const newPage = ev.detail.item.getAttribute('page-name');
if (newPage !== this.page) {
this.navigate(`/hassio/${newPage}`);
}
}
equals(a, b) {
return a === b;
}
showRefreshButton(page) {
return page === 'store' || page === 'snapshots';
}
refreshClicked() {
if (this.page === 'snapshots') {
this.shadowRoot.querySelector('hassio-snapshots').refreshData();
} else {
this.shadowRoot.querySelector('hassio-addon-store').refreshData();
}
}
openMarkdown(ev) {
this.setProperties({
markdownTitle: ev.detail.title,
markdownContent: ev.detail.content,
});
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog();
}
}
customElements.define(HassioPagesWithTabs.is, HassioPagesWithTabs);

View File

@ -16,20 +16,21 @@
<body> <body>
<hassio-app></hassio-app> <hassio-app></hassio-app>
<script> <script>
function addScript(src) { function addScript(src) {
var e = document.createElement('script'); var e = document.createElement('script');
e.src = src; e.src = src;
document.head.appendChild(e); document.head.appendChild(e);
} }
var webComponentsSupported = ( var webComponentsSupported = (
'customElements' in window && 'customElements' in window &&
'import' in document.createElement('link') && 'import' in document.createElement('link') &&
'content' in document.createElement('template')); 'content' in document.createElement('template'));
if (!webComponentsSupported) { if (!webComponentsSupported) {
addScript('/static/webcomponents-lite.js'); addScript('/static/webcomponents-bundle.js');
} }
</script> </script>
<link rel='import' href='./hassio-app.html'> <!-- This is broken. -->
<script src="./hassio-app.js"></script>
<link rel='import' href='/static/mdi.html' async> <link rel='import' href='/static/mdi.html' async>
</body> </body>
</html> </html>

View File

@ -1,17 +1,19 @@
<link rel='import' href='../../bower_components/polymer/polymer-element.html'> import '@polymer/app-layout/app-toolbar/app-toolbar.js';
<link rel='import' href='../../bower_components/paper-dialog/paper-dialog.html'> import '@polymer/paper-button/paper-button.js';
<link rel='import' href='../../bower_components/paper-dialog-scrollable/paper-dialog-scrollable.html'> import '@polymer/paper-checkbox/paper-checkbox.js';
<link rel='import' href='../../bower_components/app-layout/app-toolbar/app-toolbar.html'> import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
<link rel='import' href='../../bower_components/paper-icon-button/paper-icon-button.html'> import '@polymer/paper-dialog/paper-dialog.js';
<link rel='import' href='../../bower_components/paper-checkbox/paper-checkbox.html'> import '@polymer/paper-icon-button/paper-icon-button.js';
<link rel='import' href='../../bower_components/paper-button/paper-button.html'> import '@polymer/paper-input/paper-input.js';
<link rel="import" href='../../bower_components/paper-input/paper-input.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/resources/ha-style.html'> import '../../src/resources/ha-style.js';
<dom-module id='hassio-snapshot'> class HassioSnapshot extends PolymerElement {
<template> static get template() {
<style include='ha-style-dialog'> return html`
<style include="ha-style-dialog">
paper-dialog { paper-dialog {
min-width: 350px; min-width: 350px;
font-size: 14px; font-size: 14px;
@ -54,72 +56,58 @@
color: var(--google-red-500); color: var(--google-red-500);
} }
</style> </style>
<paper-dialog id='dialog' with-backdrop on-iron-overlay-closed='_dialogClosed'> <paper-dialog id="dialog" with-backdrop="" on-iron-overlay-closed="_dialogClosed">
<app-toolbar> <app-toolbar>
<paper-icon-button <paper-icon-button icon="mdi:close" dialog-dismiss=""></paper-icon-button>
icon='mdi:close' <div main-title="">[[_computeName(snapshot)]]</div>
dialog-dismiss
></paper-icon-button>
<div main-title>[[_computeName(snapshot)]]</div>
</app-toolbar> </app-toolbar>
<div class='details'> <div class="details">
[[_computeType(snapshot.type)]] ([[_computeSize(snapshot.size)]])<br/> [[_computeType(snapshot.type)]] ([[_computeSize(snapshot.size)]])<br>
[[_formatDatetime(snapshot.date)]] [[_formatDatetime(snapshot.date)]]
</div> </div>
<div>Home Assistant:</div> <div>Home Assistant:</div>
<paper-checkbox checked='{{restoreHass}}'> <paper-checkbox checked="{{restoreHass}}">
Home Assistant [[snapshot.homeassistant]] Home Assistant [[snapshot.homeassistant]]
</paper-checkbox> </paper-checkbox>
<template is='dom-if' if='[[snapshot.addons.length]]'> <template is="dom-if" if="[[snapshot.addons.length]]">
<div>Folders:</div> <div>Folders:</div>
<template is='dom-repeat' items='[[snapshot.folders]]'> <template is="dom-repeat" items="[[snapshot.folders]]">
<paper-checkbox checked='{{item.checked}}'> <paper-checkbox checked="{{item.checked}}">
[[item.name]] [[item.name]]
</paper-checkbox> </paper-checkbox>
</template> </template>
</template> </template>
<template is='dom-if' if='[[snapshot.addons.length]]'> <template is="dom-if" if="[[snapshot.addons.length]]">
<div>Add-ons:</div> <div>Add-ons:</div>
<paper-dialog-scrollable> <paper-dialog-scrollable>
<template is='dom-repeat' items='[[snapshot.addons]]' sort='_sortAddons'> <template is="dom-repeat" items="[[snapshot.addons]]" sort="_sortAddons">
<paper-checkbox checked='{{item.checked}}'> <paper-checkbox checked="{{item.checked}}">
[[item.name]] [[item.name]]
<span class='details'>([[item.version]])</span> <span class="details">([[item.version]])</span>
</paper-checkbox> </paper-checkbox>
</template> </template>
</paper-dialog-scrollable> </paper-dialog-scrollable>
</template> </template>
<template is='dom-if' if='[[snapshot.protected]]'> <template is="dom-if" if="[[snapshot.protected]]">
<paper-input autofocus label='Password' type='password' value='{{snapshotPassword}}'></paper-input> <paper-input autofocus="" label="Password" type="password" value="{{snapshotPassword}}"></paper-input>
</template> </template>
<template is='dom-if' if='[[error]]'> <template is="dom-if" if="[[error]]">
<p class='error'>Error: [[error]]</p> <p class="error">Error: [[error]]</p>
</template> </template>
<div class='buttons'> <div class="buttons">
<paper-icon-button <paper-icon-button icon="mdi:delete" on-click="_deleteClicked" class="warning" title="Delete snapshot"></paper-icon-button>
icon='mdi:delete' <a href="[[_computeDownloadUrl(snapshotSlug)]]" download="[[_computeDownloadName(snapshot)]]">
on-click='_deleteClicked' <paper-icon-button icon="mdi:download" class="download" title="Download snapshot"></paper-icon-button>
class='warning'
title='Delete snapshot'
></paper-icon-button>
<a href='[[_computeDownloadUrl(snapshotSlug)]]' download='[[_computeDownloadName(snapshot)]]'>
<paper-icon-button
icon='mdi:download'
class='download'
title='Download snapshot'
></paper-icon-button>
</a> </a>
<paper-button on-click='_partialRestoreClicked'>Restore selected</paper-button> <paper-button on-click="_partialRestoreClicked">Restore selected</paper-button>
<template is='dom-if' if='[[_isFullSnapshot(snapshot.type)]]'> <template is="dom-if" if="[[_isFullSnapshot(snapshot.type)]]">
<paper-button on-click='_fullRestoreClicked'>Wipe &amp; restore</paper-button> <paper-button on-click="_fullRestoreClicked">Wipe &amp; restore</paper-button>
</template> </template>
</div> </div>
</paper-dialog> </paper-dialog>
</template> `;
</dom-module> }
<script>
class HassioSnapshot extends Polymer.Element {
static get is() { return 'hassio-snapshot'; } static get is() { return 'hassio-snapshot'; }
static get properties() { static get properties() {
@ -267,4 +255,3 @@ class HassioSnapshot extends Polymer.Element {
} }
} }
customElements.define(HassioSnapshot.is, HassioSnapshot); customElements.define(HassioSnapshot.is, HassioSnapshot);
</script>

View File

@ -1,19 +1,20 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../bower_components/paper-button/paper-button.html"> import '@polymer/paper-checkbox/paper-checkbox.js';
<link rel="import" href="../../bower_components/paper-input/paper-input.html"> import '@polymer/paper-input/paper-input.js';
<link rel='import' href='../../bower_components/paper-radio-group/paper-radio-group.html'> import '@polymer/paper-radio-button/paper-radio-button.js';
<link rel='import' href='../../bower_components/paper-radio-button/paper-radio-button.html'> import '@polymer/paper-radio-group/paper-radio-group.js';
<link rel='import' href='../../bower_components/paper-checkbox/paper-checkbox.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/util/hass-mixins.html'> import '../../src/components/hassio-card-content.js';
import '../../src/resources/hassio-style.js';
import '../../src/util/hass-mixins.js';
<link rel='import' href='../../src/components/hassio-card-content.html'> class HassioSnapshots extends window.hassMixins.EventsMixin(PolymerElement) {
<link rel='import' href='../../src/resources/hassio-style.html'> static get template() {
return html`
<dom-module id="hassio-snapshots"> <style include="ha-style hassio-style">
<template>
<style include='ha-style hassio-style'>
paper-radio-group { paper-radio-group {
display: block; display: block;
} }
@ -30,83 +31,75 @@
cursor: pointer; cursor: pointer;
} }
</style> </style>
<div class='content'> <div class="content">
<div class='card-group'> <div class="card-group">
<div class='title'> <div class="title">
Create snapshot Create snapshot
<div class='description'> <div class="description">
Snapshots allow you to easily backup and Snapshots allow you to easily backup and
restore all data of your Hass.io instance. restore all data of your Hass.io instance.
</div> </div>
</div> </div>
<paper-card> <paper-card>
<div class='card-content'> <div class="card-content">
<paper-input autofocus label='Name' value='{{snapshotName}}'></paper-input> <paper-input autofocus="" label="Name" value="{{snapshotName}}"></paper-input>
Type: Type:
<paper-radio-group selected='{{snapshotType}}'> <paper-radio-group selected="{{snapshotType}}">
<paper-radio-button name='full'> <paper-radio-button name="full">
Full snapshot Full snapshot
</paper-radio-button> </paper-radio-button>
<paper-radio-button name='partial'> <paper-radio-button name="partial">
Partial snapshot Partial snapshot
</paper-radio-button> </paper-radio-button>
</paper-radio-group> </paper-radio-group>
<template is='dom-if' if='[[!_fullSelected(snapshotType)]]'> <template is="dom-if" if="[[!_fullSelected(snapshotType)]]">
Folders: Folders:
<template is='dom-repeat' items='[[folderList]]'> <template is="dom-repeat" items="[[folderList]]">
<paper-checkbox checked='{{item.checked}}'> <paper-checkbox checked="{{item.checked}}">
[[item.name]] [[item.name]]
</paper-checkbox> </paper-checkbox>
</template> </template>
Add-ons: Add-ons:
<template is='dom-repeat' items='[[addonList]]' sort='_sortAddons'> <template is="dom-repeat" items="[[addonList]]" sort="_sortAddons">
<paper-checkbox checked='{{item.checked}}'> <paper-checkbox checked="{{item.checked}}">
[[item.name]] [[item.name]]
</paper-checkbox> </paper-checkbox>
</template> </template>
</template> </template>
Security: Security:
<paper-checkbox checked='{{snapshotHasPassword}}'>Password protection</paper-checkbox> <paper-checkbox checked="{{snapshotHasPassword}}">Password protection</paper-checkbox>
<template is='dom-if' if='[[snapshotHasPassword]]'> <template is="dom-if" if="[[snapshotHasPassword]]">
<paper-input label='Password' type='password' value='{{snapshotPassword}}'></paper-input> <paper-input label="Password" type="password" value="{{snapshotPassword}}"></paper-input>
</template> </template>
<template is='dom-if' if='[[error]]'> <template is="dom-if" if="[[error]]">
<p class='error'>[[error]]</p> <p class="error">[[error]]</p>
</template> </template>
</div> </div>
<div class='card-actions'> <div class="card-actions">
<paper-button disabled='[[creatingSnapshot]]' on-click='_createSnapshot'>Create</paper-button> <paper-button disabled="[[creatingSnapshot]]" on-click="_createSnapshot">Create</paper-button>
</div> </div>
</paper-card> </paper-card>
</div> </div>
<div class='card-group'> <div class="card-group">
<div class='title'>Available snapshots</div> <div class="title">Available snapshots</div>
<template is='dom-if' if='[[!snapshots.length]]'> <template is="dom-if" if="[[!snapshots.length]]">
<paper-card> <paper-card>
<div class='card-content'>You don't have any snapshots yet.</div> <div class="card-content">You don't have any snapshots yet.</div>
</paper-card> </paper-card>
</template> </template>
<template is='dom-repeat' items='[[snapshots]]' as='snapshot' sort='_sortSnapshots'> <template is="dom-repeat" items="[[snapshots]]" as="snapshot" sort="_sortSnapshots">
<paper-card class='pointer' on-click='_snapshotClicked'> <paper-card class="pointer" on-click="_snapshotClicked">
<div class='card-content'> <div class="card-content">
<hassio-card-content <hassio-card-content title="[[_computeName(snapshot)]]" description="[[_computeDetails(snapshot)]]" datetime="[[snapshot.date]]" icon="[[_computeIcon(snapshot.type)]]" icon-class="snapshot"></hassio-card-content>
title='[[_computeName(snapshot)]]'
description='[[_computeDetails(snapshot)]]'
datetime='[[snapshot.date]]'
icon='[[_computeIcon(snapshot.type)]]'
icon-class='snapshot'
></hassio-card-content>
</div> </div>
</paper-card> </paper-card>
</template> </template>
</div> </div>
</div> </div>
</template> `;
</dom-module> }
<script>
class HassioSnapshots extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'hassio-snapshots'; } static get is() { return 'hassio-snapshots'; }
static get properties() { static get properties() {
@ -269,4 +262,3 @@ class HassioSnapshots extends window.hassMixins.EventsMixin(Polymer.Element) {
} }
customElements.define(HassioSnapshots.is, HassioSnapshots); customElements.define(HassioSnapshots.is, HassioSnapshots);
</script>

View File

@ -1,12 +1,14 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../bower_components/paper-button/paper-button.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/util/hass-mixins.html'> import '../../src/components/buttons/ha-call-api-button.js';
<link rel="import" href="../../src/components/buttons/ha-call-api-button.html"> import '../../src/util/hass-mixins.js';
<dom-module id="hassio-host-info"> class HassioHostInfo extends window.hassMixins.EventsMixin(PolymerElement) {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
paper-card { paper-card {
display: inline-block; display: inline-block;
@ -43,8 +45,8 @@
<paper-card> <paper-card>
<div class="card-content"> <div class="card-content">
<h2>Host system</h2> <h2>Host system</h2>
<table class='info'> <table class="info">
<tr> <tbody><tr>
<td>Hostname</td> <td>Hostname</td>
<td>[[data.hostname]]</td> <td>[[data.hostname]]</td>
</tr> </tr>
@ -56,44 +58,27 @@
<td>Deployment</td> <td>Deployment</td>
<td>[[data.deployment]]</td> <td>[[data.deployment]]</td>
</tr> </tr>
</table> </tbody></table>
<paper-button <paper-button raised="" on-click="_showHardware" class="info">Show hardware</paper-button>
raised <template is="dom-if" if="[[errors]]">
on-click='_showHardware' <div class="errors">Error: [[errors]]</div>
class='info'
>Show hardware</paper-button>
<template is='dom-if' if='[[errors]]'>
<div class='errors'>Error: [[errors]]</div>
</template> </template>
</div> </div>
<div class="card-actions"> <div class="card-actions">
<template is='dom-if' if='[[computeRebootAvailable(data)]]'> <template is="dom-if" if="[[computeRebootAvailable(data)]]">
<ha-call-api-button <ha-call-api-button class="warning" hass="[[hass]]" path="hassio/host/reboot">Reboot</ha-call-api-button>
class='warning'
hass='[[hass]]'
path="hassio/host/reboot"
>Reboot</ha-call-api-button>
</template> </template>
<template is='dom-if' if='[[computeShutdownAvailable(data)]]'> <template is="dom-if" if="[[computeShutdownAvailable(data)]]">
<ha-call-api-button <ha-call-api-button class="warning" hass="[[hass]]" path="hassio/host/shutdown">Shutdown</ha-call-api-button>
class='warning'
hass='[[hass]]'
path="hassio/host/shutdown"
>Shutdown</ha-call-api-button>
</template> </template>
<template is='dom-if' if='[[computeUpdateAvailable(data)]]'> <template is="dom-if" if="[[computeUpdateAvailable(data)]]">
<ha-call-api-button <ha-call-api-button hass="[[hass]]" path="hassio/host/update">Update</ha-call-api-button>
hass='[[hass]]'
path="hassio/host/update"
>Update</ha-call-api-button>
</template> </template>
</div> </div>
</paper-card> </paper-card>
</template> `;
</dom-module> }
<script>
class HassioHostInfo extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'hassio-host-info'; } static get is() { return 'hassio-host-info'; }
static get properties() { static get properties() {
@ -170,4 +155,3 @@ class HassioHostInfo extends window.hassMixins.EventsMixin(Polymer.Element) {
} }
customElements.define(HassioHostInfo.is, HassioHostInfo); customElements.define(HassioHostInfo.is, HassioHostInfo);
</script>

View File

@ -1,12 +1,14 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../bower_components/paper-button/paper-button.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../src/util/hass-mixins.html'> import '../../src/components/buttons/ha-call-api-button.js';
<link rel="import" href="../../src/components/buttons/ha-call-api-button.html"> import '../../src/util/hass-mixins.js';
<dom-module id="hassio-supervisor-info"> class HassioSupervisorInfo extends window.hassMixins.EventsMixin(PolymerElement) {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
paper-card { paper-card {
display: inline-block; display: inline-block;
@ -37,8 +39,8 @@
<paper-card> <paper-card>
<div class="card-content"> <div class="card-content">
<h2>Hass.io supervisor</h2> <h2>Hass.io supervisor</h2>
<table class='info'> <table class="info">
<tr> <tbody><tr>
<td>Version</td> <td>Version</td>
<td> <td>
[[data.version]] [[data.version]]
@ -48,49 +50,33 @@
<td>Latest version</td> <td>Latest version</td>
<td>[[data.last_version]]</td> <td>[[data.last_version]]</td>
</tr> </tr>
<template is='dom-if' if='[[!_equals(data.channel, "stable")]]'> <template is="dom-if" if="[[!_equals(data.channel, &quot;stable&quot;)]]">
<tr> <tr>
<td>Channel</td> <td>Channel</td>
<td>[[data.channel]]</td> <td>[[data.channel]]</td>
</tr> </tr>
</template> </template>
</table> </tbody></table>
<template is='dom-if' if='[[errors]]'> <template is="dom-if" if="[[errors]]">
<div class='errors'>Error: [[errors]]</div> <div class="errors">Error: [[errors]]</div>
</template> </template>
</div> </div>
<div class="card-actions"> <div class="card-actions">
<ha-call-api-button <ha-call-api-button hass="[[hass]]" path="hassio/supervisor/reload">Reload</ha-call-api-button>
hass='[[hass]]' <template is="dom-if" if="[[computeUpdateAvailable(data)]]">
path="hassio/supervisor/reload" <ha-call-api-button hass="[[hass]]" path="hassio/supervisor/update">Update</ha-call-api-button>
>Reload</ha-call-api-button>
<template is='dom-if' if='[[computeUpdateAvailable(data)]]'>
<ha-call-api-button
hass='[[hass]]'
path="hassio/supervisor/update"
>Update</ha-call-api-button>
</template> </template>
<template is='dom-if' if='[[_equals(data.channel, "beta")]]'> <template is="dom-if" if="[[_equals(data.channel, &quot;beta&quot;)]]">
<ha-call-api-button <ha-call-api-button hass="[[hass]]" path="hassio/supervisor/options" data="[[leaveBeta]]">Leave beta channel</ha-call-api-button>
hass='[[hass]]'
path='hassio/supervisor/options'
data='[[leaveBeta]]'
>Leave beta channel</ha-call-api-button>
</template> </template>
<template is='dom-if' if='[[_equals(data.channel, "stable")]]'> <template is="dom-if" if="[[_equals(data.channel, &quot;stable&quot;)]]">
<paper-button <paper-button on-click="_joinBeta" class="warning" title="Get beta updates for Home Assistant (RCs), supervisor and host">Join beta channel</paper-button>
on-click='_joinBeta'
class='warning'
title='Get beta updates for Home Assistant (RCs), supervisor and host'
>Join beta channel</paper-button>
</template> </template>
</div> </div>
</paper-card> </paper-card>
</template> `;
</dom-module> }
<script>
class HassioSupervisorInfo extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'hassio-supervisor-info'; } static get is() { return 'hassio-supervisor-info'; }
static get properties() { static get properties() {
@ -167,4 +153,3 @@ This inludes beta releases for:
} }
customElements.define(HassioSupervisorInfo.is, HassioSupervisorInfo); customElements.define(HassioSupervisorInfo.is, HassioSupervisorInfo);
</script>

View File

@ -1,27 +1,27 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel='import' href='../../bower_components/paper-card/paper-card.html'> import '@polymer/paper-card/paper-card.js';
<link rel='import' href='../../bower_components/paper-button/paper-button.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<dom-module id="hassio-supervisor-log"> class HassioSupervisorLog extends PolymerElement {
<template> static get template() {
return html`
<style include="ha-style"> <style include="ha-style">
paper-card { paper-card {
display: block; display: block;
} }
</style> </style>
<paper-card> <paper-card>
<div class='card-content'> <div class="card-content">
<pre>[[log]]</pre> <pre>[[log]]</pre>
</div> </div>
<div class='card-actions'> <div class="card-actions">
<paper-button on-click='refreshTapped'>Refresh</paper-button> <paper-button on-click="refreshTapped">Refresh</paper-button>
</div> </div>
</paper-card> </paper-card>
</template> `;
</dom-module> }
<script>
class HassioSupervisorLog extends Polymer.Element {
static get is() { return 'hassio-supervisor-log'; } static get is() { return 'hassio-supervisor-log'; }
static get properties() { static get properties() {
@ -51,4 +51,3 @@ class HassioSupervisorLog extends Polymer.Element {
} }
customElements.define(HassioSupervisorLog.is, HassioSupervisorLog); customElements.define(HassioSupervisorLog.is, HassioSupervisorLog);
</script>

View File

@ -1,54 +0,0 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="./hassio-host-info.html">
<link rel="import" href="./hassio-supervisor-info.html">
<link rel='import' href='./hassio-supervisor-log.html'>
<dom-module id="hassio-system">
<template>
<style include="iron-flex ha-style">
.content {
margin: 4px;
}
.title {
margin-top: 24px;
color: var(--primary-text-color);
font-size: 2em;
padding-left: 8px;
margin-bottom: 8px;
}
</style>
<div class='content'>
<div class='title'>Information</div>
<hassio-supervisor-info
hass='[[hass]]'
data='[[supervisorInfo]]'
></hassio-supervisor-info>
<hassio-host-info
hass='[[hass]]'
data='[[hostInfo]]'
></hassio-host-info>
<div class='title'>System log</div>
<hassio-supervisor-log
hass='[[hass]]'
></hassio-supervisor-log>
</div>
</template>
</dom-module>
<script>
class HassioSystem extends Polymer.Element {
static get is() { return 'hassio-system'; }
static get properties() {
return {
hass: Object,
supervisorInfo: Object,
hostInfo: Object,
};
}
}
customElements.define(HassioSystem.is, HassioSystem);
</script>

View File

@ -0,0 +1,45 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import './hassio-host-info.js';
import './hassio-supervisor-info.js';
import './hassio-supervisor-log.js';
class HassioSystem extends PolymerElement {
static get template() {
return html`
<style include="iron-flex ha-style">
.content {
margin: 4px;
}
.title {
margin-top: 24px;
color: var(--primary-text-color);
font-size: 2em;
padding-left: 8px;
margin-bottom: 8px;
}
</style>
<div class="content">
<div class="title">Information</div>
<hassio-supervisor-info hass="[[hass]]" data="[[supervisorInfo]]"></hassio-supervisor-info>
<hassio-host-info hass="[[hass]]" data="[[hostInfo]]"></hassio-host-info>
<div class="title">System log</div>
<hassio-supervisor-log hass="[[hass]]"></hassio-supervisor-log>
</div>
`;
}
static get is() { return 'hassio-system'; }
static get properties() {
return {
hass: Object,
supervisorInfo: Object,
hostInfo: Object,
};
}
}
customElements.define(HassioSystem.is, HassioSystem);

View File

@ -87,27 +87,23 @@
if (!webComponentsSupported) { if (!webComponentsSupported) {
var e = document.createElement('script'); var e = document.createElement('script');
e.onerror = initError; e.onerror = initError;
e.src = '/static/webcomponents-lite.js'; e.src = '/static/webcomponents-bundle.js';
if ('import' in document.createElement('link')) { if ('import' in document.createElement('link')) {
document.write(e.outerHTML); document.write(e.outerHTML);
} else { } else {
document.head.appendChild(e); document.head.appendChild(e);
} }
} }
if ('serviceWorker' in navigator) { /* if ('serviceWorker' in navigator) {
window.addEventListener('load', function () { window.addEventListener('load', function () {
navigator.serviceWorker.register('/service_worker.js'); navigator.serviceWorker.register('/service_worker.js');
}); });
} } */
window.CHART_SCRIPT = '/home-assistant-polymer/src/resources/ha-chart-scripts.html';
</script> </script>
<!--<script src='/home-assistant-polymer/build/_demo_data_compiled.js'></script>--> <!--<script src='/home-assistant-polymer/build/_demo_data_compiled.js'></script>-->
<!--EXTRA_SCRIPTS--> <!--EXTRA_SCRIPTS-->
<script src='/home-assistant-polymer/build/core.js'></script> <script src='/home-assistant-polymer/build/core.js'></script>
<link rel='import' href='/home-assistant-polymer/src/home-assistant.html' onerror='initError()'> <script src='/home-assistant-polymer/build/webpack/app.js'></script>
{% if panel_url -%}
<link rel='import' href='{{ panel_url }}' async>
{% endif -%}
<link rel='import' href='/home-assistant-polymer/hass_frontend/mdi.html' async> <link rel='import' href='/home-assistant-polymer/hass_frontend/mdi.html' async>
{% for extra_url in extra_urls -%} {% for extra_url in extra_urls -%}
<link rel='import' href='{{ extra_url }}' async> <link rel='import' href='{{ extra_url }}' async>

View File

@ -1,48 +1,104 @@
{ {
"name": "home-assistant-polymer",
"version": "1.0.0",
"description": "A frontend for Home Assistant using the Polymer framework", "description": "A frontend for Home Assistant using the Polymer framework",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/home-assistant/home-assistant-polymer" "url": "https://github.com/home-assistant/home-assistant-polymer"
}, },
"name": "home-assistant-frontend",
"version": "1.0.0",
"scripts": { "scripts": {
"clean": "rm -rf build/* build-temp/* build-es5/* build-temp-es5/* build-translations/*", "clean": "rm -rf build/* build-temp/* build-es5/* build-temp-es5/* build-translations/*",
"gulp": "gulp", "gulp": "gulp",
"build": "BUILD_DEV=0 gulp", "build": "BUILD_DEV=0 gulp && NODE_ENV=production webpack -p",
"build_demo": "BUILD_DEV=0 BUILD_DEMO=1 gulp", "build_demo": "BUILD_DEV=0 BUILD_DEMO=1 gulp",
"dev": "npm run gulp ru_all gen-service-worker", "dev": "npm run gulp ru_all gen-service-worker",
"dev-watch": "npm run gulp watch_ru_all gen-service-worker", "dev-watch": "npm run gulp watch_ru_all gen-service-worker",
"dev-es5": "npm run gulp ru_all_es5 gen-service-worker-es5", "dev-es5": "npm run gulp ru_all_es5 gen-service-worker-es5",
"dev-watch-es5": "npm run gulp watch_ru_all_es5 gen-service-worker-es5", "dev-watch-es5": "npm run gulp watch_ru_all_es5 gen-service-worker-es5",
"lint_js": "eslint src panels js hassio test-mocha --ext js,html", "lint_js": "eslint src panels js hassio test-mocha",
"lint_html": "find src panels hassio -name '*.html' | grep -v hassio/index.html | xargs polymer lint --input", "lint_html": "polymer lint",
"mocha": "node_modules/.bin/mocha --opts test-mocha/mocha.opts", "mocha": "node_modules/.bin/mocha --opts test-mocha/mocha.opts",
"test": "npm run lint_js && npm run lint_html && npm run mocha" "test": "npm run lint_js && npm run lint_html && npm run mocha"
}, },
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)", "author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@polymer/app-layout": "^3.0.0-pre.18",
"@polymer/app-localize-behavior": "^3.0.0-pre.18",
"@polymer/app-route": "^3.0.0-pre.18",
"@polymer/app-storage": "^3.0.0-pre.18",
"@polymer/font-roboto": "^3.0.0-pre.18",
"@polymer/font-roboto-local": "^3.0.0-pre.19",
"@polymer/iron-autogrow-textarea": "^3.0.0-pre.18",
"@polymer/iron-flex-layout": "^3.0.0-pre.18",
"@polymer/iron-icon": "^3.0.0-pre.18",
"@polymer/iron-iconset-svg": "^3.0.0-pre.19",
"@polymer/iron-image": "^3.0.0-pre.18",
"@polymer/iron-input": "^3.0.0-pre.18",
"@polymer/iron-label": "^3.0.0-pre.18",
"@polymer/iron-media-query": "^3.0.0-pre.18",
"@polymer/iron-pages": "^3.0.0-pre.18",
"@polymer/iron-resizable-behavior": "^3.0.0-pre.19",
"@polymer/neon-animation": "^3.0.0-pre.18",
"@polymer/paper-button": "^3.0.0-pre.18",
"@polymer/paper-card": "^3.0.0-pre.18",
"@polymer/paper-checkbox": "^3.0.0-pre.18",
"@polymer/paper-dialog": "^3.0.0-pre.18",
"@polymer/paper-dialog-behavior": "^3.0.0-pre.19",
"@polymer/paper-dialog-scrollable": "^3.0.0-pre.18",
"@polymer/paper-drawer-panel": "^3.0.0-pre.18",
"@polymer/paper-dropdown-menu": "^3.0.0-pre.18",
"@polymer/paper-fab": "^3.0.0-pre.18",
"@polymer/paper-icon-button": "^3.0.0-pre.18",
"@polymer/paper-input": "^3.0.0-pre.18",
"@polymer/paper-item": "^3.0.0-pre.18",
"@polymer/paper-listbox": "^3.0.0-pre.18",
"@polymer/paper-menu-button": "^3.0.0-pre.18",
"@polymer/paper-progress": "^3.0.0-pre.18",
"@polymer/paper-radio-button": "^3.0.0-pre.18",
"@polymer/paper-radio-group": "^3.0.0-pre.18",
"@polymer/paper-ripple": "^3.0.0-pre.19",
"@polymer/paper-scroll-header-panel": "^3.0.0-pre.18",
"@polymer/paper-slider": "^3.0.0-pre.18",
"@polymer/paper-spinner": "^3.0.0-pre.18",
"@polymer/paper-styles": "^3.0.0-pre.18",
"@polymer/paper-tabs": "^3.0.0-pre.18",
"@polymer/paper-toast": "^3.0.0-pre.18",
"@polymer/paper-toggle-button": "^3.0.0-pre.18",
"@polymer/polymer": "^3.0.0",
"@vaadin/vaadin-combo-box": "4.0.1-pre.1",
"@vaadin/vaadin-date-picker": "3.0.0-pre.3",
"@webcomponents/shadycss": "^1.0.0",
"@webcomponents/webcomponentsjs": "^2.0.0",
"chart.js": "~2.7.2",
"chartjs-chart-timeline": "0.2.0",
"es6-object-assign": "^1.1.0", "es6-object-assign": "^1.1.0",
"fecha": "^2.3.3", "fecha": "^2.3.3",
"home-assistant-js-websocket": "^1.2.1", "home-assistant-js-websocket": "^1.2.1",
"intl-messageformat": "^2.2.0",
"leaflet": "^1.0.2",
"marked": "^0.3.19",
"mdn-polyfills": "^5.5.0", "mdn-polyfills": "^5.5.0",
"moment": "^2.20.0",
"preact": "^8.2.6", "preact": "^8.2.6",
"unfetch": "^3.0.0" "unfetch": "^3.0.0",
"web-animations-js": "^2.3.1",
"xss": "^0.3.8"
}, },
"devDependencies": { "devDependencies": {
"babel-core": "^6.26.0", "babel-core": "^6.26.0",
"babel-eslint": "^8.2.3",
"babel-loader": "^7.1.4",
"babel-plugin-external-helpers": "^6.22.0", "babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-react-jsx": "^6.24.1", "babel-plugin-transform-react-jsx": "^6.24.1",
"babel-preset-env": "^1.6.1", "babel-preset-env": "^1.6.1",
"bower": "^1.8.2",
"chai": "^4.1.2", "chai": "^4.1.2",
"css-slam": "^2.0.2", "css-slam": "^2.0.2",
"del": "^3.0.0", "del": "^3.0.0",
"eslint": "^4.11.0", "eslint": "^4.11.0",
"eslint-config-airbnb-base": "^12.1.0", "eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-html": "^4.0.0",
"eslint-plugin-import": "^2.8.0", "eslint-plugin-import": "^2.8.0",
"eslint-plugin-react": "^7.0.0", "eslint-plugin-react": "^7.0.0",
"gulp": "^3.9.1", "gulp": "^3.9.1",
@ -71,7 +127,7 @@
"polymer-analyzer": "^2.3.0", "polymer-analyzer": "^2.3.0",
"polymer-build": "^2.1.0", "polymer-build": "^2.1.0",
"polymer-bundler": "^3.1.0", "polymer-bundler": "^3.1.0",
"polymer-cli": "^1.5.6", "polymer-cli": "^1.7.0",
"pump": "^3.0.0", "pump": "^3.0.0",
"reify": "^0.14.1", "reify": "^0.14.1",
"require-dir": "^1.0.0", "require-dir": "^1.0.0",
@ -86,6 +142,19 @@
"sw-precache": "^5.2.0", "sw-precache": "^5.2.0",
"uglify-es": "^3.1.9", "uglify-es": "^3.1.9",
"uglify-js": "^3.1.9", "uglify-js": "^3.1.9",
"web-component-tester": "^6.4.0" "wct-browser-legacy": "^1.0.0",
} "web-component-tester": "^6.6.0",
"webpack": "^4.8.1",
"webpack-cli": "^2.1.3"
},
"resolutions": {
"inherits": "2.0.3",
"samsam": "1.1.3",
"supports-color": "3.1.2",
"type-detect": "1.0.0",
"@webcomponents/webcomponentsjs": "2.0.0-beta.2",
"@vaadin/vaadin-overlay": "3.0.2-pre.2",
"fecha": "https://github.com/balloob/fecha/archive/51d14fd0eb4781e2ecf265d1c3080706259133b5.tar.gz"
},
"main": "src/home-assistant.js"
} }

View File

@ -1,32 +1,38 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/app-layout/app-header/app-header.js';
<link rel="import" href="../../../bower_components/app-layout/app-header/app-header.html"> import '@polymer/app-layout/app-toolbar/app-toolbar.js';
<link rel="import" href="../../../bower_components/app-layout/app-toolbar/app-toolbar.html"> import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu-light.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item-body.html"> import '@polymer/paper-fab/paper-fab.js';
<link rel="import" href="../../../bower_components/paper-icon-button/paper-icon-button.html"> import '@polymer/paper-icon-button/paper-icon-button.js';
<link rel="import" href="../../../bower_components/paper-input/paper-input.html"> import '@polymer/paper-input/paper-input.js';
<link rel="import" href="../../../bower_components/paper-input/paper-textarea.html"> import '@polymer/paper-input/paper-textarea.js';
<link rel="import" href="../../../bower_components/paper-radio-button/paper-radio-button.html"> import '@polymer/paper-item/paper-item-body.js';
<link rel="import" href="../../../bower_components/paper-radio-group/paper-radio-group.html"> import '@polymer/paper-item/paper-item.js';
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu-light.html"> import '@polymer/paper-listbox/paper-listbox.js';
<link rel="import" href="../../../bower_components/paper-listbox/paper-listbox.html"> import '@polymer/paper-menu-button/paper-menu-button.js';
<link rel="import" href="../../../bower_components/paper-menu-button/paper-menu-button.html"> import '@polymer/paper-radio-button/paper-radio-button.js';
<link rel="import" href="../../../bower_components/paper-fab/paper-fab.html"> import '@polymer/paper-radio-group/paper-radio-group.js';
<link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../../src/components/entity/ha-entity-picker.html'> import '../../../src/components/entity/ha-entity-picker.js';
<link rel='import' href='../../../src/components/ha-combo-box.html'> import '../../../src/components/ha-combo-box.js';
<link rel='import' href='../../../src/components/ha-markdown.html'> import '../../../src/components/ha-markdown.js';
<link rel='import' href='../../../src/components/ha-service-picker.html'> import '../../../src/components/ha-service-picker.js';
<link rel='import' href='../../../src/layouts/ha-app-layout.html'> import '../../../src/layouts/ha-app-layout.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/util/hass-mixins.js';
import '../ha-config-js.js';
import '../ha-config-section.js';
<link rel="import" href="../ha-config-section.html"> /*
<link rel="import" href="../ha-config-js.html"> * @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
<dom-module id="ha-automation-editor"> */
<template> class HaAutomationEditor extends
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(PolymerElement)) {
static get template() {
return html`
<style include="ha-style"> <style include="ha-style">
.errors { .errors {
padding: 20px; padding: 20px;
@ -83,42 +89,25 @@
} }
</style> </style>
<ha-app-layout has-scrolling-region> <ha-app-layout has-scrolling-region="">
<app-header slot="header" fixed> <app-header slot="header" fixed="">
<app-toolbar> <app-toolbar>
<paper-icon-button <paper-icon-button icon="mdi:arrow-left" on-click="backTapped"></paper-icon-button>
icon='mdi:arrow-left' <div main-title="">[[name]]</div>
on-click='backTapped'
></paper-icon-button>
<div main-title>[[name]]</div>
</app-toolbar> </app-toolbar>
</app-header> </app-header>
<div class='content'> <div class="content">
<template is='dom-if' if='[[errors]]'> <template is="dom-if" if="[[errors]]">
<div class='errors'>[[errors]]</div> <div class="errors">[[errors]]</div>
</template> </template>
<div id='root'></div> <div id="root"></div>
</div> </div>
<paper-fab slot="fab" <paper-fab slot="fab" is-wide\$="[[isWide]]" dirty\$="[[dirty]]" icon="mdi:content-save" title="[[localize('ui.panel.config.automation.editor.save')]]" on-click="saveAutomation"></paper-fab>
is-wide$='[[isWide]]'
dirty$='[[dirty]]'
icon='mdi:content-save'
title="[[localize('ui.panel.config.automation.editor.save')]]"
on-click='saveAutomation'
></paper-fab>
</ha-app-layout> </ha-app-layout>
`;
}
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
*/
class HaAutomationEditor extends
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(Polymer.Element)) {
static get is() { return 'ha-automation-editor'; } static get is() { return 'ha-automation-editor'; }
static get properties() { static get properties() {
@ -296,4 +285,3 @@ class HaAutomationEditor extends
} }
customElements.define(HaAutomationEditor.is, HaAutomationEditor); customElements.define(HaAutomationEditor.is, HaAutomationEditor);
</script>

View File

@ -1,20 +1,26 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/app-layout/app-header/app-header.js';
<link rel="import" href="../../../bower_components/app-layout/app-header/app-header.html"> import '@polymer/app-layout/app-toolbar/app-toolbar.js';
<link rel="import" href="../../../bower_components/app-layout/app-toolbar/app-toolbar.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-fab/paper-fab.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item.html"> import '@polymer/paper-icon-button/paper-icon-button.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item-body.html"> import '@polymer/paper-item/paper-item-body.js';
<link rel="import" href="../../../bower_components/paper-fab/paper-fab.html"> import '@polymer/paper-item/paper-item.js';
<link rel="import" href="../../../bower_components/paper-icon-button/paper-icon-button.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../../src/layouts/ha-app-layout.html'> import '../../../src/components/ha-markdown.js';
<link rel='import' href='../../../src/components/ha-markdown.html'> import '../../../src/layouts/ha-app-layout.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
<link rel="import" href="../ha-config-section.html"> /*
* @appliesMixin window.hassMixins.LocalizeMixin
<dom-module id="ha-automation-picker"> * @appliesMixin window.hassMixins.EventsMixin
<template> */
class HaAutomationPicker extends
window.hassMixins.LocalizeMixin(window.hassMixins.NavigateMixin(PolymerElement)) {
static get template() {
return html`
<style include="ha-style"> <style include="ha-style">
:host { :host {
display: block; display: block;
@ -45,61 +51,43 @@
} }
</style> </style>
<ha-app-layout has-scrolling-region> <ha-app-layout has-scrolling-region="">
<app-header slot="header" fixed> <app-header slot="header" fixed="">
<app-toolbar> <app-toolbar>
<paper-icon-button <paper-icon-button icon="mdi:arrow-left" on-click="_backTapped"></paper-icon-button>
icon='mdi:arrow-left' <div main-title="">[[localize('ui.panel.config.automation.caption')]]</div>
on-click='_backTapped'
></paper-icon-button>
<div main-title>[[localize('ui.panel.config.automation.caption')]]</div>
</app-toolbar> </app-toolbar>
</app-header> </app-header>
<ha-config-section <ha-config-section is-wide="[[isWide]]">
is-wide='[[isWide]]' <div slot="header">[[localize('ui.panel.config.automation.picker.header')]]</div>
> <div slot="introduction">
<div slot='header'>[[localize('ui.panel.config.automation.picker.header')]]</div>
<div slot='introduction'>
<ha-markdown content="[[localize('ui.panel.config.automation.picker.introduction')]]"></ha-markdown> <ha-markdown content="[[localize('ui.panel.config.automation.picker.introduction')]]"></ha-markdown>
</div> </div>
<paper-card heading="[[localize('ui.panel.config.automation.picker.pick_automation')]]"> <paper-card heading="[[localize('ui.panel.config.automation.picker.pick_automation')]]">
<template is='dom-if' if='[[!automations.length]]'> <template is="dom-if" if="[[!automations.length]]">
<div class='card-content'> <div class="card-content">
<p>[[localize('ui.panel.config.automation.picker.no_automations')]]</p> <p>[[localize('ui.panel.config.automation.picker.no_automations')]]</p>
</div> </div>
</template> </template>
<template is='dom-repeat' items='[[automations]]' as='automation'> <template is="dom-repeat" items="[[automations]]" as="automation">
<paper-item> <paper-item>
<paper-item-body two-line on-click='automationTapped'> <paper-item-body two-line="" on-click="automationTapped">
<div>[[computeName(automation)]]</div> <div>[[computeName(automation)]]</div>
<div secondary>[[computeDescription(automation)]]</div> <div secondary="">[[computeDescription(automation)]]</div>
</paper-item-body> </paper-item-body>
<iron-icon icon='mdi:chevron-right'></iron-icon> <iron-icon icon="mdi:chevron-right"></iron-icon>
</paper-item> </paper-item>
</template> </template>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
<paper-fab slot="fab" <paper-fab slot="fab" is-wide\$="[[isWide]]" icon="mdi:plus" title="[[localize('ui.panel.config.automation.picker.add_automation')]]" on-click="addAutomation"></paper-fab>
is-wide$='[[isWide]]'
icon='mdi:plus'
title="[[localize('ui.panel.config.automation.picker.add_automation')]]"
on-click='addAutomation'
></paper-fab>
</ha-app-layout> </ha-app-layout>
`;
}
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
*/
class HaAutomationPicker extends
window.hassMixins.LocalizeMixin(window.hassMixins.NavigateMixin(Polymer.Element)) {
static get is() { return 'ha-automation-picker'; } static get is() { return 'ha-automation-picker'; }
static get properties() { static get properties() {
@ -151,4 +139,3 @@ class HaAutomationPicker extends
} }
customElements.define(HaAutomationPicker.is, HaAutomationPicker); customElements.define(HaAutomationPicker.is, HaAutomationPicker);
</script>

View File

@ -1,52 +1,32 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/app-route/app-route.js';
<link rel='import' href='../../../bower_components/app-route/app-route.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="./ha-automation-picker.html"> import './ha-automation-editor.js';
<link rel="import" href="./ha-automation-editor.html"> import './ha-automation-picker.js';
<dom-module id="ha-config-automation"> class HaConfigAutomation extends PolymerElement {
<template> static get template() {
return html`
<style> <style>
ha-automation-picker, ha-automation-picker,
ha-automation-editor { ha-automation-editor {
height: 100%; height: 100%;
} }
</style> </style>
<app-route <app-route route="[[route]]" pattern="/automation/edit/:automation" data="{{_routeData}}" active="{{_edittingAutomation}}"></app-route>
route='[[route]]' <app-route route="[[route]]" pattern="/automation/new" active="{{_creatingNew}}"></app-route>
pattern='/automation/edit/:automation'
data="{{_routeData}}"
active="{{_edittingAutomation}}"
></app-route>
<app-route
route='[[route]]'
pattern='/automation/new'
active="{{_creatingNew}}"
></app-route>
<template is='dom-if' if='[[!showEditor]]'> <template is="dom-if" if="[[!showEditor]]">
<ha-automation-picker <ha-automation-picker hass="[[hass]]" narrow="[[narrow]]" show-menu="[[showMenu]]" automations="[[automations]]" is-wide="[[isWide]]"></ha-automation-picker>
hass='[[hass]]'
narrow='[[narrow]]'
show-menu='[[showMenu]]'
automations='[[automations]]'
is-wide='[[isWide]]'
></ha-automation-picker>
</template> </template>
<template is='dom-if' if='[[showEditor]]' restamp> <template is="dom-if" if="[[showEditor]]" restamp="">
<ha-automation-editor <ha-automation-editor hass="[[hass]]" automation="[[automation]]" is-wide="[[isWide]]" creating-new="[[_creatingNew]]"></ha-automation-editor>
hass='[[hass]]'
automation='[[automation]]'
is-wide='[[isWide]]'
creating-new='[[_creatingNew]]'
></ha-automation-editor>
</template> </template>
</template> `;
</dom-module> }
<script>
class HaConfigAutomation extends Polymer.Element {
static get is() { return 'ha-config-automation'; } static get is() { return 'ha-config-automation'; }
static get properties() { static get properties() {
@ -124,4 +104,3 @@ class HaConfigAutomation extends Polymer.Element {
} }
customElements.define(HaConfigAutomation.is, HaConfigAutomation); customElements.define(HaConfigAutomation.is, HaConfigAutomation);
</script>

View File

@ -1,17 +1,18 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.html'> import '@polymer/paper-button/paper-button.js';
<link rel="import" href='../../../bower_components/paper-card/paper-card.html'> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item-body.html"> import '@polymer/paper-item/paper-item-body.js';
<link rel="import" href='../../../bower_components/paper-button/paper-button.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/layouts/hass-subpage.html"> import '../../../src/components/buttons/ha-call-api-button.js';
<link rel="import" href="../../../src/util/hass-mixins.html"> import '../../../src/layouts/hass-subpage.js';
<link rel="import" href='../../../src/resources/ha-style.html'> import '../../../src/resources/ha-style.js';
<link rel="import" href='../../../src/components/buttons/ha-call-api-button.html'> import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
<link rel="import" href="../ha-config-section.html"> class HaConfigCloudAccount extends window.hassMixins.EventsMixin(PolymerElement) {
static get template() {
<dom-module id="ha-config-cloud-account"> return html`
<template>
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
padding-bottom: 24px; padding-bottom: 24px;
@ -49,59 +50,53 @@
color: var(--primary-color); color: var(--primary-color);
} }
</style> </style>
<hass-subpage header='Cloud Account'> <hass-subpage header="Cloud Account">
<div class='content'> <div class="content">
<ha-config-section <ha-config-section is-wide="[[isWide]]">
is-wide='[[isWide]]' <span slot="header">Home Assistant Cloud</span>
> <span slot="introduction">
<span slot='header'>Home Assistant Cloud</span>
<span slot='introduction'>
Thank you for supporting Home Assistant. It's because of people like you that we are able to run this project and make a great home automation experience for everyone. Thank you! Thank you for supporting Home Assistant. It's because of people like you that we are able to run this project and make a great home automation experience for everyone. Thank you!
</span> </span>
<paper-card heading='Account'> <paper-card heading="Account">
<div class='account-row'> <div class="account-row">
<paper-item-body two-line> <paper-item-body two-line="">
[[account.email]] [[account.email]]
<div secondary class='wrap'> <div secondary="" class="wrap">
<span class='nowrap'>Subscription expires on </span> <span class="nowrap">Subscription expires on </span>
<span class='nowrap'>[[_formatExpiration(account.sub_exp)]]</span> <span class="nowrap">[[_formatExpiration(account.sub_exp)]]</span>
</div> </div>
</paper-item-body> </paper-item-body>
<paper-button <paper-button on-click="handleLogout">Sign out</paper-button>
on-click='handleLogout'
>Sign out</paper-button>
</div> </div>
<div class='account-row'> <div class="account-row">
<paper-item-body> <paper-item-body>
Cloud connection status Cloud connection status
</paper-item-body> </paper-item-body>
<div class='status'>[[account.cloud]]</div> <div class="status">[[account.cloud]]</div>
</div> </div>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
<ha-config-section <ha-config-section is-wide="[[isWide]]">
is-wide='[[isWide]]' <span slot="header">Integrations</span>
> <span slot="introduction">
<span slot='header'>Integrations</span>
<span slot='introduction'>
Integrations for Home Assistant Cloud allow you to connect with services in the cloud Integrations for Home Assistant Cloud allow you to connect with services in the cloud
without having to expose your Home Assistant instance publicly on the internet. without having to expose your Home Assistant instance publicly on the internet.
</span> </span>
<paper-card heading='Alexa'> <paper-card heading="Alexa">
<div class="card-content"> <div class="card-content">
With the Alexa integration for Home Assistant Cloud you'll be able to control all your Home Assistant devices via any Alexa-enabled device. With the Alexa integration for Home Assistant Cloud you'll be able to control all your Home Assistant devices via any Alexa-enabled device.
<ul> <ul>
<li> <li>
<a href='https://alexa.amazon.com/spa/index.html#skills/dp/B0772J1QKB/?ref=skill_dsk_skb_sr_2' target='_blank'> <a href="https://alexa.amazon.com/spa/index.html#skills/dp/B0772J1QKB/?ref=skill_dsk_skb_sr_2" target="_blank">
Activate the Home Assistant skill for Alexa Activate the Home Assistant skill for Alexa
</a> </a>
</li> </li>
<li> <li>
<a href='https://www.home-assistant.io/cloud/alexa/' target='_blank'> <a href="https://www.home-assistant.io/cloud/alexa/" target="_blank">
Config documentation Config documentation
</a> </a>
</li> </li>
@ -110,38 +105,33 @@
</div> </div>
</paper-card> </paper-card>
<paper-card heading='Google Assistant'> <paper-card heading="Google Assistant">
<div class="card-content"> <div class="card-content">
With the Google Assistant integration for Home Assistant Cloud you'll be able to control all your Home Assistant devices via any Google Assistant-enabled device. With the Google Assistant integration for Home Assistant Cloud you'll be able to control all your Home Assistant devices via any Google Assistant-enabled device.
<ul> <ul>
<li> <li>
<a href='https://assistant.google.com/services/a/uid/00000091fd5fb875' target='_blank'> <a href="https://assistant.google.com/services/a/uid/00000091fd5fb875" target="_blank">
Activate the Home Assistant skill for Google Assistant Activate the Home Assistant skill for Google Assistant
</a> </a>
</li> </li>
<li> <li>
<a href='https://www.home-assistant.io/cloud/google_assistant/' target='_blank'> <a href="https://www.home-assistant.io/cloud/google_assistant/" target="_blank">
Config documentation Config documentation
</a> </a>
</li> </li>
</ul> </ul>
<p><em>This integration requires a Google Assistant-enabled device like the Google Home or Android phone.</em></p> <p><em>This integration requires a Google Assistant-enabled device like the Google Home or Android phone.</em></p>
</div> </div>
<div class='card-actions'> <div class="card-actions">
<ha-call-api-button <ha-call-api-button hass="[[hass]]" path="cloud/google_actions/sync">Sync devices</ha-call-api-button>
hass='[[hass]]'
path='cloud/google_actions/sync'
>Sync devices</ha-call-api-button>
</div> </div>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
</div> </div>
</hass-subpage> </hass-subpage>
</template> `;
</dom-module> }
<script>
class HaConfigCloudAccount extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'ha-config-cloud-account'; } static get is() { return 'ha-config-cloud-account'; }
static get properties() { static get properties() {
@ -182,4 +172,3 @@ class HaConfigCloudAccount extends window.hassMixins.EventsMixin(Polymer.Element
} }
customElements.define(HaConfigCloudAccount.is, HaConfigCloudAccount); customElements.define(HaConfigCloudAccount.is, HaConfigCloudAccount);
</script>

View File

@ -1,14 +1,16 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.html'> import '@polymer/paper-card/paper-card.js';
<link rel="import" href='../../../bower_components/paper-card/paper-card.html'> import '@polymer/paper-input/paper-input.js';
<link rel="import" href='../../../bower_components/paper-input/paper-input.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/layouts/hass-subpage.html"> import '../../../src/components/buttons/ha-progress-button.js';
<link rel="import" href="../../../src/util/hass-mixins.html"> import '../../../src/layouts/hass-subpage.js';
<link rel="import" href='../../../src/resources/ha-style.html'> import '../../../src/resources/ha-style.js';
<link rel="import" href='../../../src/components/buttons/ha-progress-button.html'> import '../../../src/util/hass-mixins.js';
<dom-module id="ha-config-cloud-forgot-password"> class HaConfigCloudForgotPassword extends window.hassMixins.EventsMixin(PolymerElement) {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
padding-bottom: 24px; padding-bottom: 24px;
@ -40,38 +42,25 @@
} }
</style> </style>
<hass-subpage header="Forgot Password"> <hass-subpage header="Forgot Password">
<div class='content'> <div class="content">
<paper-card> <paper-card>
<div class='card-content'> <div class="card-content">
<h1>Forgot your password?</h1> <h1>Forgot your password?</h1>
<p> <p>
Enter your email address and we will send you a link to reset your password. Enter your email address and we will send you a link to reset your password.
</p> </p>
<div class='error' hidden$='[[!_error]]'>[[_error]]</div> <div class="error" hidden\$="[[!_error]]">[[_error]]</div>
<paper-input <paper-input autofocus="" id="email" label="E-mail" value="{{email}}" type="email" on-keydown="_keyDown" error-message="Invalid email"></paper-input>
autofocus
id='email'
label='E-mail'
value='{{email}}'
type='email'
on-keydown='_keyDown'
error-message='Invalid email'
></paper-input>
</div> </div>
<div class='card-actions'> <div class="card-actions">
<ha-progress-button <ha-progress-button on-click="_handleEmailPasswordReset" progress="[[_requestInProgress]]">Send reset email</ha-progress-button>
on-click='_handleEmailPasswordReset'
progress='[[_requestInProgress]]'
>Send reset email</ha-progress-button>
</div> </div>
</paper-card> </paper-card>
</div> </div>
</hass-subpage> </hass-subpage>
</template> `;
</dom-module> }
<script>
class HaConfigCloudForgotPassword extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'ha-config-cloud-forgot-password'; } static get is() { return 'ha-config-cloud-forgot-password'; }
static get properties() { static get properties() {
@ -131,4 +120,3 @@ class HaConfigCloudForgotPassword extends window.hassMixins.EventsMixin(Polymer.
} }
customElements.define(HaConfigCloudForgotPassword.is, HaConfigCloudForgotPassword); customElements.define(HaConfigCloudForgotPassword.is, HaConfigCloudForgotPassword);
</script>

View File

@ -1,21 +1,23 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.html'> import '@polymer/paper-button/paper-button.js';
<link rel="import" href='../../../bower_components/paper-card/paper-card.html'> import '@polymer/paper-card/paper-card.js';
<link rel="import" href='../../../bower_components/paper-button/paper-button.html'> import '@polymer/paper-icon-button/paper-icon-button.js';
<link rel="import" href='../../../bower_components/paper-icon-button/paper-icon-button.html'> import '@polymer/paper-input/paper-input.js';
<link rel="import" href='../../../bower_components/paper-input/paper-input.html'> import '@polymer/paper-item/paper-item-body.js';
<link rel="import" href='../../../bower_components/paper-ripple/paper-ripple.html'> import '@polymer/paper-item/paper-item.js';
<link rel="import" href='../../../bower_components/paper-item/paper-item.html'> import '@polymer/paper-ripple/paper-ripple.js';
<link rel="import" href='../../../bower_components/paper-item/paper-item-body.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/layouts/hass-subpage.html"> import '../../../src/components/buttons/ha-progress-button.js';
<link rel="import" href="../../../src/util/hass-mixins.html"> import '../../../src/layouts/hass-subpage.js';
<link rel="import" href='../../../src/resources/ha-style.html'> import '../../../src/resources/ha-style.js';
<link rel="import" href='../../../src/components/buttons/ha-progress-button.html'> import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
<link rel="import" href="../ha-config-section.html"> class HaConfigCloudLogin extends
window.hassMixins.NavigateMixin(window.hassMixins.EventsMixin(PolymerElement)) {
<dom-module id="ha-config-cloud-login"> static get template() {
<template> return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
padding-bottom: 24px; padding-bottom: 24px;
@ -57,80 +59,51 @@
color: var(--secondary-text-color); color: var(--secondary-text-color);
} }
</style> </style>
<hass-subpage header='Cloud Login'> <hass-subpage header="Cloud Login">
<div class='content'> <div class="content">
<ha-config-section <ha-config-section is-wide="[[isWide]]">
is-wide='[[isWide]]' <span slot="header">Home Assistant Cloud</span>
> <span slot="introduction">
<span slot='header'>Home Assistant Cloud</span>
<span slot='introduction'>
The Home Assistant Cloud allows your local Home Assistant instance to connect with cloud-only services like Amazon Alexa. The Home Assistant Cloud allows your local Home Assistant instance to connect with cloud-only services like Amazon Alexa.
<p><a href='https://www.home-assistant.io/components/cloud/' target='_blank'>Learn more</a></p> <p><a href="https://www.home-assistant.io/components/cloud/" target="_blank">Learn more</a></p>
</span> </span>
<paper-card hidden$='[[!flashMessage]]'> <paper-card hidden\$="[[!flashMessage]]">
<div class='card-content flash-msg'> <div class="card-content flash-msg">
[[flashMessage]] [[flashMessage]]
<paper-icon-button <paper-icon-button icon="mdi:close" on-click="_dismissFlash">Dismiss</paper-icon-button>
icon='mdi:close' <paper-ripple id="flashRipple" noink=""></paper-ripple>
on-click='_dismissFlash'
>Dismiss</paper-icon-button>
<paper-ripple id='flashRipple' noink></paper-ripple>
</div> </div>
</paper-card> </paper-card>
<paper-card> <paper-card>
<div class='card-content'> <div class="card-content">
<h1>Sign In</h1> <h1>Sign In</h1>
<div class='error' hidden$='[[!_error]]'>[[_error]]</div> <div class="error" hidden\$="[[!_error]]">[[_error]]</div>
<paper-input <paper-input label="Email" id="email" type="email" value="{{email}}" on-keydown="_keyDown" error-message="Invalid email"></paper-input>
label='Email' <paper-input id="password" label="Password" value="{{_password}}" type="password" on-keydown="_keyDown" error-message="Passwords are at least 8 characters"></paper-input>
id='email'
type='email'
value='{{email}}'
on-keydown='_keyDown'
error-message='Invalid email'
></paper-input>
<paper-input
id='password'
label='Password'
value='{{_password}}'
type='password'
on-keydown='_keyDown'
error-message='Passwords are at least 8 characters'
></paper-input>
</div> </div>
<div class='card-actions'> <div class="card-actions">
<ha-progress-button <ha-progress-button on-click="_handleLogin" progress="[[_requestInProgress]]">Sign in</ha-progress-button>
on-click='_handleLogin' <button class="link" hidden="[[_requestInProgress]]" on-click="_handleForgotPassword">forgot password?</button>
progress='[[_requestInProgress]]'
>Sign in</ha-progress-button>
<button
class='link'
hidden='[[_requestInProgress]]'
on-click='_handleForgotPassword'
>forgot password?</button>
</div> </div>
</paper-card> </paper-card>
<paper-card> <paper-card>
<paper-item on-click='_handleRegister'> <paper-item on-click="_handleRegister">
<paper-item-body two-line> <paper-item-body two-line="">
Create Account Create Account
<div secondary>Get up and running quickly.</div> <div secondary="">Get up and running quickly.</div>
</paper-item-body> </paper-item-body>
<iron-icon icon='mdi:chevron-right'></iron-icon> <iron-icon icon="mdi:chevron-right"></iron-icon>
</paper-item> </paper-item>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
</div> </div>
</hass-subpage> </hass-subpage>
</template> `;
</dom-module> }
<script>
class HaConfigCloudLogin extends
window.hassMixins.NavigateMixin(window.hassMixins.EventsMixin(Polymer.Element)) {
static get is() { return 'ha-config-cloud-login'; } static get is() { return 'ha-config-cloud-login'; }
static get properties() { static get properties() {
@ -260,4 +233,3 @@ class HaConfigCloudLogin extends
} }
customElements.define(HaConfigCloudLogin.is, HaConfigCloudLogin); customElements.define(HaConfigCloudLogin.is, HaConfigCloudLogin);
</script>

View File

@ -1,16 +1,17 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.html'> import '@polymer/paper-card/paper-card.js';
<link rel="import" href='../../../bower_components/paper-card/paper-card.html'> import '@polymer/paper-input/paper-input.js';
<link rel="import" href='../../../bower_components/paper-input/paper-input.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/layouts/hass-subpage.html"> import '../../../src/components/buttons/ha-progress-button.js';
<link rel="import" href="../../../src/util/hass-mixins.html"> import '../../../src/layouts/hass-subpage.js';
<link rel="import" href='../../../src/resources/ha-style.html'> import '../../../src/resources/ha-style.js';
<link rel="import" href='../../../src/components/buttons/ha-progress-button.html'> import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
<link rel="import" href="../ha-config-section.html"> class HaConfigCloudRegister extends window.hassMixins.EventsMixin(PolymerElement) {
static get template() {
<dom-module id="ha-config-cloud-register"> return html`
<template>
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
a { a {
color: var(--primary-color); color: var(--primary-color);
@ -41,67 +42,41 @@
} }
</style> </style>
<hass-subpage header="Register Account"> <hass-subpage header="Register Account">
<div class='content'> <div class="content">
<ha-config-section <ha-config-section is-wide="[[isWide]]">
is-wide='[[isWide]]' <span slot="header">Register with the Home Assistant Cloud</span>
> <span slot="introduction">
<span slot='header'>Register with the Home Assistant Cloud</span>
<span slot='introduction'>
Register today to easily connect with the Home Assistant Cloud. This will allow you to unlock great new services and functionality, like Amazon Alexa integration. Register today to easily connect with the Home Assistant Cloud. This will allow you to unlock great new services and functionality, like Amazon Alexa integration.
<p> <p>
By registering an account you agree to the following terms and conditions. By registering an account you agree to the following terms and conditions.
<ul> </p><ul>
<li><a href='https://home-assistant.io/tos/' target='_blank'>Terms and Conditions</a></li> <li><a href="https://home-assistant.io/tos/" target="_blank">Terms and Conditions</a></li>
<li><a href='https://home-assistant.io/privacy/' target='_blank'>Privacy Policy</a></li> <li><a href="https://home-assistant.io/privacy/" target="_blank">Privacy Policy</a></li>
</ul> </ul>
</p> <p></p>
</span> </span>
<paper-card> <paper-card>
<div class='card-content'> <div class="card-content">
<div class='header'> <div class="header">
<h1>Register</h1> <h1>Register</h1>
<div class='error' hidden$='[[!_error]]'>[[_error]]</div> <div class="error" hidden\$="[[!_error]]">[[_error]]</div>
</div> </div>
<paper-input <paper-input autofocus="" id="email" label="Email address" type="email" value="{{email}}" on-keydown="_keyDown" error-message="Invalid email"></paper-input>
autofocus <paper-input id="password" label="Password" value="{{_password}}" type="password" on-keydown="_keyDown" error-message="Your password needs to be at least 8 characters"></paper-input>
id='email'
label='Email address'
type='email'
value='{{email}}'
on-keydown='_keyDown'
error-message='Invalid email'
></paper-input>
<paper-input
id='password'
label='Password'
value='{{_password}}'
type='password'
on-keydown='_keyDown'
error-message='Your password needs to be at least 8 characters'
></paper-input>
</div> </div>
<div class='card-actions'> <div class="card-actions">
<ha-progress-button <ha-progress-button on-click="_handleRegister" progress="[[_requestInProgress]]">Create Account</ha-progress-button>
on-click='_handleRegister' <button class="link" hidden="[[_requestInProgress]]" on-click="_handleResendVerifyEmail">Resend confirmation email</button>
progress='[[_requestInProgress]]'
>Create Account</ha-progress-button>
<button
class='link'
hidden='[[_requestInProgress]]'
on-click='_handleResendVerifyEmail'
>Resend confirmation email</button>
</div> </div>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
</div> </div>
</hass-subpage> </hass-subpage>
</template> `;
</dom-module> }
<script>
class HaConfigCloudRegister extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'ha-config-cloud-register'; } static get is() { return 'ha-config-cloud-register'; }
static get properties() { static get properties() {
@ -209,4 +184,3 @@ class HaConfigCloudRegister extends window.hassMixins.EventsMixin(Polymer.Elemen
} }
customElements.define(HaConfigCloudRegister.is, HaConfigCloudRegister); customElements.define(HaConfigCloudRegister.is, HaConfigCloudRegister);
</script>

View File

@ -1,133 +0,0 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.html'>
<link rel='import' href='../../../bower_components/app-route/app-route.html'>
<link rel='import' href='../../../src/util/hass-mixins.html'>
<link rel="import" href="../ha-config-section.html">
<link rel="import" href="./ha-config-cloud-login.html">
<link rel="import" href="./ha-config-cloud-register.html">
<link rel="import" href="./ha-config-cloud-forgot-password.html">
<link rel="import" href="./ha-config-cloud-account.html">
<dom-module id="ha-config-cloud">
<template>
<app-route
route='[[route]]'
pattern='/cloud/:page'
data="{{_routeData}}"
tail="{{_routeTail}}"
></app-route>
<template is='dom-if' if='[[_equals(_routeData.page, "account")]]' restamp>
<ha-config-cloud-account
hass='[[hass]]'
account='[[account]]'
is-wide='[[isWide]]'
></ha-config-cloud-account>
</template>
<template is='dom-if' if='[[_equals(_routeData.page, "login")]]' restamp>
<ha-config-cloud-login
page-name='login'
hass='[[hass]]'
is-wide='[[isWide]]'
email='{{_loginEmail}}'
flash-message='{{_flashMessage}}'
></ha-config-cloud-login>
</template>
<template is='dom-if' if='[[_equals(_routeData.page, "register")]]' restamp>
<ha-config-cloud-register
page-name='register'
hass='[[hass]]'
is-wide='[[isWide]]'
email='{{_loginEmail}}'
></ha-config-cloud-register>
</template>
<template is='dom-if' if='[[_equals(_routeData.page, "forgot-password")]]' restamp>
<ha-config-cloud-forgot-password
page-name='forgot-password'
hass='[[hass]]'
email='{{_loginEmail}}'
></ha-config-cloud-forgot-password>
</template>
</template>
</dom-module>
<script>
{
const LOGGED_IN_URLS = [
'/cloud/account',
];
const NOT_LOGGED_IN_URLS = [
'/cloud/login',
'/cloud/register',
'/cloud/forgot-password',
];
class HaConfigCloud extends window.hassMixins.NavigateMixin(Polymer.Element) {
static get is() { return 'ha-config-cloud'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
loadingAccount: {
type: Boolean,
value: false
},
account: {
type: Object,
},
_flashMessage: {
type: String,
value: '',
},
route: Object,
_routeData: Object,
_routeTail: Object,
_loginEmail: String,
};
}
static get observers() {
return [
'_checkRoute(route, account)'
];
}
ready() {
super.ready();
this.addEventListener('cloud-done', (ev) => {
this._flashMessage = ev.detail.flashMessage;
this.navigate('/config/cloud/login');
});
}
_checkRoute(route) {
if (!route || route.path.substr(0, 6) !== '/cloud') return;
this._debouncer = Polymer.Debouncer.debounce(
this._debouncer,
Polymer.Async.timeOut.after(0),
() => {
if (!this.account && !NOT_LOGGED_IN_URLS.includes(route.path)) {
this.navigate('/config/cloud/login', true);
} else if (this.account && !LOGGED_IN_URLS.includes(route.path)) {
this.navigate('/config/cloud/account', true);
}
}
);
}
_equals(a, b) {
return a === b;
}
}
customElements.define(HaConfigCloud.is, HaConfigCloud);
}
</script>

View File

@ -0,0 +1,109 @@
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 '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
import './ha-config-cloud-account.js';
import './ha-config-cloud-forgot-password.js';
import './ha-config-cloud-login.js';
import './ha-config-cloud-register.js';
{
const LOGGED_IN_URLS = [
'/cloud/account',
];
const NOT_LOGGED_IN_URLS = [
'/cloud/login',
'/cloud/register',
'/cloud/forgot-password',
];
class HaConfigCloud extends window.hassMixins.NavigateMixin(PolymerElement) {
static get template() {
return html`
<app-route route="[[route]]" pattern="/cloud/:page" data="{{_routeData}}" tail="{{_routeTail}}"></app-route>
<template is="dom-if" if="[[_equals(_routeData.page, &quot;account&quot;)]]" restamp="">
<ha-config-cloud-account hass="[[hass]]" account="[[account]]" is-wide="[[isWide]]"></ha-config-cloud-account>
</template>
<template is="dom-if" if="[[_equals(_routeData.page, &quot;login&quot;)]]" restamp="">
<ha-config-cloud-login page-name="login" hass="[[hass]]" is-wide="[[isWide]]" email="{{_loginEmail}}" flash-message="{{_flashMessage}}"></ha-config-cloud-login>
</template>
<template is="dom-if" if="[[_equals(_routeData.page, &quot;register&quot;)]]" restamp="">
<ha-config-cloud-register page-name="register" hass="[[hass]]" is-wide="[[isWide]]" email="{{_loginEmail}}"></ha-config-cloud-register>
</template>
<template is="dom-if" if="[[_equals(_routeData.page, &quot;forgot-password&quot;)]]" restamp="">
<ha-config-cloud-forgot-password page-name="forgot-password" hass="[[hass]]" email="{{_loginEmail}}"></ha-config-cloud-forgot-password>
</template>
`;
}
static get is() { return 'ha-config-cloud'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
loadingAccount: {
type: Boolean,
value: false
},
account: {
type: Object,
},
_flashMessage: {
type: String,
value: '',
},
route: Object,
_routeData: Object,
_routeTail: Object,
_loginEmail: String,
};
}
static get observers() {
return [
'_checkRoute(route, account)'
];
}
ready() {
super.ready();
this.addEventListener('cloud-done', (ev) => {
this._flashMessage = ev.detail.flashMessage;
this.navigate('/config/cloud/login');
});
}
_checkRoute(route) {
if (!route || route.path.substr(0, 6) !== '/cloud') return;
this._debouncer = Debouncer.debounce(
this._debouncer,
timeOut.after(0),
() => {
if (!this.account && !NOT_LOGGED_IN_URLS.includes(route.path)) {
this.navigate('/config/cloud/login', true);
} else if (this.account && !LOGGED_IN_URLS.includes(route.path)) {
this.navigate('/config/cloud/account', true);
}
}
);
}
_equals(a, b) {
return a === b;
}
}
customElements.define(HaConfigCloud.is, HaConfigCloud);
}

View File

@ -1,20 +1,26 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.html'> import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
<link rel='import' href='../../../bower_components/paper-button/paper-button.html'> import '@polymer/paper-button/paper-button.js';
<link rel='import' href='../../../bower_components/paper-card/paper-card.html'> import '@polymer/paper-card/paper-card.js';
<link rel='import' href='../../../bower_components/paper-item/paper-item-body.html'> import '@polymer/paper-item/paper-item-body.js';
<link rel='import' href='../../../bower_components/iron-flex-layout/iron-flex-layout-classes.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/layouts/hass-subpage.js';
<link rel='import' href='../../../src/resources/ha-style.html'> import '../../../src/resources/ha-style.js';
<link rel='import' href='../../../src/layouts/hass-subpage.html'> import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
import './ha-config-flow.js';
<link rel='import' href='../ha-config-section.html'> {
/*
<link rel='import' href='./ha-config-flow.html'> * @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
<dom-module id="ha-config-entries"> */
<template> class HaConfigManager extends
<style include='iron-flex ha-style'> window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(PolymerElement)) {
static get template() {
return html`
<style include="iron-flex ha-style">
paper-button { paper-button {
color: var(--primary-color); color: var(--primary-color);
font-weight: 500; font-weight: 500;
@ -30,79 +36,66 @@
} }
</style> </style>
<hass-subpage header='Integrations'> <hass-subpage header="Integrations">
<template is='dom-if' if='[[_progress.length]]'> <template is="dom-if" if="[[_progress.length]]">
<ha-config-section is-wide='[[isWide]]'> <ha-config-section is-wide="[[isWide]]">
<span slot='header'>In Progress</span> <span slot="header">In Progress</span>
<paper-card> <paper-card>
<template is='dom-repeat' items='[[_progress]]'> <template is="dom-repeat" items="[[_progress]]">
<div class='config-entry-row'> <div class="config-entry-row">
<paper-item-body> <paper-item-body>
[[_computeIntegrationTitle(localize, item.handler)]] [[_computeIntegrationTitle(localize, item.handler)]]
</paper-item-body> </paper-item-body>
<paper-button on-click='_continueFlow'>Configure</paper-button> <paper-button on-click="_continueFlow">Configure</paper-button>
</div> </div>
</template> </template>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
</template> </template>
<ha-config-section is-wide='[[isWide]]'> <ha-config-section is-wide="[[isWide]]">
<span slot='header'>Configured</span> <span slot="header">Configured</span>
<paper-card> <paper-card>
<template is='dom-if' if='[[!_entries.length]]'> <template is="dom-if" if="[[!_entries.length]]">
<div class='config-entry-row'> <div class="config-entry-row">
<paper-item-body> <paper-item-body>
Nothing configured yet Nothing configured yet
</paper-item-body> </paper-item-body>
</div> </div>
</template> </template>
<template is='dom-repeat' items='[[_entries]]'> <template is="dom-repeat" items="[[_entries]]">
<div class='config-entry-row'> <div class="config-entry-row">
<paper-item-body three-line> <paper-item-body three-line="">
[[item.title]] [[item.title]]
<div secondary>Integration: [[_computeIntegrationTitle(localize, item.domain)]]</div> <div secondary="">Integration: [[_computeIntegrationTitle(localize, item.domain)]]</div>
<div secondary>Added by: [[item.source]]</div> <div secondary="">Added by: [[item.source]]</div>
<div secondary>State: [[item.state]]</div> <div secondary="">State: [[item.state]]</div>
</paper-item-body> </paper-item-body>
<paper-button on-click='_removeEntry'>Remove</paper-button> <paper-button on-click="_removeEntry">Remove</paper-button>
</div> </div>
</template> </template>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
<ha-config-section is-wide='[[isWide]]'> <ha-config-section is-wide="[[isWide]]">
<span slot='header'>Available</span> <span slot="header">Available</span>
<paper-card> <paper-card>
<template is='dom-repeat' items='[[_handlers]]'> <template is="dom-repeat" items="[[_handlers]]">
<div class='config-entry-row'> <div class="config-entry-row">
<paper-item-body> <paper-item-body>
[[_computeIntegrationTitle(localize, item)]] [[_computeIntegrationTitle(localize, item)]]
</paper-item-body> </paper-item-body>
<paper-button on-click='_createFlow'>Configure</paper-button> <paper-button on-click="_createFlow">Configure</paper-button>
</div> </div>
</template> </template>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
</hass-subpage> </hass-subpage>
<ha-config-flow <ha-config-flow hass="[[hass]]" flow-id="[[_flowId]]" step="{{_flowStep}}" on-flow-closed="_flowClose"></ha-config-flow>
hass='[[hass]]' `;
flow-id='[[_flowId]]' }
step='{{_flowStep}}'
on-flow-closed='_flowClose'
></ha-config-flow>
</template>
</dom-module>
<script>
{
/*
* @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
*/
class HaConfigManager extends
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(Polymer.Element)) {
static get is() { return 'ha-config-entries'; } static get is() { return 'ha-config-entries'; }
static get properties() { static get properties() {
@ -209,4 +202,3 @@
customElements.define(HaConfigManager.is, HaConfigManager); customElements.define(HaConfigManager.is, HaConfigManager);
} }
</script>

View File

@ -1,16 +1,23 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.html'> import '@polymer/paper-button/paper-button.js';
<link rel='import' href='../../../bower_components/paper-dialog/paper-dialog.html'> import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
<link rel='import' href='../../../bower_components/paper-dialog-scrollable/paper-dialog-scrollable.html'> import '@polymer/paper-dialog/paper-dialog.js';
<link rel="import" href='../../../bower_components/paper-button/paper-button.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/components/ha-form.js';
<link rel="import" href='../../../src/components/ha-markdown.html'> import '../../../src/components/ha-markdown.js';
<link rel='import' href='../../../src/resources/ha-style.html'> import '../../../src/resources/ha-style.js';
<link rel="import" href='../../../src/components/ha-form.html'> import '../../../src/util/hass-mixins.js';
<dom-module id="ha-config-flow"> /*
<template> * @appliesMixin window.hassMixins.LocalizeMixin
<style include='ha-style-dialog'> * @appliesMixin window.hassMixins.EventsMixin
*/
class HaConfigFlow extends
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(PolymerElement)) {
static get template() {
return html`
<style include="ha-style-dialog">
.error { .error {
color: red; color: red;
} }
@ -22,73 +29,55 @@
margin: 0 auto; margin: 0 auto;
} }
</style> </style>
<paper-dialog <paper-dialog id="dialog" with-backdrop="" opened="[[step]]" on-opened-changed="_openedChanged">
id='dialog'
with-backdrop
opened='[[step]]'
on-opened-changed='_openedChanged'
>
<h2> <h2>
<template is='dom-if' if='[[_equals(step.type, "abort")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;abort&quot;)]]">
Aborted Aborted
</template> </template>
<template is='dom-if' if='[[_equals(step.type, "create_entry")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;create_entry&quot;)]]">
Success! Success!
</template> </template>
<template is='dom-if' if='[[_equals(step.type, "form")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;form&quot;)]]">
[[_computeStepTitle(localize, step)]] [[_computeStepTitle(localize, step)]]
</template> </template>
</h2> </h2>
<paper-dialog-scrollable> <paper-dialog-scrollable>
<template is='dom-if' if='[[!step]]'> <template is="dom-if" if="[[!step]]">
Loading flow. Loading flow.
</template> </template>
<template is='dom-if' if='[[step]]'> <template is="dom-if" if="[[step]]">
<template is='dom-if' if='[[_equals(step.type, "abort")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;abort&quot;)]]">
<p>[[_computeStepAbortedReason(localize, step)]]</p> <p>[[_computeStepAbortedReason(localize, step)]]</p>
</template> </template>
<template is='dom-if' if='[[_equals(step.type, "create_entry")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;create_entry&quot;)]]">
<p>Created config for [[step.title]]</p> <p>Created config for [[step.title]]</p>
</template> </template>
<template is='dom-if' if='[[_equals(step.type, "form")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;form&quot;)]]">
<template is='dom-if' if='[[_computeStepDescription(localize, step)]]'> <template is="dom-if" if="[[_computeStepDescription(localize, step)]]">
<ha-markdown content='[[_computeStepDescription(localize, step)]]'></ha-markdown> <ha-markdown content="[[_computeStepDescription(localize, step)]]"></ha-markdown>
</template> </template>
<ha-form <ha-form data="{{stepData}}" schema="[[step.data_schema]]" error="[[step.errors]]" compute-label="[[_computeLabelCallback(localize, step)]]" compute-error="[[_computeErrorCallback(localize, step)]]"></ha-form>
data='{{stepData}}'
schema='[[step.data_schema]]'
error='[[step.errors]]'
compute-label='[[_computeLabelCallback(localize, step)]]'
compute-error='[[_computeErrorCallback(localize, step)]]'
></ha-form>
</template> </template>
</template> </template>
</paper-dialog-scrollable> </paper-dialog-scrollable>
<div class='buttons'> <div class="buttons">
<template is='dom-if' if='[[_equals(step.type, "abort")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;abort&quot;)]]">
<paper-button on-click='_flowDone'>Close</paper-button> <paper-button on-click="_flowDone">Close</paper-button>
</template> </template>
<template is='dom-if' if='[[_equals(step.type, "create_entry")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;create_entry&quot;)]]">
<paper-button on-click='_flowDone'>Close</paper-button> <paper-button on-click="_flowDone">Close</paper-button>
</template> </template>
<template is='dom-if' if='[[_equals(step.type, "form")]]'> <template is="dom-if" if="[[_equals(step.type, &quot;form&quot;)]]">
<paper-button on-click='_submitStep'>Submit</paper-button> <paper-button on-click="_submitStep">Submit</paper-button>
</template> </template>
</div> </div>
</paper-dialog> </paper-dialog>
</template> `;
</dom-module> }
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
*/
class HaConfigFlow extends
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(Polymer.Element)) {
static get is() { return 'ha-config-flow'; } static get is() { return 'ha-config-flow'; }
static get properties() { static get properties() {
@ -204,4 +193,3 @@ class HaConfigFlow extends
} }
customElements.define(HaConfigFlow.is, HaConfigFlow); customElements.define(HaConfigFlow.is, HaConfigFlow);
</script>

View File

@ -1,121 +0,0 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.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/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../../src/resources/ha-style.html">
<link rel='import' href='../../../src/layouts/ha-app-layout.html'>
<link rel='import' href='../../../src/util/hass-mixins.html'>
<link rel="import" href="./ha-config-section-core.html">
<link rel="import" href="./ha-config-section-push-notifications.html">
<link rel="import" href="./ha-config-section-translation.html">
<link rel="import" href="./ha-config-section-themes.html">
<dom-module id="ha-config-core">
<template>
<style include="iron-flex ha-style">
.content {
padding-bottom: 32px;
}
.border {
margin: 32px auto 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
max-width: 1040px;
}
.narrow .border {
max-width: 640px;
}
</style>
<ha-app-layout has-scrolling-region>
<app-header slot="header" fixed>
<app-toolbar>
<paper-icon-button
icon='mdi:arrow-left'
on-click='_backTapped'
></paper-icon-button>
<div main-title>[[localize('ui.panel.config.core.caption')]]</div>
</app-toolbar>
</app-header>
<div class$='[[computeClasses(isWide)]]'>
<ha-config-section-core
is-wide='[[isWide]]'
hass='[[hass]]'
></ha-config-section-core>
<template is='dom-if' if='[[pushSupported]]'>
<div class='border'></div>
<ha-config-section-push-notifications
is-wide='[[isWide]]'
hass='[[hass]]'
push-supported='{{pushSupported}}'
></ha-config-section-push-notifications>
</template>
<template is='dom-if' if='[[computeIsTranslationLoaded(hass)]]'>
<div class='border'></div>
<ha-config-section-translation
is-wide='[[isWide]]'
hass='[[hass]]'
></ha-config-section-translation>
</template>
<template is='dom-if' if='[[computeIsThemesLoaded(hass)]]'>
<div class='border'></div>
<ha-config-section-themes
is-wide='[[isWide]]'
hass='[[hass]]'
></ha-config-section-themes>
</template>
</div>
</ha-app-layout>
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigCore extends window.hassMixins.LocalizeMixin(Polymer.Element) {
static get is() { return 'ha-config-core'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
pushSupported: {
type: Boolean,
value: true,
},
};
}
computeClasses(isWide) {
return isWide ? 'content' : 'content narrow';
}
computeIsZwaveLoaded(hass) {
return window.hassUtil.isComponentLoaded(hass, 'config.zwave');
}
computeIsTranslationLoaded(hass) {
return hass.translationMetadata &&
Object.keys(hass.translationMetadata.translations).length;
}
computeIsThemesLoaded(hass) {
return hass.themes && hass.themes.themes &&
Object.keys(hass.themes.themes).length;
}
_backTapped() {
history.back();
}
}
customElements.define(HaConfigCore.is, HaConfigCore);
</script>

View File

@ -0,0 +1,103 @@
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
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 '../../../src/layouts/ha-app-layout.js';
import '../../../src/resources/ha-style.js';
import '../../../src/util/hass-mixins.js';
import './ha-config-section-core.js';
import './ha-config-section-push-notifications.js';
import './ha-config-section-themes.js';
import './ha-config-section-translation.js';
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigCore extends window.hassMixins.LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex ha-style">
.content {
padding-bottom: 32px;
}
.border {
margin: 32px auto 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
max-width: 1040px;
}
.narrow .border {
max-width: 640px;
}
</style>
<ha-app-layout has-scrolling-region="">
<app-header slot="header" fixed="">
<app-toolbar>
<paper-icon-button icon="mdi:arrow-left" on-click="_backTapped"></paper-icon-button>
<div main-title="">[[localize('ui.panel.config.core.caption')]]</div>
</app-toolbar>
</app-header>
<div class\$="[[computeClasses(isWide)]]">
<ha-config-section-core is-wide="[[isWide]]" hass="[[hass]]"></ha-config-section-core>
<template is="dom-if" if="[[pushSupported]]">
<div class="border"></div>
<ha-config-section-push-notifications is-wide="[[isWide]]" hass="[[hass]]" push-supported="{{pushSupported}}"></ha-config-section-push-notifications>
</template>
<template is="dom-if" if="[[computeIsTranslationLoaded(hass)]]">
<div class="border"></div>
<ha-config-section-translation is-wide="[[isWide]]" hass="[[hass]]"></ha-config-section-translation>
</template>
<template is="dom-if" if="[[computeIsThemesLoaded(hass)]]">
<div class="border"></div>
<ha-config-section-themes is-wide="[[isWide]]" hass="[[hass]]"></ha-config-section-themes>
</template>
</div>
</ha-app-layout>
`;
}
static get is() { return 'ha-config-core'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
pushSupported: {
type: Boolean,
value: true,
},
};
}
computeClasses(isWide) {
return isWide ? 'content' : 'content narrow';
}
computeIsZwaveLoaded(hass) {
return window.hassUtil.isComponentLoaded(hass, 'config.zwave');
}
computeIsTranslationLoaded(hass) {
return hass.translationMetadata &&
Object.keys(hass.translationMetadata.translations).length;
}
computeIsThemesLoaded(hass) {
return hass.themes && hass.themes.themes &&
Object.keys(hass.themes.themes).length;
}
_backTapped() {
history.back();
}
}
customElements.define(HaConfigCore.is, HaConfigCore);

View File

@ -1,17 +1,20 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../../bower_components/paper-button/paper-button.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-input/paper-input.html"> import '@polymer/paper-input/paper-input.js';
<link rel="import" href="../../../bower_components/paper-button/paper-button.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/components/buttons/ha-call-service-button.html"> import '../../../src/components/buttons/ha-call-service-button.js';
<link rel="import" href="../../../src/resources/ha-style.html"> import '../../../src/resources/ha-style.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
<link rel="import" href="../ha-config-section.html"> /*
* @appliesMixin window.hassMixins.LocalizeMixin
<dom-module id="ha-config-section-core"> */
<template> class HaConfigSectionCore extends window.hassMixins.LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.validate-container { .validate-container {
@apply --layout-vertical; @apply --layout-vertical;
@ -42,112 +45,76 @@
white-space: pre-wrap; white-space: pre-wrap;
} }
</style> </style>
<ha-config-section <ha-config-section is-wide="[[isWide]]">
is-wide='[[isWide]]' <span slot="header">[[localize('ui.panel.config.core.section.core.header')]]</span>
> <span slot="introduction">[[localize('ui.panel.config.core.section.core.introduction')]]</span>
<span slot='header'>[[localize('ui.panel.config.core.section.core.header')]]</span>
<span slot='introduction'>[[localize('ui.panel.config.core.section.core.introduction')]]</span>
<paper-card heading="[[localize('ui.panel.config.core.section.core.validation.heading')]]"> <paper-card heading="[[localize('ui.panel.config.core.section.core.validation.heading')]]">
<div class='card-content'> <div class="card-content">
[[localize('ui.panel.config.core.section.core.validation.introduction')]] [[localize('ui.panel.config.core.section.core.validation.introduction')]]
<template is='dom-if' if='[[!validateLog]]'> <template is="dom-if" if="[[!validateLog]]">
<div class='validate-container'> <div class="validate-container">
<template is='dom-if' if='[[!validating]]'> <template is="dom-if" if="[[!validating]]">
<template is='dom-if' if='[[isValid]]'> <template is="dom-if" if="[[isValid]]">
<div class='validate-result' id='result'> <div class="validate-result" id="result">
[[localize('ui.panel.config.core.section.core.validation.valid')]] [[localize('ui.panel.config.core.section.core.validation.valid')]]
</div> </div>
</template> </template>
<paper-button raised on-click='validateConfig'> <paper-button raised="" on-click="validateConfig">
[[localize('ui.panel.config.core.section.core.validation.check_config')]] [[localize('ui.panel.config.core.section.core.validation.check_config')]]
</paper-button> </paper-button>
</template> </template>
<template is='dom-if' if='[[validating]]'> <template is="dom-if" if="[[validating]]">
<paper-spinner active></paper-spinner> <paper-spinner active=""></paper-spinner>
</template> </template>
</div> </div>
</template> </template>
<template is='dom-if' if='[[validateLog]]'> <template is="dom-if" if="[[validateLog]]">
<div class='config-invalid'> <div class="config-invalid">
<span class='text'> <span class="text">
[[localize('ui.panel.config.core.section.core.validation.invalid')]] [[localize('ui.panel.config.core.section.core.validation.invalid')]]
</span> </span>
<paper-button raised on-click='validateConfig'> <paper-button raised="" on-click="validateConfig">
[[localize('ui.panel.config.core.section.core.validation.check_config')]] [[localize('ui.panel.config.core.section.core.validation.check_config')]]
</paper-button> </paper-button>
</div> </div>
<div id='configLog' class='validate-log'>[[validateLog]]</div> <div id="configLog" class="validate-log">[[validateLog]]</div>
</template> </template>
</div> </div>
</paper-card> </paper-card>
<paper-card heading="[[localize('ui.panel.config.core.section.core.reloading.heading')]]"> <paper-card heading="[[localize('ui.panel.config.core.section.core.reloading.heading')]]">
<div class='card-content'> <div class="card-content">
[[localize('ui.panel.config.core.section.core.reloading.introduction')]] [[localize('ui.panel.config.core.section.core.reloading.introduction')]]
</div> </div>
<div class='card-actions'> <div class="card-actions">
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="homeassistant" service="reload_core_config">[[localize('ui.panel.config.core.section.core.reloading.core')]]
hass='[[hass]]'
domain='homeassistant'
service='reload_core_config'
>[[localize('ui.panel.config.core.section.core.reloading.core')]]
</ha-call-service-button> </ha-call-service-button>
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="group" service="reload" hidden\$="[[!groupLoaded(hass)]]">[[localize('ui.panel.config.core.section.core.reloading.group')]]
hass='[[hass]]'
domain='group'
service='reload'
hidden$='[[!groupLoaded(hass)]]'
>[[localize('ui.panel.config.core.section.core.reloading.group')]]
</ha-call-service-button> </ha-call-service-button>
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="automation" service="reload" hidden\$="[[!automationLoaded(hass)]]">[[localize('ui.panel.config.core.section.core.reloading.automation')]]
hass='[[hass]]'
domain='automation'
service='reload'
hidden$='[[!automationLoaded(hass)]]'
>[[localize('ui.panel.config.core.section.core.reloading.automation')]]
</ha-call-service-button> </ha-call-service-button>
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="script" service="reload" hidden\$="[[!scriptLoaded(hass)]]">[[localize('ui.panel.config.core.section.core.reloading.script')]]
hass='[[hass]]'
domain='script'
service='reload'
hidden$='[[!scriptLoaded(hass)]]'
>[[localize('ui.panel.config.core.section.core.reloading.script')]]
</ha-call-service-button> </ha-call-service-button>
</div> </div>
</paper-card> </paper-card>
<paper-card heading="[[localize('ui.panel.config.core.section.core.server_management.heading')]]"> <paper-card heading="[[localize('ui.panel.config.core.section.core.server_management.heading')]]">
<div class='card-content'> <div class="card-content">
[[localize('ui.panel.config.core.section.core.server_management.introduction')]] [[localize('ui.panel.config.core.section.core.server_management.introduction')]]
</div> </div>
<div class='card-actions warning'> <div class="card-actions warning">
<ha-call-service-button <ha-call-service-button class="warning" hass="[[hass]]" domain="homeassistant" service="restart">[[localize('ui.panel.config.core.section.core.server_management.restart')]]
class='warning'
hass='[[hass]]'
domain='homeassistant'
service='restart'
>[[localize('ui.panel.config.core.section.core.server_management.restart')]]
</ha-call-service-button> </ha-call-service-button>
<ha-call-service-button <ha-call-service-button class="warning" hass="[[hass]]" domain="homeassistant" service="stop">[[localize('ui.panel.config.core.section.core.server_management.stop')]]
class='warning'
hass='[[hass]]'
domain='homeassistant'
service='stop'
>[[localize('ui.panel.config.core.section.core.server_management.stop')]]
</ha-call-service-button> </ha-call-service-button>
</div> </div>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
</template> `;
</dom-module> }
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigSectionCore extends window.hassMixins.LocalizeMixin(Polymer.Element) {
static get is() { return 'ha-config-section-core'; } static get is() { return 'ha-config-section-core'; }
static get properties() { static get properties() {
@ -207,4 +174,3 @@ class HaConfigSectionCore extends window.hassMixins.LocalizeMixin(Polymer.Elemen
} }
customElements.define(HaConfigSectionCore.is, HaConfigSectionCore); customElements.define(HaConfigSectionCore.is, HaConfigSectionCore);
</script>

View File

@ -1,59 +0,0 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../../bower_components/iron-label/iron-label.html">
<link rel="import" href="../../../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel='import' href='../../../src/util/hass-mixins.html'>
<link rel="import" href="../ha-config-section.html">
<link rel='import' href='../../../src/components/ha-push-notifications-toggle.html'>
<dom-module id="ha-config-section-push-notifications">
<template>
<style include="iron-flex iron-flex-alignment iron-positioning">
ha-push-notifications-toggle {
margin-left: 16px;
}
</style>
<ha-config-section is-wide='[[isWide]]'>
<span slot='header'>[[localize('ui.panel.config.core.section.push_notifications.header')]]</span>
<span slot='introduction'>
[[localize('ui.panel.config.core.section.push_notifications.introduction')]]
</span>
<paper-card>
<div class='card-content'>
<iron-label class='horizontal layout'>
[[localize('ui.panel.config.core.section.push_notifications.push_notifications')]]
<ha-push-notifications-toggle
hass='[[hass]]'
push-supported='{{pushSupported}}'
></ha-push-notifications-toggle>
</iron-label>
</div>
</paper-card>
</ha-config-section>
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigSectionPushNotifications extends window.hassMixins.LocalizeMixin(Polymer.Element) {
static get is() { return 'ha-config-section-push-notifications'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
pushSupported: {
type: Boolean,
notify: true,
},
};
}
}
customElements.define(HaConfigSectionPushNotifications.is, HaConfigSectionPushNotifications);
</script>

View File

@ -0,0 +1,54 @@
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
import '@polymer/iron-label/iron-label.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 '../../../src/components/ha-push-notifications-toggle.js';
import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigSectionPushNotifications extends window.hassMixins.LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex iron-flex-alignment iron-positioning">
ha-push-notifications-toggle {
margin-left: 16px;
}
</style>
<ha-config-section is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.core.section.push_notifications.header')]]</span>
<span slot="introduction">
[[localize('ui.panel.config.core.section.push_notifications.introduction')]]
</span>
<paper-card>
<div class="card-content">
<iron-label class="horizontal layout">
[[localize('ui.panel.config.core.section.push_notifications.push_notifications')]]
<ha-push-notifications-toggle hass="[[hass]]" push-supported="{{pushSupported}}"></ha-push-notifications-toggle>
</iron-label>
</div>
</paper-card>
</ha-config-section>
`;
}
static get is() { return 'ha-config-section-push-notifications'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
pushSupported: {
type: Boolean,
notify: true,
},
};
}
}
customElements.define(HaConfigSectionPushNotifications.is, HaConfigSectionPushNotifications);

View File

@ -1,28 +1,32 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> import '@polymer/paper-item/paper-item.js';
<link rel='import' href='../../../bower_components/paper-listbox/paper-listbox.html'> import '@polymer/paper-listbox/paper-listbox.js';
<link rel='import' href='../../../bower_components/paper-item/paper-item.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/util/hass-mixins.js';
<link rel="import" href="../ha-config-section.html"> import '../ha-config-section.js';
<dom-module id="ha-config-section-themes"> /*
<template> * @appliesMixin window.hassMixins.LocalizeMixin
<ha-config-section is-wide='[[isWide]]'> * @appliesMixin window.hassMixins.EventsMixin
<span slot='header'>[[localize('ui.panel.config.core.section.themes.header')]]</span> */
<span slot='introduction'> class HaConfigSectionThemes extends
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(PolymerElement)) {
static get template() {
return html`
<ha-config-section is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.core.section.themes.header')]]</span>
<span slot="introduction">
[[localize('ui.panel.config.core.section.themes.introduction')]] [[localize('ui.panel.config.core.section.themes.introduction')]]
</span> </span>
<paper-card> <paper-card>
<div class='card-content'> <div class="card-content">
<paper-dropdown-menu label="[[localize('ui.panel.config.core.section.themes.header')]]" dynamic-align> <paper-dropdown-menu label="[[localize('ui.panel.config.core.section.themes.header')]]" dynamic-align="">
<paper-listbox <paper-listbox slot="dropdown-content" selected="{{selectedTheme}}">
slot="dropdown-content" <template is="dom-repeat" items="[[themes]]" as="theme">
selected='{{selectedTheme}}'
>
<template is='dom-repeat' items='[[themes]]' as='theme'>
<paper-item>[[theme]]</paper-item> <paper-item>[[theme]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
@ -30,16 +34,9 @@
</div> </div>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
</template> `;
</dom-module> }
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
*/
class HaConfigSectionThemes extends
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(Polymer.Element)) {
static get is() { return 'ha-config-section-themes'; } static get is() { return 'ha-config-section-themes'; }
static get properties() { static get properties() {
@ -95,4 +92,3 @@ class HaConfigSectionThemes extends
} }
customElements.define(HaConfigSectionThemes.is, HaConfigSectionThemes); customElements.define(HaConfigSectionThemes.is, HaConfigSectionThemes);
</script>

View File

@ -1,42 +1,42 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> import '@polymer/paper-item/paper-item.js';
<link rel='import' href='../../../bower_components/paper-listbox/paper-listbox.html'> import '@polymer/paper-listbox/paper-listbox.js';
<link rel='import' href='../../../bower_components/paper-item/paper-item.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/util/hass-mixins.js';
<link rel="import" href="../ha-config-section.html"> import '../ha-config-section.js';
<dom-module id="ha-config-section-translation">
<template>
<ha-config-section is-wide='[[isWide]]'>
<span slot='header'>[[localize('ui.panel.config.core.section.translation.header')]]</span>
<span slot='introduction'>
[[localize('ui.panel.config.core.section.translation.introduction')]]
</span>
<paper-card>
<div class='card-content'>
<paper-dropdown-menu label="[[localize('ui.panel.config.core.section.translation.language')]]" dynamic-align>
<paper-listbox slot="dropdown-content" attr-for-selected="language-tag" selected="{{languageSelection}}">
<template is='dom-repeat' items='[[languages]]'>
<paper-item language-tag$="[[item.tag]]">[[item.nativeName]]</paper-item>
</template>
</paper-listbox>
></paper-dropdown-menu>
</div>
</paper-card>
</ha-config-section>
</template>
</dom-module>
<script>
/* /*
* @appliesMixin window.hassMixins.LocalizeMixin * @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin * @appliesMixin window.hassMixins.EventsMixin
*/ */
class HaConfigSectionTranslation extends class HaConfigSectionTranslation extends
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(Polymer.Element)) { window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(PolymerElement)) {
static get template() {
return html`
<ha-config-section is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.core.section.translation.header')]]</span>
<span slot="introduction">
[[localize('ui.panel.config.core.section.translation.introduction')]]
</span>
<paper-card>
<div class="card-content">
<paper-dropdown-menu label="[[localize('ui.panel.config.core.section.translation.language')]]" dynamic-align="">
<paper-listbox slot="dropdown-content" attr-for-selected="language-tag" selected="{{languageSelection}}">
<template is="dom-repeat" items="[[languages]]">
<paper-item language-tag\$="[[item.tag]]">[[item.nativeName]]</paper-item>
</template>
</paper-listbox>
&gt;</paper-dropdown-menu>
</div>
</paper-card>
</ha-config-section>
`;
}
static get is() { return 'ha-config-section-translation'; } static get is() { return 'ha-config-section-translation'; }
static get properties() { static get properties() {
@ -84,4 +84,3 @@ class HaConfigSectionTranslation extends
} }
customElements.define(HaConfigSectionTranslation.is, HaConfigSectionTranslation); customElements.define(HaConfigSectionTranslation.is, HaConfigSectionTranslation);
</script>

View File

@ -1,93 +0,0 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/app-layout/app-header-layout/app-header-layout.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/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../../src/util/hass-util.html">
<link rel="import" href="../../../src/resources/ha-style.html">
<link rel='import' href='../../../src/util/hass-mixins.html'>
<link rel="import" href="./ha-form-customize.html">
<link rel="import" href="../ha-config-section.html">
<link rel="import" href="../ha-entity-config.html">
<dom-module id="ha-config-customize">
<template>
<style include="ha-style">
</style>
<app-header-layout has-scrolling-region>
<app-header slot="header" fixed>
<app-toolbar>
<paper-icon-button
icon='mdi:arrow-left'
on-click='_backTapped'
></paper-icon-button>
<div main-title>[[localize('ui.panel.config.customize.caption')]]</div>
</app-toolbar>
</app-header>
<div class$='[[computeClasses(isWide)]]'>
<ha-config-section is-wide='[[isWide]]'>
<span slot='header'>Customization</span>
<span slot='introduction'>
Tweak per-entity attributes.<br>
Added/edited customizations will take effect immediately. Removed customizations will take effect when the entity is updated.
</span>
<ha-entity-config
hass='[[hass]]'
label='Entity'
entities='[[entities]]'
config='[[entityConfig]]'>
</ha-entity-config>
</ha-config-section>
</div>
</app-header-layout>
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigCustomize extends window.hassMixins.LocalizeMixin(Polymer.Element) {
static get is() { return 'ha-config-customize'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
entities: {
type: Array,
computed: 'computeEntities(hass)',
},
entityConfig: {
type: Object,
value: {
component: 'ha-form-customize',
computeSelectCaption: stateObj =>
window.hassUtil.computeStateName(stateObj) + ' (' + window.hassUtil.computeDomain(stateObj) + ')'
}
},
};
}
computeClasses(isWide) {
return isWide ? 'content' : 'content narrow';
}
_backTapped() {
history.back();
}
computeEntities(hass) {
return Object.keys(hass.states)
.map(key => hass.states[key])
.sort(window.hassUtil.sortByName);
}
}
customElements.define(HaConfigCustomize.is, HaConfigCustomize);
</script>

View File

@ -0,0 +1,84 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
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 '../../../src/resources/ha-style.js';
import '../../../src/util/hass-mixins.js';
import '../../../src/util/hass-util.js';
import '../ha-config-section.js';
import '../ha-entity-config.js';
import './ha-form-customize.js';
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigCustomize extends window.hassMixins.LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="ha-style">
</style>
<app-header-layout has-scrolling-region="">
<app-header slot="header" fixed="">
<app-toolbar>
<paper-icon-button icon="mdi:arrow-left" on-click="_backTapped"></paper-icon-button>
<div main-title="">[[localize('ui.panel.config.customize.caption')]]</div>
</app-toolbar>
</app-header>
<div class\$="[[computeClasses(isWide)]]">
<ha-config-section is-wide="[[isWide]]">
<span slot="header">Customization</span>
<span slot="introduction">
Tweak per-entity attributes.<br>
Added/edited customizations will take effect immediately. Removed customizations will take effect when the entity is updated.
</span>
<ha-entity-config hass="[[hass]]" label="Entity" entities="[[entities]]" config="[[entityConfig]]">
</ha-entity-config>
</ha-config-section>
</div>
</app-header-layout>
`;
}
static get is() { return 'ha-config-customize'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
entities: {
type: Array,
computed: 'computeEntities(hass)',
},
entityConfig: {
type: Object,
value: {
component: 'ha-form-customize',
computeSelectCaption: stateObj =>
window.hassUtil.computeStateName(stateObj) + ' (' + window.hassUtil.computeDomain(stateObj) + ')'
}
},
};
}
computeClasses(isWide) {
return isWide ? 'content' : 'content narrow';
}
_backTapped() {
history.back();
}
computeEntities(hass) {
return Object.keys(hass.states)
.map(key => hass.states[key])
.sort(window.hassUtil.sortByName);
}
}
customElements.define(HaConfigCustomize.is, HaConfigCustomize);

View File

@ -1,17 +1,18 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-icon-button/paper-icon-button.js';
<link rel='import' href="../../../bower_components/paper-icon-button/paper-icon-button.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/util/hass-attributes-util.html"> import '../../../src/util/hass-attributes-util.js';
import '../ha-form-style.js';
import './types/ha-customize-array.js';
import './types/ha-customize-boolean.js';
import './types/ha-customize-icon.js';
import './types/ha-customize-key-value.js';
import './types/ha-customize-string.js';
<link rel="import" href="../ha-form-style.html"> class HaCustomizeAttribute extends PolymerElement {
<link rel="import" href="./types/ha-customize-array.html"> static get template() {
<link rel="import" href="./types/ha-customize-boolean.html"> return html`
<link rel="import" href="./types/ha-customize-icon.html">
<link rel="import" href="./types/ha-customize-key-value.html">
<link rel="import" href="./types/ha-customize-string.html">
<dom-module id="ha-customize-attribute">
<template>
<style include="ha-form-style"> <style include="ha-form-style">
:host { :host {
display: block; display: block;
@ -26,13 +27,11 @@
right: 0; right: 0;
} }
</style> </style>
<div id='wrapper' class='form-group'></div> <div id="wrapper" class="form-group"></div>
<paper-icon-button class="button" icon="[[getIcon(item.secondary)]]" on-click="tapButton"></paper-icon-button> <paper-icon-button class="button" icon="[[getIcon(item.secondary)]]" on-click="tapButton"></paper-icon-button>
</template> `;
</dom-module> }
<script>
class HaCustomizeAttribute extends Polymer.Element {
static get is() { return 'ha-customize-attribute'; } static get is() { return 'ha-customize-attribute'; }
static get properties() { static get properties() {
@ -82,4 +81,3 @@ class HaCustomizeAttribute extends Polymer.Element {
} }
} }
customElements.define(HaCustomizeAttribute.is, HaCustomizeAttribute); customElements.define(HaCustomizeAttribute.is, HaCustomizeAttribute);
</script>

View File

@ -1,36 +0,0 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/polymer/lib/mixins/mutable-data.html">
<link rel="import" href="./ha-customize-attribute.html">
<dom-module id="ha-form-customize-attributes">
<template>
<style>
[hidden] {
display: none;
}
</style>
<template is='dom-repeat' items='{{attributes}}' mutable-data>
<ha-customize-attribute
item="{{item}}"
hidden$="[[item.closed]]">
</ha-customize-attribute>
</template>
</template>
</dom-module>
<script>
class HaFormCustomizeAttributes extends Polymer.MutableData(Polymer.Element) {
static get is() { return 'ha-form-customize-attributes'; }
static get properties() {
return {
attributes: {
type: Array,
notify: true,
},
};
}
}
customElements.define(HaFormCustomizeAttributes.is, HaFormCustomizeAttributes);
</script>

View File

@ -0,0 +1,33 @@
import { MutableData } from '@polymer/polymer/lib/mixins/mutable-data.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import './ha-customize-attribute.js';
class HaFormCustomizeAttributes extends MutableData(PolymerElement) {
static get template() {
return html`
<style>
[hidden] {
display: none;
}
</style>
<template is="dom-repeat" items="{{attributes}}" mutable-data="">
<ha-customize-attribute item="{{item}}" hidden\$="[[item.closed]]">
</ha-customize-attribute>
</template>
`;
}
static get is() { return 'ha-form-customize-attributes'; }
static get properties() {
return {
attributes: {
type: Array,
notify: true,
},
};
}
}
customElements.define(HaFormCustomizeAttributes.is, HaFormCustomizeAttributes);

View File

@ -1,15 +1,16 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> import '@polymer/paper-item/paper-item.js';
<link rel='import' href='../../../bower_components/paper-listbox/paper-listbox.html'> import '@polymer/paper-listbox/paper-listbox.js';
<link rel='import' href='../../../bower_components/paper-item/paper-item.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/util/hass-util.html"> import '../../../src/util/hass-attributes-util.js';
<link rel="import" href="../../../src/util/hass-attributes-util.html"> import '../../../src/util/hass-util.js';
import './ha-form-customize-attributes.js';
<link rel="import" href="./ha-form-customize-attributes.html"> class HaFormCustomize extends PolymerElement {
static get template() {
<dom-module id="ha-form-customize"> return html`
<template>
<style include="iron-flex ha-style ha-form-style"> <style include="iron-flex ha-style ha-form-style">
.warning { .warning {
color: red; color: red;
@ -19,59 +20,50 @@
padding-left: 20px; padding-left: 20px;
} }
</style> </style>
<template is='dom-if' if='[[computeShowWarning(localConfig, globalConfig)]]'> <template is="dom-if" if="[[computeShowWarning(localConfig, globalConfig)]]">
<div class="warning"> <div class="warning">
It seems that your configuration.yaml doesn't properly include customize.yaml<br> It seems that your configuration.yaml doesn't properly include customize.yaml<br>
Changes made here won't affect your configuration. Changes made here won't affect your configuration.
</div> </div>
</template> </template>
<template is='dom-if' if='[[hasLocalAttributes]]'> <template is="dom-if" if="[[hasLocalAttributes]]">
<h4 class="attributes-text"> <h4 class="attributes-text">
The following attributes are already set in customize.yaml<br> The following attributes are already set in customize.yaml<br>
</h4> </h4>
<ha-form-customize-attributes attributes="{{localAttributes}}"></ha-form-customize-attributes> <ha-form-customize-attributes attributes="{{localAttributes}}"></ha-form-customize-attributes>
</template> </template>
<template is='dom-if' if='[[hasGlobalAttributes]]'> <template is="dom-if" if="[[hasGlobalAttributes]]">
<h4 class="attributes-text"> <h4 class="attributes-text">
The following attributes are customized from outside of customize.yaml<br> The following attributes are customized from outside of customize.yaml<br>
Possibly via a domain, a glob or a different include. Possibly via a domain, a glob or a different include.
</h4> </h4>
<ha-form-customize-attributes attributes="{{globalAttributes}}"></ha-form-customize-attributes> <ha-form-customize-attributes attributes="{{globalAttributes}}"></ha-form-customize-attributes>
</template> </template>
<template is='dom-if' if='[[hasExistingAttributes]]'> <template is="dom-if" if="[[hasExistingAttributes]]">
<h4 class="attributes-text"> <h4 class="attributes-text">
The following attributes of the entity are set programatically.<br> The following attributes of the entity are set programatically.<br>
You can override them if you like. You can override them if you like.
</h4> </h4>
<ha-form-customize-attributes attributes="{{existingAttributes}}"></ha-form-customize-attributes> <ha-form-customize-attributes attributes="{{existingAttributes}}"></ha-form-customize-attributes>
</template> </template>
<template is='dom-if' if='[[hasNewAttributes]]'> <template is="dom-if" if="[[hasNewAttributes]]">
<h4 class="attributes-text"> <h4 class="attributes-text">
The following attributes weren't set. Set them if you like. The following attributes weren't set. Set them if you like.
</h4> </h4>
<ha-form-customize-attributes attributes="{{newAttributes}}"></ha-form-customize-attributes> <ha-form-customize-attributes attributes="{{newAttributes}}"></ha-form-customize-attributes>
</template> </template>
<div class='form-group'> <div class="form-group">
<paper-dropdown-menu <paper-dropdown-menu label="Pick an attribute to override" class="flex" dynamic-align="">
label='Pick an attribute to override' <paper-listbox slot="dropdown-content" selected="{{selectedNewAttribute}}">
class='flex' <template is="dom-repeat" items="[[newAttributesOptions]]" as="option">
dynamic-align
>
<paper-listbox
slot="dropdown-content"
selected='{{selectedNewAttribute}}'
>
<template is='dom-repeat' items='[[newAttributesOptions]]' as='option'>
<paper-item>[[option]]</paper-item> <paper-item>[[option]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
</template> `;
</dom-module> }
<script>
class HaFormCustomize extends Polymer.Element {
static get is() { return 'ha-form-customize'; } static get is() { return 'ha-form-customize'; }
static get properties() { static get properties() {
@ -275,4 +267,3 @@ class HaFormCustomize extends Polymer.Element {
} }
} }
customElements.define(HaFormCustomize.is, HaFormCustomize); customElements.define(HaFormCustomize.is, HaFormCustomize);
</script>

View File

@ -1,36 +1,29 @@
<link rel='import' href='../../../../bower_components/polymer/polymer-element.html'> import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
<link rel="import" href="../../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> import '@polymer/paper-item/paper-item.js';
<link rel='import' href='../../../../bower_components/paper-listbox/paper-listbox.html'> import '@polymer/paper-listbox/paper-listbox.js';
<link rel='import' href='../../../../bower_components/paper-item/paper-item.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
<link rel="import" href="../../../../src/util/hass-mixins.html"> import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<dom-module id='ha-customize-array'> import '../../../../src/util/hass-mixins.js';
<template>
class HaCustomizeArray extends window.hassMixins.EventsMixin(PolymerElement) {
static get template() {
return html`
<style> <style>
paper-dropdown-menu { paper-dropdown-menu {
margin: -9px 0; margin: -9px 0;
} }
</style> </style>
<paper-dropdown-menu <paper-dropdown-menu label="[[item.description]]" disabled="[[item.secondary]]" selected-item-label="{{item.value}}" dynamic-align="">
label='[[item.description]]' <paper-listbox slot="dropdown-content" selected="[[computeSelected(item)]]">
disabled='[[item.secondary]]' <template is="dom-repeat" items="[[getOptions(item)]]" as="option">
selected-item-label="{{item.value}}"
dynamic-align
>
<paper-listbox
slot="dropdown-content"
selected='[[computeSelected(item)]]'
>
<template is='dom-repeat' items='[[getOptions(item)]]' as='option'>
<paper-item>[[option]]</paper-item> <paper-item>[[option]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</template> `;
</dom-module> }
<script>
class HaCustomizeArray extends window.hassMixins.EventsMixin(Polymer.Element) {
static get is() { return 'ha-customize-array'; } static get is() { return 'ha-customize-array'; }
static get properties() { static get properties() {
@ -59,4 +52,3 @@ class HaCustomizeArray extends window.hassMixins.EventsMixin(Polymer.Element) {
} }
} }
customElements.define(HaCustomizeArray.is, HaCustomizeArray); customElements.define(HaCustomizeArray.is, HaCustomizeArray);
</script>

View File

@ -1,29 +0,0 @@
<link rel='import' href='../../../../bower_components/polymer/polymer-element.html'>
<link rel='import' href='../../../../bower_components/paper-checkbox/paper-checkbox.html'>
<dom-module id='ha-customize-boolean'>
<template>
<paper-checkbox
disabled='[[item.secondary]]'
checked="{{item.value}}"
>
[[item.description]]
</paper-checkbox>
</template>
</dom-module>
<script>
class HaCustomizeBoolean extends Polymer.Element {
static get is() { return 'ha-customize-boolean'; }
static get properties() {
return {
item: {
type: Object,
notifies: true,
}
};
}
}
customElements.define(HaCustomizeBoolean.is, HaCustomizeBoolean);
</script>

View File

@ -0,0 +1,25 @@
import '@polymer/paper-checkbox/paper-checkbox.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
class HaCustomizeBoolean extends PolymerElement {
static get template() {
return html`
<paper-checkbox disabled="[[item.secondary]]" checked="{{item.value}}">
[[item.description]]
</paper-checkbox>
`;
}
static get is() { return 'ha-customize-boolean'; }
static get properties() {
return {
item: {
type: Object,
notifies: true,
}
};
}
}
customElements.define(HaCustomizeBoolean.is, HaCustomizeBoolean);

View File

@ -1,42 +0,0 @@
<link rel='import' href='../../../../bower_components/polymer/polymer-element.html'>
<link rel='import' href='../../../../bower_components/iron-icon/iron-icon.html'>
<link rel='import' href='../../../../bower_components/paper-input/paper-input.html'>
<dom-module id='ha-customize-icon'>
<template>
<style>
:host {
@apply --layout-horizontal;
}
.icon-image {
border: 1px solid grey;
padding: 8px;
margin-right: 20px;
margin-top: 10px;
}
</style>
<iron-icon class="icon-image" icon="[[item.value]]"></iron-icon>
<paper-input
auto-validate pattern="(mdi:.*)?" error-message="Must start with 'mdi:'"
disabled='[[item.secondary]]'
label='icon'
value='{{item.value}}'>
</paper-input>
</template>
</dom-module>
<script>
class HaCustomizeIcon extends Polymer.Element {
static get is() { return 'ha-customize-icon'; }
static get properties() {
return {
item: {
type: Object,
notifies: true,
}
};
}
}
customElements.define(HaCustomizeIcon.is, HaCustomizeIcon);
</script>

View File

@ -0,0 +1,37 @@
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/paper-input/paper-input.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
class HaCustomizeIcon extends PolymerElement {
static get template() {
return html`
<style>
:host {
@apply --layout-horizontal;
}
.icon-image {
border: 1px solid grey;
padding: 8px;
margin-right: 20px;
margin-top: 10px;
}
</style>
<iron-icon class="icon-image" icon="[[item.value]]"></iron-icon>
<paper-input auto-validate="" pattern="(mdi:.*)?" error-message="Must start with 'mdi:'" disabled="[[item.secondary]]" label="icon" value="{{item.value}}">
</paper-input>
`;
}
static get is() { return 'ha-customize-icon'; }
static get properties() {
return {
item: {
type: Object,
notifies: true,
}
};
}
}
customElements.define(HaCustomizeIcon.is, HaCustomizeIcon);

View File

@ -1,45 +0,0 @@
<link rel='import' href='../../../../bower_components/polymer/polymer-element.html'>
<link rel='import' href='../../../../bower_components/paper-input/paper-input.html'>
<dom-module id='ha-customize-key-value'>
<template>
<style>
:host {
@apply --layout-horizontal;
}
paper-input {
@apply --layout-flex;
}
.key {
padding-right: 20px;
}
</style>
<paper-input
disabled='[[item.secondary]]'
class='key'
label='Attribute name'
value='{{item.attribute}}'>
</paper-input>
<paper-input
disabled='[[item.secondary]]'
label='Attribute value'
value='{{item.value}}'>
</paper-input>
</template>
</dom-module>
<script>
class HaCustomizeKeyValue extends Polymer.Element {
static get is() { return 'ha-customize-key-value'; }
static get properties() {
return {
item: {
type: Object,
notifies: true,
}
};
}
}
customElements.define(HaCustomizeKeyValue.is, HaCustomizeKeyValue);
</script>

View File

@ -0,0 +1,37 @@
import '@polymer/paper-input/paper-input.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
class HaCustomizeKeyValue extends PolymerElement {
static get template() {
return html`
<style>
:host {
@apply --layout-horizontal;
}
paper-input {
@apply --layout-flex;
}
.key {
padding-right: 20px;
}
</style>
<paper-input disabled="[[item.secondary]]" class="key" label="Attribute name" value="{{item.attribute}}">
</paper-input>
<paper-input disabled="[[item.secondary]]" label="Attribute value" value="{{item.value}}">
</paper-input>
`;
}
static get is() { return 'ha-customize-key-value'; }
static get properties() {
return {
item: {
type: Object,
notifies: true,
}
};
}
}
customElements.define(HaCustomizeKeyValue.is, HaCustomizeKeyValue);

View File

@ -1,32 +0,0 @@
<link rel='import' href='../../../../bower_components/polymer/polymer-element.html'>
<link rel='import' href='../../../../bower_components/paper-input/paper-input.html'>
<dom-module id='ha-customize-string'>
<template>
<paper-input
disabled='[[item.secondary]]'
label='[[getLabel(item)]]'
value='{{item.value}}'>
</paper-input>
</template>
</dom-module>
<script>
class HaCustomizeString extends Polymer.Element {
static get is() { return 'ha-customize-string'; }
static get properties() {
return {
item: {
type: Object,
notifies: true,
}
};
}
getLabel(item) {
return item.description + (item.type === 'json' ? ' (JSON formatted)' : '');
}
}
customElements.define(HaCustomizeString.is, HaCustomizeString);
</script>

View File

@ -0,0 +1,28 @@
import '@polymer/paper-input/paper-input.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
class HaCustomizeString extends PolymerElement {
static get template() {
return html`
<paper-input disabled="[[item.secondary]]" label="[[getLabel(item)]]" value="{{item.value}}">
</paper-input>
`;
}
static get is() { return 'ha-customize-string'; }
static get properties() {
return {
item: {
type: Object,
notifies: true,
}
};
}
getLabel(item) {
return item.description + (item.type === 'json' ? ' (JSON formatted)' : '');
}
}
customElements.define(HaCustomizeString.is, HaCustomizeString);

View File

@ -1,54 +0,0 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.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-item/paper-item-body.html">
<link rel="import" href="../../../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../../../src/util/hass-mixins.html">
<dom-module id="ha-config-cloud-menu">
<template>
<style include="iron-flex">
paper-card {
display: block;
}
paper-item {
cursor: pointer;
}
</style>
<paper-card>
<paper-item on-click='_navigate'>
<paper-item-body two-line>
Home Assistant Cloud
<template is='dom-if' if='[[account]]'>
<div secondary>Logged in as [[account.email]]</div>
</template>
<template is='dom-if' if='[[!account]]'>
<div secondary>Not logged in</div>
</template>
</paper-item-body>
<iron-icon icon='mdi:chevron-right'></iron-icon>
</paper-item>
</paper-card>
</template>
</dom-module>
<script>
class HaConfigCloudMenu extends window.hassMixins.NavigateMixin(Polymer.Element) {
static get is() { return 'ha-config-cloud-menu'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
account: Object,
};
}
_navigate() {
this.navigate('/config/cloud');
}
}
customElements.define(HaConfigCloudMenu.is, HaConfigCloudMenu);
</script>

View File

@ -0,0 +1,53 @@
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 '../../../src/util/hass-mixins.js';
class HaConfigCloudMenu extends window.hassMixins.NavigateMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex">
paper-card {
display: block;
}
paper-item {
cursor: pointer;
}
</style>
<paper-card>
<paper-item on-click="_navigate">
<paper-item-body two-line="">
Home Assistant Cloud
<template is="dom-if" if="[[account]]">
<div secondary="">Logged in as [[account.email]]</div>
</template>
<template is="dom-if" if="[[!account]]">
<div secondary="">Not logged in</div>
</template>
</paper-item-body>
<iron-icon icon="mdi:chevron-right"></iron-icon>
</paper-item>
</paper-card>
`;
}
static get is() { return 'ha-config-cloud-menu'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
account: Object,
};
}
_navigate() {
this.navigate('/config/cloud');
}
}
customElements.define(HaConfigCloudMenu.is, HaConfigCloudMenu);

View File

@ -1,83 +0,0 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.html'>
<link rel="import" href="../../../bower_components/app-layout/app-header-layout/app-header-layout.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="../../../src/components/ha-menu-button.html">
<link rel='import' href='../../../src/util/hass-mixins.html'>
<link rel="import" href="../ha-config-section.html">
<link rel="import" href="./ha-config-navigation.html">
<link rel="import" href="./ha-config-cloud-menu.html">
<link rel="import" href="./ha-config-entries-menu.html">
<dom-module id="ha-config-dashboard">
<template>
<style include="iron-flex ha-style">
.content {
padding-bottom: 32px;
}
</style>
<app-header-layout has-scrolling-region>
<app-header slot="header" fixed>
<app-toolbar>
<ha-menu-button narrow='[[narrow]]' show-menu='[[showMenu]]'></ha-menu-button>
<div main-title>[[localize('panel.configuration')]]</div>
</app-toolbar>
</app-header>
<div class='content'>
<ha-config-section
is-wide='[[isWide]]'
>
<span slot='header'>[[localize('ui.panel.config.header')]]</span>
<span slot='introduction'>[[localize('ui.panel.config.introduction')]]</span>
<template is='dom-if' if='[[computeIsLoaded(hass, "cloud")]]'>
<ha-config-cloud-menu
hass='[[hass]]'
account='[[account]]'
></ha-config-cloud-menu>
</template>
<template is='dom-if' if='[[computeIsLoaded(hass, "config.config_entries")]]'>
<ha-config-entries-menu
hass='[[hass]]'
></ha-config-entries-menu>
</template>
<ha-config-navigation
hass='[[hass]]'
></ha-config-navigation>
</ha-config-section>
</div>
</app-header-layout>
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigDashboard extends window.hassMixins.LocalizeMixin(Polymer.Element) {
static get is() { return 'ha-config-dashboard'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
account: Object,
narrow: Boolean,
showMenu: Boolean,
};
}
computeIsLoaded(hass, component) {
return window.hassUtil.isComponentLoaded(hass, component);
}
}
customElements.define(HaConfigDashboard.is, HaConfigDashboard);
</script>

View File

@ -0,0 +1,71 @@
import '@polymer/app-layout/app-header-layout/app-header-layout.js';
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../../src/components/ha-menu-button.js';
import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
import './ha-config-cloud-menu.js';
import './ha-config-entries-menu.js';
import './ha-config-navigation.js';
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigDashboard extends window.hassMixins.LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex ha-style">
.content {
padding-bottom: 32px;
}
</style>
<app-header-layout has-scrolling-region="">
<app-header slot="header" fixed="">
<app-toolbar>
<ha-menu-button narrow="[[narrow]]" show-menu="[[showMenu]]"></ha-menu-button>
<div main-title="">[[localize('panel.configuration')]]</div>
</app-toolbar>
</app-header>
<div class="content">
<ha-config-section is-wide="[[isWide]]">
<span slot="header">[[localize('ui.panel.config.header')]]</span>
<span slot="introduction">[[localize('ui.panel.config.introduction')]]</span>
<template is="dom-if" if="[[computeIsLoaded(hass, &quot;cloud&quot;)]]">
<ha-config-cloud-menu hass="[[hass]]" account="[[account]]"></ha-config-cloud-menu>
</template>
<template is="dom-if" if="[[computeIsLoaded(hass, &quot;config.config_entries&quot;)]]">
<ha-config-entries-menu hass="[[hass]]"></ha-config-entries-menu>
</template>
<ha-config-navigation hass="[[hass]]"></ha-config-navigation>
</ha-config-section>
</div>
</app-header-layout>
`;
}
static get is() { return 'ha-config-dashboard'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
account: Object,
narrow: Boolean,
showMenu: Boolean,
};
}
computeIsLoaded(hass, component) {
return window.hassUtil.isComponentLoaded(hass, component);
}
}
customElements.define(HaConfigDashboard.is, HaConfigDashboard);

View File

@ -1,49 +0,0 @@
<link rel="import" href='../../../bower_components/polymer/polymer-element.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-item/paper-item-body.html">
<link rel="import" href="../../../bower_components/iron-icon/iron-icon.html">
<link rel="import" href="../../../src/util/hass-mixins.html">
<dom-module id="ha-config-entries-menu">
<template>
<style include="iron-flex">
paper-card {
display: block;
}
paper-item {
cursor: pointer;
}
</style>
<paper-card>
<paper-item on-click='_navigate'>
<paper-item-body two-line>
Integrations
<div secondary>EXPERIMENTAL Manage connected devices and services</div>
</paper-item-body>
<iron-icon icon='mdi:chevron-right'></iron-icon>
</paper-item>
</paper-card>
</template>
</dom-module>
<script>
class HaConfigEntriesMenu extends window.hassMixins.NavigateMixin(Polymer.Element) {
static get is() { return 'ha-config-entries-menu'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
account: Object,
};
}
_navigate() {
this.navigate('/config/integrations');
}
}
customElements.define(HaConfigEntriesMenu.is, HaConfigEntriesMenu);
</script>

View File

@ -0,0 +1,48 @@
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 '../../../src/util/hass-mixins.js';
class HaConfigEntriesMenu extends window.hassMixins.NavigateMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex">
paper-card {
display: block;
}
paper-item {
cursor: pointer;
}
</style>
<paper-card>
<paper-item on-click="_navigate">
<paper-item-body two-line="">
Integrations
<div secondary="">EXPERIMENTAL Manage connected devices and services</div>
</paper-item-body>
<iron-icon icon="mdi:chevron-right"></iron-icon>
</paper-item>
</paper-card>
`;
}
static get is() { return 'ha-config-entries-menu'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
account: Object,
};
}
_navigate() {
this.navigate('/config/integrations');
}
}
customElements.define(HaConfigEntriesMenu.is, HaConfigEntriesMenu);

View File

@ -1,38 +1,12 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/iron-icon/iron-icon.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item.html"> import '@polymer/paper-item/paper-item-body.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item-body.html"> import '@polymer/paper-item/paper-item.js';
<link rel="import" href="../../../bower_components/iron-icon/iron-icon.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/util/hass-mixins.js';
<dom-module id="ha-config-navigation">
<template>
<style include="iron-flex">
paper-card {
display: block;
}
paper-item {
cursor: pointer;
}
</style>
<paper-card>
<template is='dom-repeat' items='[[pages]]'>
<template is='dom-if' if='[[_computeLoaded(hass, item)]]'>
<paper-item on-click='_navigate'>
<paper-item-body two-line>
[[_computeCaption(item, localize)]]
<div secondary>[[_computeDescription(item, localize)]]</div>
</paper-item-body>
<iron-icon icon='mdi:chevron-right'></iron-icon>
</paper-item>
</template>
</template>
</paper-card>
</template>
</dom-module>
<script>
{ {
const CORE_PAGES = [ const CORE_PAGES = [
'core', 'core',
@ -43,7 +17,33 @@
* @appliesMixin window.hassMixins.EventsMixin * @appliesMixin window.hassMixins.EventsMixin
*/ */
class HaConfigNavigation extends class HaConfigNavigation extends
window.hassMixins.LocalizeMixin(window.hassMixins.NavigateMixin(Polymer.Element)) { window.hassMixins.LocalizeMixin(window.hassMixins.NavigateMixin(PolymerElement)) {
static get template() {
return html`
<style include="iron-flex">
paper-card {
display: block;
}
paper-item {
cursor: pointer;
}
</style>
<paper-card>
<template is="dom-repeat" items="[[pages]]">
<template is="dom-if" if="[[_computeLoaded(hass, item)]]">
<paper-item on-click="_navigate">
<paper-item-body two-line="">
[[_computeCaption(item, localize)]]
<div secondary="">[[_computeDescription(item, localize)]]</div>
</paper-item-body>
<iron-icon icon="mdi:chevron-right"></iron-icon>
</paper-item>
</template>
</template>
</paper-card>
`;
}
static get is() { return 'ha-config-navigation'; } static get is() { return 'ha-config-navigation'; }
static get properties() { static get properties() {
@ -84,4 +84,3 @@
customElements.define(HaConfigNavigation.is, HaConfigNavigation); customElements.define(HaConfigNavigation.is, HaConfigNavigation);
} }
</script>

View File

@ -1 +0,0 @@
<script src='../../build-temp/panel-config.js'></script>

View File

@ -0,0 +1 @@

View File

@ -1,8 +1,11 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
<link rel="import" href="../../src/resources/ha-style.html"> import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<dom-module id="ha-config-section"> import '../../src/resources/ha-style.js';
<template>
class HaConfigSection extends PolymerElement {
static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
padding: 28px 20px 0; padding: 28px 20px 0;
@ -52,22 +55,20 @@
max-width: 500px; max-width: 500px;
} }
</style> </style>
<div class$='[[computeContentClasses(isWide)]]'> <div class\$="[[computeContentClasses(isWide)]]">
<div class='header'><slot name="header"></slot></div> <div class="header"><slot name="header"></slot></div>
<div class$='[[computeClasses(isWide)]]'> <div class\$="[[computeClasses(isWide)]]">
<div class='intro'> <div class="intro">
<slot name="introduction"></slot> <slot name="introduction"></slot>
</div> </div>
<div class='panel flex-auto'> <div class="panel flex-auto">
<slot></slot> <slot></slot>
</div> </div>
</div> </div>
</div> </div>
</template> `;
</dom-module> }
<script>
class HaConfigSection extends Polymer.Element {
static get is() { return 'ha-config-section'; } static get is() { return 'ha-config-section'; }
static get properties() { static get properties() {
@ -106,4 +107,3 @@ class HaConfigSection extends Polymer.Element {
} }
customElements.define(HaConfigSection.is, HaConfigSection); customElements.define(HaConfigSection.is, HaConfigSection);
</script>

View File

@ -1,13 +1,15 @@
<link rel="import" href="../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../bower_components/paper-button/paper-button.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../bower_components/paper-spinner/paper-spinner.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
<link rel="import" href="../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> import '@polymer/paper-item/paper-item.js';
<link rel="import" href="../../bower_components/paper-listbox/paper-listbox.html"> import '@polymer/paper-listbox/paper-listbox.js';
<link rel="import" href="../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-spinner/paper-spinner.js';
<link rel="import" href="../../bower_components/paper-item/paper-item.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<dom-module id="ha-entity-config"> class HaEntityConfig extends PolymerElement {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
paper-card { paper-card {
display: block; display: block;
@ -34,61 +36,44 @@
} }
</style> </style>
<paper-card> <paper-card>
<div class='card-content'> <div class="card-content">
<div class='device-picker'> <div class="device-picker">
<paper-dropdown-menu <paper-dropdown-menu label="[[label]]" class="flex" disabled="[[!entities.length]]">
label='[[label]]' <paper-listbox slot="dropdown-content" selected="{{selectedEntity}}">
class='flex' <template is="dom-repeat" items="[[entities]]" as="state">
disabled='[[!entities.length]]'
>
<paper-listbox
slot="dropdown-content"
selected='{{selectedEntity}}'
>
<template is='dom-repeat' items='[[entities]]' as='state'>
<paper-item>[[computeSelectCaption(state)]]</paper-item> <paper-item>[[computeSelectCaption(state)]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<div class='form-container'> <div class="form-container">
<template is='dom-if' if='[[computeShowPlaceholder(formState)]]'> <template is="dom-if" if="[[computeShowPlaceholder(formState)]]">
<div class='form-placeholder'> <div class="form-placeholder">
<template is='dom-if' if='[[computeShowNoDevices(formState)]]'> <template is="dom-if" if="[[computeShowNoDevices(formState)]]">
No entities found! :-( No entities found! :-(
</template> </template>
<template is='dom-if' if='[[computeShowSpinner(formState)]]'> <template is="dom-if" if="[[computeShowSpinner(formState)]]">
<paper-spinner active alt='[[formState]]'></paper-spinner> <paper-spinner active="" alt="[[formState]]"></paper-spinner>
[[formState]] [[formState]]
</template> </template>
</div> </div>
</template> </template>
<div hidden$='[[!computeShowForm(formState)]]' id='form'></div> <div hidden\$="[[!computeShowForm(formState)]]" id="form"></div>
</div> </div>
</div> </div>
<div class='card-actions'> <div class="card-actions">
<paper-button <paper-button on-click="saveEntity" disabled="[[computeShowPlaceholder(formState)]]">SAVE</paper-button>
on-click='saveEntity' <template is="dom-if" if="[[allowDelete]]">
disabled='[[computeShowPlaceholder(formState)]]' <paper-button class="warning" on-click="deleteEntity" disabled="[[computeShowPlaceholder(formState)]]">DELETE</paper-button>
>SAVE</paper-button>
<template is='dom-if' if='[[allowDelete]]'>
<paper-button
class='warning'
on-click='deleteEntity'
disabled='[[computeShowPlaceholder(formState)]]'
>DELETE</paper-button>
</template> </template>
</div> </div>
</paper-card> </paper-card>
`;
}
</template>
</dom-module>
<script>
class HaEntityConfig extends Polymer.Element {
static get is() { return 'ha-entity-config'; } static get is() { return 'ha-entity-config'; }
static get properties() { static get properties() {
@ -214,4 +199,3 @@ class HaEntityConfig extends Polymer.Element {
} }
customElements.define(HaEntityConfig.is, HaEntityConfig); customElements.define(HaEntityConfig.is, HaEntityConfig);
</script>

View File

@ -1,4 +1,7 @@
<dom-module id='ha-form-style'> const documentContainer = document.createElement('template');
documentContainer.setAttribute('style', 'display: none;');
documentContainer.innerHTML = `<dom-module id="ha-form-style">
<template> <template>
<style> <style>
.form-group { .form-group {
@ -25,4 +28,6 @@
} }
</style> </style>
</template> </template>
</dom-module> </dom-module>`;
document.head.appendChild(documentContainer.content);

View File

@ -1,21 +1,24 @@
<link rel="import" href='../../bower_components/polymer/polymer-element.html'> import '@polymer/app-route/app-route.js';
<link rel='import' href='../../bower_components/iron-media-query/iron-media-query.html'> import '@polymer/iron-media-query/iron-media-query.js';
<link rel='import' href='../../bower_components/app-route/app-route.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../src/layouts/hass-error-screen.html"> import '../../build-temp/panel-config.js';
<link rel="import" href="../../src/util/hass-mixins.html"> import '../../src/layouts/hass-error-screen.js';
import '../../src/util/hass-mixins.js';
import './automation/ha-config-automation.js';
import './cloud/ha-config-cloud.js';
import './config-entries/ha-config-entries.js';
import './core/ha-config-core.js';
import './customize/ha-config-customize.js';
import './dashboard/ha-config-dashboard.js';
import './script/ha-config-script.js';
import './zwave/ha-config-zwave.js';
<link rel="import" href="./dashboard/ha-config-dashboard.html">
<link rel="import" href="./core/ha-config-core.html">
<link rel="import" href="./cloud/ha-config-cloud.html">
<link rel="import" href="./automation/ha-config-automation.html">
<link rel="import" href="./script/ha-config-script.html">
<link rel="import" href="./zwave/ha-config-zwave.html">
<link rel="import" href="./customize/ha-config-customize.html">
<link rel="import" href="./config-entries/ha-config-entries.html">
<dom-module id="ha-panel-config"> class HaPanelConfig extends window.hassMixins.NavigateMixin(PolymerElement) {
<template> static get template() {
return html`
<app-route <app-route
route='[[route]]' route='[[route]]'
pattern='/:page' pattern='/:page'
@ -97,11 +100,9 @@
is-wide='[[isWide]]' is-wide='[[isWide]]'
></ha-config-entries> ></ha-config-entries>
</template> </template>
</template> `;
</dom-module> }
<script>
class HaPanelConfig extends window.hassMixins.NavigateMixin(Polymer.Element) {
static get is() { return 'ha-panel-config'; } static get is() { return 'ha-panel-config'; }
static get properties() { static get properties() {
@ -154,4 +155,3 @@ class HaPanelConfig extends window.hassMixins.NavigateMixin(Polymer.Element) {
} }
customElements.define(HaPanelConfig.is, HaPanelConfig); customElements.define(HaPanelConfig.is, HaPanelConfig);
</script>

View File

@ -1,52 +1,32 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/app-route/app-route.js';
<link rel='import' href='../../../bower_components/app-route/app-route.html'> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="./ha-script-picker.html"> import './ha-script-editor.js';
<link rel="import" href="./ha-script-editor.html"> import './ha-script-picker.js';
<dom-module id="ha-config-script"> class HaConfigScript extends PolymerElement {
<template> static get template() {
return html`
<style> <style>
ha-script-picker, ha-script-picker,
ha-script-editor { ha-script-editor {
height: 100%; height: 100%;
} }
</style> </style>
<app-route <app-route route="[[route]]" pattern="/script/edit/:script" data="{{_routeData}}" active="{{_edittingScript}}"></app-route>
route='[[route]]' <app-route route="[[route]]" pattern="/script/new" active="{{_creatingNew}}"></app-route>
pattern='/script/edit/:script'
data="{{_routeData}}"
active="{{_edittingScript}}"
></app-route>
<app-route
route='[[route]]'
pattern='/script/new'
active="{{_creatingNew}}"
></app-route>
<template is='dom-if' if='[[!showEditor]]'> <template is="dom-if" if="[[!showEditor]]">
<ha-script-picker <ha-script-picker hass="[[hass]]" narrow="[[narrow]]" show-menu="[[showMenu]]" scripts="[[scripts]]" is-wide="[[isWide]]"></ha-script-picker>
hass='[[hass]]'
narrow='[[narrow]]'
show-menu='[[showMenu]]'
scripts='[[scripts]]'
is-wide='[[isWide]]'
></ha-script-picker>
</template> </template>
<template is='dom-if' if='[[showEditor]]' restamp> <template is="dom-if" if="[[showEditor]]" restamp="">
<ha-script-editor <ha-script-editor hass="[[hass]]" script="[[script]]" is-wide="[[isWide]]" creating-new="[[_creatingNew]]"></ha-script-editor>
hass='[[hass]]'
script='[[script]]'
is-wide='[[isWide]]'
creating-new='[[_creatingNew]]'
></ha-script-editor>
</template> </template>
</template> `;
</dom-module> }
<script>
class HaConfigScript extends Polymer.Element {
static get is() { return 'ha-config-script'; } static get is() { return 'ha-config-script'; }
static get properties() { static get properties() {
@ -121,4 +101,3 @@ class HaConfigScript extends Polymer.Element {
} }
customElements.define(HaConfigScript.is, HaConfigScript); customElements.define(HaConfigScript.is, HaConfigScript);
</script>

View File

@ -1,31 +1,34 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/app-layout/app-header/app-header.js';
<link rel="import" href="../../../bower_components/app-layout/app-header/app-header.html"> import '@polymer/app-layout/app-toolbar/app-toolbar.js';
<link rel="import" href="../../../bower_components/app-layout/app-toolbar/app-toolbar.html"> import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu-light.js';
<link rel="import" href="../../../bower_components/paper-item/paper-item-body.html"> import '@polymer/paper-fab/paper-fab.js';
<link rel="import" href="../../../bower_components/paper-icon-button/paper-icon-button.html"> import '@polymer/paper-icon-button/paper-icon-button.js';
<link rel="import" href="../../../bower_components/paper-input/paper-input.html"> import '@polymer/paper-input/paper-input.js';
<link rel="import" href="../../../bower_components/paper-input/paper-textarea.html"> import '@polymer/paper-input/paper-textarea.js';
<link rel="import" href="../../../bower_components/paper-radio-button/paper-radio-button.html"> import '@polymer/paper-item/paper-item-body.js';
<link rel="import" href="../../../bower_components/paper-radio-group/paper-radio-group.html"> import '@polymer/paper-item/paper-item.js';
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu-light.html"> import '@polymer/paper-listbox/paper-listbox.js';
<link rel="import" href="../../../bower_components/paper-listbox/paper-listbox.html"> import '@polymer/paper-menu-button/paper-menu-button.js';
<link rel="import" href="../../../bower_components/paper-menu-button/paper-menu-button.html"> import '@polymer/paper-radio-button/paper-radio-button.js';
<link rel="import" href="../../../bower_components/paper-fab/paper-fab.html"> import '@polymer/paper-radio-group/paper-radio-group.js';
<link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel='import' href='../../../src/components/entity/ha-entity-picker.html'> import '../../../src/components/entity/ha-entity-picker.js';
<link rel='import' href='../../../src/components/ha-combo-box.html'> import '../../../src/components/ha-combo-box.js';
<link rel='import' href='../../../src/layouts/ha-app-layout.html'> import '../../../src/layouts/ha-app-layout.js';
<link rel='import' href='../../../src/util/hass-mixins.html'> import '../../../src/util/hass-mixins.js';
import '../ha-config-js.js';
import '../ha-config-section.js';
<link rel="import" href="../ha-config-section.html"> /*
* @appliesMixin window.hassMixins.LocalizeMixin
<link rel="import" href="../ha-config-js.html"> */
class HaScriptEditor extends window.hassMixins.LocalizeMixin(PolymerElement) {
<dom-module id="ha-script-editor"> static get template() {
<template> return html`
<style include="ha-style"> <style include="ha-style">
.errors { .errors {
padding: 20px; padding: 20px;
@ -81,39 +84,24 @@
margin-bottom: 0; margin-bottom: 0;
} }
</style> </style>
<ha-app-layout has-scrolling-region> <ha-app-layout has-scrolling-region="">
<app-header slot="header" fixed> <app-header slot="header" fixed="">
<app-toolbar> <app-toolbar>
<paper-icon-button <paper-icon-button icon="mdi:arrow-left" on-click="backTapped"></paper-icon-button>
icon='mdi:arrow-left' <div main-title="">Script [[name]]</div>
on-click='backTapped'
></paper-icon-button>
<div main-title>Script [[name]]</div>
</app-toolbar> </app-toolbar>
</app-header> </app-header>
<div class='content'> <div class="content">
<template is='dom-if' if='[[errors]]'> <template is="dom-if" if="[[errors]]">
<div class='errors'>[[errors]]</div> <div class="errors">[[errors]]</div>
</template> </template>
<div id='root'></div> <div id="root"></div>
</div> </div>
<paper-fab slot="fab" <paper-fab slot="fab" is-wide\$="[[isWide]]" dirty\$="[[dirty]]" icon="mdi:content-save" title="Save" on-click="saveScript"></paper-fab>
is-wide$='[[isWide]]'
dirty$='[[dirty]]'
icon='mdi:content-save'
title='Save'
on-click='saveScript'
></paper-fab>
</ha-app-layout> </ha-app-layout>
`;
}
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaScriptEditor extends window.hassMixins.LocalizeMixin(Polymer.Element) {
static get is() { return 'ha-script-editor'; } static get is() { return 'ha-script-editor'; }
static get properties() { static get properties() {
@ -286,4 +274,3 @@ class HaScriptEditor extends window.hassMixins.LocalizeMixin(Polymer.Element) {
} }
customElements.define(HaScriptEditor.is, HaScriptEditor); customElements.define(HaScriptEditor.is, HaScriptEditor);
</script>

View File

@ -1,150 +0,0 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.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/paper-card/paper-card.html">
<link rel="import" href="../../../bower_components/paper-item/paper-item.html">
<link rel="import" href="../../../bower_components/paper-item/paper-item-body.html">
<link rel="import" href="../../../bower_components/paper-fab/paper-fab.html">
<link rel="import" href="../../../bower_components/paper-icon-button/paper-icon-button.html">
<link rel='import' href='../../../src/layouts/ha-app-layout.html'>
<link rel='import' href='../../../src/util/hass-mixins.html'>
<link rel="import" href="../ha-config-section.html">
<dom-module id="ha-script-picker">
<template>
<style include="ha-style">
:host {
display: block;
}
paper-item {
cursor: pointer;
}
paper-fab {
position: fixed;
bottom: 16px;
right: 16px;
z-index: 1;
}
paper-fab[is-wide] {
bottom: 24px;
right: 24px;
}
a {
color: var(--primary-color);
}
</style>
<ha-app-layout has-scrolling-region>
<app-header slot="header" fixed>
<app-toolbar>
<paper-icon-button
icon='mdi:arrow-left'
on-click='_backTapped'
></paper-icon-button>
<div main-title>[[localize('ui.panel.config.script.caption')]]</div>
</app-toolbar>
</app-header>
<ha-config-section
is-wide='[[isWide]]'
>
<div slot='header'>Script Editor</div>
<div slot='introduction'>
The script editor allows you to create and edit scripts.
Please read <a href='https://home-assistant.io/docs/scripts/editor/' target='_blank'>the instructions</a> to make sure that you have configured Home Assistant correctly.
</div>
<paper-card heading='Pick script to edit'>
<template is='dom-if' if='[[!scripts.length]]'>
<div class='card-content'>
<p>We couldn't find any editable scripts.</p>
</div>
</template>
<template is='dom-repeat' items='[[scripts]]' as='script'>
<paper-item>
<paper-item-body two-line on-click='scriptTapped'>
<div>[[computeName(script)]]</div>
<div secondary>[[computeDescription(script)]]</div>
</paper-item-body>
<iron-icon icon='mdi:chevron-right'></iron-icon>
</paper-item>
</template>
</paper-card>
</ha-config-section>
<paper-fab slot="fab"
is-wide$='[[isWide]]'
icon='mdi:plus'
title='Add Script'
on-click='addScript'
></paper-fab>
</ha-app-layout>
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
*/
class HaScriptPicker extends
window.hassMixins.LocalizeMixin(window.hassMixins.NavigateMixin(Polymer.Element)) {
static get is() { return 'ha-script-picker'; }
static get properties() {
return {
hass: {
type: Object,
},
narrow: {
type: Boolean,
},
showMenu: {
type: Boolean,
value: false,
},
scripts: {
type: Array,
},
isWide: {
type: Boolean,
},
};
}
scriptTapped(ev) {
this.navigate('/config/script/edit/' + this.scripts[ev.model.index].entity_id);
}
addScript() {
this.navigate('/config/script/new');
}
computeName(script) {
return window.hassUtil.computeStateName(script);
}
// Still thinking of something to add here.
// eslint-disable-next-line
computeDescription(script) {
return '';
}
_backTapped() {
history.back();
}
}
customElements.define(HaScriptPicker.is, HaScriptPicker);
</script>

View File

@ -0,0 +1,137 @@
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-fab/paper-fab.js';
import '@polymer/paper-icon-button/paper-icon-button.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 '../../../src/layouts/ha-app-layout.js';
import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
/*
* @appliesMixin window.hassMixins.LocalizeMixin
* @appliesMixin window.hassMixins.EventsMixin
*/
class HaScriptPicker extends
window.hassMixins.LocalizeMixin(window.hassMixins.NavigateMixin(PolymerElement)) {
static get template() {
return html`
<style include="ha-style">
:host {
display: block;
}
paper-item {
cursor: pointer;
}
paper-fab {
position: fixed;
bottom: 16px;
right: 16px;
z-index: 1;
}
paper-fab[is-wide] {
bottom: 24px;
right: 24px;
}
a {
color: var(--primary-color);
}
</style>
<ha-app-layout has-scrolling-region="">
<app-header slot="header" fixed="">
<app-toolbar>
<paper-icon-button icon="mdi:arrow-left" on-click="_backTapped"></paper-icon-button>
<div main-title="">[[localize('ui.panel.config.script.caption')]]</div>
</app-toolbar>
</app-header>
<ha-config-section is-wide="[[isWide]]">
<div slot="header">Script Editor</div>
<div slot="introduction">
The script editor allows you to create and edit scripts.
Please read <a href="https://home-assistant.io/docs/scripts/editor/" target="_blank">the instructions</a> to make sure that you have configured Home Assistant correctly.
</div>
<paper-card heading="Pick script to edit">
<template is="dom-if" if="[[!scripts.length]]">
<div class="card-content">
<p>We couldn't find any editable scripts.</p>
</div>
</template>
<template is="dom-repeat" items="[[scripts]]" as="script">
<paper-item>
<paper-item-body two-line="" on-click="scriptTapped">
<div>[[computeName(script)]]</div>
<div secondary="">[[computeDescription(script)]]</div>
</paper-item-body>
<iron-icon icon="mdi:chevron-right"></iron-icon>
</paper-item>
</template>
</paper-card>
</ha-config-section>
<paper-fab slot="fab" is-wide\$="[[isWide]]" icon="mdi:plus" title="Add Script" on-click="addScript"></paper-fab>
</ha-app-layout>
`;
}
static get is() { return 'ha-script-picker'; }
static get properties() {
return {
hass: {
type: Object,
},
narrow: {
type: Boolean,
},
showMenu: {
type: Boolean,
value: false,
},
scripts: {
type: Array,
},
isWide: {
type: Boolean,
},
};
}
scriptTapped(ev) {
this.navigate('/config/script/edit/' + this.scripts[ev.model.index].entity_id);
}
addScript() {
this.navigate('/config/script/new');
}
computeName(script) {
return window.hassUtil.computeStateName(script);
}
// Still thinking of something to add here.
// eslint-disable-next-line
computeDescription(script) {
return '';
}
_backTapped() {
history.back();
}
}
customElements.define(HaScriptPicker.is, HaScriptPicker);

View File

@ -1,618 +0,0 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../../src/components/ha-menu-button.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/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel='import' href='../../../bower_components/paper-item/paper-item.html'>
<link rel='import' href="../../../bower_components/paper-listbox/paper-listbox.html">
<link rel='import' href="../../../bower_components/paper-input/paper-input.html">
<link rel="import" href="../../../src/components/buttons/ha-call-service-button.html">
<link rel="import" href="../../../src/components/ha-service-description.html">
<link rel='import' href='../../../src/layouts/ha-app-layout.html'>
<link rel="import" href="../../../src/resources/ha-style.html">
<link rel='import' href='../../../src/util/hass-mixins.html'>
<link rel="import" href="../ha-config-section.html">
<link rel="import" href="../ha-form-style.html">
<link rel="import" href="./zwave-log.html">
<link rel="import" href="./zwave-network.html">
<link rel="import" href="./zwave-node-information.html">
<link rel="import" href="./zwave-values.html">
<link rel="import" href="./zwave-groups.html">
<link rel="import" href="./zwave-node-config.html">
<link rel="import" href="./zwave-usercodes.html">
<dom-module id="ha-config-zwave">
<template>
<style include="iron-flex ha-style ha-form-style">
.content {
margin-top: 24px;
}
.node-info {
margin-left: 16px;
}
.help-text {
padding-left: 24px;
padding-right: 24px;
}
paper-card {
display: block;
margin: 0 auto;
max-width: 600px;
}
.device-picker {
@apply --layout-horizontal;
@apply --layout-center-center;
padding-left: 24px;
padding-right: 24px;
padding-bottom: 24px;
}
ha-service-description {
display: block;
color: grey;
}
[hidden] {
display: none;
}
.toggle-help-icon {
position: absolute;
top: 6px;
right: 0;
color: var(--primary-color);
}
</style>
<ha-app-layout has-scrolling-region>
<app-header slot="header" fixed>
<app-toolbar>
<paper-icon-button
icon='mdi:arrow-left'
on-click='_backTapped'
></paper-icon-button>
<div main-title>[[localize('ui.panel.config.zwave.caption')]]</div>
</app-toolbar>
</app-header>
<zwave-network
id='zwave-network'
is-wide='[[isWide]]'
hass='[[hass]]'
></zwave-network>
<!--Node card-->
<ha-config-section is-wide='[[isWide]]'>
<div style="position: relative" slot='header'>
<span>Z-Wave Node Management</span>
<paper-icon-button
class="toggle-help-icon"
on-click='toggleHelp'
icon='mdi:help-circle'
></paper-icon-button>
</div>
<span slot='introduction'>
Run Z-Wave commands that affect a single node. Pick a node to see a list of available commands.
</span>
<paper-card class="content">
<div class='device-picker'>
<paper-dropdown-menu dynamic-align label="Nodes" class="flex">
<paper-listbox slot="dropdown-content" selected='{{selectedNode}}'>
<template is='dom-repeat' items='[[nodes]]' as='state'>
<paper-item>[[computeSelectCaption(state)]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
<template is='dom-if' if='[[!computeIsNodeSelected(selectedNode)]]'>
<template is='dom-if' if='[[showHelp]]'>
<div style='color: grey; padding: 12px'>Select node to view per-node options</div>
</template>
</template>
<template is='dom-if' if='[[computeIsNodeSelected(selectedNode)]]'>
<div class='card-actions'>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='refresh_node'
service-data=[[computeNodeServiceData(selectedNode)]]
>Refresh Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='refresh_node'
hidden$='[[!showHelp]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='remove_failed_node'
service-data=[[computeNodeServiceData(selectedNode)]]
>Remove Failed Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='remove_failed_node'
hidden$='[[!showHelp]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='replace_failed_node'
service-data=[[computeNodeServiceData(selectedNode)]]
>Replace Failed Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='replace_failed_node'
hidden$='[[!showHelp]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='print_node'
service-data=[[computeNodeServiceData(selectedNode)]]
>Print Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='print_node'
hidden$='[[!showHelp]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='heal_node'
service-data=[[computeHealNodeServiceData(selectedNode)]]
>Heal Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='heal_node'
hidden$='[[!showHelp]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='test_node'
service-data=[[computeNodeServiceData(selectedNode)]]
>Test Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='test_node'
hidden$='[[!showHelp]]'
></ha-service-description>
</div>
<div class='card-actions'>
<paper-input
float-label="New node name"
type=text
value={{newNodeNameInput}}
placeholder=[[computeGetNodeName(selectedNode)]]>
</paper-input>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='rename_node'
service-data=[[computeNodeNameServiceData(newNodeNameInput)]]
>Rename Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='rename_node'
hidden$='[[!showHelp]]'
></ha-service-description>
</div>
<div class='device-picker'>
<paper-dropdown-menu label="Entities of this node" dynamic-align class="flex">
<paper-listbox
slot="dropdown-content"
selected='{{selectedEntity}}'>
<template is='dom-repeat' items='[[entities]]' as='state'>
<paper-item>[[computeSelectCaptionEnt(state)]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
<template is='dom-if' if='[[!computeIsEntitySelected(selectedEntity)]]'>
<div class='card-actions'>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='refresh_entity'
service-data=[[computeRefreshEntityServiceData(selectedEntity)]]
>Refresh Entity</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='refresh_entity'
hidden$='[[!showHelp]]'
></ha-service-description>
</div>
<div class='form-group'>
<paper-checkbox
checked='{{entityIgnored}}'
class='form-control'
>
Exclude this entity from Home Assistant
</paper-checkbox>
<paper-input
disabled='{{entityIgnored}}'
label="Polling intensity"
type=number
min=0
value={{entityPollingIntensity}}>
</paper-input>
</div>
<div class='card-actions'>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='set_poll_intensity'
service-data=[[computePollIntensityServiceData(entityPollingIntensity)]]
>Save</ha-call-service-button>
</div>
<div class='content'>
<div class='card-actions'>
<paper-button toggles raised noink active={{entityInfoActive}}>Entity Attributes</paper-button>
</div>
<template is='dom-if' if={{entityInfoActive}}>
<template is='dom-repeat' items='[[selectedEntityAttrs]]' as='state'>
<div class='node-info'>
<span>[[state]]</span>
</div>
</template>
</template>
</div>
</template>
</template>
</paper-card>
<template is='dom-if' if='[[computeIsNodeSelected(selectedNode)]]'>
<!--Node info card-->
<zwave-node-information
id='zwave-node-information'
nodes='[[nodes]]'
selected-node='[[selectedNode]]'
></zwave-node-information>
<!--Value card-->
<zwave-values
hass='[[hass]]'
nodes='[[nodes]]'
selected-node='[[selectedNode]]'
values='[[values]]'
></zwave-values>
<!--Group card-->
<zwave-groups
hass='[[hass]]'
nodes='[[nodes]]'
selected-node='[[selectedNode]]'
groups='[[groups]]'
></zwave-groups>
<!--Config card-->
<zwave-node-config
hass='[[hass]]'
nodes='[[nodes]]'
selected-node='[[selectedNode]]'
config='[[config]]'
></zwave-node-config>
</template>
<!--User Codes-->
<template is='dom-if' if='{{hasNodeUserCodes}}'>
<zwave-usercodes
id='zwave-usercodes'
hass='[[hass]]'
nodes='[[nodes]]'
user-codes='[[userCodes]]'
selected-node='[[selectedNode]]'
></zwave-usercodes>
</template>
</ha-config-section>
<!--Ozw log-->
<ozw-log
is-wide='[[isWide]]'
hass='[[hass]]'
></ozw-log>
</ha-app-layout>
</template>
</dom-module>
<script>
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigZwave extends window.hassMixins.LocalizeMixin(Polymer.Element) {
static get is() { return 'ha-config-zwave'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
nodes: {
type: Array,
computed: 'computeNodes(hass)'
},
selectedNode: {
type: Number,
value: -1,
observer: 'selectedNodeChanged'
},
config: {
type: Array,
value: function () {
return [];
}
},
entities: {
type: Array,
computed: 'computeEntities(selectedNode)',
},
entityInfoActive: {
type: Boolean,
},
selectedEntity: {
type: Number,
value: -1,
observer: 'selectedEntityChanged',
},
selectedEntityAttrs: {
type: Array,
computed: 'computeSelectedEntityAttrs(selectedEntity)'
},
values: {
type: Array,
},
groups: {
type: Array,
},
newNodeNameInput: {
type: String,
},
userCodes: {
type: Array,
value: function () {
return [];
},
},
hasNodeUserCodes: {
type: Boolean,
value: false,
},
showHelp: {
type: Boolean,
value: false,
},
entityIgnored: {
type: Boolean,
},
entityPollingIntensity: {
type: Number,
value: 0,
},
};
}
ready() {
super.ready();
this.addEventListener('hass-service-called', ev => this.serviceCalled(ev));
}
serviceCalled(ev) {
var el = this;
if ((ev.detail.success) && (ev.detail.service === 'set_poll_intensity')) {
el.saveEntity();
}
}
computeNodes(hass) {
return Object.keys(hass.states)
.map(function (key) { return hass.states[key]; })
.filter(function (ent) {
return ((ent.entity_id).match('zwave[.]'));
})
.sort(window.hassUtil.sortByName);
}
computeEntities(selectedNode) {
if (!this.nodes || selectedNode === -1) return -1;
var hass = this.hass;
var nodeid = this.nodes[this.selectedNode].attributes.node_id;
return Object.keys(hass.states)
.map(function (key) { return hass.states[key]; })
.filter(function (ent) {
if (ent.attributes.node_id === undefined) {
return false;
}
return (!ent.attributes.hidden &&
'node_id' in ent.attributes &&
ent.attributes.node_id === nodeid &&
(!(ent.entity_id).match('zwave[.]')));
})
.sort(window.hassUtil.sortByName);
}
selectedNodeChanged(selectedNode) {
this.newNodeNameInput = '';
if (selectedNode === -1) return;
this.selectedConfigParameter = -1;
this.selectedConfigParameterValue = -1;
this.selectedGroup = -1;
this.hass.callApi('GET', 'zwave/config/' + this.nodes[selectedNode].attributes.node_id).then((configs) => {
this.config = this._objToArray(configs);
});
this.hass.callApi('GET', 'zwave/values/' + this.nodes[selectedNode].attributes.node_id).then((values) => {
this.values = this._objToArray(values);
});
this.hass.callApi('GET', 'zwave/groups/' + this.nodes[selectedNode].attributes.node_id).then((groups) => {
this.groups = this._objToArray(groups);
});
this.hasNodeUserCodes = false;
this.notifyPath('hasNodeUserCodes');
this.hass.callApi('GET', 'zwave/usercodes/' + this.nodes[selectedNode].attributes.node_id).then((usercodes) => {
this.userCodes = this._objToArray(usercodes);
this.hasNodeUserCodes = this.userCodes.length > 0;
this.notifyPath('hasNodeUserCodes');
});
}
selectedEntityChanged(selectedEntity) {
if (selectedEntity === -1) return;
var el = this;
el.hass.callApi('GET', 'zwave/values/' + el.nodes[el.selectedNode].attributes.node_id).then((values) => {
el.values = el._objToArray(values);
});
var valueId = el.entities[selectedEntity].attributes.value_id;
var valueData = el.values.find(function (obj) { return obj.key === valueId; });
var valueIndex = el.values.indexOf(valueData);
el.hass.callApi('GET', 'config/zwave/device_config/' + valueId)
.then(function (data) {
el.entityIgnored = data.ignored || false;
el.entityPollingIntensity = el.values[valueIndex].value.poll_intensity;
});
}
computeSelectedEntityAttrs(selectedEntity) {
if (selectedEntity === -1) return 'No entity selected';
var entityAttrs = this.entities[selectedEntity].attributes;
var att = [];
Object.keys(entityAttrs).forEach(function (key) {
att.push(key + ': ' + entityAttrs[key]);
});
return att.sort();
}
computeSelectCaption(stateObj) {
return window.hassUtil.computeStateName(stateObj) + ' (Node:' +
stateObj.attributes.node_id + ' ' +
stateObj.attributes.query_stage + ')';
}
computeSelectCaptionEnt(stateObj) {
return (window.hassUtil.computeDomain(stateObj) + '.'
+ window.hassUtil.computeStateName(stateObj));
}
computeIsNodeSelected() {
return (this.nodes && this.selectedNode !== -1);
}
computeIsEntitySelected(selectedEntity) {
return (selectedEntity === -1);
}
computeNodeServiceData(selectedNode) {
return { node_id: this.nodes[selectedNode].attributes.node_id };
}
computeHealNodeServiceData(selectedNode) {
return {
node_id: this.nodes[selectedNode].attributes.node_id,
return_routes: true
};
}
computeGetNodeName(selectedNode) {
if (this.selectedNode === -1 ||
!this.nodes[selectedNode].entity_id) return -1;
return this.nodes[selectedNode].attributes.node_name;
}
computeNodeNameServiceData(newNodeNameInput) {
return {
node_id: this.nodes[this.selectedNode].attributes.node_id,
name: newNodeNameInput
};
}
computeRefreshEntityServiceData(selectedEntity) {
if (selectedEntity === -1) return -1;
return { entity_id: this.entities[selectedEntity].entity_id };
}
computePollIntensityServiceData(entityPollingIntensity) {
if (!this.selectedNode === -1 || this.selectedEntity === -1) return -1;
return {
node_id: this.nodes[this.selectedNode].attributes.node_id,
value_id: this.entities[this.selectedEntity].attributes.value_id,
poll_intensity: parseInt(entityPollingIntensity),
};
}
saveEntity() {
var data = {
ignored: this.entityIgnored,
polling_intensity: parseInt(this.entityPollingIntensity),
};
return this.hass.callApi('POST', 'config/zwave/device_config/' + this.entities[this.selectedEntity].entity_id, data);
}
toggleHelp() {
this.showHelp = !this.showHelp;
}
_objToArray(obj) {
var array = [];
Object.keys(obj).forEach(function (key) {
array.push({
key: key,
value: obj[key],
});
});
return array;
}
_backTapped() {
history.back();
}
}
customElements.define(HaConfigZwave.is, HaConfigZwave);
</script>

View File

@ -0,0 +1,477 @@
import '@polymer/app-layout/app-header/app-header.js';
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
import '@polymer/paper-icon-button/paper-icon-button.js';
import '@polymer/paper-input/paper-input.js';
import '@polymer/paper-item/paper-item.js';
import '@polymer/paper-listbox/paper-listbox.js';
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import '../../../src/components/buttons/ha-call-service-button.js';
import '../../../src/components/ha-menu-button.js';
import '../../../src/components/ha-service-description.js';
import '../../../src/layouts/ha-app-layout.js';
import '../../../src/resources/ha-style.js';
import '../../../src/util/hass-mixins.js';
import '../ha-config-section.js';
import '../ha-form-style.js';
import './zwave-groups.js';
import './zwave-log.js';
import './zwave-network.js';
import './zwave-node-config.js';
import './zwave-node-information.js';
import './zwave-usercodes.js';
import './zwave-values.js';
/*
* @appliesMixin window.hassMixins.LocalizeMixin
*/
class HaConfigZwave extends window.hassMixins.LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex ha-style ha-form-style">
.content {
margin-top: 24px;
}
.node-info {
margin-left: 16px;
}
.help-text {
padding-left: 24px;
padding-right: 24px;
}
paper-card {
display: block;
margin: 0 auto;
max-width: 600px;
}
.device-picker {
@apply --layout-horizontal;
@apply --layout-center-center;
padding-left: 24px;
padding-right: 24px;
padding-bottom: 24px;
}
ha-service-description {
display: block;
color: grey;
}
[hidden] {
display: none;
}
.toggle-help-icon {
position: absolute;
top: 6px;
right: 0;
color: var(--primary-color);
}
</style>
<ha-app-layout has-scrolling-region="">
<app-header slot="header" fixed="">
<app-toolbar>
<paper-icon-button icon="mdi:arrow-left" on-click="_backTapped"></paper-icon-button>
<div main-title="">[[localize('ui.panel.config.zwave.caption')]]</div>
</app-toolbar>
</app-header>
<zwave-network id="zwave-network" is-wide="[[isWide]]" hass="[[hass]]"></zwave-network>
<!--Node card-->
<ha-config-section is-wide="[[isWide]]">
<div style="position: relative" slot="header">
<span>Z-Wave Node Management</span>
<paper-icon-button class="toggle-help-icon" on-click="toggleHelp" icon="mdi:help-circle"></paper-icon-button>
</div>
<span slot="introduction">
Run Z-Wave commands that affect a single node. Pick a node to see a list of available commands.
</span>
<paper-card class="content">
<div class="device-picker">
<paper-dropdown-menu dynamic-align="" label="Nodes" class="flex">
<paper-listbox slot="dropdown-content" selected="{{selectedNode}}">
<template is="dom-repeat" items="[[nodes]]" as="state">
<paper-item>[[computeSelectCaption(state)]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
<template is="dom-if" if="[[!computeIsNodeSelected(selectedNode)]]">
<template is="dom-if" if="[[showHelp]]">
<div style="color: grey; padding: 12px">Select node to view per-node options</div>
</template>
</template>
<template is="dom-if" if="[[computeIsNodeSelected(selectedNode)]]">
<div class="card-actions">
<ha-call-service-button hass="[[hass]]" domain="zwave" service="refresh_node" service-data="[[computeNodeServiceData(selectedNode)]]">Refresh Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="refresh_node" hidden\$="[[!showHelp]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="remove_failed_node" service-data="[[computeNodeServiceData(selectedNode)]]">Remove Failed Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="remove_failed_node" hidden\$="[[!showHelp]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="replace_failed_node" service-data="[[computeNodeServiceData(selectedNode)]]">Replace Failed Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="replace_failed_node" hidden\$="[[!showHelp]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="print_node" service-data="[[computeNodeServiceData(selectedNode)]]">Print Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="print_node" hidden\$="[[!showHelp]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="heal_node" service-data="[[computeHealNodeServiceData(selectedNode)]]">Heal Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="heal_node" hidden\$="[[!showHelp]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="test_node" service-data="[[computeNodeServiceData(selectedNode)]]">Test Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="test_node" hidden\$="[[!showHelp]]"></ha-service-description>
</div>
<div class="card-actions">
<paper-input float-label="New node name" type="text" value="{{newNodeNameInput}}" placeholder="[[computeGetNodeName(selectedNode)]]">
</paper-input>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="rename_node" service-data="[[computeNodeNameServiceData(newNodeNameInput)]]">Rename Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="rename_node" hidden\$="[[!showHelp]]"></ha-service-description>
</div>
<div class="device-picker">
<paper-dropdown-menu label="Entities of this node" dynamic-align="" class="flex">
<paper-listbox slot="dropdown-content" selected="{{selectedEntity}}">
<template is="dom-repeat" items="[[entities]]" as="state">
<paper-item>[[computeSelectCaptionEnt(state)]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
<template is="dom-if" if="[[!computeIsEntitySelected(selectedEntity)]]">
<div class="card-actions">
<ha-call-service-button hass="[[hass]]" domain="zwave" service="refresh_entity" service-data="[[computeRefreshEntityServiceData(selectedEntity)]]">Refresh Entity</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="refresh_entity" hidden\$="[[!showHelp]]"></ha-service-description>
</div>
<div class="form-group">
<paper-checkbox checked="{{entityIgnored}}" class="form-control">
Exclude this entity from Home Assistant
</paper-checkbox>
<paper-input disabled="{{entityIgnored}}" label="Polling intensity" type="number" min="0" value="{{entityPollingIntensity}}">
</paper-input>
</div>
<div class="card-actions">
<ha-call-service-button hass="[[hass]]" domain="zwave" service="set_poll_intensity" service-data="[[computePollIntensityServiceData(entityPollingIntensity)]]">Save</ha-call-service-button>
</div>
<div class="content">
<div class="card-actions">
<paper-button toggles="" raised="" noink="" active="{{entityInfoActive}}">Entity Attributes</paper-button>
</div>
<template is="dom-if" if="{{entityInfoActive}}">
<template is="dom-repeat" items="[[selectedEntityAttrs]]" as="state">
<div class="node-info">
<span>[[state]]</span>
</div>
</template>
</template>
</div>
</template>
</template>
</paper-card>
<template is="dom-if" if="[[computeIsNodeSelected(selectedNode)]]">
<!--Node info card-->
<zwave-node-information id="zwave-node-information" nodes="[[nodes]]" selected-node="[[selectedNode]]"></zwave-node-information>
<!--Value card-->
<zwave-values hass="[[hass]]" nodes="[[nodes]]" selected-node="[[selectedNode]]" values="[[values]]"></zwave-values>
<!--Group card-->
<zwave-groups hass="[[hass]]" nodes="[[nodes]]" selected-node="[[selectedNode]]" groups="[[groups]]"></zwave-groups>
<!--Config card-->
<zwave-node-config hass="[[hass]]" nodes="[[nodes]]" selected-node="[[selectedNode]]" config="[[config]]"></zwave-node-config>
</template>
<!--User Codes-->
<template is="dom-if" if="{{hasNodeUserCodes}}">
<zwave-usercodes id="zwave-usercodes" hass="[[hass]]" nodes="[[nodes]]" user-codes="[[userCodes]]" selected-node="[[selectedNode]]"></zwave-usercodes>
</template>
</ha-config-section>
<!--Ozw log-->
<ozw-log is-wide="[[isWide]]" hass="[[hass]]"></ozw-log>
</ha-app-layout>
`;
}
static get is() { return 'ha-config-zwave'; }
static get properties() {
return {
hass: Object,
isWide: Boolean,
nodes: {
type: Array,
computed: 'computeNodes(hass)'
},
selectedNode: {
type: Number,
value: -1,
observer: 'selectedNodeChanged'
},
config: {
type: Array,
value: function () {
return [];
}
},
entities: {
type: Array,
computed: 'computeEntities(selectedNode)',
},
entityInfoActive: {
type: Boolean,
},
selectedEntity: {
type: Number,
value: -1,
observer: 'selectedEntityChanged',
},
selectedEntityAttrs: {
type: Array,
computed: 'computeSelectedEntityAttrs(selectedEntity)'
},
values: {
type: Array,
},
groups: {
type: Array,
},
newNodeNameInput: {
type: String,
},
userCodes: {
type: Array,
value: function () {
return [];
},
},
hasNodeUserCodes: {
type: Boolean,
value: false,
},
showHelp: {
type: Boolean,
value: false,
},
entityIgnored: {
type: Boolean,
},
entityPollingIntensity: {
type: Number,
value: 0,
},
};
}
ready() {
super.ready();
this.addEventListener('hass-service-called', ev => this.serviceCalled(ev));
}
serviceCalled(ev) {
var el = this;
if ((ev.detail.success) && (ev.detail.service === 'set_poll_intensity')) {
el.saveEntity();
}
}
computeNodes(hass) {
return Object.keys(hass.states)
.map(function (key) { return hass.states[key]; })
.filter(function (ent) {
return ((ent.entity_id).match('zwave[.]'));
})
.sort(window.hassUtil.sortByName);
}
computeEntities(selectedNode) {
if (!this.nodes || selectedNode === -1) return -1;
var hass = this.hass;
var nodeid = this.nodes[this.selectedNode].attributes.node_id;
return Object.keys(hass.states)
.map(function (key) { return hass.states[key]; })
.filter(function (ent) {
if (ent.attributes.node_id === undefined) {
return false;
}
return (!ent.attributes.hidden &&
'node_id' in ent.attributes &&
ent.attributes.node_id === nodeid &&
(!(ent.entity_id).match('zwave[.]')));
})
.sort(window.hassUtil.sortByName);
}
selectedNodeChanged(selectedNode) {
this.newNodeNameInput = '';
if (selectedNode === -1) return;
this.selectedConfigParameter = -1;
this.selectedConfigParameterValue = -1;
this.selectedGroup = -1;
this.hass.callApi('GET', 'zwave/config/' + this.nodes[selectedNode].attributes.node_id).then((configs) => {
this.config = this._objToArray(configs);
});
this.hass.callApi('GET', 'zwave/values/' + this.nodes[selectedNode].attributes.node_id).then((values) => {
this.values = this._objToArray(values);
});
this.hass.callApi('GET', 'zwave/groups/' + this.nodes[selectedNode].attributes.node_id).then((groups) => {
this.groups = this._objToArray(groups);
});
this.hasNodeUserCodes = false;
this.notifyPath('hasNodeUserCodes');
this.hass.callApi('GET', 'zwave/usercodes/' + this.nodes[selectedNode].attributes.node_id).then((usercodes) => {
this.userCodes = this._objToArray(usercodes);
this.hasNodeUserCodes = this.userCodes.length > 0;
this.notifyPath('hasNodeUserCodes');
});
}
selectedEntityChanged(selectedEntity) {
if (selectedEntity === -1) return;
var el = this;
el.hass.callApi('GET', 'zwave/values/' + el.nodes[el.selectedNode].attributes.node_id).then((values) => {
el.values = el._objToArray(values);
});
var valueId = el.entities[selectedEntity].attributes.value_id;
var valueData = el.values.find(function (obj) { return obj.key === valueId; });
var valueIndex = el.values.indexOf(valueData);
el.hass.callApi('GET', 'config/zwave/device_config/' + valueId)
.then(function (data) {
el.entityIgnored = data.ignored || false;
el.entityPollingIntensity = el.values[valueIndex].value.poll_intensity;
});
}
computeSelectedEntityAttrs(selectedEntity) {
if (selectedEntity === -1) return 'No entity selected';
var entityAttrs = this.entities[selectedEntity].attributes;
var att = [];
Object.keys(entityAttrs).forEach(function (key) {
att.push(key + ': ' + entityAttrs[key]);
});
return att.sort();
}
computeSelectCaption(stateObj) {
return window.hassUtil.computeStateName(stateObj) + ' (Node:' +
stateObj.attributes.node_id + ' ' +
stateObj.attributes.query_stage + ')';
}
computeSelectCaptionEnt(stateObj) {
return (window.hassUtil.computeDomain(stateObj) + '.'
+ window.hassUtil.computeStateName(stateObj));
}
computeIsNodeSelected() {
return (this.nodes && this.selectedNode !== -1);
}
computeIsEntitySelected(selectedEntity) {
return (selectedEntity === -1);
}
computeNodeServiceData(selectedNode) {
return { node_id: this.nodes[selectedNode].attributes.node_id };
}
computeHealNodeServiceData(selectedNode) {
return {
node_id: this.nodes[selectedNode].attributes.node_id,
return_routes: true
};
}
computeGetNodeName(selectedNode) {
if (this.selectedNode === -1 ||
!this.nodes[selectedNode].entity_id) return -1;
return this.nodes[selectedNode].attributes.node_name;
}
computeNodeNameServiceData(newNodeNameInput) {
return {
node_id: this.nodes[this.selectedNode].attributes.node_id,
name: newNodeNameInput
};
}
computeRefreshEntityServiceData(selectedEntity) {
if (selectedEntity === -1) return -1;
return { entity_id: this.entities[selectedEntity].entity_id };
}
computePollIntensityServiceData(entityPollingIntensity) {
if (!this.selectedNode === -1 || this.selectedEntity === -1) return -1;
return {
node_id: this.nodes[this.selectedNode].attributes.node_id,
value_id: this.entities[this.selectedEntity].attributes.value_id,
poll_intensity: parseInt(entityPollingIntensity),
};
}
saveEntity() {
var data = {
ignored: this.entityIgnored,
polling_intensity: parseInt(this.entityPollingIntensity),
};
return this.hass.callApi('POST', 'config/zwave/device_config/' + this.entities[this.selectedEntity].entity_id, data);
}
toggleHelp() {
this.showHelp = !this.showHelp;
}
_objToArray(obj) {
var array = [];
Object.keys(obj).forEach(function (key) {
array.push({
key: key,
value: obj[key],
});
});
return array;
}
_backTapped() {
history.back();
}
}
customElements.define(HaConfigZwave.is, HaConfigZwave);

View File

@ -1,13 +1,15 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> import '@polymer/paper-item/paper-item.js';
<link rel='import' href='../../../bower_components/paper-item/paper-item.html'> import '@polymer/paper-listbox/paper-listbox.js';
<link rel='import' href="../../../bower_components/paper-listbox/paper-listbox.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/components/buttons/ha-call-service-button.html"> import '../../../src/components/buttons/ha-call-service-button.js';
<dom-module id='zwave-groups'> class ZwaveGroups extends PolymerElement {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
margin-top: 24px; margin-top: 24px;
@ -33,70 +35,54 @@
padding-bottom: 12px; padding-bottom: 12px;
} }
</style> </style>
<paper-card class="content" heading='Node group associations'> <paper-card class="content" heading="Node group associations">
<!--TODO make api for getting groups and members--> <!--TODO make api for getting groups and members-->
<div class='device-picker'> <div class="device-picker">
<paper-dropdown-menu label="Group" dynamic-align class='flex'> <paper-dropdown-menu label="Group" dynamic-align="" class="flex">
<paper-listbox <paper-listbox slot="dropdown-content" selected="{{selectedGroup}}">
slot="dropdown-content" <template is="dom-repeat" items="[[groups]]" as="state">
selected='{{selectedGroup}}'>
<template is='dom-repeat' items='[[groups]]' as='state'>
<paper-item>[[computeSelectCaptionGroup(state)]]</paper-item> <paper-item>[[computeSelectCaptionGroup(state)]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<template is='dom-if' if='[[computeIsGroupSelected(selectedGroup)]]'> <template is="dom-if" if="[[computeIsGroupSelected(selectedGroup)]]">
<div class='device-picker'> <div class="device-picker">
<paper-dropdown-menu label="Node to control" dynamic-align class='flex'> <paper-dropdown-menu label="Node to control" dynamic-align="" class="flex">
<paper-listbox <paper-listbox slot="dropdown-content" selected="{{selectedTargetNode}}">
slot="dropdown-content" <template is="dom-repeat" items="[[nodes]]" as="state">
selected='{{selectedTargetNode}}'>
<template is='dom-repeat' items='[[nodes]]' as='state'>
<paper-item>[[computeSelectCaption(state)]]</paper-item> <paper-item>[[computeSelectCaption(state)]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<div class='help-text'> <div class="help-text">
<span>Other Nodes in this group:</span> <span>Other Nodes in this group:</span>
<template is='dom-repeat' items='[[otherGroupNodes]]' as='state'> <template is="dom-repeat" items="[[otherGroupNodes]]" as="state">
<div>[[state]]</div> <div>[[state]]</div>
</template> </template>
</div> </div>
<div class='help-text'> <div class="help-text">
<span>Max Associations:</span> <span>Max Associations:</span>
<span>[[maxAssociations]]</span> <span>[[maxAssociations]]</span>
</div> </div>
</template> </template>
<template is='dom-if' if='[[computeIsTargetNodeSelected(selectedTargetNode)]]'> <template is="dom-if" if="[[computeIsTargetNodeSelected(selectedTargetNode)]]">
<div class='card-actions'> <div class="card-actions">
<template is='dom-if' if='[[!noAssociationsLeft]]'> <template is="dom-if" if="[[!noAssociationsLeft]]">
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="zwave" service="change_association" service-data="[[computeAssocServiceData(selectedGroup, &quot;add&quot;)]]">Add To Group</ha-call-service-button>
hass='[[hass]]'
domain='zwave'
service='change_association'
service-data='[[computeAssocServiceData(selectedGroup, "add")]]'
>Add To Group</ha-call-service-button>
</template> </template>
<template is='dom-if' if='[[computeTargetInGroup(selectedGroup, selectedTargetNode)]]'> <template is="dom-if" if="[[computeTargetInGroup(selectedGroup, selectedTargetNode)]]">
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="zwave" service="change_association" service-data="[[computeAssocServiceData(selectedGroup, &quot;remove&quot;)]]">Remove From Group</ha-call-service-button>
hass='[[hass]]'
domain='zwave'
service='change_association'
service-data='[[computeAssocServiceData(selectedGroup, "remove")]]'
>Remove From Group</ha-call-service-button>
</template> </template>
</div> </div>
</template> </template>
</paper-card> </paper-card>
</template> `;
</dom-module> }
<script>
class ZwaveGroups extends Polymer.Element {
static get is() { return 'zwave-groups'; } static get is() { return 'zwave-groups'; }
static get properties() { static get properties() {
@ -253,4 +239,3 @@ class ZwaveGroups extends Polymer.Element {
} }
customElements.define(ZwaveGroups.is, ZwaveGroups); customElements.define(ZwaveGroups.is, ZwaveGroups);
</script>

View File

@ -1,13 +1,15 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-button/paper-button.html"> import '@polymer/paper-checkbox/paper-checkbox.js';
<link rel="import" href="../../../bower_components/paper-checkbox/paper-checkbox.html"> import '@polymer/paper-input/paper-input.js';
<link rel="import" href="../../../bower_components/paper-input/paper-input.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../ha-config-section.html"> import '../ha-config-section.js';
<dom-module id='ozw-log'> class OzwLog extends PolymerElement {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
margin-top: 24px; margin-top: 24px;
@ -25,32 +27,24 @@
padding-bottom: 24px; padding-bottom: 24px;
} }
</style> </style>
<ha-config-section is-wide='[[isWide]]'> <ha-config-section is-wide="[[isWide]]">
<span slot='header'>OZW Log</span> <span slot="header">OZW Log</span>
<paper-card> <paper-card>
<div class='device-picker'> <div class="device-picker">
<paper-input <paper-input label="Number of last log lines." type="number" min="0" max="1000" step="10" value="{{numLogLines}}">
label="Number of last log lines."
type=number
min=0
max=1000
step=10
value={{numLogLines}}>
</paper-input> </paper-input>
</div> </div>
<div class="card-actions"> <div class="card-actions">
<paper-button raised on-click='refreshLog'>Refresh</paper-button> <paper-button raised="" on-click="refreshLog">Refresh</paper-button>
</div> </div>
<div class='help-text'> <div class="help-text">
<pre>[[ozwLogs]]</pre> <pre>[[ozwLogs]]</pre>
</div> </div>
</paper-card> </paper-card>
</ha-config-section> </ha-config-section>
</template> `;
</dom-module> }
<script>
class OzwLog extends Polymer.Element {
static get is() { return 'ozw-log'; } static get is() { return 'ozw-log'; }
static get properties() { static get properties() {
@ -86,4 +80,3 @@ class OzwLog extends Polymer.Element {
} }
customElements.define(OzwLog.is, OzwLog); customElements.define(OzwLog.is, OzwLog);
</script>

View File

@ -1,204 +0,0 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../../src/components/buttons/ha-call-service-button.html">
<link rel="import" href="../../../src/components/buttons/ha-call-api-button.html">
<link rel="import" href="../../../src/components/ha-service-description.html">
<link rel="import" href="../ha-config-section.html">
<dom-module id='zwave-network'>
<template>
<style include="iron-flex ha-style">
.content {
margin-top: 24px;
}
paper-card {
display: block;
margin: 0 auto;
max-width: 600px;
}
.card-actions.warning ha-call-service-button {
color: var(--google-red-500);
}
.toggle-help-icon {
position: absolute;
top: -6px;
right: 0;
color: var(--primary-color);
}
ha-service-description {
display: block;
color: grey;
}
[hidden] {
display: none;
}
</style>
<ha-config-section is-wide='[[isWide]]'>
<div style="position: relative" slot='header'>
<span>Z-Wave Network Management</span>
<paper-icon-button
class="toggle-help-icon"
on-click='helpTap'
icon='mdi:help-circle'
></paper-icon-button>
</div>
<span slot='introduction'>
Run commands that affect the Z-Wave network. You won't get feedback on whether the command succeeded, but you can look in the OZW Log to try to figure out.
</span>
<paper-card class="content">
<div class='card-actions'>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='add_node_secure'
>Add Node Secure</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='add_node_secure'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='add_node'
>Add Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='add_node'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='remove_node'
>Remove Node</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='remove_node'
hidden$='[[!showDescription]]'
></ha-service-description>
</div>
<div class='card-actions warning'>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='cancel_command'
>Cancel Command</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='cancel_command'
hidden$='[[!showDescription]]'
></ha-service-description>
</div>
<div class='card-actions'>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='heal_network'
>Heal Network</ha-call-service-button>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='start_network'
>Start Network</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='start_network'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='stop_network'
>Stop Network</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='stop_network'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='soft_reset'
>Soft Reset</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='soft_reset'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-service-button
hass='[[hass]]'
domain='zwave'
service='test_network'
>Test Network</ha-call-service-button>
<ha-service-description
hass='[[hass]]'
domain='zwave'
service='test_network'
hidden$='[[!showDescription]]'
></ha-service-description>
<ha-call-api-button
hass='[[hass]]'
path="zwave/saveconfig"
>Save Config</ha-call-api-button>
</div>
</paper-card>
</ha-config-section>
</template>
</dom-module>
<script>
class ZwaveNetwork extends Polymer.Element {
static get is() { return 'zwave-network'; }
static get properties() {
return {
hass: {
type: Object,
},
isWide: {
type: Boolean,
value: false,
},
showDescription: {
type: Boolean,
value: false,
},
};
}
helpTap() {
this.showDescription = !this.showDescription;
}
}
customElements.define(ZwaveNetwork.is, ZwaveNetwork);
</script>

View File

@ -0,0 +1,120 @@
import '@polymer/paper-card/paper-card.js';
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 '../../../src/components/buttons/ha-call-api-button.js';
import '../../../src/components/buttons/ha-call-service-button.js';
import '../../../src/components/ha-service-description.js';
import '../ha-config-section.js';
class ZwaveNetwork extends PolymerElement {
static get template() {
return html`
<style include="iron-flex ha-style">
.content {
margin-top: 24px;
}
paper-card {
display: block;
margin: 0 auto;
max-width: 600px;
}
.card-actions.warning ha-call-service-button {
color: var(--google-red-500);
}
.toggle-help-icon {
position: absolute;
top: -6px;
right: 0;
color: var(--primary-color);
}
ha-service-description {
display: block;
color: grey;
}
[hidden] {
display: none;
}
</style>
<ha-config-section is-wide="[[isWide]]">
<div style="position: relative" slot="header">
<span>Z-Wave Network Management</span>
<paper-icon-button class="toggle-help-icon" on-click="helpTap" icon="mdi:help-circle"></paper-icon-button>
</div>
<span slot="introduction">
Run commands that affect the Z-Wave network. You won't get feedback on whether the command succeeded, but you can look in the OZW Log to try to figure out.
</span>
<paper-card class="content">
<div class="card-actions">
<ha-call-service-button hass="[[hass]]" domain="zwave" service="add_node_secure">Add Node Secure</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="add_node_secure" hidden\$="[[!showDescription]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="add_node">Add Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="add_node" hidden\$="[[!showDescription]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="remove_node">Remove Node</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="remove_node" hidden\$="[[!showDescription]]"></ha-service-description>
</div>
<div class="card-actions warning">
<ha-call-service-button hass="[[hass]]" domain="zwave" service="cancel_command">Cancel Command</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="cancel_command" hidden\$="[[!showDescription]]"></ha-service-description>
</div>
<div class="card-actions">
<ha-call-service-button hass="[[hass]]" domain="zwave" service="heal_network">Heal Network</ha-call-service-button>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="start_network">Start Network</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="start_network" hidden\$="[[!showDescription]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="stop_network">Stop Network</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="stop_network" hidden\$="[[!showDescription]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="soft_reset">Soft Reset</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="soft_reset" hidden\$="[[!showDescription]]"></ha-service-description>
<ha-call-service-button hass="[[hass]]" domain="zwave" service="test_network">Test Network</ha-call-service-button>
<ha-service-description hass="[[hass]]" domain="zwave" service="test_network" hidden\$="[[!showDescription]]"></ha-service-description>
<ha-call-api-button hass="[[hass]]" path="zwave/saveconfig">Save Config</ha-call-api-button>
</div>
</paper-card>
</ha-config-section>
`;
}
static get is() { return 'zwave-network'; }
static get properties() {
return {
hass: {
type: Object,
},
isWide: {
type: Boolean,
value: false,
},
showDescription: {
type: Boolean,
value: false,
},
};
}
helpTap() {
this.showDescription = !this.showDescription;
}
}
customElements.define(ZwaveNetwork.is, ZwaveNetwork);

View File

@ -1,14 +1,16 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> import '@polymer/paper-input/paper-input.js';
<link rel='import' href='../../../bower_components/paper-item/paper-item.html'> import '@polymer/paper-item/paper-item.js';
<link rel='import' href="../../../bower_components/paper-listbox/paper-listbox.html"> import '@polymer/paper-listbox/paper-listbox.js';
<link rel='import' href="../../../bower_components/paper-input/paper-input.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/components/buttons/ha-call-service-button.html"> import '../../../src/components/buttons/ha-call-service-button.js';
<dom-module id='zwave-node-config'> class ZwaveNodeConfig extends PolymerElement {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
margin-top: 24px; margin-top: 24px;
@ -33,43 +35,30 @@
padding-right: 24px; padding-right: 24px;
} }
</style> </style>
<div class='content'> <div class="content">
<paper-card heading='Node config options'> <paper-card heading="Node config options">
<template is='dom-if' if='[[wakeupNode]]'> <template is="dom-if" if="[[wakeupNode]]">
<div class='card-actions'> <div class="card-actions">
<paper-input <paper-input float-label="Wakeup Interval" type="number" value="{{wakeupInput}}" placeholder="[[computeGetWakeupValue(selectedNode)]]">
float-label="Wakeup Interval" <div suffix="">seconds</div>
type=number
value={{wakeupInput}}
placeholder=[[computeGetWakeupValue(selectedNode)]]>
<div suffix>seconds</div>
</paper-input> </paper-input>
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="zwave" service="set_wakeup" service-data="[[computeWakeupServiceData(wakeupInput)]]">Set Wakeup</ha-call-service-button>
hass='[[hass]]'
domain='zwave'
service='set_wakeup'
service-data='[[computeWakeupServiceData(wakeupInput)]]'
>Set Wakeup</ha-call-service-button>
</div> </div>
</template> </template>
<div class='device-picker'> <div class="device-picker">
<paper-dropdown-menu label="Config parameter" dynamic-align class='flex'> <paper-dropdown-menu label="Config parameter" dynamic-align="" class="flex">
<paper-listbox <paper-listbox slot="dropdown-content" selected="{{selectedConfigParameter}}">
slot="dropdown-content" <template is="dom-repeat" items="[[config]]" as="state">
selected='{{selectedConfigParameter}}'>
<template is='dom-repeat' items='[[config]]' as='state'>
<paper-item>[[computeSelectCaptionConfigParameter(state)]]</paper-item> <paper-item>[[computeSelectCaptionConfigParameter(state)]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<template is='dom-if' if="[[isConfigParameterSelected(selectedConfigParameter, 'List')]]"> <template is="dom-if" if="[[isConfigParameterSelected(selectedConfigParameter, 'List')]]">
<div class='device-picker'> <div class="device-picker">
<paper-dropdown-menu label="Config value" dynamic-align class='flex' placeholder='{{loadedConfigValue}}'> <paper-dropdown-menu label="Config value" dynamic-align="" class="flex" placeholder="{{loadedConfigValue}}">
<paper-listbox <paper-listbox slot="dropdown-content" selected="{{selectedConfigValue}}">
slot="dropdown-content" <template is="dom-repeat" items="[[selectedConfigParameterValues]]" as="state">
selected='{{selectedConfigValue}}'>
<template is='dom-repeat' items='[[selectedConfigParameterValues]]' as='state'>
<paper-item>[[state]]</paper-item> <paper-item>[[state]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
@ -77,50 +66,36 @@
</div> </div>
</template> </template>
<template is='dom-if' if="[[isConfigParameterSelected(selectedConfigParameter, 'Byte Short Int')]]"> <template is="dom-if" if="[[isConfigParameterSelected(selectedConfigParameter, 'Byte Short Int')]]">
<div class='card-actions'> <div class="card-actions">
<paper-input <paper-input label="{{selectedConfigParameterNumValues}}" type="number" value="{{selectedConfigValue}}" max="{{configParameterMax}}" min="{{configParameterMin}}">
label='{{selectedConfigParameterNumValues}}'
type=number
value='{{selectedConfigValue}}'
max='{{configParameterMax}}'
min='{{configParameterMin}}'>
</paper-input> </paper-input>
</div> </div>
</template> </template>
<template is='dom-if' if="[[isConfigParameterSelected(selectedConfigParameter, 'Bool Button')]]"> <template is="dom-if" if="[[isConfigParameterSelected(selectedConfigParameter, 'Bool Button')]]">
<div class='device-picker'> <div class="device-picker">
<paper-dropdown-menu label="Config value" class='flex' dynamic-align placeholder='{{loadedConfigValue}}'> <paper-dropdown-menu label="Config value" class="flex" dynamic-align="" placeholder="{{loadedConfigValue}}">
<paper-listbox <paper-listbox slot="dropdown-content" selected="{{selectedConfigValue}}">
slot="dropdown-content" <template is="dom-repeat" items="[[selectedConfigParameterValues]]" as="state">
selected='{{selectedConfigValue}}'>
<template is='dom-repeat' items='[[selectedConfigParameterValues]]' as='state'>
<paper-item>[[state]]</paper-item> <paper-item>[[state]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
</template> </template>
<div class='help-text'> <div class="help-text">
<span>[[configValueHelpText]]</span> <span>[[configValueHelpText]]</span>
</div> </div>
<template is='dom-if' if="[[isConfigParameterSelected(selectedConfigParameter, 'Bool Button Byte Short Int List')]]"> <template is="dom-if" if="[[isConfigParameterSelected(selectedConfigParameter, 'Bool Button Byte Short Int List')]]">
<div class='card-actions'> <div class="card-actions">
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="zwave" service="set_config_parameter" service-data="[[computeSetConfigParameterServiceData(selectedConfigValue)]]">Set Config Parameter</ha-call-service-button>
hass='[[hass]]'
domain='zwave'
service='set_config_parameter'
service-data=[[computeSetConfigParameterServiceData(selectedConfigValue)]]
>Set Config Parameter</ha-call-service-button>
</div> </div>
</template> </template>
</paper-card> </paper-card>
</div> </div>
</template> `;
</dom-module> }
<script>
class ZwaveNodeConfig extends Polymer.Element {
static get is() { return 'zwave-node-config'; } static get is() { return 'zwave-node-config'; }
static get properties() { static get properties() {
@ -321,4 +296,3 @@ class ZwaveNodeConfig extends Polymer.Element {
} }
customElements.define(ZwaveNodeConfig.is, ZwaveNodeConfig); customElements.define(ZwaveNodeConfig.is, ZwaveNodeConfig);
</script>

View File

@ -1,9 +1,11 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-button/paper-button.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-button/paper-button.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<dom-module id='zwave-node-information'> class ZwaveNodeInformation extends PolymerElement {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
margin-top: 24px; margin-top: 24px;
@ -25,26 +27,23 @@
</style> </style>
<div class='content'> <div class="content">
<paper-card heading='Node Information'> <paper-card heading="Node Information">
<div class='card-actions'> <div class="card-actions">
<paper-button toggles raised noink active={{nodeInfoActive}}>Show</paper-button> <paper-button toggles="" raised="" noink="" active="{{nodeInfoActive}}">Show</paper-button>
</div> </div>
<template is='dom-if' if={{nodeInfoActive}}> <template is="dom-if" if="{{nodeInfoActive}}">
<template is='dom-repeat' items='[[selectedNodeAttrs]]' as='state'> <template is="dom-repeat" items="[[selectedNodeAttrs]]" as="state">
<div class='node-info'> <div class="node-info">
<span>[[state]]</span> <span>[[state]]</span>
</div> </div>
</template> </template>
</template> </template>
</paper-card> </paper-card>
</div> </div>
`;
}
</template>
</dom-module>
<script>
class ZwaveNodeInformation extends Polymer.Element {
static get is() { return 'zwave-node-information'; } static get is() { return 'zwave-node-information'; }
static get properties() { static get properties() {
@ -82,4 +81,3 @@ class ZwaveNodeInformation extends Polymer.Element {
} }
customElements.define(ZwaveNodeInformation.is, ZwaveNodeInformation); customElements.define(ZwaveNodeInformation.is, ZwaveNodeInformation);
</script>

View File

@ -1,14 +1,16 @@
<link rel="import" href="../../../bower_components/polymer/polymer-element.html"> import '@polymer/paper-card/paper-card.js';
<link rel="import" href="../../../bower_components/paper-card/paper-card.html"> import '@polymer/paper-dropdown-menu/paper-dropdown-menu.js';
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html"> import '@polymer/paper-input/paper-input.js';
<link rel='import' href='../../../bower_components/paper-item/paper-item.html'> import '@polymer/paper-item/paper-item.js';
<link rel='import' href="../../../bower_components/paper-listbox/paper-listbox.html"> import '@polymer/paper-listbox/paper-listbox.js';
<link rel='import' href="../../../bower_components/paper-input/paper-input.html"> import { html } from '@polymer/polymer/lib/utils/html-tag.js';
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
<link rel="import" href="../../../src/components/buttons/ha-call-service-button.html"> import '../../../src/components/buttons/ha-call-service-button.js';
<dom-module id='zwave-usercodes'> class ZwaveUsercodes extends PolymerElement {
<template> static get template() {
return html`
<style include="iron-flex ha-style"> <style include="iron-flex ha-style">
.content { .content {
margin-top: 24px; margin-top: 24px;
@ -28,54 +30,34 @@
padding-bottom: 24px; padding-bottom: 24px;
} }
</style> </style>
<div class='content'> <div class="content">
<paper-card heading='Node user codes'> <paper-card heading="Node user codes">
<div class='device-picker'> <div class="device-picker">
<paper-dropdown-menu label="Code slot" dynamic-align class='flex'> <paper-dropdown-menu label="Code slot" dynamic-align="" class="flex">
<paper-listbox <paper-listbox slot="dropdown-content" selected="{{selectedUserCode}}">
slot="dropdown-content" <template is="dom-repeat" items="[[userCodes]]" as="state">
selected='{{selectedUserCode}}'>
<template is='dom-repeat' items='[[userCodes]]' as='state'>
<paper-item>[[computeSelectCaptionUserCodes(state)]]</paper-item> <paper-item>[[computeSelectCaptionUserCodes(state)]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
</div> </div>
<template is='dom-if' if="[[isUserCodeSelected(selectedUserCode)]]"> <template is="dom-if" if="[[isUserCodeSelected(selectedUserCode)]]">
<div class='card-actions'> <div class="card-actions">
<paper-input <paper-input label="User code" type="text" allowed-pattern="[0-9,a-f,x,\\\\]" maxlength="{{userCodeMaxLen}}" minlength="16" value="{{selectedUserCodeValue}}">
label='User code'
type='text'
allowed-pattern='[0-9,a-f,x,\\]'
maxlength='{{userCodeMaxLen}}'
minlength='16'
value='{{selectedUserCodeValue}}'>
</paper-input> </paper-input>
<pre>Ascii: [[computedCodeOutput]]</pre> <pre>Ascii: [[computedCodeOutput]]</pre>
</div> </div>
<div class='card-actions'> <div class="card-actions">
<ha-call-service-button <ha-call-service-button hass="[[hass]]" domain="lock" service="set_usercode" service-data="[[computeUserCodeServiceData(selectedUserCodeValue, &quot;Add&quot;)]]">Set Usercode</ha-call-service-button>
hass='[[hass]]' <ha-call-service-button hass="[[hass]]" domain="lock" service="clear_usercode" service-data="[[computeUserCodeServiceData(selectedUserCode, &quot;Delete&quot;)]]">Delete Usercode</ha-call-service-button>
domain='lock'
service='set_usercode'
service-data='[[computeUserCodeServiceData(selectedUserCodeValue, "Add")]]'
>Set Usercode</ha-call-service-button>
<ha-call-service-button
hass='[[hass]]'
domain='lock'
service='clear_usercode'
service-data='[[computeUserCodeServiceData(selectedUserCode, "Delete")]]'
>Delete Usercode</ha-call-service-button>
</div> </div>
</template> </template>
</paper-card> </paper-card>
</div> </div>
</template> `;
</dom-module> }
<script>
class ZwaveUsercodes extends Polymer.Element {
static get is() { return 'zwave-usercodes'; } static get is() { return 'zwave-usercodes'; }
static get properties() { static get properties() {
@ -213,4 +195,3 @@ class ZwaveUsercodes extends Polymer.Element {
} }
customElements.define(ZwaveUsercodes.is, ZwaveUsercodes); customElements.define(ZwaveUsercodes.is, ZwaveUsercodes);
</script>

Some files were not shown because too many files have changed in this diff Show More