mirror of
https://github.com/home-assistant/frontend.git
synced 2025-09-08 20:56:34 +00:00
Compare commits
228 Commits
20180826.0
...
20181024.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1feb9f6a27 | ||
![]() |
337a760e73 | ||
![]() |
54cd412107 | ||
![]() |
cf2171ece1 | ||
![]() |
47fb8a5513 | ||
![]() |
06bf134bd4 | ||
![]() |
cf8899fcbe | ||
![]() |
c05b77961e | ||
![]() |
19c365cd12 | ||
![]() |
29f032087e | ||
![]() |
d0cb7b9724 | ||
![]() |
ad162677a6 | ||
![]() |
fbbbe7d17d | ||
![]() |
ef0d11c042 | ||
![]() |
fc2608980f | ||
![]() |
cc97e82a78 | ||
![]() |
54e3191de6 | ||
![]() |
4f8c8762c7 | ||
![]() |
c190f1986e | ||
![]() |
b418048bc9 | ||
![]() |
0fdd1c74f2 | ||
![]() |
3b1b2b95e7 | ||
![]() |
3bb5484b7f | ||
![]() |
d93c09b27b | ||
![]() |
e7ec18d270 | ||
![]() |
3ebe21e135 | ||
![]() |
aca1ecf1ee | ||
![]() |
e8ef2fdc2c | ||
![]() |
b129d5fb08 | ||
![]() |
11f4564465 | ||
![]() |
c9d140281b | ||
![]() |
fa637a37d5 | ||
![]() |
1589c3fc51 | ||
![]() |
bdc2b31202 | ||
![]() |
0970e1e33c | ||
![]() |
028003dffc | ||
![]() |
1eb4ac7f34 | ||
![]() |
d97e356376 | ||
![]() |
d36352af16 | ||
![]() |
05ae92d5f8 | ||
![]() |
dce612f944 | ||
![]() |
3a196203c3 | ||
![]() |
33578a6289 | ||
![]() |
4c3db2119b | ||
![]() |
4a7ff3cd94 | ||
![]() |
5578580d78 | ||
![]() |
dc1d8366a5 | ||
![]() |
252f0692c8 | ||
![]() |
9d13925280 | ||
![]() |
5462a71f52 | ||
![]() |
42953a0b62 | ||
![]() |
f146a1d80f | ||
![]() |
a113c71de7 | ||
![]() |
1f642f436a | ||
![]() |
62d27a17d5 | ||
![]() |
35941a58a5 | ||
![]() |
2ace2165e0 | ||
![]() |
1cfcacfa9a | ||
![]() |
e020fd1154 | ||
![]() |
1dcc645fec | ||
![]() |
87fba75860 | ||
![]() |
294360d35a | ||
![]() |
a7684d7206 | ||
![]() |
af81ede100 | ||
![]() |
698beedaa2 | ||
![]() |
a6b4cce7f3 | ||
![]() |
ba66ff840f | ||
![]() |
c296f33ba1 | ||
![]() |
e7a49192bd | ||
![]() |
5774d913af | ||
![]() |
b068db3f7a | ||
![]() |
8e49241e7c | ||
![]() |
b8cee5cc9c | ||
![]() |
794808d3a7 | ||
![]() |
48f6d1dfec | ||
![]() |
97e1aae9c0 | ||
![]() |
e2511c5ed3 | ||
![]() |
74bdfc8c2d | ||
![]() |
fbccf23d36 | ||
![]() |
906aaa15a3 | ||
![]() |
0ae1f9c754 | ||
![]() |
f1bd89fd02 | ||
![]() |
3949b47e51 | ||
![]() |
2f6595bca7 | ||
![]() |
3bcd0ddc46 | ||
![]() |
ca93c2cfcd | ||
![]() |
a633e3c553 | ||
![]() |
bef2731207 | ||
![]() |
ee53ee4077 | ||
![]() |
34bfc12647 | ||
![]() |
3b425c3e14 | ||
![]() |
69eb007ea2 | ||
![]() |
90c3350d40 | ||
![]() |
a7ddbd72b3 | ||
![]() |
5a2ee98ae2 | ||
![]() |
ea0b5d5e26 | ||
![]() |
af2cb1be1a | ||
![]() |
c30e7ac683 | ||
![]() |
7fb5ac11fd | ||
![]() |
b2dc0ac819 | ||
![]() |
dbdf873ba4 | ||
![]() |
1b70b6e88c | ||
![]() |
c90e13d35e | ||
![]() |
442375f76e | ||
![]() |
81d493e1d6 | ||
![]() |
151f16af47 | ||
![]() |
606a220603 | ||
![]() |
362e758c40 | ||
![]() |
2eb3a55f59 | ||
![]() |
6720c03cbc | ||
![]() |
a76386b53b | ||
![]() |
0243632357 | ||
![]() |
bb24b55a67 | ||
![]() |
f47fd8eec4 | ||
![]() |
f1f9f13d82 | ||
![]() |
d2dd82c0ec | ||
![]() |
e1738b625d | ||
![]() |
7aa37183b6 | ||
![]() |
c91b28a850 | ||
![]() |
70225c1a18 | ||
![]() |
3d9d7d899d | ||
![]() |
f0619c7d13 | ||
![]() |
305fa84d38 | ||
![]() |
edf0e2bedb | ||
![]() |
8be5561d19 | ||
![]() |
f11ca53282 | ||
![]() |
2c25d6cc0a | ||
![]() |
db6ab4d8ec | ||
![]() |
3961eff372 | ||
![]() |
458a7827f9 | ||
![]() |
68d1c77a79 | ||
![]() |
aa97e30d51 | ||
![]() |
9027d7d391 | ||
![]() |
974fd5de0f | ||
![]() |
f9d28fbf83 | ||
![]() |
b944089087 | ||
![]() |
7b6cf28459 | ||
![]() |
be91688efb | ||
![]() |
a5d47231aa | ||
![]() |
01e833a399 | ||
![]() |
c363ba8056 | ||
![]() |
7cec39ba6c | ||
![]() |
3f15cbd2bd | ||
![]() |
3235d33463 | ||
![]() |
140597c7f8 | ||
![]() |
e1407a7d73 | ||
![]() |
03525c010f | ||
![]() |
8dc202af92 | ||
![]() |
369977f8f3 | ||
![]() |
7f8c092dfc | ||
![]() |
d517cad6e6 | ||
![]() |
62a68890d3 | ||
![]() |
3d8a8cc77b | ||
![]() |
55dc35a8fc | ||
![]() |
82e49a5e44 | ||
![]() |
17ac6f96a0 | ||
![]() |
085db3e0a6 | ||
![]() |
348bebc417 | ||
![]() |
15d21cc673 | ||
![]() |
7e0ff14f28 | ||
![]() |
67d09e8b3d | ||
![]() |
ce3b53a920 | ||
![]() |
a32809e14b | ||
![]() |
1d8c515da2 | ||
![]() |
81e0f1a025 | ||
![]() |
c593e2789c | ||
![]() |
650d2d7a47 | ||
![]() |
2665c86683 | ||
![]() |
8b262f3424 | ||
![]() |
5187f3b84f | ||
![]() |
443e083a79 | ||
![]() |
6c262c20ce | ||
![]() |
cfbf2903c1 | ||
![]() |
19b8ff7d9f | ||
![]() |
ec6ffd2115 | ||
![]() |
433b1e2979 | ||
![]() |
bd3d079dfb | ||
![]() |
fe776191b7 | ||
![]() |
c546d8787d | ||
![]() |
a672b84b88 | ||
![]() |
e3a137c675 | ||
![]() |
10aa99abdc | ||
![]() |
34567d451f | ||
![]() |
494e3dc62c | ||
![]() |
0997274f29 | ||
![]() |
76161329b6 | ||
![]() |
8505750958 | ||
![]() |
4077105db1 | ||
![]() |
3f31d83a55 | ||
![]() |
d729e3c567 | ||
![]() |
9af75f9a43 | ||
![]() |
d32d334a2e | ||
![]() |
94006a843c | ||
![]() |
4790590327 | ||
![]() |
7cf7763e21 | ||
![]() |
0d7979a72f | ||
![]() |
300425e698 | ||
![]() |
59010baf89 | ||
![]() |
47fcb122a2 | ||
![]() |
bbb50b1397 | ||
![]() |
ae8724d699 | ||
![]() |
2169f6979d | ||
![]() |
9cc577e9c7 | ||
![]() |
6ead58f62f | ||
![]() |
ec3118227c | ||
![]() |
0d3d9bc78a | ||
![]() |
e16b3db0d4 | ||
![]() |
cdab874b5b | ||
![]() |
bf40995b16 | ||
![]() |
68b3a4fbb7 | ||
![]() |
c38bfa1101 | ||
![]() |
af7a85eeb7 | ||
![]() |
2bd5dc21a8 | ||
![]() |
18a151c8e8 | ||
![]() |
da19a1a9c6 | ||
![]() |
45cdb5a3e4 | ||
![]() |
ab19dbc35e | ||
![]() |
6a443734a1 | ||
![]() |
f0251d3056 | ||
![]() |
31127ccf29 | ||
![]() |
b97e055b39 | ||
![]() |
f4ce1ee0fa | ||
![]() |
2a29311ca5 | ||
![]() |
8cfd7ee170 | ||
![]() |
59a8354a7f | ||
![]() |
f443942e03 | ||
![]() |
772208ba22 | ||
![]() |
e46a1be5d7 |
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "airbnb-base",
|
||||
"extends": ["airbnb-base", "prettier"],
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
@@ -67,13 +67,11 @@
|
||||
"react/no-find-dom-node": 2,
|
||||
"react/no-is-mounted": 2,
|
||||
"react/jsx-no-comment-textnodes": 2,
|
||||
"react/jsx-curly-spacing": 2,
|
||||
"react/jsx-no-undef": 2,
|
||||
"react/jsx-uses-react": 2,
|
||||
"react/jsx-uses-vars": 2,
|
||||
"no-restricted-syntax": [0, "ForOfStatement"]
|
||||
"no-restricted-syntax": [0, "ForOfStatement"],
|
||||
"prettier/prettier": "error"
|
||||
},
|
||||
"plugins": [
|
||||
"react"
|
||||
]
|
||||
"plugins": ["react", "prettier"]
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
"parser": "babel-eslint",
|
||||
"rules": {
|
||||
"import/no-unresolved": 2,
|
||||
"linebreak-style": 0
|
||||
"linebreak-style": 0,
|
||||
"implicit-arrow-linebreak": 0
|
||||
}
|
||||
}
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -21,6 +21,9 @@ lib
|
||||
bin
|
||||
dist
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# Secrets
|
||||
.lokalise_token
|
||||
yarn-error.log
|
||||
|
28
Dockerfile
28
Dockerfile
@@ -1,25 +1,31 @@
|
||||
FROM node:8.2.1-alpine
|
||||
FROM node:8.11.1-alpine
|
||||
|
||||
# install yarn
|
||||
ENV PATH /root/.yarn/bin:$PATH
|
||||
|
||||
## Install/force base tools
|
||||
RUN apk update \
|
||||
&& apk add curl bash binutils tar git python3 \
|
||||
&& apk add make g++ curl bash binutils tar git python2 python3 \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& /bin/bash \
|
||||
&& touch ~/.bashrc \
|
||||
&& curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||
&& touch ~/.bashrc
|
||||
|
||||
## Install yarn
|
||||
RUN curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||
|
||||
## Setup the project
|
||||
RUN mkdir -p /frontend
|
||||
|
||||
WORKDIR /frontend
|
||||
|
||||
ENV NODE_ENV production
|
||||
COPY package.json yarn.lock ./
|
||||
|
||||
COPY package.json ./
|
||||
RUN yarn
|
||||
|
||||
COPY bower.json ./
|
||||
RUN ./node_modules/.bin/bower install --allow-root
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
CMD [ "/bin/bash", "./script/build_frontend" ]
|
||||
|
||||
COPY script/docker_entrypoint.sh /usr/bin/docker_entrypoint.sh
|
||||
|
||||
RUN chmod +x /usr/bin/docker_entrypoint.sh
|
||||
|
||||
CMD [ "docker_entrypoint.sh" ]
|
||||
|
12
README.md
12
README.md
@@ -16,6 +16,18 @@ This is the repository for the official [Home Assistant](https://home-assistant.
|
||||
- Gallery: `cd gallery && script/develop_gallery`
|
||||
- Hass.io: [Instructions](https://developers.home-assistant.io/docs/en/hassio_hass.html)
|
||||
|
||||
## Frontend development
|
||||
|
||||
### Classic environment
|
||||
A complete guide can be found at the following [link](https://www.home-assistant.io/developers/frontend/). It describes a short guide for the build of project.
|
||||
|
||||
### Docker environment
|
||||
It is possible to compile the project and/or run commands in the development environment having only the [Docker](https://www.docker.com) pre-installed in the system. On the root of project you can do:
|
||||
* `sh ./script/docker_run.sh build` Build all the project with one command
|
||||
* `sh ./script/docker_run.sh bash` Open an interactive shell (the same environment generated by the *classic environment*) where you can run commands. This bash work on your project directory and any change on your file is automatically present within your build bash.
|
||||
|
||||
**Note**: if you have installed `npm` in addition to the `docker`, you can use the commands `npm run docker_build` and `npm run bash` to get a full build or bash as explained above
|
||||
|
||||
## License
|
||||
|
||||
Home Assistant is open-source and Apache 2 licensed. Feel free to browse the repository, learn and reuse parts in your own projects.
|
||||
|
35
config/babel.js
Normal file
35
config/babel.js
Normal file
@@ -0,0 +1,35 @@
|
||||
module.exports.babelLoaderConfig = ({ latestBuild }) => {
|
||||
if (latestBuild === undefined) {
|
||||
throw Error("latestBuild not defined for babel loader config");
|
||||
}
|
||||
return {
|
||||
test: /\.m?js$|\.ts$/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [
|
||||
!latestBuild && [
|
||||
require("@babel/preset-env").default,
|
||||
{ modules: false },
|
||||
],
|
||||
require("@babel/preset-typescript").default,
|
||||
].filter(Boolean),
|
||||
plugins: [
|
||||
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
||||
[
|
||||
"@babel/plugin-proposal-object-rest-spread",
|
||||
{ loose: true, useBuiltIns: true },
|
||||
],
|
||||
// Only support the syntax, Webpack will handle it.
|
||||
"@babel/syntax-dynamic-import",
|
||||
[
|
||||
"@babel/transform-react-jsx",
|
||||
{
|
||||
pragma: "h",
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
@@ -1,12 +1,12 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import JsYaml from 'js-yaml';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
import JsYaml from "js-yaml";
|
||||
|
||||
import HomeAssistant from '../data/hass.js';
|
||||
import demoConfig from '../data/demo_config.js';
|
||||
import demoResources from '../data/demo_resources.js';
|
||||
import demoStates from '../data/demo_states.js';
|
||||
import createCardElement from '../../../src/panels/lovelace/common/create-card-element.js';
|
||||
import HomeAssistant from "../data/hass.js";
|
||||
import demoConfig from "../data/demo_config.js";
|
||||
import demoResources from "../data/demo_resources.js";
|
||||
import demoStates from "../data/demo_states.js";
|
||||
import createCardElement from "../../../src/panels/lovelace/common/create-card-element.js";
|
||||
|
||||
class DemoCard extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -50,11 +50,11 @@ class DemoCard extends PolymerElement {
|
||||
return {
|
||||
hass: {
|
||||
type: Object,
|
||||
observer: '_hassChanged',
|
||||
observer: "_hassChanged",
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
observer: '_configChanged'
|
||||
observer: "_configChanged",
|
||||
},
|
||||
showConfig: Boolean,
|
||||
};
|
||||
@@ -74,7 +74,7 @@ class DemoCard extends PolymerElement {
|
||||
const hass = new HomeAssistant(demoStates);
|
||||
hass.config = demoConfig;
|
||||
hass.resources = demoResources;
|
||||
hass.language = 'en';
|
||||
hass.language = "en";
|
||||
hass.states = demoStates;
|
||||
el.hass = hass;
|
||||
}
|
||||
@@ -92,4 +92,4 @@ class DemoCard extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-card', DemoCard);
|
||||
customElements.define("demo-card", DemoCard);
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import '@polymer/app-layout/app-toolbar/app-toolbar.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 "@polymer/app-layout/app-toolbar/app-toolbar.js";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button.js";
|
||||
|
||||
import './demo-card.js';
|
||||
import "./demo-card.js";
|
||||
|
||||
class DemoCards extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -50,9 +50,9 @@ class DemoCards extends PolymerElement {
|
||||
_showConfig: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-cards', DemoCards);
|
||||
customElements.define("demo-cards", DemoCards);
|
||||
|
@@ -1,10 +1,9 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
|
||||
import '../../../src/state-summary/state-card-content.js';
|
||||
import '../../../src/dialogs/more-info/controls/more-info-content.js';
|
||||
import '../../../src/components/ha-card.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import "../../../src/state-summary/state-card-content.js";
|
||||
import "../../../src/dialogs/more-info/controls/more-info-content.js";
|
||||
import "../../../src/components/ha-card.js";
|
||||
|
||||
class DemoMoreInfo extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -68,8 +67,8 @@ class DemoMoreInfo extends PolymerElement {
|
||||
showConfig: Boolean,
|
||||
_stateObj: {
|
||||
type: Object,
|
||||
computed: '_getState(entityId, hass.states)'
|
||||
}
|
||||
computed: "_getState(entityId, hass.states)",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,7 +81,7 @@ class DemoMoreInfo extends PolymerElement {
|
||||
// (it sucks, we will remove in the future)
|
||||
const tmp = {};
|
||||
Object.keys(stateObj).forEach((key) => {
|
||||
if (key[0] !== '_') {
|
||||
if (key[0] !== "_") {
|
||||
tmp[key] = stateObj[key];
|
||||
}
|
||||
});
|
||||
@@ -90,4 +89,4 @@ class DemoMoreInfo extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-more-info', DemoMoreInfo);
|
||||
customElements.define("demo-more-info", DemoMoreInfo);
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import '@polymer/app-layout/app-toolbar/app-toolbar.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 "@polymer/app-layout/app-toolbar/app-toolbar.js";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button.js";
|
||||
|
||||
import './demo-more-info.js';
|
||||
import "./demo-more-info.js";
|
||||
|
||||
class DemoMoreInfos extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -50,9 +50,9 @@ class DemoMoreInfos extends PolymerElement {
|
||||
_showConfig: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-more-infos', DemoMoreInfos);
|
||||
customElements.define("demo-more-infos", DemoMoreInfos);
|
||||
|
@@ -4,172 +4,106 @@ export default {
|
||||
latitude: 51.5287352,
|
||||
longitude: -0.381773,
|
||||
unit_system: {
|
||||
length: 'km',
|
||||
mass: 'kg',
|
||||
temperature: '°C',
|
||||
volume: 'L'
|
||||
}
|
||||
length: "km",
|
||||
mass: "kg",
|
||||
temperature: "°C",
|
||||
volume: "L",
|
||||
},
|
||||
},
|
||||
services: {
|
||||
configurator: [
|
||||
'configure'
|
||||
],
|
||||
tts: [
|
||||
'demo_say',
|
||||
'clear_cache'
|
||||
],
|
||||
configurator: ["configure"],
|
||||
tts: ["demo_say", "clear_cache"],
|
||||
cover: [
|
||||
'open_cover',
|
||||
'close_cover',
|
||||
'open_cover_tilt',
|
||||
'close_cover_tilt',
|
||||
'set_cover_tilt_position',
|
||||
'set_cover_position',
|
||||
'stop_cover_tilt',
|
||||
'stop_cover'
|
||||
],
|
||||
group: [
|
||||
'set',
|
||||
'reload',
|
||||
'remove',
|
||||
'set_visibility'
|
||||
"open_cover",
|
||||
"close_cover",
|
||||
"open_cover_tilt",
|
||||
"close_cover_tilt",
|
||||
"set_cover_tilt_position",
|
||||
"set_cover_position",
|
||||
"stop_cover_tilt",
|
||||
"stop_cover",
|
||||
],
|
||||
group: ["set", "reload", "remove", "set_visibility"],
|
||||
alarm_control_panel: [
|
||||
'alarm_arm_night',
|
||||
'alarm_disarm',
|
||||
'alarm_trigger',
|
||||
'alarm_arm_home',
|
||||
'alarm_arm_away',
|
||||
'alarm_arm_custom_bypass'
|
||||
],
|
||||
conversation: [
|
||||
'process'
|
||||
],
|
||||
notify: [
|
||||
'demo_test_target_name',
|
||||
'notify'
|
||||
],
|
||||
lock: [
|
||||
'open',
|
||||
'lock',
|
||||
'unlock'
|
||||
"alarm_arm_night",
|
||||
"alarm_disarm",
|
||||
"alarm_trigger",
|
||||
"alarm_arm_home",
|
||||
"alarm_arm_away",
|
||||
"alarm_arm_custom_bypass",
|
||||
],
|
||||
conversation: ["process"],
|
||||
notify: ["demo_test_target_name", "notify"],
|
||||
lock: ["open", "lock", "unlock"],
|
||||
input_select: [
|
||||
'select_previous',
|
||||
'set_options',
|
||||
'select_next',
|
||||
'select_option'
|
||||
],
|
||||
recorder: [
|
||||
'purge'
|
||||
],
|
||||
persistent_notification: [
|
||||
'create',
|
||||
'dismiss'
|
||||
],
|
||||
timer: [
|
||||
'pause',
|
||||
'cancel',
|
||||
'finish',
|
||||
'start'
|
||||
],
|
||||
input_boolean: [
|
||||
'turn_off',
|
||||
'toggle',
|
||||
'turn_on'
|
||||
"select_previous",
|
||||
"set_options",
|
||||
"select_next",
|
||||
"select_option",
|
||||
],
|
||||
recorder: ["purge"],
|
||||
persistent_notification: ["create", "dismiss"],
|
||||
timer: ["pause", "cancel", "finish", "start"],
|
||||
input_boolean: ["turn_off", "toggle", "turn_on"],
|
||||
fan: [
|
||||
'set_speed',
|
||||
'turn_on',
|
||||
'turn_off',
|
||||
'set_direction',
|
||||
'oscillate',
|
||||
'toggle'
|
||||
"set_speed",
|
||||
"turn_on",
|
||||
"turn_off",
|
||||
"set_direction",
|
||||
"oscillate",
|
||||
"toggle",
|
||||
],
|
||||
climate: [
|
||||
'set_humidity',
|
||||
'set_operation_mode',
|
||||
'set_aux_heat',
|
||||
'turn_on',
|
||||
'set_hold_mode',
|
||||
'set_away_mode',
|
||||
'turn_off',
|
||||
'set_fan_mode',
|
||||
'set_temperature',
|
||||
'set_swing_mode'
|
||||
],
|
||||
switch: [
|
||||
'turn_off',
|
||||
'toggle',
|
||||
'turn_on'
|
||||
],
|
||||
script: [
|
||||
'turn_off',
|
||||
'demo',
|
||||
'reload',
|
||||
'toggle',
|
||||
'turn_on'
|
||||
],
|
||||
scene: [
|
||||
'turn_on'
|
||||
],
|
||||
system_log: [
|
||||
'clear',
|
||||
'write'
|
||||
],
|
||||
camera: [
|
||||
'disable_motion_detection',
|
||||
'enable_motion_detection',
|
||||
'snapshot'
|
||||
],
|
||||
image_processing: [
|
||||
'scan'
|
||||
"set_humidity",
|
||||
"set_operation_mode",
|
||||
"set_aux_heat",
|
||||
"turn_on",
|
||||
"set_hold_mode",
|
||||
"set_away_mode",
|
||||
"turn_off",
|
||||
"set_fan_mode",
|
||||
"set_temperature",
|
||||
"set_swing_mode",
|
||||
],
|
||||
switch: ["turn_off", "toggle", "turn_on"],
|
||||
script: ["turn_off", "demo", "reload", "toggle", "turn_on"],
|
||||
scene: ["turn_on"],
|
||||
system_log: ["clear", "write"],
|
||||
camera: ["disable_motion_detection", "enable_motion_detection", "snapshot"],
|
||||
image_processing: ["scan"],
|
||||
media_player: [
|
||||
'media_previous_track',
|
||||
'clear_playlist',
|
||||
'shuffle_set',
|
||||
'media_seek',
|
||||
'turn_on',
|
||||
'media_play_pause',
|
||||
'media_next_track',
|
||||
'media_pause',
|
||||
'volume_down',
|
||||
'volume_set',
|
||||
'media_stop',
|
||||
'toggle',
|
||||
'media_play',
|
||||
'play_media',
|
||||
'volume_mute',
|
||||
'turn_off',
|
||||
'select_sound_mode',
|
||||
'select_source',
|
||||
'volume_up'
|
||||
],
|
||||
input_number: [
|
||||
'set_value',
|
||||
'increment',
|
||||
'decrement'
|
||||
],
|
||||
device_tracker: [
|
||||
'see'
|
||||
"media_previous_track",
|
||||
"clear_playlist",
|
||||
"shuffle_set",
|
||||
"media_seek",
|
||||
"turn_on",
|
||||
"media_play_pause",
|
||||
"media_next_track",
|
||||
"media_pause",
|
||||
"volume_down",
|
||||
"volume_set",
|
||||
"media_stop",
|
||||
"toggle",
|
||||
"media_play",
|
||||
"play_media",
|
||||
"volume_mute",
|
||||
"turn_off",
|
||||
"select_sound_mode",
|
||||
"select_source",
|
||||
"volume_up",
|
||||
],
|
||||
input_number: ["set_value", "increment", "decrement"],
|
||||
device_tracker: ["see"],
|
||||
homeassistant: [
|
||||
'stop',
|
||||
'check_config',
|
||||
'reload_core_config',
|
||||
'turn_on',
|
||||
'turn_off',
|
||||
'restart',
|
||||
'toggle'
|
||||
"stop",
|
||||
"check_config",
|
||||
"reload_core_config",
|
||||
"turn_on",
|
||||
"turn_off",
|
||||
"restart",
|
||||
"toggle",
|
||||
],
|
||||
light: [
|
||||
'turn_off',
|
||||
'toggle',
|
||||
'turn_on'
|
||||
],
|
||||
input_text: [
|
||||
'set_value'
|
||||
]
|
||||
}
|
||||
light: ["turn_off", "toggle", "turn_on"],
|
||||
input_text: ["set_value"],
|
||||
},
|
||||
};
|
||||
|
@@ -1,253 +1,264 @@
|
||||
export default {
|
||||
en: {
|
||||
'state.default.off': 'Off',
|
||||
'state.default.on': 'On',
|
||||
'state.default.unknown': 'Unknown',
|
||||
'state.default.unavailable': 'Unavailable',
|
||||
'state.alarm_control_panel.armed': 'Armed',
|
||||
'state.alarm_control_panel.disarmed': 'Disarmed',
|
||||
'state.alarm_control_panel.armed_home': 'Armed home',
|
||||
'state.alarm_control_panel.armed_away': 'Armed away',
|
||||
'state.alarm_control_panel.armed_night': 'Armed night',
|
||||
'state.alarm_control_panel.armed_custom_bypass': 'Armed custom bypass',
|
||||
'state.alarm_control_panel.pending': 'Pending',
|
||||
'state.alarm_control_panel.arming': 'Arming',
|
||||
'state.alarm_control_panel.disarming': 'Disarming',
|
||||
'state.alarm_control_panel.triggered': 'Triggered',
|
||||
'state.automation.off': 'Off',
|
||||
'state.automation.on': 'On',
|
||||
'state.binary_sensor.default.off': 'Off',
|
||||
'state.binary_sensor.default.on': 'On',
|
||||
'state.binary_sensor.battery.off': 'Normal',
|
||||
'state.binary_sensor.battery.on': 'Low',
|
||||
'state.binary_sensor.cold.off': 'Normal',
|
||||
'state.binary_sensor.cold.on': 'Cold',
|
||||
'state.binary_sensor.connectivity.off': 'Disconnected',
|
||||
'state.binary_sensor.connectivity.on': 'Connected',
|
||||
'state.binary_sensor.door.off': 'Closed',
|
||||
'state.binary_sensor.door.on': 'Open',
|
||||
'state.binary_sensor.garage_door.off': 'Closed',
|
||||
'state.binary_sensor.garage_door.on': 'Open',
|
||||
'state.binary_sensor.gas.off': 'Clear',
|
||||
'state.binary_sensor.gas.on': 'Detected',
|
||||
'state.binary_sensor.heat.off': 'Normal',
|
||||
'state.binary_sensor.heat.on': 'Hot',
|
||||
'state.binary_sensor.lock.off': 'Locked',
|
||||
'state.binary_sensor.lock.on': 'Unlocked',
|
||||
'state.binary_sensor.moisture.off': 'Dry',
|
||||
'state.binary_sensor.moisture.on': 'Wet',
|
||||
'state.binary_sensor.motion.off': 'Clear',
|
||||
'state.binary_sensor.motion.on': 'Detected',
|
||||
'state.binary_sensor.occupancy.off': 'Clear',
|
||||
'state.binary_sensor.occupancy.on': 'Detected',
|
||||
'state.binary_sensor.opening.off': 'Closed',
|
||||
'state.binary_sensor.opening.on': 'Open',
|
||||
'state.binary_sensor.presence.off': 'Away',
|
||||
'state.binary_sensor.presence.on': 'Home',
|
||||
'state.binary_sensor.problem.off': 'OK',
|
||||
'state.binary_sensor.problem.on': 'Problem',
|
||||
'state.binary_sensor.safety.off': 'Safe',
|
||||
'state.binary_sensor.safety.on': 'Unsafe',
|
||||
'state.binary_sensor.smoke.off': 'Clear',
|
||||
'state.binary_sensor.smoke.on': 'Detected',
|
||||
'state.binary_sensor.sound.off': 'Clear',
|
||||
'state.binary_sensor.sound.on': 'Detected',
|
||||
'state.binary_sensor.vibration.off': 'Clear',
|
||||
'state.binary_sensor.vibration.on': 'Detected',
|
||||
'state.binary_sensor.window.off': 'Closed',
|
||||
'state.binary_sensor.window.on': 'Open',
|
||||
'state.calendar.off': 'Off',
|
||||
'state.calendar.on': 'On',
|
||||
'state.camera.recording': 'Recording',
|
||||
'state.camera.streaming': 'Streaming',
|
||||
'state.camera.idle': 'Idle',
|
||||
'state.climate.off': 'Off',
|
||||
'state.climate.on': 'On',
|
||||
'state.climate.heat': 'Heat',
|
||||
'state.climate.cool': 'Cool',
|
||||
'state.climate.idle': 'Idle',
|
||||
'state.climate.auto': 'Auto',
|
||||
'state.climate.dry': 'Dry',
|
||||
'state.climate.fan_only': 'Fan only',
|
||||
'state.climate.eco': 'Eco',
|
||||
'state.climate.electric': 'Electric',
|
||||
'state.climate.performance': 'Performance',
|
||||
'state.climate.high_demand': 'High demand',
|
||||
'state.climate.heat_pump': 'Heat pump',
|
||||
'state.climate.gas': 'Gas',
|
||||
'state.configurator.configure': 'Configure',
|
||||
'state.configurator.configured': 'Configured',
|
||||
'state.cover.open': 'Open',
|
||||
'state.cover.opening': 'Opening',
|
||||
'state.cover.closed': 'Closed',
|
||||
'state.cover.closing': 'Closing',
|
||||
'state.cover.stopped': 'Stopped',
|
||||
'state.device_tracker.home': 'Home',
|
||||
'state.device_tracker.not_home': 'Away',
|
||||
'state.fan.off': 'Off',
|
||||
'state.fan.on': 'On',
|
||||
'state.group.off': 'Off',
|
||||
'state.group.on': 'On',
|
||||
'state.group.home': 'Home',
|
||||
'state.group.not_home': 'Away',
|
||||
'state.group.open': 'Open',
|
||||
'state.group.opening': 'Opening',
|
||||
'state.group.closed': 'Closed',
|
||||
'state.group.closing': 'Closing',
|
||||
'state.group.stopped': 'Stopped',
|
||||
'state.group.locked': 'Locked',
|
||||
'state.group.unlocked': 'Unlocked',
|
||||
'state.group.ok': 'OK',
|
||||
'state.group.problem': 'Problem',
|
||||
'state.input_boolean.off': 'Off',
|
||||
'state.input_boolean.on': 'On',
|
||||
'state.light.off': 'Off',
|
||||
'state.light.on': 'On',
|
||||
'state.lock.locked': 'Locked',
|
||||
'state.lock.unlocked': 'Unlocked',
|
||||
'state.media_player.off': 'Off',
|
||||
'state.media_player.on': 'On',
|
||||
'state.media_player.playing': 'Playing',
|
||||
'state.media_player.paused': 'Paused',
|
||||
'state.media_player.idle': 'Idle',
|
||||
'state.media_player.standby': 'Standby',
|
||||
'state.plant.ok': 'OK',
|
||||
'state.plant.problem': 'Problem',
|
||||
'state.remote.off': 'Off',
|
||||
'state.remote.on': 'On',
|
||||
'state.scene.scening': 'Scening',
|
||||
'state.script.off': 'Off',
|
||||
'state.script.on': 'On',
|
||||
'state.sensor.off': 'Off',
|
||||
'state.sensor.on': 'On',
|
||||
'state.sun.above_horizon': 'Above horizon',
|
||||
'state.sun.below_horizon': 'Below horizon',
|
||||
'state.switch.off': 'Off',
|
||||
'state.switch.on': 'On',
|
||||
'state.weather.clear-night': 'Clear, night',
|
||||
'state.weather.cloudy': 'Cloudy',
|
||||
'state.weather.fog': 'Fog',
|
||||
'state.weather.hail': 'Hail',
|
||||
'state.weather.lightning': 'Lightning',
|
||||
'state.weather.lightning-rainy': 'Lightning, rainy',
|
||||
'state.weather.partlycloudy': 'Partly cloudy',
|
||||
'state.weather.pouring': 'Pouring',
|
||||
'state.weather.rainy': 'Rainy',
|
||||
'state.weather.snowy': 'Snowy',
|
||||
'state.weather.snowy-rainy': 'Snowy, rainy',
|
||||
'state.weather.sunny': 'Sunny',
|
||||
'state.weather.windy': 'Windy',
|
||||
'state.weather.windy-variant': 'Windy',
|
||||
'state.zwave.default.initializing': 'Initializing',
|
||||
'state.zwave.default.dead': 'Dead',
|
||||
'state.zwave.default.sleeping': 'Sleeping',
|
||||
'state.zwave.default.ready': 'Ready',
|
||||
'state.zwave.query_stage.initializing': 'Initializing ({query_stage})',
|
||||
'state.zwave.query_stage.dead': 'Dead ({query_stage})',
|
||||
'state_badge.default.unknown': 'Unk',
|
||||
'state_badge.default.unavailable': 'Unavai',
|
||||
'state_badge.alarm_control_panel.armed': 'Armed',
|
||||
'state_badge.alarm_control_panel.disarmed': 'Disarm',
|
||||
'state_badge.alarm_control_panel.armed_home': 'Armed',
|
||||
'state_badge.alarm_control_panel.armed_away': 'Armed',
|
||||
'state_badge.alarm_control_panel.armed_night': 'Armed',
|
||||
'state_badge.alarm_control_panel.armed_custom_bypass': 'Armed',
|
||||
'state_badge.alarm_control_panel.pending': 'Pend',
|
||||
'state_badge.alarm_control_panel.arming': 'Arming',
|
||||
'state_badge.alarm_control_panel.disarming': 'Disarm',
|
||||
'state_badge.alarm_control_panel.triggered': 'Trig',
|
||||
'state_badge.device_tracker.home': 'Home',
|
||||
'state_badge.device_tracker.not_home': 'Away',
|
||||
'ui.card.alarm_control_panel.code': 'Code',
|
||||
'ui.card.alarm_control_panel.clear_code': 'Clear',
|
||||
'ui.card.alarm_control_panel.disarm': 'Disarm',
|
||||
'ui.card.alarm_control_panel.arm_home': 'Arm home',
|
||||
'ui.card.alarm_control_panel.arm_away': 'Arm away',
|
||||
'ui.card.automation.last_triggered': 'Last triggered',
|
||||
'ui.card.automation.trigger': 'Trigger',
|
||||
'ui.card.camera.not_available': 'Image not available',
|
||||
'ui.card.climate.currently': 'Currently',
|
||||
'ui.card.climate.on_off': 'On / off',
|
||||
'ui.card.climate.target_temperature': 'Target temperature',
|
||||
'ui.card.climate.target_humidity': 'Target humidity',
|
||||
'ui.card.climate.operation': 'Operation',
|
||||
'ui.card.climate.fan_mode': 'Fan mode',
|
||||
'ui.card.climate.swing_mode': 'Swing mode',
|
||||
'ui.card.climate.away_mode': 'Away mode',
|
||||
'ui.card.climate.aux_heat': 'Aux heat',
|
||||
'ui.card.cover.position': 'Position',
|
||||
'ui.card.cover.tilt_position': 'Tilt position',
|
||||
'ui.card.fan.speed': 'Speed',
|
||||
'ui.card.fan.oscillate': 'Oscillate',
|
||||
'ui.card.fan.direction': 'Direction',
|
||||
'ui.card.light.brightness': 'Brightness',
|
||||
'ui.card.light.color_temperature': 'Color temperature',
|
||||
'ui.card.light.white_value': 'White value',
|
||||
'ui.card.light.effect': 'Effect',
|
||||
'ui.card.lock.code': 'Code',
|
||||
'ui.card.lock.lock': 'Lock',
|
||||
'ui.card.lock.unlock': 'Unlock',
|
||||
'ui.card.media_player.source': 'Source',
|
||||
'ui.card.media_player.sound_mode': 'Sound mode',
|
||||
'ui.card.media_player.text_to_speak': 'Text to speak',
|
||||
'ui.card.persistent_notification.dismiss': 'Dismiss',
|
||||
'ui.card.scene.activate': 'Activate',
|
||||
'ui.card.script.execute': 'Execute',
|
||||
'ui.card.weather.attributes.air_pressure': 'Air pressure',
|
||||
'ui.card.weather.attributes.humidity': 'Humidity',
|
||||
'ui.card.weather.attributes.temperature': 'Temperature',
|
||||
'ui.card.weather.attributes.visibility': 'Visibility',
|
||||
'ui.card.weather.attributes.wind_speed': 'Wind speed',
|
||||
'ui.card.weather.cardinal_direction.e': 'E',
|
||||
'ui.card.weather.cardinal_direction.ene': 'ENE',
|
||||
'ui.card.weather.cardinal_direction.ese': 'ESE',
|
||||
'ui.card.weather.cardinal_direction.n': 'N',
|
||||
'ui.card.weather.cardinal_direction.ne': 'NE',
|
||||
'ui.card.weather.cardinal_direction.nne': 'NNE',
|
||||
'ui.card.weather.cardinal_direction.nw': 'NW',
|
||||
'ui.card.weather.cardinal_direction.nnw': 'NNW',
|
||||
'ui.card.weather.cardinal_direction.s': 'S',
|
||||
'ui.card.weather.cardinal_direction.se': 'SE',
|
||||
'ui.card.weather.cardinal_direction.sse': 'SSE',
|
||||
'ui.card.weather.cardinal_direction.ssw': 'SSW',
|
||||
'ui.card.weather.cardinal_direction.sw': 'SW',
|
||||
'ui.card.weather.cardinal_direction.w': 'W',
|
||||
'ui.card.weather.cardinal_direction.wnw': 'WNW',
|
||||
'ui.card.weather.cardinal_direction.wsw': 'WSW',
|
||||
'ui.card.weather.forecast': 'Forecast',
|
||||
'ui.common.loading': 'Loading',
|
||||
'ui.common.cancel': 'Cancel',
|
||||
'ui.components.entity.entity-picker.entity': 'Entity',
|
||||
'ui.components.relative_time.past': '{time} ago',
|
||||
'ui.components.relative_time.future': 'In {time}',
|
||||
'ui.components.relative_time.never': 'Never',
|
||||
'ui.components.relative_time.duration.second': '{count} {count, plural,\n one {second}\n other {seconds}\n}',
|
||||
'ui.components.relative_time.duration.minute': '{count} {count, plural,\n one {minute}\n other {minutes}\n}',
|
||||
'ui.components.relative_time.duration.hour': '{count} {count, plural,\n one {hour}\n other {hours}\n}',
|
||||
'ui.components.relative_time.duration.day': '{count} {count, plural,\n one {day}\n other {days}\n}',
|
||||
'ui.components.relative_time.duration.week': '{count} {count, plural,\n one {week}\n other {weeks}\n}',
|
||||
'ui.components.history_charts.loading_history': 'Loading state history...',
|
||||
'ui.components.history_charts.no_history_found': 'No state history found.',
|
||||
'ui.components.service-picker.service': 'Service',
|
||||
'ui.dialogs.more_info_settings.save': 'Save',
|
||||
'ui.dialogs.more_info_settings.name': 'Name',
|
||||
'ui.duration.second': '{count} {count, plural,\n one {second}\n other {seconds}\n}',
|
||||
'ui.duration.minute': '{count} {count, plural,\n one {minute}\n other {minutes}\n}',
|
||||
'ui.duration.hour': '{count} {count, plural,\n one {hour}\n other {hours}\n}',
|
||||
'ui.duration.day': '{count} {count, plural,\n one {day}\n other {days}\n}',
|
||||
'ui.duration.week': '{count} {count, plural,\n one {week}\n other {weeks}\n}',
|
||||
'ui.login-form.password': 'Password',
|
||||
'ui.login-form.remember': 'Remember',
|
||||
'ui.login-form.log_in': 'Log in',
|
||||
'ui.notification_toast.entity_turned_on': 'Turned on {entity}.',
|
||||
'ui.notification_toast.entity_turned_off': 'Turned off {entity}.',
|
||||
'ui.notification_toast.service_called': 'Service {service} called.',
|
||||
'ui.notification_toast.service_call_failed': 'Failed to call service {service}.',
|
||||
'ui.notification_toast.connection_lost': 'Connection lost. Reconnecting…',
|
||||
'ui.sidebar.developer_tools': 'Developer tools',
|
||||
'ui.sidebar.log_out': 'Log out',
|
||||
'attribute.weather.humidity': 'Humidity',
|
||||
'attribute.weather.visibility': 'Visibility',
|
||||
'attribute.weather.wind_speed': 'Wind speed',
|
||||
}
|
||||
"state.default.off": "Off",
|
||||
"state.default.on": "On",
|
||||
"state.default.unknown": "Unknown",
|
||||
"state.default.unavailable": "Unavailable",
|
||||
"state.alarm_control_panel.armed": "Armed",
|
||||
"state.alarm_control_panel.disarmed": "Disarmed",
|
||||
"state.alarm_control_panel.armed_home": "Armed home",
|
||||
"state.alarm_control_panel.armed_away": "Armed away",
|
||||
"state.alarm_control_panel.armed_night": "Armed night",
|
||||
"state.alarm_control_panel.armed_custom_bypass": "Armed custom bypass",
|
||||
"state.alarm_control_panel.pending": "Pending",
|
||||
"state.alarm_control_panel.arming": "Arming",
|
||||
"state.alarm_control_panel.disarming": "Disarming",
|
||||
"state.alarm_control_panel.triggered": "Triggered",
|
||||
"state.automation.off": "Off",
|
||||
"state.automation.on": "On",
|
||||
"state.binary_sensor.default.off": "Off",
|
||||
"state.binary_sensor.default.on": "On",
|
||||
"state.binary_sensor.battery.off": "Normal",
|
||||
"state.binary_sensor.battery.on": "Low",
|
||||
"state.binary_sensor.cold.off": "Normal",
|
||||
"state.binary_sensor.cold.on": "Cold",
|
||||
"state.binary_sensor.connectivity.off": "Disconnected",
|
||||
"state.binary_sensor.connectivity.on": "Connected",
|
||||
"state.binary_sensor.door.off": "Closed",
|
||||
"state.binary_sensor.door.on": "Open",
|
||||
"state.binary_sensor.garage_door.off": "Closed",
|
||||
"state.binary_sensor.garage_door.on": "Open",
|
||||
"state.binary_sensor.gas.off": "Clear",
|
||||
"state.binary_sensor.gas.on": "Detected",
|
||||
"state.binary_sensor.heat.off": "Normal",
|
||||
"state.binary_sensor.heat.on": "Hot",
|
||||
"state.binary_sensor.lock.off": "Locked",
|
||||
"state.binary_sensor.lock.on": "Unlocked",
|
||||
"state.binary_sensor.moisture.off": "Dry",
|
||||
"state.binary_sensor.moisture.on": "Wet",
|
||||
"state.binary_sensor.motion.off": "Clear",
|
||||
"state.binary_sensor.motion.on": "Detected",
|
||||
"state.binary_sensor.occupancy.off": "Clear",
|
||||
"state.binary_sensor.occupancy.on": "Detected",
|
||||
"state.binary_sensor.opening.off": "Closed",
|
||||
"state.binary_sensor.opening.on": "Open",
|
||||
"state.binary_sensor.presence.off": "Away",
|
||||
"state.binary_sensor.presence.on": "Home",
|
||||
"state.binary_sensor.problem.off": "OK",
|
||||
"state.binary_sensor.problem.on": "Problem",
|
||||
"state.binary_sensor.safety.off": "Safe",
|
||||
"state.binary_sensor.safety.on": "Unsafe",
|
||||
"state.binary_sensor.smoke.off": "Clear",
|
||||
"state.binary_sensor.smoke.on": "Detected",
|
||||
"state.binary_sensor.sound.off": "Clear",
|
||||
"state.binary_sensor.sound.on": "Detected",
|
||||
"state.binary_sensor.vibration.off": "Clear",
|
||||
"state.binary_sensor.vibration.on": "Detected",
|
||||
"state.binary_sensor.window.off": "Closed",
|
||||
"state.binary_sensor.window.on": "Open",
|
||||
"state.calendar.off": "Off",
|
||||
"state.calendar.on": "On",
|
||||
"state.camera.recording": "Recording",
|
||||
"state.camera.streaming": "Streaming",
|
||||
"state.camera.idle": "Idle",
|
||||
"state.climate.off": "Off",
|
||||
"state.climate.on": "On",
|
||||
"state.climate.heat": "Heat",
|
||||
"state.climate.cool": "Cool",
|
||||
"state.climate.idle": "Idle",
|
||||
"state.climate.auto": "Auto",
|
||||
"state.climate.dry": "Dry",
|
||||
"state.climate.fan_only": "Fan only",
|
||||
"state.climate.eco": "Eco",
|
||||
"state.climate.electric": "Electric",
|
||||
"state.climate.performance": "Performance",
|
||||
"state.climate.high_demand": "High demand",
|
||||
"state.climate.heat_pump": "Heat pump",
|
||||
"state.climate.gas": "Gas",
|
||||
"state.configurator.configure": "Configure",
|
||||
"state.configurator.configured": "Configured",
|
||||
"state.cover.open": "Open",
|
||||
"state.cover.opening": "Opening",
|
||||
"state.cover.closed": "Closed",
|
||||
"state.cover.closing": "Closing",
|
||||
"state.cover.stopped": "Stopped",
|
||||
"state.device_tracker.home": "Home",
|
||||
"state.device_tracker.not_home": "Away",
|
||||
"state.fan.off": "Off",
|
||||
"state.fan.on": "On",
|
||||
"state.group.off": "Off",
|
||||
"state.group.on": "On",
|
||||
"state.group.home": "Home",
|
||||
"state.group.not_home": "Away",
|
||||
"state.group.open": "Open",
|
||||
"state.group.opening": "Opening",
|
||||
"state.group.closed": "Closed",
|
||||
"state.group.closing": "Closing",
|
||||
"state.group.stopped": "Stopped",
|
||||
"state.group.locked": "Locked",
|
||||
"state.group.unlocked": "Unlocked",
|
||||
"state.group.ok": "OK",
|
||||
"state.group.problem": "Problem",
|
||||
"state.input_boolean.off": "Off",
|
||||
"state.input_boolean.on": "On",
|
||||
"state.light.off": "Off",
|
||||
"state.light.on": "On",
|
||||
"state.lock.locked": "Locked",
|
||||
"state.lock.unlocked": "Unlocked",
|
||||
"state.media_player.off": "Off",
|
||||
"state.media_player.on": "On",
|
||||
"state.media_player.playing": "Playing",
|
||||
"state.media_player.paused": "Paused",
|
||||
"state.media_player.idle": "Idle",
|
||||
"state.media_player.standby": "Standby",
|
||||
"state.plant.ok": "OK",
|
||||
"state.plant.problem": "Problem",
|
||||
"state.remote.off": "Off",
|
||||
"state.remote.on": "On",
|
||||
"state.scene.scening": "Scening",
|
||||
"state.script.off": "Off",
|
||||
"state.script.on": "On",
|
||||
"state.sensor.off": "Off",
|
||||
"state.sensor.on": "On",
|
||||
"state.sun.above_horizon": "Above horizon",
|
||||
"state.sun.below_horizon": "Below horizon",
|
||||
"state.switch.off": "Off",
|
||||
"state.switch.on": "On",
|
||||
"state.weather.clear-night": "Clear, night",
|
||||
"state.weather.cloudy": "Cloudy",
|
||||
"state.weather.fog": "Fog",
|
||||
"state.weather.hail": "Hail",
|
||||
"state.weather.lightning": "Lightning",
|
||||
"state.weather.lightning-rainy": "Lightning, rainy",
|
||||
"state.weather.partlycloudy": "Partly cloudy",
|
||||
"state.weather.pouring": "Pouring",
|
||||
"state.weather.rainy": "Rainy",
|
||||
"state.weather.snowy": "Snowy",
|
||||
"state.weather.snowy-rainy": "Snowy, rainy",
|
||||
"state.weather.sunny": "Sunny",
|
||||
"state.weather.windy": "Windy",
|
||||
"state.weather.windy-variant": "Windy",
|
||||
"state.zwave.default.initializing": "Initializing",
|
||||
"state.zwave.default.dead": "Dead",
|
||||
"state.zwave.default.sleeping": "Sleeping",
|
||||
"state.zwave.default.ready": "Ready",
|
||||
"state.zwave.query_stage.initializing": "Initializing ({query_stage})",
|
||||
"state.zwave.query_stage.dead": "Dead ({query_stage})",
|
||||
"state_badge.default.unknown": "Unk",
|
||||
"state_badge.default.unavailable": "Unavai",
|
||||
"state_badge.alarm_control_panel.armed": "Armed",
|
||||
"state_badge.alarm_control_panel.disarmed": "Disarm",
|
||||
"state_badge.alarm_control_panel.armed_home": "Armed",
|
||||
"state_badge.alarm_control_panel.armed_away": "Armed",
|
||||
"state_badge.alarm_control_panel.armed_night": "Armed",
|
||||
"state_badge.alarm_control_panel.armed_custom_bypass": "Armed",
|
||||
"state_badge.alarm_control_panel.pending": "Pend",
|
||||
"state_badge.alarm_control_panel.arming": "Arming",
|
||||
"state_badge.alarm_control_panel.disarming": "Disarm",
|
||||
"state_badge.alarm_control_panel.triggered": "Trig",
|
||||
"state_badge.device_tracker.home": "Home",
|
||||
"state_badge.device_tracker.not_home": "Away",
|
||||
"ui.card.alarm_control_panel.code": "Code",
|
||||
"ui.card.alarm_control_panel.clear_code": "Clear",
|
||||
"ui.card.alarm_control_panel.disarm": "Disarm",
|
||||
"ui.card.alarm_control_panel.arm_home": "Arm home",
|
||||
"ui.card.alarm_control_panel.arm_away": "Arm away",
|
||||
"ui.card.automation.last_triggered": "Last triggered",
|
||||
"ui.card.automation.trigger": "Trigger",
|
||||
"ui.card.camera.not_available": "Image not available",
|
||||
"ui.card.climate.currently": "Currently",
|
||||
"ui.card.climate.on_off": "On / off",
|
||||
"ui.card.climate.target_temperature": "Target temperature",
|
||||
"ui.card.climate.target_humidity": "Target humidity",
|
||||
"ui.card.climate.operation": "Operation",
|
||||
"ui.card.climate.fan_mode": "Fan mode",
|
||||
"ui.card.climate.swing_mode": "Swing mode",
|
||||
"ui.card.climate.away_mode": "Away mode",
|
||||
"ui.card.climate.aux_heat": "Aux heat",
|
||||
"ui.card.cover.position": "Position",
|
||||
"ui.card.cover.tilt_position": "Tilt position",
|
||||
"ui.card.fan.speed": "Speed",
|
||||
"ui.card.fan.oscillate": "Oscillate",
|
||||
"ui.card.fan.direction": "Direction",
|
||||
"ui.card.light.brightness": "Brightness",
|
||||
"ui.card.light.color_temperature": "Color temperature",
|
||||
"ui.card.light.white_value": "White value",
|
||||
"ui.card.light.effect": "Effect",
|
||||
"ui.card.lock.code": "Code",
|
||||
"ui.card.lock.lock": "Lock",
|
||||
"ui.card.lock.unlock": "Unlock",
|
||||
"ui.card.media_player.source": "Source",
|
||||
"ui.card.media_player.sound_mode": "Sound mode",
|
||||
"ui.card.media_player.text_to_speak": "Text to speak",
|
||||
"ui.card.persistent_notification.dismiss": "Dismiss",
|
||||
"ui.card.scene.activate": "Activate",
|
||||
"ui.card.script.execute": "Execute",
|
||||
"ui.card.weather.attributes.air_pressure": "Air pressure",
|
||||
"ui.card.weather.attributes.humidity": "Humidity",
|
||||
"ui.card.weather.attributes.temperature": "Temperature",
|
||||
"ui.card.weather.attributes.visibility": "Visibility",
|
||||
"ui.card.weather.attributes.wind_speed": "Wind speed",
|
||||
"ui.card.weather.cardinal_direction.e": "E",
|
||||
"ui.card.weather.cardinal_direction.ene": "ENE",
|
||||
"ui.card.weather.cardinal_direction.ese": "ESE",
|
||||
"ui.card.weather.cardinal_direction.n": "N",
|
||||
"ui.card.weather.cardinal_direction.ne": "NE",
|
||||
"ui.card.weather.cardinal_direction.nne": "NNE",
|
||||
"ui.card.weather.cardinal_direction.nw": "NW",
|
||||
"ui.card.weather.cardinal_direction.nnw": "NNW",
|
||||
"ui.card.weather.cardinal_direction.s": "S",
|
||||
"ui.card.weather.cardinal_direction.se": "SE",
|
||||
"ui.card.weather.cardinal_direction.sse": "SSE",
|
||||
"ui.card.weather.cardinal_direction.ssw": "SSW",
|
||||
"ui.card.weather.cardinal_direction.sw": "SW",
|
||||
"ui.card.weather.cardinal_direction.w": "W",
|
||||
"ui.card.weather.cardinal_direction.wnw": "WNW",
|
||||
"ui.card.weather.cardinal_direction.wsw": "WSW",
|
||||
"ui.card.weather.forecast": "Forecast",
|
||||
"ui.common.loading": "Loading",
|
||||
"ui.common.cancel": "Cancel",
|
||||
"ui.components.entity.entity-picker.entity": "Entity",
|
||||
"ui.components.relative_time.past": "{time} ago",
|
||||
"ui.components.relative_time.future": "In {time}",
|
||||
"ui.components.relative_time.never": "Never",
|
||||
"ui.components.relative_time.duration.second":
|
||||
"{count} {count, plural,\n one {second}\n other {seconds}\n}",
|
||||
"ui.components.relative_time.duration.minute":
|
||||
"{count} {count, plural,\n one {minute}\n other {minutes}\n}",
|
||||
"ui.components.relative_time.duration.hour":
|
||||
"{count} {count, plural,\n one {hour}\n other {hours}\n}",
|
||||
"ui.components.relative_time.duration.day":
|
||||
"{count} {count, plural,\n one {day}\n other {days}\n}",
|
||||
"ui.components.relative_time.duration.week":
|
||||
"{count} {count, plural,\n one {week}\n other {weeks}\n}",
|
||||
"ui.components.history_charts.loading_history": "Loading state history...",
|
||||
"ui.components.history_charts.no_history_found": "No state history found.",
|
||||
"ui.components.service-picker.service": "Service",
|
||||
"ui.dialogs.more_info_settings.save": "Save",
|
||||
"ui.dialogs.more_info_settings.name": "Name",
|
||||
"ui.duration.second":
|
||||
"{count} {count, plural,\n one {second}\n other {seconds}\n}",
|
||||
"ui.duration.minute":
|
||||
"{count} {count, plural,\n one {minute}\n other {minutes}\n}",
|
||||
"ui.duration.hour":
|
||||
"{count} {count, plural,\n one {hour}\n other {hours}\n}",
|
||||
"ui.duration.day":
|
||||
"{count} {count, plural,\n one {day}\n other {days}\n}",
|
||||
"ui.duration.week":
|
||||
"{count} {count, plural,\n one {week}\n other {weeks}\n}",
|
||||
"ui.login-form.password": "Password",
|
||||
"ui.login-form.remember": "Remember",
|
||||
"ui.login-form.log_in": "Log in",
|
||||
"ui.notification_toast.entity_turned_on": "Turned on {entity}.",
|
||||
"ui.notification_toast.entity_turned_off": "Turned off {entity}.",
|
||||
"ui.notification_toast.service_called": "Service {service} called.",
|
||||
"ui.notification_toast.service_call_failed":
|
||||
"Failed to call service {service}.",
|
||||
"ui.notification_toast.connection_lost": "Connection lost. Reconnecting…",
|
||||
"ui.sidebar.developer_tools": "Developer tools",
|
||||
"ui.sidebar.log_out": "Log out",
|
||||
"attribute.weather.humidity": "Humidity",
|
||||
"attribute.weather.visibility": "Visibility",
|
||||
"attribute.weather.wind_speed": "Wind speed",
|
||||
},
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
const now = () => new Date().toISOString();
|
||||
const randomTime = () =>
|
||||
new Date(new Date().getTime() - (Math.random() * 80 * 60 * 1000)).toISOString();
|
||||
new Date(new Date().getTime() - Math.random() * 80 * 60 * 1000).toISOString();
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
@@ -18,19 +18,23 @@ export class Entity {
|
||||
}
|
||||
|
||||
async handleService(domain, service, data) {
|
||||
console.log(`Unmocked service for ${this.entityId}: ${domain}/${service}`, data);
|
||||
console.log(
|
||||
`Unmocked service for ${this.entityId}: ${domain}/${service}`,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
update(state, attributes = {}) {
|
||||
this.state = state;
|
||||
this.lastUpdated = now();
|
||||
this.lastChanged = state === this.state ? this.lastChanged : this.lastUpdated;
|
||||
this.lastChanged =
|
||||
state === this.state ? this.lastChanged : this.lastUpdated;
|
||||
this.attributes = Object.assign({}, this.baseAttributes, attributes);
|
||||
|
||||
console.log('update', this.entityId, this);
|
||||
console.log("update", this.entityId, this);
|
||||
|
||||
this.hass.updateStates({
|
||||
[this.entityId]: this.toState()
|
||||
[this.entityId]: this.toState(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -47,22 +51,25 @@ export class Entity {
|
||||
|
||||
export class LightEntity extends Entity {
|
||||
async handleService(domain, service, data) {
|
||||
if (!['homeassistant', this.domain].includes(domain)) return;
|
||||
if (!["homeassistant", this.domain].includes(domain)) return;
|
||||
|
||||
if (service === 'turn_on') {
|
||||
if (service === "turn_on") {
|
||||
// eslint-disable-next-line
|
||||
const { brightness, hs_color } = data;
|
||||
this.update('on', Object.assign(this.attributes, {
|
||||
brightness,
|
||||
hs_color,
|
||||
}));
|
||||
} else if (service === 'turn_off') {
|
||||
this.update('off');
|
||||
} else if (service === 'toggle') {
|
||||
if (this.state === 'on') {
|
||||
this.handleService(domain, 'turn_off', data);
|
||||
this.update(
|
||||
"on",
|
||||
Object.assign(this.attributes, {
|
||||
brightness,
|
||||
hs_color,
|
||||
})
|
||||
);
|
||||
} else if (service === "turn_off") {
|
||||
this.update("off");
|
||||
} else if (service === "toggle") {
|
||||
if (this.state === "on") {
|
||||
this.handleService(domain, "turn_off", data);
|
||||
} else {
|
||||
this.handleService(domain, 'turn_on', data);
|
||||
this.handleService(domain, "turn_on", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,10 +79,10 @@ export class LockEntity extends Entity {
|
||||
async handleService(domain, service, data) {
|
||||
if (domain !== this.domain) return;
|
||||
|
||||
if (service === 'lock') {
|
||||
this.update('locked');
|
||||
} else if (service === 'unlock') {
|
||||
this.update('unlocked');
|
||||
if (service === "lock") {
|
||||
this.update("locked");
|
||||
} else if (service === "unlock") {
|
||||
this.update("unlocked");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,24 +91,26 @@ export class CoverEntity extends Entity {
|
||||
async handleService(domain, service, data) {
|
||||
if (domain !== this.domain) return;
|
||||
|
||||
if (service === 'open_cover') {
|
||||
this.update('open');
|
||||
} else if (service === 'close_cover') {
|
||||
this.update('closing');
|
||||
if (service === "open_cover") {
|
||||
this.update("open");
|
||||
} else if (service === "close_cover") {
|
||||
this.update("closing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class GroupEntity extends Entity {
|
||||
async handleService(domain, service, data) {
|
||||
if (!['homeassistant', this.domain].includes(domain)) return;
|
||||
if (!["homeassistant", this.domain].includes(domain)) return;
|
||||
|
||||
await Promise.all(this.attributes.entity_id.map((ent) => {
|
||||
const entity = this.hass.mockEntities[ent];
|
||||
return entity.handleService(entity.domain, service, data);
|
||||
}));
|
||||
await Promise.all(
|
||||
this.attributes.entity_id.map((ent) => {
|
||||
const entity = this.hass.mockEntities[ent];
|
||||
return entity.handleService(entity.domain, service, data);
|
||||
})
|
||||
);
|
||||
|
||||
this.update(service === 'turn_on' ? 'on' : 'off');
|
||||
this.update(service === "turn_on" ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -9,16 +9,18 @@ export default class FakeHass {
|
||||
}
|
||||
|
||||
async callService(domain, service, serviceData) {
|
||||
console.log('callService', { domain, service, serviceData });
|
||||
console.log("callService", { domain, service, serviceData });
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
async callWS(msg) {
|
||||
const callback = this._wsCommands[msg.type];
|
||||
return callback ? callback(msg) : Promise.reject({
|
||||
code: 'command_not_mocked',
|
||||
message: 'This command is not implemented in the gallery.',
|
||||
});
|
||||
return callback
|
||||
? callback(msg)
|
||||
: Promise.reject({
|
||||
code: "command_not_mocked",
|
||||
message: "This command is not implemented in the gallery.",
|
||||
});
|
||||
}
|
||||
|
||||
async sendWS(msg) {
|
||||
@@ -29,6 +31,6 @@ export default class FakeHass {
|
||||
} else {
|
||||
console.error(`Unknown command: ${msg.type}`);
|
||||
}
|
||||
console.log('sendWS', msg);
|
||||
console.log("sendWS", msg);
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import fireEvent from '../../../src/common/dom/fire_event.js';
|
||||
import { fireEvent } from "../../../src/common/dom/fire_event.js";
|
||||
|
||||
import demoConfig from './demo_config.js';
|
||||
import demoResources from './demo_resources.js';
|
||||
import demoConfig from "./demo_config.js";
|
||||
import demoResources from "./demo_resources.js";
|
||||
|
||||
const ensureArray = val => (Array.isArray(val) ? val : [val]);
|
||||
const ensureArray = (val) => (Array.isArray(val) ? val : [val]);
|
||||
|
||||
export default (elements, { initialStates = {} } = {}) => {
|
||||
elements = ensureArray(elements);
|
||||
@@ -14,13 +14,15 @@ export default (elements, { initialStates = {} } = {}) => {
|
||||
|
||||
function updateHass(obj) {
|
||||
hass = Object.assign({}, hass, obj);
|
||||
elements.forEach((el) => { el.hass = hass; });
|
||||
elements.forEach((el) => {
|
||||
el.hass = hass;
|
||||
});
|
||||
}
|
||||
|
||||
updateHass({
|
||||
// Home Assistant properties
|
||||
config: demoConfig,
|
||||
language: 'en',
|
||||
language: "en",
|
||||
resources: demoResources,
|
||||
states: initialStates,
|
||||
|
||||
@@ -29,21 +31,28 @@ export default (elements, { initialStates = {} } = {}) => {
|
||||
|
||||
// Home Assistant functions
|
||||
async callService(domain, service, data) {
|
||||
fireEvent(elements[0], 'show-notification', { message: `Called service ${domain}/${service}` });
|
||||
fireEvent(elements[0], "show-notification", {
|
||||
message: `Called service ${domain}/${service}`,
|
||||
});
|
||||
if (data.entity_id) {
|
||||
await Promise.all(ensureArray(data.entity_id).map(ent =>
|
||||
entities[ent].handleService(domain, service, data)));
|
||||
await Promise.all(
|
||||
ensureArray(data.entity_id).map((ent) =>
|
||||
entities[ent].handleService(domain, service, data)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
console.log('unmocked callService', domain, service, data);
|
||||
console.log("unmocked callService", domain, service, data);
|
||||
}
|
||||
},
|
||||
|
||||
async callWS(msg) {
|
||||
const callback = wsCommands[msg.type];
|
||||
return callback ? callback(msg) : Promise.reject({
|
||||
code: 'command_not_mocked',
|
||||
message: 'This command is not implemented in the gallery.',
|
||||
});
|
||||
return callback
|
||||
? callback(msg)
|
||||
: Promise.reject({
|
||||
code: "command_not_mocked",
|
||||
message: "This command is not implemented in the gallery.",
|
||||
});
|
||||
},
|
||||
|
||||
async sendWS(msg) {
|
||||
@@ -54,7 +63,7 @@ export default (elements, { initialStates = {} } = {}) => {
|
||||
} else {
|
||||
console.error(`Unknown command: ${msg.type}`);
|
||||
}
|
||||
console.log('sendWS', msg);
|
||||
console.log("sendWS", msg);
|
||||
},
|
||||
|
||||
// Mock functions
|
||||
@@ -72,7 +81,7 @@ export default (elements, { initialStates = {} } = {}) => {
|
||||
states[ent.entityId] = ent.toState();
|
||||
});
|
||||
this.updateStates(states);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return hass;
|
||||
|
75
gallery/src/demos/demo-hui-alarm-panel-card.js
Normal file
75
gallery/src/demos/demo-hui-alarm-panel-card.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import getEntity from "../data/entity.js";
|
||||
import provideHass from "../data/provide_hass.js";
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
||||
friendly_name: "Alarm",
|
||||
}),
|
||||
getEntity("alarm_control_panel", "alarm_armed", "armed_home", {
|
||||
friendly_name: "Alarm",
|
||||
}),
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: "Basic Example",
|
||||
config: `
|
||||
- type: alarm-panel
|
||||
entity: alarm_control_panel.alarm
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "With Title",
|
||||
config: `
|
||||
- type: alarm-panel
|
||||
entity: alarm_control_panel.alarm_armed
|
||||
title: My Alarm
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Using only Arm_Home State",
|
||||
config: `
|
||||
- type: alarm-panel
|
||||
entity: alarm_control_panel.alarm
|
||||
states:
|
||||
- arm_home
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Invalid Entity",
|
||||
config: `
|
||||
- type: alarm-panel
|
||||
entity: alarm_control_panel.alarm1
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
class DemoAlarmPanelEntity extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
<demo-cards id='demos' hass='[[hass]]' configs="[[_configs]]"></demo-cards>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS,
|
||||
},
|
||||
hass: Object,
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
const hass = provideHass(this.$.demos);
|
||||
hass.addEntities(ENTITIES);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("demo-hui-alarm-panel-card", DemoAlarmPanelEntity);
|
@@ -1,28 +1,28 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import getEntity from '../data/entity.js';
|
||||
import provideHass from '../data/provide_hass.js';
|
||||
import '../components/demo-cards.js';
|
||||
import getEntity from "../data/entity.js";
|
||||
import provideHass from "../data/provide_hass.js";
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity('light', 'controller_1', 'on', {
|
||||
friendly_name: 'Controller 1'
|
||||
getEntity("light", "controller_1", "on", {
|
||||
friendly_name: "Controller 1",
|
||||
}),
|
||||
getEntity('light', 'controller_2', 'on', {
|
||||
friendly_name: 'Controller 2'
|
||||
getEntity("light", "controller_2", "on", {
|
||||
friendly_name: "Controller 2",
|
||||
}),
|
||||
getEntity('light', 'floor', 'off', {
|
||||
friendly_name: 'Floor light'
|
||||
getEntity("light", "floor", "off", {
|
||||
friendly_name: "Floor light",
|
||||
}),
|
||||
getEntity('light', 'kitchen', 'on', {
|
||||
friendly_name: 'Kitchen light'
|
||||
getEntity("light", "kitchen", "on", {
|
||||
friendly_name: "Kitchen light",
|
||||
}),
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Controller',
|
||||
heading: "Controller",
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
@@ -31,10 +31,10 @@ const CONFIGS = [
|
||||
- type: divider
|
||||
- light.floor
|
||||
- light.kitchen
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Demo',
|
||||
heading: "Demo",
|
||||
config: `
|
||||
- type: conditional
|
||||
conditions:
|
||||
@@ -49,7 +49,7 @@ const CONFIGS = [
|
||||
- light.controller_2
|
||||
- light.floor
|
||||
- light.kitchen
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -68,7 +68,7 @@ class DemoConditional extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
value: CONFIGS,
|
||||
},
|
||||
hass: Object,
|
||||
};
|
||||
@@ -81,4 +81,4 @@ class DemoConditional extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-conditional-card', DemoConditional);
|
||||
customElements.define("demo-hui-conditional-card", DemoConditional);
|
||||
|
@@ -1,75 +1,70 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import getEntity from '../data/entity.js';
|
||||
import provideHass from '../data/provide_hass.js';
|
||||
import '../components/demo-cards.js';
|
||||
import getEntity from "../data/entity.js";
|
||||
import provideHass from "../data/provide_hass.js";
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity('light', 'bed_light', 'on', {
|
||||
friendly_name: 'Bed Light'
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
getEntity('group', 'kitchen', 'on', {
|
||||
entity_id: [
|
||||
'light.bed_light',
|
||||
],
|
||||
getEntity("group", "kitchen", "on", {
|
||||
entity_id: ["light.bed_light"],
|
||||
order: 8,
|
||||
friendly_name: 'Kitchen'
|
||||
friendly_name: "Kitchen",
|
||||
}),
|
||||
getEntity('lock', 'kitchen_door', 'locked', {
|
||||
friendly_name: 'Kitchen Door'
|
||||
getEntity("lock", "kitchen_door", "locked", {
|
||||
friendly_name: "Kitchen Door",
|
||||
}),
|
||||
getEntity('cover', 'kitchen_window', 'open', {
|
||||
friendly_name: 'Kitchen Window',
|
||||
supported_features: 11
|
||||
getEntity("cover", "kitchen_window", "open", {
|
||||
friendly_name: "Kitchen Window",
|
||||
supported_features: 11,
|
||||
}),
|
||||
getEntity('scene', 'romantic_lights', 'scening', {
|
||||
entity_id: [
|
||||
'light.bed_light',
|
||||
'light.ceiling_lights'
|
||||
],
|
||||
friendly_name: 'Romantic lights'
|
||||
getEntity("scene", "romantic_lights", "scening", {
|
||||
entity_id: ["light.bed_light", "light.ceiling_lights"],
|
||||
friendly_name: "Romantic lights",
|
||||
}),
|
||||
getEntity('device_tracker', 'demo_paulus', 'home', {
|
||||
source_type: 'gps',
|
||||
getEntity("device_tracker", "demo_paulus", "home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: 'Paulus'
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity('climate', 'ecobee', 'auto', {
|
||||
getEntity("climate", "ecobee", "auto", {
|
||||
current_temperature: 73,
|
||||
min_temp: 45,
|
||||
max_temp: 95,
|
||||
temperature: null,
|
||||
target_temp_high: 75,
|
||||
target_temp_low: 70,
|
||||
fan_mode: 'Auto Low',
|
||||
fan_list: ['On Low', 'On High', 'Auto Low', 'Auto High', 'Off'],
|
||||
operation_mode: 'auto',
|
||||
operation_list: ['heat', 'cool', 'auto', 'off'],
|
||||
hold_mode: 'home',
|
||||
swing_mode: 'Auto',
|
||||
swing_list: ['Auto', '1', '2', '3', 'Off'],
|
||||
unit_of_measurement: '°F',
|
||||
friendly_name: 'Ecobee',
|
||||
supported_features: 1014
|
||||
fan_mode: "Auto Low",
|
||||
fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
operation_mode: "auto",
|
||||
operation_list: ["heat", "cool", "auto", "off"],
|
||||
hold_mode: "home",
|
||||
swing_mode: "Auto",
|
||||
swing_list: ["Auto", "1", "2", "3", "Off"],
|
||||
unit_of_measurement: "°F",
|
||||
friendly_name: "Ecobee",
|
||||
supported_features: 1014,
|
||||
}),
|
||||
getEntity('input_number', 'noise_allowance', 5, {
|
||||
getEntity("input_number", "noise_allowance", 5, {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
mode: 'slider',
|
||||
unit_of_measurement: 'dB',
|
||||
friendly_name: 'Allowed Noise',
|
||||
icon: 'mdi:bell-ring'
|
||||
})
|
||||
mode: "slider",
|
||||
unit_of_measurement: "dB",
|
||||
friendly_name: "Allowed Noise",
|
||||
icon: "mdi:bell-ring",
|
||||
}),
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Basic',
|
||||
heading: "Basic",
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
@@ -82,10 +77,10 @@ const CONFIGS = [
|
||||
- light.non_existing
|
||||
- climate.ecobee
|
||||
- input_number.noise_allowance
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'With title, toggle-able',
|
||||
heading: "With title, toggle-able",
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
@@ -98,10 +93,10 @@ const CONFIGS = [
|
||||
- climate.ecobee
|
||||
- input_number.noise_allowance
|
||||
title: Random group
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'With title, toggle = false',
|
||||
heading: "With title, toggle = false",
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
@@ -115,19 +110,19 @@ const CONFIGS = [
|
||||
- input_number.noise_allowance
|
||||
title: Random group
|
||||
show_header_toggle: false
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'With title, can\'t toggle',
|
||||
heading: "With title, can't toggle",
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
- device_tracker.demo_paulus
|
||||
title: Random group
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Custom name, secondary info, custom icon',
|
||||
heading: "Custom name, secondary info, custom icon",
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
@@ -147,17 +142,13 @@ const CONFIGS = [
|
||||
- input_number.noise_allowance
|
||||
title: Random group
|
||||
show_header_toggle: false
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Special rows',
|
||||
heading: "Special rows",
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
- type: weblink
|
||||
url: http://google.com/
|
||||
icon: mdi:google
|
||||
name: Google
|
||||
- type: call-service
|
||||
icon: mdi:power
|
||||
name: Bed light
|
||||
@@ -165,13 +156,19 @@ const CONFIGS = [
|
||||
service: light.toggle
|
||||
service_data:
|
||||
entity_id: light.bed_light
|
||||
- type: section
|
||||
label: Links
|
||||
- type: weblink
|
||||
url: http://google.com/
|
||||
icon: mdi:google
|
||||
name: Google
|
||||
- type: divider
|
||||
- type: divider
|
||||
style:
|
||||
height: 30px
|
||||
margin: 4px 0
|
||||
background: center / contain url("/images/divider.png") no-repeat
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -190,7 +187,7 @@ class DemoEntities extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
value: CONFIGS,
|
||||
},
|
||||
hass: Object,
|
||||
};
|
||||
@@ -203,4 +200,4 @@ class DemoEntities extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-entities-card', DemoEntities);
|
||||
customElements.define("demo-hui-entities-card", DemoEntities);
|
||||
|
95
gallery/src/demos/demo-hui-entity-button-card.js
Normal file
95
gallery/src/demos/demo-hui-entity-button-card.js
Normal file
@@ -0,0 +1,95 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import getEntity from "../data/entity.js";
|
||||
import provideHass from "../data/provide_hass.js";
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Bed Light",
|
||||
}),
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: "Basic example",
|
||||
config: `
|
||||
- type: entity-button
|
||||
entity: light.bed_light
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "With Name",
|
||||
config: `
|
||||
- type: entity-button
|
||||
name: Bedroom
|
||||
entity: light.bed_light
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "With Icon",
|
||||
config: `
|
||||
- type: entity-button
|
||||
entity: light.bed_light
|
||||
icon: mdi:hotel
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Without State",
|
||||
config: `
|
||||
- type: entity-button
|
||||
entity: light.bed_light
|
||||
show_state: false
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Custom Tap Action (toggle)",
|
||||
config: `
|
||||
- type: entity-button
|
||||
entity: light.bed_light
|
||||
tap_action: toggle
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Running Service",
|
||||
config: `
|
||||
- type: entity-button
|
||||
entity: light.bed_light
|
||||
service: light.toggle
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Invalid Entity",
|
||||
config: `
|
||||
- type: entity-button
|
||||
entity: sensor.invalid_entity
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
class DemoEntityButtonEntity extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
<demo-cards id='demos' hass='[[hass]]' configs="[[_configs]]"></demo-cards>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS,
|
||||
},
|
||||
hass: Object,
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
const hass = provideHass(this.$.demos);
|
||||
hass.addEntities(ENTITIES);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("demo-hui-entity-button-card", DemoEntityButtonEntity);
|
@@ -1,11 +1,11 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/demo-cards.js';
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Basic',
|
||||
heading: "Basic",
|
||||
config: `
|
||||
- type: entity-filter
|
||||
entities:
|
||||
@@ -18,10 +18,10 @@ const CONFIGS = [
|
||||
state_filter:
|
||||
- "on"
|
||||
- not_home
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'With card config',
|
||||
heading: "With card config",
|
||||
config: `
|
||||
- type: entity-filter
|
||||
entities:
|
||||
@@ -37,10 +37,10 @@ const CONFIGS = [
|
||||
card:
|
||||
type: glance
|
||||
show_state: false
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Showing single entity conditionally',
|
||||
heading: "Showing single entity conditionally",
|
||||
config: `
|
||||
- type: entity-filter
|
||||
entities:
|
||||
@@ -50,8 +50,8 @@ const CONFIGS = [
|
||||
card:
|
||||
type: media-control
|
||||
entity: media_player.lounge_room
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
class DemoFilter extends PolymerElement {
|
||||
@@ -65,10 +65,10 @@ class DemoFilter extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
}
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-entity-filter-card', DemoFilter);
|
||||
customElements.define("demo-hui-entity-filter-card", DemoFilter);
|
||||
|
83
gallery/src/demos/demo-hui-gauge-card.js
Normal file
83
gallery/src/demos/demo-hui-gauge-card.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: "Basic example",
|
||||
config: `
|
||||
- type: gauge
|
||||
entity: sensor.brightness
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "With title",
|
||||
config: `
|
||||
- type: gauge
|
||||
title: Humidity
|
||||
entity: sensor.outside_humidity
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Custom Unit of Measurement",
|
||||
config: `
|
||||
- type: gauge
|
||||
entity: sensor.outside_temperature
|
||||
unit_of_measurement: C
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Setting Severity Levels",
|
||||
config: `
|
||||
- type: gauge
|
||||
entity: sensor.brightness
|
||||
severity:
|
||||
red: 32
|
||||
green: 0
|
||||
yellow: 23
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Setting Min and Max Values",
|
||||
config: `
|
||||
- type: gauge
|
||||
entity: sensor.brightness
|
||||
min: 0
|
||||
max: 38
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Invalid Entity",
|
||||
config: `
|
||||
- type: gauge
|
||||
entity: sensor.invalid_entity
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Non-Numeric Value",
|
||||
config: `
|
||||
- type: gauge
|
||||
entity: plant.bonsai
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
class DemoGaugeEntity extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
<demo-cards configs="[[_configs]]"></demo-cards>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("demo-hui-gauge-card", DemoGaugeEntity);
|
@@ -1,11 +1,11 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/demo-cards.js';
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Basic example',
|
||||
heading: "Basic example",
|
||||
config: `
|
||||
- type: glance
|
||||
entities:
|
||||
@@ -16,10 +16,10 @@ const CONFIGS = [
|
||||
- light.kitchen_lights
|
||||
- lock.kitchen_door
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'With title',
|
||||
heading: "With title",
|
||||
config: `
|
||||
- type: glance
|
||||
title: This is glance
|
||||
@@ -31,10 +31,10 @@ const CONFIGS = [
|
||||
- light.kitchen_lights
|
||||
- lock.kitchen_door
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Custom column width',
|
||||
heading: "Custom column width",
|
||||
config: `
|
||||
- type: glance
|
||||
column_width: calc(100% / 7)
|
||||
@@ -46,10 +46,10 @@ const CONFIGS = [
|
||||
- light.kitchen_lights
|
||||
- lock.kitchen_door
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'No name',
|
||||
heading: "No name",
|
||||
config: `
|
||||
- type: glance
|
||||
show_name: false
|
||||
@@ -61,10 +61,10 @@ const CONFIGS = [
|
||||
- light.kitchen_lights
|
||||
- lock.kitchen_door
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'No state',
|
||||
heading: "No state",
|
||||
config: `
|
||||
- type: glance
|
||||
show_state: false
|
||||
@@ -76,10 +76,10 @@ const CONFIGS = [
|
||||
- light.kitchen_lights
|
||||
- lock.kitchen_door
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'No name and no state',
|
||||
heading: "No name and no state",
|
||||
config: `
|
||||
- type: glance
|
||||
show_name: false
|
||||
@@ -92,10 +92,10 @@ const CONFIGS = [
|
||||
- light.kitchen_lights
|
||||
- lock.kitchen_door
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Custom name, custom icon',
|
||||
heading: "Custom name, custom icon",
|
||||
config: `
|
||||
- type: glance
|
||||
entities:
|
||||
@@ -109,10 +109,10 @@ const CONFIGS = [
|
||||
icon: mdi:alarm-light
|
||||
- lock.kitchen_door
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Custom tap action',
|
||||
heading: "Custom tap action",
|
||||
config: `
|
||||
- type: glance
|
||||
entities:
|
||||
@@ -126,10 +126,10 @@ const CONFIGS = [
|
||||
- sun.sun
|
||||
- cover.kitchen_window
|
||||
- light.kitchen_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Selectively hidden name',
|
||||
heading: "Selectively hidden name",
|
||||
config: `
|
||||
- type: glance
|
||||
entities:
|
||||
@@ -140,7 +140,22 @@ const CONFIGS = [
|
||||
- entity: cover.kitchen_window
|
||||
name:
|
||||
- light.kitchen_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Primary theme",
|
||||
config: `
|
||||
- type: glance
|
||||
theming: primary
|
||||
entities:
|
||||
- device_tracker.demo_paulus
|
||||
- media_player.living_room
|
||||
- sun.sun
|
||||
- cover.kitchen_window
|
||||
- light.kitchen_lights
|
||||
- lock.kitchen_door
|
||||
- light.ceiling_lights
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -155,10 +170,10 @@ class DemoPicEntity extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
}
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-glance-card', DemoPicEntity);
|
||||
customElements.define("demo-hui-glance-card", DemoPicEntity);
|
||||
|
@@ -1,39 +1,39 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/demo-cards.js';
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Without title',
|
||||
heading: "Without title",
|
||||
config: `
|
||||
- type: iframe
|
||||
url: https://embed.windy.com/embed2.html
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'With title',
|
||||
heading: "With title",
|
||||
config: `
|
||||
- type: iframe
|
||||
url: https://embed.windy.com/embed2.html
|
||||
title: Weather radar
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Height-Width 3:4',
|
||||
heading: "Height-Width 3:4",
|
||||
config: `
|
||||
- type: iframe
|
||||
url: https://embed.windy.com/embed2.html
|
||||
aspect_ratio: 75%
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Height-Width 1:1',
|
||||
heading: "Height-Width 1:1",
|
||||
config: `
|
||||
- type: iframe
|
||||
url: https://embed.windy.com/embed2.html
|
||||
aspect_ratio: 100%
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -48,10 +48,10 @@ class DemoIframe extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
}
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-iframe-card', DemoIframe);
|
||||
customElements.define("demo-hui-iframe-card", DemoIframe);
|
||||
|
@@ -1,120 +1,120 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import getEntity from '../data/entity.js';
|
||||
import provideHass from '../data/provide_hass.js';
|
||||
import '../components/demo-cards.js';
|
||||
import getEntity from "../data/entity.js";
|
||||
import provideHass from "../data/provide_hass.js";
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity('device_tracker', 'demo_paulus', 'not_home', {
|
||||
source_type: 'gps',
|
||||
getEntity("device_tracker", "demo_paulus", "not_home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.877105,
|
||||
longitude: 117.232185,
|
||||
gps_accuracy: 91,
|
||||
battery: 71,
|
||||
friendly_name: 'Paulus'
|
||||
friendly_name: "Paulus",
|
||||
}),
|
||||
getEntity('device_tracker', 'demo_home_boy', 'home', {
|
||||
source_type: 'gps',
|
||||
getEntity("device_tracker", "demo_home_boy", "home", {
|
||||
source_type: "gps",
|
||||
latitude: 32.87334,
|
||||
longitude: 117.22745,
|
||||
gps_accuracy: 20,
|
||||
battery: 53,
|
||||
friendly_name: 'Home Boy'
|
||||
friendly_name: "Home Boy",
|
||||
}),
|
||||
getEntity('zone', 'home', 'zoning', {
|
||||
getEntity("zone", "home", "zoning", {
|
||||
latitude: 32.87354,
|
||||
longitude: 117.22765,
|
||||
radius: 100,
|
||||
friendly_name: 'Home',
|
||||
icon: 'mdi:home'
|
||||
})
|
||||
friendly_name: "Home",
|
||||
icon: "mdi:home",
|
||||
}),
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Without title',
|
||||
heading: "Without title",
|
||||
config: `
|
||||
- type: map
|
||||
entities:
|
||||
- entity: device_tracker.demo_paulus
|
||||
- device_tracker.demo_home_boy
|
||||
- zone.home
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'With title',
|
||||
heading: "With title",
|
||||
config: `
|
||||
- type: map
|
||||
entities:
|
||||
- entity: device_tracker.demo_paulus
|
||||
- zone.home
|
||||
title: Where is Paulus?
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Height-Width 1:2',
|
||||
heading: "Height-Width 1:2",
|
||||
config: `
|
||||
- type: map
|
||||
entities:
|
||||
- entity: device_tracker.demo_paulus
|
||||
- zone.home
|
||||
aspect_ratio: 50%
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Default Zoom',
|
||||
heading: "Default Zoom",
|
||||
config: `
|
||||
- type: map
|
||||
default_zoom: 12
|
||||
entities:
|
||||
- entity: device_tracker.demo_paulus
|
||||
- zone.home
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Default Zoom too High',
|
||||
heading: "Default Zoom too High",
|
||||
config: `
|
||||
- type: map
|
||||
default_zoom: 20
|
||||
entities:
|
||||
- entity: device_tracker.demo_paulus
|
||||
- zone.home
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Single Marker',
|
||||
heading: "Single Marker",
|
||||
config: `
|
||||
- type: map
|
||||
entities:
|
||||
- device_tracker.demo_paulus
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Single Marker Default Zoom',
|
||||
heading: "Single Marker Default Zoom",
|
||||
config: `
|
||||
- type: map
|
||||
default_zoom: 8
|
||||
entities:
|
||||
- device_tracker.demo_paulus
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'No Entities',
|
||||
heading: "No Entities",
|
||||
config: `
|
||||
- type: map
|
||||
entities:
|
||||
- light.bed_light
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'No Entities, Default Zoom',
|
||||
heading: "No Entities, Default Zoom",
|
||||
config: `
|
||||
- type: map
|
||||
default_zoom: 8
|
||||
entities:
|
||||
- light.bed_light
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -133,9 +133,9 @@ class DemoMap extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
value: CONFIGS,
|
||||
},
|
||||
hass: Object
|
||||
hass: Object,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -146,4 +146,4 @@ class DemoMap extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-map-card', DemoMap);
|
||||
customElements.define("demo-hui-map-card", DemoMap);
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/demo-cards.js';
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'markdown-it demo',
|
||||
heading: "markdown-it demo",
|
||||
config: `
|
||||
- type: markdown
|
||||
content: >
|
||||
@@ -248,7 +248,7 @@ const CONFIGS = [
|
||||
::: warning
|
||||
*here be dragons*
|
||||
:::
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -263,10 +263,10 @@ class DemoMarkdown extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
}
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-markdown-card', DemoMarkdown);
|
||||
customElements.define("demo-hui-markdown-card", DemoMarkdown);
|
||||
|
105
gallery/src/demos/demo-hui-media-player-rows.js
Normal file
105
gallery/src/demos/demo-hui-media-player-rows.js
Normal file
@@ -0,0 +1,105 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import getEntity from "../data/entity.js";
|
||||
import provideHass from "../data/provide_hass.js";
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("media_player", "bedroom", "playing", {
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
supported_features: 32,
|
||||
}),
|
||||
getEntity("media_player", "family_room", "paused", {
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
supported_features: 16417,
|
||||
}),
|
||||
getEntity("media_player", "family_room_no_play", "paused", {
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
supported_features: 33,
|
||||
}),
|
||||
getEntity("media_player", "living_room", "playing", {
|
||||
media_content_type: "tvshow",
|
||||
media_title: "Chapter 1",
|
||||
media_series_title: "House of Cards",
|
||||
app_name: "Netflix",
|
||||
supported_features: 1,
|
||||
}),
|
||||
getEntity("media_player", "lounge_room", "idle", {
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
supported_features: 1,
|
||||
}),
|
||||
getEntity("media_player", "theater", "off", {
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
supported_features: 33,
|
||||
}),
|
||||
getEntity("media_player", "android_cast", "playing", {
|
||||
media_title: "Android Screen Casting",
|
||||
app_name: "Screen Mirroring",
|
||||
supported_features: 21437,
|
||||
}),
|
||||
];
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: "Media Players",
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
- entity: media_player.bedroom
|
||||
name: Skip, no pause
|
||||
- entity: media_player.family_room
|
||||
name: Paused, music
|
||||
- entity: media_player.family_room_no_play
|
||||
name: Paused, no play
|
||||
- entity: media_player.living_room
|
||||
name: Pause, No skip, tvshow
|
||||
- entity: media_player.android_cast
|
||||
name: Screen casting
|
||||
- entity: media_player.lounge_room
|
||||
name: Chromcast Idle
|
||||
- entity: media_player.theater
|
||||
name: 'Player Off'
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
class DemoHuiMediaPlayerRows extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
<demo-cards
|
||||
id='demos'
|
||||
hass='[[hass]]'
|
||||
configs="[[_configs]]"
|
||||
></demo-cards>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS,
|
||||
},
|
||||
hass: Object,
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
const hass = provideHass(this.$.demos);
|
||||
hass.addEntities(ENTITIES);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("demo-hui-media-player-rows", DemoHuiMediaPlayerRows);
|
@@ -1,11 +1,11 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/demo-cards.js';
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Card with few elements',
|
||||
heading: "Card with few elements",
|
||||
config: `
|
||||
- type: picture-elements
|
||||
image: /images/floorplan.png
|
||||
@@ -49,7 +49,7 @@ const CONFIGS = [
|
||||
style:
|
||||
top: 8%
|
||||
left: 35%
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -64,10 +64,10 @@ class DemoPicElements extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
}
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-picture-elements-card', DemoPicElements);
|
||||
customElements.define("demo-hui-picture-elements-card", DemoPicElements);
|
||||
|
@@ -1,67 +1,67 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/demo-cards.js';
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'State on',
|
||||
heading: "State on",
|
||||
config: `
|
||||
- type: picture-entity
|
||||
image: /images/kitchen.png
|
||||
entity: light.kitchen_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'State off',
|
||||
heading: "State off",
|
||||
config: `
|
||||
- type: picture-entity
|
||||
image: /images/bed.png
|
||||
entity: light.bed_light
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Entity unavailable',
|
||||
heading: "Entity unavailable",
|
||||
config: `
|
||||
- type: picture-entity
|
||||
image: /images/living_room.png
|
||||
entity: light.non_existing
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Camera entity',
|
||||
heading: "Camera entity",
|
||||
config: `
|
||||
- type: picture-entity
|
||||
entity: camera.demo_camera
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Hidden name',
|
||||
heading: "Hidden name",
|
||||
config: `
|
||||
- type: picture-entity
|
||||
image: /images/kitchen.png
|
||||
entity: light.kitchen_lights
|
||||
show_name: false
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Hidden state',
|
||||
heading: "Hidden state",
|
||||
config: `
|
||||
- type: picture-entity
|
||||
image: /images/kitchen.png
|
||||
entity: light.kitchen_lights
|
||||
show_state: false
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Both hidden',
|
||||
heading: "Both hidden",
|
||||
config: `
|
||||
- type: picture-entity
|
||||
image: /images/kitchen.png
|
||||
entity: light.kitchen_lights
|
||||
show_name: false
|
||||
show_state: false
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -76,10 +76,10 @@ class DemoPicEntity extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
}
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-picture-entity-card', DemoPicEntity);
|
||||
customElements.define("demo-hui-picture-entity-card", DemoPicEntity);
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/demo-cards.js';
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Title, dialog, toggle',
|
||||
heading: "Title, dialog, toggle",
|
||||
config: `
|
||||
- type: picture-glance
|
||||
image: /images/living_room.png
|
||||
@@ -15,10 +15,10 @@ const CONFIGS = [
|
||||
- light.ceiling_lights
|
||||
- binary_sensor.movement_backyard
|
||||
- binary_sensor.basement_floor_wet
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Title, dialog, no toggle',
|
||||
heading: "Title, dialog, no toggle",
|
||||
config: `
|
||||
- type: picture-glance
|
||||
image: /images/living_room.png
|
||||
@@ -26,10 +26,10 @@ const CONFIGS = [
|
||||
entities:
|
||||
- binary_sensor.movement_backyard
|
||||
- binary_sensor.basement_floor_wet
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Title, no dialog, toggle',
|
||||
heading: "Title, no dialog, toggle",
|
||||
config: `
|
||||
- type: picture-glance
|
||||
image: /images/living_room.png
|
||||
@@ -37,10 +37,10 @@ const CONFIGS = [
|
||||
entities:
|
||||
- switch.decorative_lights
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'No title, dialog, toggle',
|
||||
heading: "No title, dialog, toggle",
|
||||
config: `
|
||||
- type: picture-glance
|
||||
image: /images/living_room.png
|
||||
@@ -49,30 +49,30 @@ const CONFIGS = [
|
||||
- light.ceiling_lights
|
||||
- binary_sensor.movement_backyard
|
||||
- binary_sensor.basement_floor_wet
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'No title, dialog, no toggle',
|
||||
heading: "No title, dialog, no toggle",
|
||||
config: `
|
||||
- type: picture-glance
|
||||
image: /images/living_room.png
|
||||
entities:
|
||||
- binary_sensor.movement_backyard
|
||||
- binary_sensor.basement_floor_wet
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'No title, no dialog, toggle',
|
||||
heading: "No title, no dialog, toggle",
|
||||
config: `
|
||||
- type: picture-glance
|
||||
image: /images/living_room.png
|
||||
entities:
|
||||
- switch.decorative_lights
|
||||
- light.ceiling_lights
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Custom icon',
|
||||
heading: "Custom icon",
|
||||
config: `
|
||||
- type: picture-glance
|
||||
image: /images/living_room.png
|
||||
@@ -81,7 +81,7 @@ const CONFIGS = [
|
||||
- entity: switch.decorative_lights
|
||||
icon: mdi:power
|
||||
- binary_sensor.basement_floor_wet
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -96,10 +96,10 @@ class DemoPicGlance extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
}
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-picture-glance-card', DemoPicGlance);
|
||||
customElements.define("demo-hui-picture-glance-card", DemoPicGlance);
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/demo-cards.js';
|
||||
import "../components/demo-cards.js";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: 'Vertical Stack',
|
||||
heading: "Vertical Stack",
|
||||
config: `
|
||||
- type: vertical-stack
|
||||
cards:
|
||||
@@ -17,10 +17,10 @@ const CONFIGS = [
|
||||
- device_tracker.demo_anne_therese
|
||||
- device_tracker.demo_home_boy
|
||||
- device_tracker.demo_paulus
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Horizontal Stack',
|
||||
heading: "Horizontal Stack",
|
||||
config: `
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
@@ -32,10 +32,10 @@ const CONFIGS = [
|
||||
- device_tracker.demo_anne_therese
|
||||
- device_tracker.demo_home_boy
|
||||
- device_tracker.demo_paulus
|
||||
`
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: 'Combination of both',
|
||||
heading: "Combination of both",
|
||||
config: `
|
||||
- type: vertical-stack
|
||||
cards:
|
||||
@@ -52,7 +52,7 @@ const CONFIGS = [
|
||||
- type: picture-entity
|
||||
image: /images/bed.png
|
||||
entity: light.bed_light
|
||||
`
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -67,10 +67,10 @@ class DemoStack extends PolymerElement {
|
||||
return {
|
||||
_configs: {
|
||||
type: Object,
|
||||
value: CONFIGS
|
||||
}
|
||||
value: CONFIGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-hui-stack-card', DemoStack);
|
||||
customElements.define("demo-hui-stack-card", DemoStack);
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../../../src/dialogs/more-info/controls/more-info-content.js';
|
||||
import '../../../src/components/ha-card.js';
|
||||
import "../../../src/dialogs/more-info/controls/more-info-content.js";
|
||||
import "../../../src/components/ha-card.js";
|
||||
|
||||
import getEntity from '../data/entity.js';
|
||||
import provideHass from '../data/provide_hass.js';
|
||||
import getEntity from "../data/entity.js";
|
||||
import provideHass from "../data/provide_hass.js";
|
||||
|
||||
import '../components/demo-more-infos.js';
|
||||
import "../components/demo-more-infos.js";
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
@@ -20,17 +20,16 @@ const SUPPORT_TRANSITION = 32;
|
||||
const SUPPORT_WHITE_VALUE = 128;
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity('light', 'bed_light', 'on', {
|
||||
friendly_name: 'Basic Light'
|
||||
getEntity("light", "bed_light", "on", {
|
||||
friendly_name: "Basic Light",
|
||||
}),
|
||||
getEntity('light', 'kitchen_light', 'on', {
|
||||
friendly_name: 'Brightness Light',
|
||||
getEntity("light", "kitchen_light", "on", {
|
||||
friendly_name: "Brightness Light",
|
||||
brightness: 80,
|
||||
supported_features: SUPPORT_BRIGHTNESS,
|
||||
}),
|
||||
];
|
||||
|
||||
|
||||
class DemoMoreInfoLight extends PolymerElement {
|
||||
static get template() {
|
||||
return html`
|
||||
@@ -45,7 +44,7 @@ class DemoMoreInfoLight extends PolymerElement {
|
||||
return {
|
||||
_entities: {
|
||||
type: Array,
|
||||
value: ENTITIES.map(ent => ent.entityId),
|
||||
value: ENTITIES.map((ent) => ent.entityId),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -57,4 +56,4 @@ class DemoMoreInfoLight extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('demo-more-info-light', DemoMoreInfoLight);
|
||||
customElements.define("demo-more-info-light", DemoMoreInfoLight);
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import '@polymer/paper-styles/typography.js';
|
||||
import '@polymer/polymer/lib/elements/dom-if.js';
|
||||
import '@polymer/polymer/lib/elements/dom-repeat.js';
|
||||
import "@polymer/paper-styles/typography.js";
|
||||
import "@polymer/polymer/lib/elements/dom-if.js";
|
||||
import "@polymer/polymer/lib/elements/dom-repeat.js";
|
||||
|
||||
import '../../src/resources/hass-icons.js';
|
||||
import '../../src/resources/ha-style.js';
|
||||
import '../../src/resources/roboto.js';
|
||||
import '../../src/components/ha-iconset-svg.js';
|
||||
import "../../src/resources/hass-icons.js";
|
||||
import "../../src/resources/ha-style.js";
|
||||
import "../../src/resources/roboto.js";
|
||||
import "../../src/components/ha-iconset-svg.js";
|
||||
|
||||
import './ha-gallery.js';
|
||||
import "./ha-gallery.js";
|
||||
|
||||
document.body.appendChild(document.createElement('ha-gallery'));
|
||||
document.body.appendChild(document.createElement("ha-gallery"));
|
||||
|
@@ -1,19 +1,19 @@
|
||||
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/iron-icon/iron-icon.js';
|
||||
import '@polymer/paper-card/paper-card.js';
|
||||
import '@polymer/paper-item/paper-item.js';
|
||||
import '@polymer/paper-item/paper-item-body.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 "@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/iron-icon/iron-icon.js";
|
||||
import "@polymer/paper-card/paper-card.js";
|
||||
import "@polymer/paper-item/paper-item.js";
|
||||
import "@polymer/paper-item/paper-item-body.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/managers/notification-manager.js';
|
||||
import "../../src/managers/notification-manager.js";
|
||||
|
||||
const DEMOS = require.context('./demos', true, /^(.*\.(js$))[^.]*$/im);
|
||||
const DEMOS = require.context("./demos", true, /^(.*\.(js$))[^.]*$/im);
|
||||
|
||||
const fixPath = path => path.substr(2, path.length - 5);
|
||||
const fixPath = (path) => path.substr(2, path.length - 5);
|
||||
|
||||
class HaGallery extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -131,19 +131,19 @@ class HaGallery extends PolymerElement {
|
||||
_demo: {
|
||||
type: String,
|
||||
value: document.location.hash.substr(1),
|
||||
observer: '_demoChanged',
|
||||
observer: "_demoChanged",
|
||||
},
|
||||
_demos: {
|
||||
type: Array,
|
||||
value: DEMOS.keys().map(fixPath)
|
||||
value: DEMOS.keys().map(fixPath),
|
||||
},
|
||||
_lovelaceDemos: {
|
||||
type: Array,
|
||||
computed: '_computeLovelace(_demos)',
|
||||
computed: "_computeLovelace(_demos)",
|
||||
},
|
||||
_moreInfoDemos: {
|
||||
type: Array,
|
||||
computed: '_computeMoreInfos(_demos)',
|
||||
computed: "_computeMoreInfos(_demos)",
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -151,18 +151,21 @@ class HaGallery extends PolymerElement {
|
||||
ready() {
|
||||
super.ready();
|
||||
|
||||
this.addEventListener(
|
||||
'show-notification',
|
||||
ev => this.$.notifications.showNotification(ev.detail.message)
|
||||
this.addEventListener("show-notification", (ev) =>
|
||||
this.$.notifications.showNotification(ev.detail.message)
|
||||
);
|
||||
|
||||
this.addEventListener('hass-more-info', (ev) => {
|
||||
this.addEventListener("hass-more-info", (ev) => {
|
||||
if (ev.detail.entityId) {
|
||||
this.$.notifications.showNotification(`Showing more info for ${ev.detail.entityId}`);
|
||||
this.$.notifications.showNotification(
|
||||
`Showing more info for ${ev.detail.entityId}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('hashchange', () => { this._demo = document.location.hash.substr(1); });
|
||||
window.addEventListener("hashchange", () => {
|
||||
this._demo = document.location.hash.substr(1);
|
||||
});
|
||||
}
|
||||
|
||||
_withDefault(value, def) {
|
||||
@@ -182,20 +185,20 @@ class HaGallery extends PolymerElement {
|
||||
}
|
||||
|
||||
_computeHeaderButtonClass(demo) {
|
||||
return demo ? '' : 'invisible';
|
||||
return demo ? "" : "invisible";
|
||||
}
|
||||
|
||||
_backTapped() {
|
||||
document.location.hash = '';
|
||||
document.location.hash = "";
|
||||
}
|
||||
|
||||
_computeLovelace(demos) {
|
||||
return demos.filter(demo => demo.includes('hui'));
|
||||
return demos.filter((demo) => demo.includes("hui"));
|
||||
}
|
||||
|
||||
_computeMoreInfos(demos) {
|
||||
return demos.filter(demo => demo.includes('more-info'));
|
||||
return demos.filter((demo) => demo.includes("more-info"));
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-gallery', HaGallery);
|
||||
customElements.define("ha-gallery", HaGallery);
|
||||
|
@@ -1,76 +1,71 @@
|
||||
const path = require('path');
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const path = require("path");
|
||||
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const { babelLoaderConfig } = require("../config/babel.js");
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const chunkFilename = isProd ?
|
||||
'chunk.[chunkhash].js' : '[name].chunk.js';
|
||||
const buildPath = path.resolve(__dirname, 'dist');
|
||||
const publicPath = isProd ? './' : 'http://localhost:8080/';
|
||||
const isProd = process.env.NODE_ENV === "production";
|
||||
const chunkFilename = isProd ? "chunk.[chunkhash].js" : "[name].chunk.js";
|
||||
const buildPath = path.resolve(__dirname, "dist");
|
||||
const publicPath = isProd ? "./" : "http://localhost:8080/";
|
||||
|
||||
module.exports = {
|
||||
mode: isProd ? 'production' : 'development',
|
||||
mode: isProd ? "production" : "development",
|
||||
// Disabled in prod while we make Home Assistant able to serve the right files.
|
||||
// Was source-map
|
||||
devtool: isProd ? 'none' : 'inline-source-map',
|
||||
entry: './src/entrypoint.js',
|
||||
devtool: isProd ? "none" : "inline-source-map",
|
||||
entry: "./src/entrypoint.js",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
plugins: [
|
||||
// Only support the syntax, Webpack will handle it.
|
||||
'syntax-dynamic-import',
|
||||
[
|
||||
'transform-react-jsx',
|
||||
{
|
||||
pragma: 'h'
|
||||
}
|
||||
],
|
||||
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
babelLoaderConfig({ latestBuild: true }),
|
||||
{
|
||||
test: /\.(html)$/,
|
||||
use: {
|
||||
loader: 'html-loader',
|
||||
loader: "html-loader",
|
||||
options: {
|
||||
exportAsEs6Default: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new CopyWebpackPlugin([
|
||||
'public',
|
||||
{ from: '../public', to: 'static' },
|
||||
{ from: '../build-translations/output', to: 'static/translations' },
|
||||
{ from: '../node_modules/leaflet/dist/leaflet.css', to: 'static/images/leaflet/' },
|
||||
{ from: '../node_modules/@polymer/font-roboto-local/fonts', to: 'static/fonts' },
|
||||
{ from: '../node_modules/leaflet/dist/images', to: 'static/images/leaflet/' },
|
||||
"public",
|
||||
{ from: "../public", to: "static" },
|
||||
{ from: "../build-translations/output", to: "static/translations" },
|
||||
{
|
||||
from: "../node_modules/leaflet/dist/leaflet.css",
|
||||
to: "static/images/leaflet/",
|
||||
},
|
||||
{
|
||||
from: "../node_modules/@polymer/font-roboto-local/fonts",
|
||||
to: "static/fonts",
|
||||
},
|
||||
{
|
||||
from: "../node_modules/leaflet/dist/images",
|
||||
to: "static/images/leaflet/",
|
||||
},
|
||||
]),
|
||||
isProd && new UglifyJsPlugin({
|
||||
extractComments: true,
|
||||
sourceMap: true,
|
||||
uglifyOptions: {
|
||||
// Disabling because it broke output
|
||||
mangle: false,
|
||||
}
|
||||
}),
|
||||
isProd &&
|
||||
new UglifyJsPlugin({
|
||||
extractComments: true,
|
||||
sourceMap: true,
|
||||
uglifyOptions: {
|
||||
// Disabling because it broke output
|
||||
mangle: false,
|
||||
},
|
||||
}),
|
||||
].filter(Boolean),
|
||||
resolve: {
|
||||
extensions: [".ts", ".js", ".json"],
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
filename: "[name].js",
|
||||
chunkFilename: chunkFilename,
|
||||
path: buildPath,
|
||||
publicPath,
|
||||
},
|
||||
devServer: {
|
||||
contentBase: './public',
|
||||
}
|
||||
contentBase: "./public",
|
||||
},
|
||||
};
|
||||
|
@@ -1,8 +1,8 @@
|
||||
var path = require('path');
|
||||
var path = require("path");
|
||||
|
||||
module.exports = {
|
||||
polymer_dir: path.resolve(__dirname, '..'),
|
||||
build_dir: path.resolve(__dirname, '../build'),
|
||||
output: path.resolve(__dirname, '../hass_frontend'),
|
||||
output_es5: path.resolve(__dirname, '../hass_frontend_es5'),
|
||||
polymer_dir: path.resolve(__dirname, ".."),
|
||||
build_dir: path.resolve(__dirname, "../build"),
|
||||
output: path.resolve(__dirname, "../hass_frontend"),
|
||||
output_es5: path.resolve(__dirname, "../hass_frontend_es5"),
|
||||
};
|
||||
|
@@ -1,31 +1,34 @@
|
||||
const gulp = require('gulp');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const config = require('../config');
|
||||
const gulp = require("gulp");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const config = require("../config");
|
||||
|
||||
const ICON_PACKAGE_PATH = path.resolve(__dirname, '../../node_modules/@mdi/svg/');
|
||||
const META_PATH = path.resolve(ICON_PACKAGE_PATH, 'meta.json');
|
||||
const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, 'svg');
|
||||
const OUTPUT_DIR = path.resolve(__dirname, '../../build');
|
||||
const MDI_OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'mdi.html');
|
||||
const HASS_OUTPUT_PATH = path.resolve(OUTPUT_DIR, 'hass-icons.html');
|
||||
const ICON_PACKAGE_PATH = path.resolve(
|
||||
__dirname,
|
||||
"../../node_modules/@mdi/svg/"
|
||||
);
|
||||
const META_PATH = path.resolve(ICON_PACKAGE_PATH, "meta.json");
|
||||
const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, "svg");
|
||||
const OUTPUT_DIR = path.resolve(__dirname, "../../build");
|
||||
const MDI_OUTPUT_PATH = path.resolve(OUTPUT_DIR, "mdi.html");
|
||||
const HASS_OUTPUT_PATH = path.resolve(OUTPUT_DIR, "hass-icons.html");
|
||||
|
||||
const BUILT_IN_PANEL_ICONS = [
|
||||
'calendar', // Calendar
|
||||
'settings', // Config
|
||||
'home-assistant', // Hass.io
|
||||
'poll-box', // History panel
|
||||
'format-list-bulleted-type', // Logbook
|
||||
'mailbox', // Mailbox
|
||||
'account-location', // Map
|
||||
'cart', // Shopping List
|
||||
"calendar", // Calendar
|
||||
"settings", // Config
|
||||
"home-assistant", // Hass.io
|
||||
"poll-box", // History panel
|
||||
"format-list-bulleted-type", // Logbook
|
||||
"mailbox", // Mailbox
|
||||
"account-location", // Map
|
||||
"cart", // Shopping List
|
||||
];
|
||||
|
||||
// Given an icon name, load the SVG file
|
||||
function loadIcon(name) {
|
||||
const iconPath = path.resolve(ICON_PATH, `${name}.svg`);
|
||||
try {
|
||||
return fs.readFileSync(iconPath, 'utf-8');
|
||||
return fs.readFileSync(iconPath, "utf-8");
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
@@ -33,7 +36,7 @@ function loadIcon(name) {
|
||||
|
||||
// Given an SVG file, convert it to an iron-iconset-svg definition
|
||||
function transformXMLtoPolymer(name, xml) {
|
||||
const start = xml.indexOf('><path') + 1;
|
||||
const start = xml.indexOf("><path") + 1;
|
||||
const end = xml.length - start - 6;
|
||||
const path = xml.substr(start, end);
|
||||
return `<g id="${name}">${path}</g>`;
|
||||
@@ -41,22 +44,26 @@ function transformXMLtoPolymer(name, xml) {
|
||||
|
||||
// Given an iconset name and icon names, generate a polymer iconset
|
||||
function generateIconset(name, iconNames) {
|
||||
const iconDefs = iconNames.map(name => {
|
||||
const iconDef = loadIcon(name);
|
||||
if (!iconDef) {
|
||||
throw new Error(`Unknown icon referenced: ${name}`);
|
||||
}
|
||||
return transformXMLtoPolymer(name, iconDef)
|
||||
}).join('');
|
||||
const iconDefs = iconNames
|
||||
.map((name) => {
|
||||
const iconDef = loadIcon(name);
|
||||
if (!iconDef) {
|
||||
throw new Error(`Unknown icon referenced: ${name}`);
|
||||
}
|
||||
return transformXMLtoPolymer(name, iconDef);
|
||||
})
|
||||
.join("");
|
||||
return `<ha-iconset-svg name="${name}" size="24"><svg><defs>${iconDefs}</defs></svg></ha-iconset-svg>`;
|
||||
}
|
||||
|
||||
// Generate the full MDI iconset
|
||||
function genMDIIcons() {
|
||||
const meta = JSON.parse(fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), 'UTF-8'));
|
||||
const iconNames = meta.map(iconInfo => iconInfo.name);
|
||||
const meta = JSON.parse(
|
||||
fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), "UTF-8")
|
||||
);
|
||||
const iconNames = meta.map((iconInfo) => iconInfo.name);
|
||||
fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR);
|
||||
fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset('mdi', iconNames));
|
||||
fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset("mdi", iconNames));
|
||||
}
|
||||
|
||||
// Helper function to map recursively over files in a folder and it's subfolders
|
||||
@@ -75,30 +82,31 @@ function mapFiles(startPath, filter, mapFunc) {
|
||||
|
||||
// Find all icons used by the project.
|
||||
function findIcons(path, iconsetName) {
|
||||
const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, 'g');
|
||||
const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, "g");
|
||||
const icons = new Set();
|
||||
function processFile(filename) {
|
||||
const content = fs.readFileSync(filename);
|
||||
let match;
|
||||
// eslint-disable-next-line
|
||||
while (match = iconRegex.exec(content)) {
|
||||
while ((match = iconRegex.exec(content))) {
|
||||
// strip off "hass:" and add to set
|
||||
icons.add(match[0].substr(iconsetName.length + 1));
|
||||
}
|
||||
}
|
||||
mapFiles(path, '.js', processFile);
|
||||
mapFiles(path, ".js", processFile);
|
||||
mapFiles(path, ".ts", processFile);
|
||||
return Array.from(icons);
|
||||
}
|
||||
|
||||
function genHassIcons() {
|
||||
const iconNames = findIcons('./src', 'hass').concat(BUILT_IN_PANEL_ICONS);
|
||||
const iconNames = findIcons("./src", "hass").concat(BUILT_IN_PANEL_ICONS);
|
||||
fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR);
|
||||
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset('hass', iconNames));
|
||||
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset("hass", iconNames));
|
||||
}
|
||||
|
||||
gulp.task('gen-icons-mdi', () => genMDIIcons());
|
||||
gulp.task('gen-icons-hass', () => genHassIcons());
|
||||
gulp.task('gen-icons', ['gen-icons-hass', 'gen-icons-mdi'], () => {});
|
||||
gulp.task("gen-icons-mdi", () => genMDIIcons());
|
||||
gulp.task("gen-icons-hass", () => genHassIcons());
|
||||
gulp.task("gen-icons", ["gen-icons-hass", "gen-icons-mdi"], () => {});
|
||||
|
||||
module.exports = {
|
||||
findIcons,
|
||||
|
@@ -1,37 +1,44 @@
|
||||
const path = require('path');
|
||||
const gulp = require('gulp');
|
||||
const foreach = require('gulp-foreach');
|
||||
const hash = require('gulp-hash');
|
||||
const insert = require('gulp-insert');
|
||||
const merge = require('gulp-merge-json');
|
||||
const minify = require('gulp-jsonminify');
|
||||
const rename = require('gulp-rename');
|
||||
const transform = require('gulp-json-transform');
|
||||
const path = require("path");
|
||||
const gulp = require("gulp");
|
||||
const foreach = require("gulp-foreach");
|
||||
const hash = require("gulp-hash");
|
||||
const insert = require("gulp-insert");
|
||||
const merge = require("gulp-merge-json");
|
||||
const minify = require("gulp-jsonminify");
|
||||
const rename = require("gulp-rename");
|
||||
const transform = require("gulp-json-transform");
|
||||
|
||||
const inDir = 'translations';
|
||||
const workDir = 'build-translations';
|
||||
const fullDir = workDir + '/full';
|
||||
const coreDir = workDir + '/core';
|
||||
const outDir = workDir + '/output';
|
||||
const inDir = "translations";
|
||||
const workDir = "build-translations";
|
||||
const fullDir = workDir + "/full";
|
||||
const coreDir = workDir + "/core";
|
||||
const outDir = workDir + "/output";
|
||||
|
||||
// Panel translations which should be split from the core translations. These
|
||||
// should mirror the fragment definitions in polymer.json, so that we load
|
||||
// additional resources at equivalent points.
|
||||
const TRANSLATION_FRAGMENTS = [
|
||||
'config',
|
||||
'history',
|
||||
'logbook',
|
||||
'mailbox',
|
||||
'shopping-list',
|
||||
"config",
|
||||
"history",
|
||||
"logbook",
|
||||
"mailbox",
|
||||
"profile",
|
||||
"shopping-list",
|
||||
"page-authorize",
|
||||
"page-onboarding",
|
||||
];
|
||||
|
||||
const tasks = [];
|
||||
|
||||
function recursiveFlatten(prefix, data) {
|
||||
let output = {};
|
||||
Object.keys(data).forEach(function (key) {
|
||||
if (typeof (data[key]) === 'object') {
|
||||
output = Object.assign({}, output, recursiveFlatten(prefix + key + '.', data[key]));
|
||||
Object.keys(data).forEach(function(key) {
|
||||
if (typeof data[key] === "object") {
|
||||
output = Object.assign(
|
||||
{},
|
||||
output,
|
||||
recursiveFlatten(prefix + key + ".", data[key])
|
||||
);
|
||||
} else {
|
||||
output[prefix + key] = data[key];
|
||||
}
|
||||
@@ -40,14 +47,14 @@ function recursiveFlatten(prefix, data) {
|
||||
}
|
||||
|
||||
function flatten(data) {
|
||||
return recursiveFlatten('', data);
|
||||
return recursiveFlatten("", data);
|
||||
}
|
||||
|
||||
function emptyFilter(data) {
|
||||
const newData = {};
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (data[key]) {
|
||||
if (typeof (data[key]) === 'object') {
|
||||
if (typeof data[key] === "object") {
|
||||
newData[key] = emptyFilter(data[key]);
|
||||
} else {
|
||||
newData[key] = data[key];
|
||||
@@ -67,16 +74,18 @@ function emptyFilter(data) {
|
||||
* @link https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing
|
||||
*/
|
||||
const re_key_reference = /\[%key:([^%]+)%\]/;
|
||||
function lokalise_transform (data, original) {
|
||||
function lokalise_transform(data, original) {
|
||||
const output = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
if (value instanceof Object) {
|
||||
output[key] = lokalise_transform(value, original);
|
||||
} else {
|
||||
output[key] = value.replace(re_key_reference, (match, key) => {
|
||||
const replace = key.split('::').reduce((tr, k) => tr[k], original);
|
||||
if (typeof replace !== 'string') {
|
||||
throw Error(`Invalid key placeholder ${key} in src/translations/en.json`);
|
||||
const replace = key.split("::").reduce((tr, k) => tr[k], original);
|
||||
if (typeof replace !== "string") {
|
||||
throw Error(
|
||||
`Invalid key placeholder ${key} in src/translations/en.json`
|
||||
);
|
||||
}
|
||||
return replace;
|
||||
});
|
||||
@@ -94,21 +103,24 @@ function lokalise_transform (data, original) {
|
||||
* project is buildable immediately after merging new translation keys, since
|
||||
* the Lokalise update to translations/en.json will not happen immediately.
|
||||
*/
|
||||
let taskName = 'build-master-translation';
|
||||
gulp.task(taskName, function () {
|
||||
return gulp.src('src/translations/en.json')
|
||||
.pipe(transform(function(data, file) {
|
||||
return lokalise_transform(data, data);
|
||||
}))
|
||||
.pipe(rename('translationMaster.json'))
|
||||
let taskName = "build-master-translation";
|
||||
gulp.task(taskName, function() {
|
||||
return gulp
|
||||
.src("src/translations/en.json")
|
||||
.pipe(
|
||||
transform(function(data, file) {
|
||||
return lokalise_transform(data, data);
|
||||
})
|
||||
)
|
||||
.pipe(rename("translationMaster.json"))
|
||||
.pipe(gulp.dest(workDir));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = 'build-merged-translations';
|
||||
gulp.task(taskName, ['build-master-translation'], function () {
|
||||
return gulp.src(inDir + '/*.json')
|
||||
.pipe(foreach(function(stream, file) {
|
||||
taskName = "build-merged-translations";
|
||||
gulp.task(taskName, ["build-master-translation"], function() {
|
||||
return gulp.src(inDir + "/*.json").pipe(
|
||||
foreach(function(stream, file) {
|
||||
// For each language generate a merged json file. It begins with the master
|
||||
// translation as a failsafe for untranslated strings, and merges all parent
|
||||
// tags into one file for each specific subtag
|
||||
@@ -116,139 +128,169 @@ gulp.task(taskName, ['build-master-translation'], function () {
|
||||
// TODO: This is a naive interpretation of BCP47 that should be improved.
|
||||
// Will be OK for now as long as we don't have anything more complicated
|
||||
// than a base translation + region.
|
||||
const tr = path.basename(file.history[0], '.json');
|
||||
const subtags = tr.split('-');
|
||||
const src = [workDir + '/translationMaster.json'];
|
||||
const tr = path.basename(file.history[0], ".json");
|
||||
const subtags = tr.split("-");
|
||||
const src = [workDir + "/translationMaster.json"];
|
||||
for (let i = 1; i <= subtags.length; i++) {
|
||||
const lang = subtags.slice(0, i).join('-');
|
||||
src.push(inDir + '/' + lang + '.json');
|
||||
const lang = subtags.slice(0, i).join("-");
|
||||
src.push(inDir + "/" + lang + ".json");
|
||||
}
|
||||
return gulp.src(src)
|
||||
.pipe(transform(data => emptyFilter(data)))
|
||||
.pipe(merge({
|
||||
fileName: tr + '.json',
|
||||
}))
|
||||
return gulp
|
||||
.src(src)
|
||||
.pipe(transform((data) => emptyFilter(data)))
|
||||
.pipe(
|
||||
merge({
|
||||
fileName: tr + ".json",
|
||||
})
|
||||
)
|
||||
.pipe(gulp.dest(fullDir));
|
||||
}));
|
||||
})
|
||||
);
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
const splitTasks = [];
|
||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||
taskName = 'build-translation-fragment-' + fragment;
|
||||
gulp.task(taskName, ['build-merged-translations'], function () {
|
||||
taskName = "build-translation-fragment-" + fragment;
|
||||
gulp.task(taskName, ["build-merged-translations"], function() {
|
||||
// Return only the translations for this fragment.
|
||||
return gulp.src(fullDir + '/*.json')
|
||||
.pipe(transform(data => ({
|
||||
ui: {
|
||||
panel: {
|
||||
[fragment]: data.ui.panel[fragment],
|
||||
return gulp
|
||||
.src(fullDir + "/*.json")
|
||||
.pipe(
|
||||
transform((data) => ({
|
||||
ui: {
|
||||
panel: {
|
||||
[fragment]: data.ui.panel[fragment],
|
||||
},
|
||||
},
|
||||
},
|
||||
})))
|
||||
.pipe(gulp.dest(workDir + '/' + fragment));
|
||||
}))
|
||||
)
|
||||
.pipe(gulp.dest(workDir + "/" + fragment));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
splitTasks.push(taskName);
|
||||
});
|
||||
|
||||
taskName = 'build-translation-core';
|
||||
gulp.task(taskName, ['build-merged-translations'], function () {
|
||||
taskName = "build-translation-core";
|
||||
gulp.task(taskName, ["build-merged-translations"], function() {
|
||||
// Remove the fragment translations from the core translation.
|
||||
return gulp.src(fullDir + '/*.json')
|
||||
.pipe(transform((data) => {
|
||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||
delete data.ui.panel[fragment];
|
||||
});
|
||||
return data;
|
||||
}))
|
||||
return gulp
|
||||
.src(fullDir + "/*.json")
|
||||
.pipe(
|
||||
transform((data) => {
|
||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||
delete data.ui.panel[fragment];
|
||||
});
|
||||
return data;
|
||||
})
|
||||
)
|
||||
.pipe(gulp.dest(coreDir));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
splitTasks.push(taskName);
|
||||
|
||||
taskName = 'build-flattened-translations';
|
||||
gulp.task(taskName, splitTasks, function () {
|
||||
taskName = "build-flattened-translations";
|
||||
gulp.task(taskName, splitTasks, function() {
|
||||
// Flatten the split versions of our translations, and move them into outDir
|
||||
return gulp.src(
|
||||
TRANSLATION_FRAGMENTS.map(fragment => workDir + '/' + fragment + '/*.json')
|
||||
.concat(coreDir + '/*.json'),
|
||||
{ base: workDir },
|
||||
)
|
||||
.pipe(transform(function (data) {
|
||||
// Polymer.AppLocalizeBehavior requires flattened json
|
||||
return flatten(data);
|
||||
}))
|
||||
return gulp
|
||||
.src(
|
||||
TRANSLATION_FRAGMENTS.map(
|
||||
(fragment) => workDir + "/" + fragment + "/*.json"
|
||||
).concat(coreDir + "/*.json"),
|
||||
{ base: workDir }
|
||||
)
|
||||
.pipe(
|
||||
transform(function(data) {
|
||||
// Polymer.AppLocalizeBehavior requires flattened json
|
||||
return flatten(data);
|
||||
})
|
||||
)
|
||||
.pipe(minify())
|
||||
.pipe(rename((filePath) => {
|
||||
if (filePath.dirname === 'core') {
|
||||
filePath.dirname = '';
|
||||
}
|
||||
}))
|
||||
.pipe(
|
||||
rename((filePath) => {
|
||||
if (filePath.dirname === "core") {
|
||||
filePath.dirname = "";
|
||||
}
|
||||
})
|
||||
)
|
||||
.pipe(gulp.dest(outDir));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = 'build-translation-fingerprints';
|
||||
gulp.task(taskName, ['build-flattened-translations'], function () {
|
||||
return gulp.src(outDir + '/**/*.json')
|
||||
.pipe(rename({
|
||||
extname: '',
|
||||
}))
|
||||
.pipe(hash({
|
||||
algorithm: 'md5',
|
||||
hashLength: 32,
|
||||
template: '<%= name %>-<%= hash %>.json',
|
||||
}))
|
||||
.pipe(hash.manifest('translationFingerprints.json'))
|
||||
.pipe(transform(function (data) {
|
||||
// After generating fingerprints of our translation files, consolidate
|
||||
// all translation fragment fingerprints under the translation name key
|
||||
const newData = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
const parts = key.split('/');
|
||||
let translation = key;
|
||||
if (parts.length === 2) {
|
||||
translation = parts[1];
|
||||
}
|
||||
if (!(translation in newData)) {
|
||||
newData[translation] = {
|
||||
fingerprints: {},
|
||||
};
|
||||
}
|
||||
newData[translation].fingerprints[key] = value;
|
||||
});
|
||||
return newData;
|
||||
}))
|
||||
taskName = "build-translation-fingerprints";
|
||||
gulp.task(taskName, ["build-flattened-translations"], function() {
|
||||
return gulp
|
||||
.src(outDir + "/**/*.json")
|
||||
.pipe(
|
||||
rename({
|
||||
extname: "",
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
hash({
|
||||
algorithm: "md5",
|
||||
hashLength: 32,
|
||||
template: "<%= name %>-<%= hash %>.json",
|
||||
})
|
||||
)
|
||||
.pipe(hash.manifest("translationFingerprints.json"))
|
||||
.pipe(
|
||||
transform(function(data) {
|
||||
// After generating fingerprints of our translation files, consolidate
|
||||
// all translation fragment fingerprints under the translation name key
|
||||
const newData = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
const parts = key.split("/");
|
||||
let translation = key;
|
||||
if (parts.length === 2) {
|
||||
translation = parts[1];
|
||||
}
|
||||
if (!(translation in newData)) {
|
||||
newData[translation] = {
|
||||
fingerprints: {},
|
||||
};
|
||||
}
|
||||
newData[translation].fingerprints[key] = value;
|
||||
});
|
||||
return newData;
|
||||
})
|
||||
)
|
||||
.pipe(gulp.dest(workDir));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = 'build-translations';
|
||||
gulp.task(taskName, ['build-translation-fingerprints'], function () {
|
||||
return gulp.src([
|
||||
'src/translations/translationMetadata.json',
|
||||
workDir + '/translationFingerprints.json',
|
||||
])
|
||||
taskName = "build-translations";
|
||||
gulp.task(taskName, ["build-translation-fingerprints"], function() {
|
||||
return gulp
|
||||
.src([
|
||||
"src/translations/translationMetadata.json",
|
||||
workDir + "/translationFingerprints.json",
|
||||
])
|
||||
.pipe(merge({}))
|
||||
.pipe(transform(function (data) {
|
||||
const newData = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
// Filter out translations without native name.
|
||||
if (data[key].nativeName) {
|
||||
newData[key] = data[key];
|
||||
} else {
|
||||
console.warn(`Skipping language ${key}. Native name was not translated.`);
|
||||
}
|
||||
if (data[key]) newData[key] = value;
|
||||
});
|
||||
return newData;
|
||||
}))
|
||||
.pipe(transform(data => ({
|
||||
fragments: TRANSLATION_FRAGMENTS,
|
||||
translations: data,
|
||||
})))
|
||||
.pipe(rename('translationMetadata.json'))
|
||||
.pipe(
|
||||
transform(function(data) {
|
||||
const newData = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
// Filter out translations without native name.
|
||||
if (data[key].nativeName) {
|
||||
newData[key] = data[key];
|
||||
} else {
|
||||
console.warn(
|
||||
`Skipping language ${key}. Native name was not translated.`
|
||||
);
|
||||
}
|
||||
if (data[key]) newData[key] = value;
|
||||
});
|
||||
return newData;
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
transform((data) => ({
|
||||
fragments: TRANSLATION_FRAGMENTS,
|
||||
translations: data,
|
||||
}))
|
||||
)
|
||||
.pipe(rename("translationMetadata.json"))
|
||||
.pipe(gulp.dest(workDir));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
1
hassio/.gitignore
vendored
Normal file
1
hassio/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
hassio-icons.html
|
@@ -1,8 +1,8 @@
|
||||
const path = require('path');
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
// Target directory for the build.
|
||||
buildDir: path.resolve(__dirname, 'build'),
|
||||
buildDir: path.resolve(__dirname, "build"),
|
||||
// Path where the Hass.io frontend will be publicly available.
|
||||
publicPath: '/api/hassio/app',
|
||||
}
|
||||
publicPath: "/api/hassio/app",
|
||||
};
|
||||
|
@@ -1,15 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
const fs = require('fs');
|
||||
const {
|
||||
findIcons,
|
||||
generateIconset,
|
||||
} = require('../../gulp/tasks/gen-icons.js');
|
||||
const fs = require("fs");
|
||||
const { findIcons, generateIconset } = require("../../gulp/tasks/gen-icons.js");
|
||||
|
||||
const MENU_BUTTON_ICON = 'menu';
|
||||
const MENU_BUTTON_ICON = "menu";
|
||||
|
||||
function genHassioIcons() {
|
||||
const iconNames = findIcons('./src', 'hassio').concat(MENU_BUTTON_ICON);
|
||||
fs.writeFileSync('./hassio-icons.html', generateIconset('hassio', iconNames));
|
||||
const iconNames = findIcons("./src", "hassio").concat(MENU_BUTTON_ICON);
|
||||
fs.writeFileSync("./hassio-icons.html", generateIconset("hassio", iconNames));
|
||||
}
|
||||
|
||||
genHassioIcons();
|
||||
|
@@ -1,10 +1,10 @@
|
||||
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 "@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 '../components/hassio-card-content.js';
|
||||
import '../resources/hassio-style.js';
|
||||
import NavigateMixin from '../../../src/mixins/navigate-mixin.js';
|
||||
import "../components/hassio-card-content.js";
|
||||
import "../resources/hassio-style.js";
|
||||
import NavigateMixin from "../../../src/mixins/navigate-mixin.js";
|
||||
|
||||
class HassioAddonRepository extends NavigateMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -48,21 +48,27 @@ class HassioAddonRepository extends NavigateMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
sortAddons(a, b) {
|
||||
return a.name < b.name ? -1 : 1;
|
||||
return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
|
||||
}
|
||||
|
||||
computeIcon(addon) {
|
||||
return addon.installed && addon.installed !== addon.version ? 'hassio:arrow-up-bold-circle' : 'hassio:puzzle';
|
||||
return addon.installed && addon.installed !== addon.version
|
||||
? "hassio:arrow-up-bold-circle"
|
||||
: "hassio:puzzle";
|
||||
}
|
||||
|
||||
computeIconTitle(addon) {
|
||||
if (addon.installed) return addon.installed !== addon.version ? 'New version available' : 'Add-on is installed';
|
||||
return 'Add-on is not installed';
|
||||
if (addon.installed)
|
||||
return addon.installed !== addon.version
|
||||
? "New version available"
|
||||
: "Add-on is installed";
|
||||
return "Add-on is not installed";
|
||||
}
|
||||
|
||||
computeIconClass(addon) {
|
||||
if (addon.installed) return addon.installed !== addon.version ? 'update' : 'installed';
|
||||
return '';
|
||||
if (addon.installed)
|
||||
return addon.installed !== addon.version ? "update" : "installed";
|
||||
return "";
|
||||
}
|
||||
|
||||
addonTapped(ev) {
|
||||
@@ -70,4 +76,4 @@ class HassioAddonRepository extends NavigateMixin(PolymerElement) {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-addon-repository', HassioAddonRepository);
|
||||
customElements.define("hassio-addon-repository", HassioAddonRepository);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import './hassio-addon-repository.js';
|
||||
import './hassio-repositories-editor.js';
|
||||
import "./hassio-addon-repository.js";
|
||||
import "./hassio-repositories-editor.js";
|
||||
|
||||
class HassioAddonStore extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -30,7 +30,7 @@ class HassioAddonStore extends PolymerElement {
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
|
||||
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
@@ -41,42 +41,45 @@ class HassioAddonStore extends PolymerElement {
|
||||
}
|
||||
|
||||
sortRepos(a, b) {
|
||||
if (a.slug === 'local') {
|
||||
if (a.slug === "local") {
|
||||
return -1;
|
||||
} else if (b.slug === 'local') {
|
||||
return 1;
|
||||
} else if (a.slug === 'core') {
|
||||
return -1;
|
||||
} else if (b.slug === 'core') {
|
||||
}
|
||||
if (b.slug === "local") {
|
||||
return 1;
|
||||
}
|
||||
return a.name < b.name ? -1 : 1;
|
||||
if (a.slug === "core") {
|
||||
return -1;
|
||||
}
|
||||
if (b.slug === "core") {
|
||||
return 1;
|
||||
}
|
||||
return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
|
||||
}
|
||||
|
||||
computeAddons(repo) {
|
||||
return this.addons.filter(function (addon) {
|
||||
return this.addons.filter(function(addon) {
|
||||
return addon.repository === repo;
|
||||
});
|
||||
}
|
||||
|
||||
loadData() {
|
||||
this.hass.callApi('get', 'hassio/addons')
|
||||
.then((info) => {
|
||||
this.hass.callApi("get", "hassio/addons").then(
|
||||
(info) => {
|
||||
this.addons = info.data.addons;
|
||||
this.repos = info.data.repositories;
|
||||
}, () => {
|
||||
},
|
||||
() => {
|
||||
this.addons = [];
|
||||
this.repos = [];
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
refreshData() {
|
||||
this.hass.callApi('post', 'hassio/addons/reload')
|
||||
.then(() => {
|
||||
this.loadData();
|
||||
});
|
||||
this.hass.callApi("post", "hassio/addons/reload").then(() => {
|
||||
this.loadData();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-addon-store', HassioAddonStore);
|
||||
customElements.define("hassio-addon-store", HassioAddonStore);
|
||||
|
@@ -1,12 +1,12 @@
|
||||
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 "@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 '../components/hassio-card-content.js';
|
||||
import '../resources/hassio-style.js';
|
||||
import "../../../src/components/buttons/ha-call-api-button.js";
|
||||
import "../components/hassio-card-content.js";
|
||||
import "../resources/hassio-style.js";
|
||||
|
||||
class HassioRepositoriesEditor extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -60,7 +60,7 @@ class HassioRepositoriesEditor extends PolymerElement {
|
||||
hass: Object,
|
||||
repos: {
|
||||
type: Array,
|
||||
observer: 'reposChanged',
|
||||
observer: "reposChanged",
|
||||
},
|
||||
repoList: Array,
|
||||
repoUrl: String,
|
||||
@@ -68,8 +68,10 @@ class HassioRepositoriesEditor extends PolymerElement {
|
||||
}
|
||||
|
||||
reposChanged(repos) {
|
||||
this.repoList = repos.filter(repo => repo.slug !== 'core' && repo.slug !== 'local');
|
||||
this.repoUrl = '';
|
||||
this.repoList = repos.filter(
|
||||
(repo) => repo.slug !== "core" && repo.slug !== "local"
|
||||
);
|
||||
this.repoUrl = "";
|
||||
}
|
||||
|
||||
sortRepos(a, b) {
|
||||
@@ -77,15 +79,17 @@ class HassioRepositoriesEditor extends PolymerElement {
|
||||
}
|
||||
|
||||
computeRemoveRepoData(repoList, url) {
|
||||
const list = repoList.filter(repo => repo.url !== url).map(repo => repo.url);
|
||||
const list = repoList
|
||||
.filter((repo) => repo.url !== url)
|
||||
.map((repo) => repo.url);
|
||||
return { addons_repositories: list };
|
||||
}
|
||||
|
||||
computeAddRepoData(repoList, url) {
|
||||
const list = repoList ? repoList.map(repo => repo.url) : [];
|
||||
const list = repoList ? repoList.map((repo) => repo.url) : [];
|
||||
list.push(url);
|
||||
return { addons_repositories: list };
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-repositories-editor', HassioRepositoriesEditor);
|
||||
customElements.define("hassio-repositories-editor", HassioRepositoriesEditor);
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import 'web-animations-js/web-animations-next-lite.min.js';
|
||||
import "web-animations-js/web-animations-next-lite.min.js";
|
||||
|
||||
import '@polymer/paper-button/paper-button.js';
|
||||
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';
|
||||
import "@polymer/paper-button/paper-button.js";
|
||||
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";
|
||||
|
||||
import '../../../src/resources/ha-style.js';
|
||||
import EventsMixin from '../../../src/mixins/events-mixin.js';
|
||||
import "../../../src/resources/ha-style.js";
|
||||
import EventsMixin from "../../../src/mixins/events-mixin.js";
|
||||
|
||||
class HassioAddonAudio extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -64,7 +64,7 @@ class HassioAddonAudio extends EventsMixin(PolymerElement) {
|
||||
hass: Object,
|
||||
addon: {
|
||||
type: Object,
|
||||
observer: 'addonChanged'
|
||||
observer: "addonChanged",
|
||||
},
|
||||
inputDevices: Array,
|
||||
outputDevices: Array,
|
||||
@@ -76,40 +76,55 @@ class HassioAddonAudio extends EventsMixin(PolymerElement) {
|
||||
|
||||
addonChanged(addon) {
|
||||
this.setProperties({
|
||||
selectedInput: addon.audio_input || 'null',
|
||||
selectedOutput: addon.audio_output || 'null'
|
||||
selectedInput: addon.audio_input || "null",
|
||||
selectedOutput: addon.audio_output || "null",
|
||||
});
|
||||
if (this.outputDevices) return;
|
||||
|
||||
const noDevice = [{ device: 'null', name: '-' }];
|
||||
this.hass.callApi('get', 'hassio/hardware/audio').then((resp) => {
|
||||
const dev = resp.data.audio;
|
||||
const input = Object.keys(dev.input).map(key => ({ device: key, name: dev.input[key] }));
|
||||
const output = Object.keys(dev.output).map(key => ({ device: key, name: dev.output[key] }));
|
||||
this.setProperties({
|
||||
inputDevices: noDevice.concat(input),
|
||||
outputDevices: noDevice.concat(output)
|
||||
});
|
||||
}, () => {
|
||||
this.setProperties({
|
||||
inputDevices: noDevice,
|
||||
outputDevices: noDevice
|
||||
});
|
||||
});
|
||||
const noDevice = [{ device: "null", name: "-" }];
|
||||
this.hass.callApi("get", "hassio/hardware/audio").then(
|
||||
(resp) => {
|
||||
const dev = resp.data.audio;
|
||||
const input = Object.keys(dev.input).map((key) => ({
|
||||
device: key,
|
||||
name: dev.input[key],
|
||||
}));
|
||||
const output = Object.keys(dev.output).map((key) => ({
|
||||
device: key,
|
||||
name: dev.output[key],
|
||||
}));
|
||||
this.setProperties({
|
||||
inputDevices: noDevice.concat(input),
|
||||
outputDevices: noDevice.concat(output),
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.setProperties({
|
||||
inputDevices: noDevice,
|
||||
outputDevices: noDevice,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_saveSettings() {
|
||||
this.error = null;
|
||||
const path = `hassio/addons/${this.addon.slug}/options`;
|
||||
this.hass.callApi('post', path, {
|
||||
audio_input: this.selectedInput === 'null' ? null : this.selectedInput,
|
||||
audio_output: this.selectedOutput === 'null' ? null : this.selectedOutput
|
||||
}).then(() => {
|
||||
this.fire('hass-api-called', { success: true, path: path });
|
||||
}, (resp) => {
|
||||
this.error = resp.body.message;
|
||||
});
|
||||
this.hass
|
||||
.callApi("post", path, {
|
||||
audio_input: this.selectedInput === "null" ? null : this.selectedInput,
|
||||
audio_output:
|
||||
this.selectedOutput === "null" ? null : this.selectedOutput,
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
this.fire("hass-api-called", { success: true, path: path });
|
||||
},
|
||||
(resp) => {
|
||||
this.error = resp.body.message;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-addon-audio', HassioAddonAudio);
|
||||
customElements.define("hassio-addon-audio", HassioAddonAudio);
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js';
|
||||
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 "@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js";
|
||||
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/buttons/ha-call-api-button.js";
|
||||
|
||||
class HassioAddonConfig extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -52,12 +52,12 @@ class HassioAddonConfig extends PolymerElement {
|
||||
hass: Object,
|
||||
addon: {
|
||||
type: Object,
|
||||
observer: 'addonChanged',
|
||||
observer: "addonChanged",
|
||||
},
|
||||
addonSlug: String,
|
||||
config: {
|
||||
type: String,
|
||||
observer: 'configChanged',
|
||||
observer: "configChanged",
|
||||
},
|
||||
configParsed: Object,
|
||||
error: String,
|
||||
@@ -71,15 +71,15 @@ class HassioAddonConfig extends PolymerElement {
|
||||
}
|
||||
|
||||
addonChanged(addon) {
|
||||
this.config = addon ? JSON.stringify(addon.options, null, 2) : '';
|
||||
this.config = addon ? JSON.stringify(addon.options, null, 2) : "";
|
||||
}
|
||||
|
||||
configChanged(config) {
|
||||
try {
|
||||
this.$.config.classList.remove('syntaxerror');
|
||||
this.$.config.classList.remove("syntaxerror");
|
||||
this.configParsed = JSON.parse(config);
|
||||
} catch (err) {
|
||||
this.$.config.classList.add('syntaxerror');
|
||||
this.$.config.classList.add("syntaxerror");
|
||||
this.configParsed = null;
|
||||
}
|
||||
}
|
||||
@@ -87,12 +87,14 @@ class HassioAddonConfig extends PolymerElement {
|
||||
saveTapped() {
|
||||
this.error = null;
|
||||
|
||||
this.hass.callApi('post', `hassio/addons/${this.addonSlug}/options`, {
|
||||
options: this.configParsed
|
||||
}).catch((resp) => {
|
||||
this.error = resp.body.message;
|
||||
});
|
||||
this.hass
|
||||
.callApi("post", `hassio/addons/${this.addonSlug}/options`, {
|
||||
options: this.configParsed,
|
||||
})
|
||||
.catch((resp) => {
|
||||
this.error = resp.body.message;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-addon-config', HassioAddonConfig);
|
||||
customElements.define("hassio-addon-config", HassioAddonConfig);
|
||||
|
@@ -1,16 +1,16 @@
|
||||
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 "@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/resources/ha-style.js';
|
||||
import EventsMixin from '../../../src/mixins/events-mixin.js';
|
||||
import "../../../src/components/buttons/ha-call-api-button.js";
|
||||
import "../../../src/components/ha-markdown.js";
|
||||
import "../../../src/resources/ha-style.js";
|
||||
import EventsMixin from "../../../src/mixins/events-mixin.js";
|
||||
|
||||
import '../components/hassio-card-content.js';
|
||||
import "../components/hassio-card-content.js";
|
||||
|
||||
class HassioAddonInfo extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -157,21 +157,26 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
|
||||
addonSlug: String,
|
||||
isRunning: {
|
||||
type: Boolean,
|
||||
computed: 'computeIsRunning(addon)',
|
||||
computed: "computeIsRunning(addon)",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
computeIsRunning(addon) {
|
||||
return addon && addon.state === 'started';
|
||||
return addon && addon.state === "started";
|
||||
}
|
||||
|
||||
computeUpdateAvailable(addon) {
|
||||
return addon && !addon.detached && addon.version && addon.version !== addon.last_version;
|
||||
return (
|
||||
addon &&
|
||||
!addon.detached &&
|
||||
addon.version &&
|
||||
addon.version !== addon.last_version
|
||||
);
|
||||
}
|
||||
|
||||
pathWebui(webui) {
|
||||
return webui && webui.replace('[HOST]', document.location.hostname);
|
||||
return webui && webui.replace("[HOST]", document.location.hostname);
|
||||
}
|
||||
|
||||
computeShowWebUI(webui, isRunning) {
|
||||
@@ -179,49 +184,54 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
computeStartOnBoot(state) {
|
||||
return state === 'auto';
|
||||
return state === "auto";
|
||||
}
|
||||
|
||||
startOnBootToggled() {
|
||||
const data = { boot: this.addon.boot === 'auto' ? 'manual' : 'auto' };
|
||||
this.hass.callApi('POST', `hassio/addons/${this.addonSlug}/options`, data);
|
||||
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);
|
||||
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',
|
||||
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?')) {
|
||||
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);
|
||||
});
|
||||
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('hassio-addon-info', HassioAddonInfo);
|
||||
customElements.define("hassio-addon-info", HassioAddonInfo);
|
||||
|
@@ -1,9 +1,9 @@
|
||||
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 "@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/resources/ha-style.js';
|
||||
import "../../../src/resources/ha-style.js";
|
||||
|
||||
class HassioAddonLogs extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -33,7 +33,7 @@ class HassioAddonLogs extends PolymerElement {
|
||||
hass: Object,
|
||||
addonSlug: {
|
||||
type: String,
|
||||
observer: 'addonSlugChanged',
|
||||
observer: "addonSlugChanged",
|
||||
},
|
||||
log: String,
|
||||
};
|
||||
@@ -41,7 +41,9 @@ class HassioAddonLogs extends PolymerElement {
|
||||
|
||||
addonSlugChanged(slug) {
|
||||
if (!this.hass) {
|
||||
setTimeout(() => { this.addonChanged(slug); }, 0);
|
||||
setTimeout(() => {
|
||||
this.addonChanged(slug);
|
||||
}, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,11 +51,12 @@ class HassioAddonLogs extends PolymerElement {
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.hass.callApi('get', `hassio/addons/${this.addonSlug}/logs`)
|
||||
this.hass
|
||||
.callApi("get", `hassio/addons/${this.addonSlug}/logs`)
|
||||
.then((info) => {
|
||||
this.log = info;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-addon-logs', HassioAddonLogs);
|
||||
customElements.define("hassio-addon-logs", HassioAddonLogs);
|
||||
|
@@ -1,11 +1,11 @@
|
||||
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 "@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/resources/ha-style.js';
|
||||
import EventsMixin from '../../../src/mixins/events-mixin.js';
|
||||
import "../../../src/components/buttons/ha-call-api-button.js";
|
||||
import "../../../src/resources/ha-style.js";
|
||||
import EventsMixin from "../../../src/mixins/events-mixin.js";
|
||||
|
||||
class HassioAddonNetwork extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -64,7 +64,7 @@ class HassioAddonNetwork extends EventsMixin(PolymerElement) {
|
||||
config: Object,
|
||||
addon: {
|
||||
type: Object,
|
||||
observer: 'addonChanged',
|
||||
observer: "addonChanged",
|
||||
},
|
||||
error: String,
|
||||
resetData: {
|
||||
@@ -80,29 +80,36 @@ class HassioAddonNetwork extends EventsMixin(PolymerElement) {
|
||||
if (!addon) return;
|
||||
|
||||
const network = addon.network || {};
|
||||
const items = Object.keys(network).map(key => ({
|
||||
const items = Object.keys(network).map((key) => ({
|
||||
container: key,
|
||||
host: network[key]
|
||||
host: network[key],
|
||||
}));
|
||||
this.config = items.sort(function (el1, el2) { return el1.host - el2.host; });
|
||||
this.config = items.sort(function(el1, el2) {
|
||||
return el1.host - el2.host;
|
||||
});
|
||||
}
|
||||
|
||||
saveTapped() {
|
||||
this.error = null;
|
||||
const data = {};
|
||||
this.config.forEach(function (item) {
|
||||
this.config.forEach(function(item) {
|
||||
data[item.container] = parseInt(item.host);
|
||||
});
|
||||
const path = `hassio/addons/${this.addonSlug}/options`;
|
||||
|
||||
this.hass.callApi('post', path, {
|
||||
network: data
|
||||
}).then(() => {
|
||||
this.fire('hass-api-called', { success: true, path: path });
|
||||
}, (resp) => {
|
||||
this.error = resp.body.message;
|
||||
});
|
||||
this.hass
|
||||
.callApi("post", path, {
|
||||
network: data,
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
this.fire("hass-api-called", { success: true, path: path });
|
||||
},
|
||||
(resp) => {
|
||||
this.error = resp.body.message;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-addon-network', HassioAddonNetwork);
|
||||
customElements.define("hassio-addon-network", HassioAddonNetwork);
|
||||
|
@@ -1,19 +1,19 @@
|
||||
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 "@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';
|
||||
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() {
|
||||
@@ -91,7 +91,7 @@ class HassioAddonView extends PolymerElement {
|
||||
route: Object,
|
||||
routeData: {
|
||||
type: Object,
|
||||
observer: 'routeDataChanged',
|
||||
observer: "routeDataChanged",
|
||||
},
|
||||
routeMatches: Boolean,
|
||||
addon: Object,
|
||||
@@ -99,15 +99,17 @@ class HassioAddonView extends PolymerElement {
|
||||
markdownTitle: String,
|
||||
markdownContent: {
|
||||
type: String,
|
||||
value: '',
|
||||
value: "",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
|
||||
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev));
|
||||
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
||||
this.addEventListener("hassio-markdown-dialog", (ev) =>
|
||||
this.openMarkdown(ev)
|
||||
);
|
||||
}
|
||||
|
||||
apiCalled(ev) {
|
||||
@@ -115,7 +117,7 @@ class HassioAddonView extends PolymerElement {
|
||||
|
||||
if (!path) return;
|
||||
|
||||
if (path.substr(path.lastIndexOf('/') + 1) === 'uninstall') {
|
||||
if (path.substr(path.lastIndexOf("/") + 1) === "uninstall") {
|
||||
this.backTapped();
|
||||
} else {
|
||||
this.routeDataChanged(this.routeData);
|
||||
@@ -124,12 +126,14 @@ class HassioAddonView extends PolymerElement {
|
||||
|
||||
routeDataChanged(routeData) {
|
||||
if (!this.routeMatches || !routeData || !routeData.slug) return;
|
||||
this.hass.callApi('get', `hassio/addons/${routeData.slug}/info`)
|
||||
.then((info) => {
|
||||
this.hass.callApi("get", `hassio/addons/${routeData.slug}/info`).then(
|
||||
(info) => {
|
||||
this.addon = info.data;
|
||||
}, () => {
|
||||
},
|
||||
() => {
|
||||
this.addon = null;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
backTapped() {
|
||||
@@ -141,8 +145,8 @@ class HassioAddonView extends PolymerElement {
|
||||
markdownTitle: ev.detail.title,
|
||||
markdownContent: ev.detail.content,
|
||||
});
|
||||
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog();
|
||||
this.shadowRoot.querySelector("hassio-markdown-dialog").openDialog();
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-addon-view', HassioAddonView);
|
||||
customElements.define("hassio-addon-view", HassioAddonView);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import '@polymer/iron-icon/iron-icon.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import "@polymer/iron-icon/iron-icon.js";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../../../src/components/ha-relative-time.js';
|
||||
import "../../../src/components/ha-relative-time.js";
|
||||
|
||||
class HassioCardContent extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -65,11 +65,11 @@ class HassioCardContent extends PolymerElement {
|
||||
datetime: String,
|
||||
icon: {
|
||||
type: String,
|
||||
value: 'hass:help-circle'
|
||||
value: "hass:help-circle",
|
||||
},
|
||||
iconTitle: String,
|
||||
iconClass: String,
|
||||
};
|
||||
}
|
||||
}
|
||||
customElements.define('hassio-card-content', HassioCardContent);
|
||||
customElements.define("hassio-card-content", HassioCardContent);
|
||||
|
@@ -1,10 +1,10 @@
|
||||
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 "@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 '../components/hassio-card-content.js';
|
||||
import '../resources/hassio-style.js';
|
||||
import NavigateMixin from '../../../src/mixins/navigate-mixin.js';
|
||||
import "../components/hassio-card-content.js";
|
||||
import "../resources/hassio-style.js";
|
||||
import NavigateMixin from "../../../src/mixins/navigate-mixin.js";
|
||||
|
||||
class HassioAddons extends NavigateMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -46,28 +46,32 @@ class HassioAddons extends NavigateMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
computeIcon(addon) {
|
||||
return addon.installed !== addon.version ? 'hassio:arrow-up-bold-circle' : 'hassio:puzzle';
|
||||
return addon.installed !== addon.version
|
||||
? "hassio:arrow-up-bold-circle"
|
||||
: "hassio:puzzle";
|
||||
}
|
||||
|
||||
computeIconTitle(addon) {
|
||||
if (addon.installed !== addon.version) return 'New version available';
|
||||
return addon.state === 'started' ? 'Add-on is running' : 'Add-on is stopped';
|
||||
if (addon.installed !== addon.version) return "New version available";
|
||||
return addon.state === "started"
|
||||
? "Add-on is running"
|
||||
: "Add-on is stopped";
|
||||
}
|
||||
|
||||
computeIconClass(addon) {
|
||||
if (addon.installed !== addon.version) return 'update';
|
||||
return addon.state === 'started' ? 'running' : '';
|
||||
if (addon.installed !== addon.version) return "update";
|
||||
return addon.state === "started" ? "running" : "";
|
||||
}
|
||||
|
||||
addonTapped(ev) {
|
||||
this.navigate('/hassio/addon/' + ev.model.addon.slug);
|
||||
this.navigate("/hassio/addon/" + ev.model.addon.slug);
|
||||
ev.target.blur();
|
||||
}
|
||||
|
||||
openStore(ev) {
|
||||
this.navigate('/hassio/store');
|
||||
this.navigate("/hassio/store");
|
||||
ev.target.blur();
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-addons', HassioAddons);
|
||||
customElements.define("hassio-addons", HassioAddons);
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
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';
|
||||
import EventsMixin from '../../../src/mixins/events-mixin.js';
|
||||
import "./hassio-addons.js";
|
||||
import "./hassio-hass-update.js";
|
||||
import EventsMixin from "../../../src/mixins/events-mixin.js";
|
||||
|
||||
class HassioDashboard extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -29,4 +29,4 @@ class HassioDashboard extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-dashboard', HassioDashboard);
|
||||
customElements.define("hassio-dashboard", HassioDashboard);
|
||||
|
@@ -1,11 +1,11 @@
|
||||
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 "@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 '../components/hassio-card-content.js';
|
||||
import '../resources/hassio-style.js';
|
||||
import "../../../src/components/buttons/ha-call-api-button.js";
|
||||
import "../components/hassio-card-content.js";
|
||||
import "../resources/hassio-style.js";
|
||||
|
||||
class HassioHassUpdate extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -19,6 +19,9 @@ class HassioHassUpdate extends PolymerElement {
|
||||
color: var(--google-red-500);
|
||||
margin-top: 16px;
|
||||
}
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
<template is="dom-if" if="[[computeUpdateAvailable(hassInfo)]]">
|
||||
<div class="content">
|
||||
@@ -30,6 +33,7 @@ class HassioHassUpdate extends PolymerElement {
|
||||
<template is="dom-if" if="[[error]]">
|
||||
<div class="error">Error: [[error]]</div>
|
||||
</template>
|
||||
<p><a href='https://www.home-assistant.io/latest-release-notes/' target='_blank'>Read the release notes</a></p>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<ha-call-api-button hass="[[hass]]" path="hassio/homeassistant/update">Update</ha-call-api-button>
|
||||
@@ -52,7 +56,7 @@ class HassioHassUpdate extends PolymerElement {
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
|
||||
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
||||
}
|
||||
|
||||
apiCalled(ev) {
|
||||
@@ -63,8 +67,8 @@ class HassioHassUpdate extends PolymerElement {
|
||||
|
||||
const response = ev.detail.response;
|
||||
|
||||
if (typeof response.body === 'object') {
|
||||
this.errors = response.body.message || 'Unknown error';
|
||||
if (typeof response.body === "object") {
|
||||
this.errors = response.body.message || "Unknown error";
|
||||
} else {
|
||||
this.errors = response.body;
|
||||
}
|
||||
@@ -75,4 +79,4 @@ class HassioHassUpdate extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-hass-update', HassioHassUpdate);
|
||||
customElements.define("hassio-hass-update", HassioHassUpdate);
|
||||
|
@@ -1,5 +1,4 @@
|
||||
window.loadES5Adapter().then(() => {
|
||||
import(/* webpackChunkName: "hassio-icons" */ './resources/hassio-icons.js');
|
||||
import(/* webpackChunkName: "hassio-main" */ './hassio-main.js');
|
||||
import(/* webpackChunkName: "hassio-icons" */ "./resources/hassio-icons.js");
|
||||
import(/* webpackChunkName: "hassio-main" */ "./hassio-main.js");
|
||||
});
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import './hassio-main.js';
|
||||
import './resources/hassio-icons.js';
|
||||
import "./hassio-main.js";
|
||||
import "./resources/hassio-icons.js";
|
||||
|
||||
class HassioApp extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -29,13 +29,13 @@ class HassioApp extends PolymerElement {
|
||||
ready() {
|
||||
super.ready();
|
||||
window.setProperties = this.setProperties.bind(this);
|
||||
this.addEventListener('location-changed', () => this._locationChanged());
|
||||
this.addEventListener('hass-open-menu', () => this._menuEvent(true));
|
||||
this.addEventListener('hass-close-menu', () => this._menuEvent(false));
|
||||
this.addEventListener("location-changed", () => this._locationChanged());
|
||||
this.addEventListener("hass-open-menu", () => this._menuEvent(true));
|
||||
this.addEventListener("hass-close-menu", () => this._menuEvent(false));
|
||||
}
|
||||
|
||||
_menuEvent(shouldOpen) {
|
||||
this.hassioPanel.fire(shouldOpen ? 'hass-open-menu' : 'hass-close-menu');
|
||||
this.hassioPanel.fire(shouldOpen ? "hass-open-menu" : "hass-close-menu");
|
||||
}
|
||||
|
||||
_locationChanged() {
|
||||
@@ -43,4 +43,4 @@ class HassioApp extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-app', HassioApp);
|
||||
customElements.define("hassio-app", HassioApp);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
class HassioData extends PolymerElement {
|
||||
static get properties() {
|
||||
@@ -36,25 +36,24 @@ class HassioData extends PolymerElement {
|
||||
}
|
||||
|
||||
fetchSupervisorInfo() {
|
||||
return this.hass.callApi('get', 'hassio/supervisor/info')
|
||||
.then((info) => {
|
||||
this.supervisor = info.data;
|
||||
});
|
||||
return this.hass.callApi("get", "hassio/supervisor/info").then((info) => {
|
||||
this.supervisor = info.data;
|
||||
});
|
||||
}
|
||||
|
||||
fetchHostInfo() {
|
||||
return this.hass.callApi('get', 'hassio/host/info')
|
||||
.then((info) => {
|
||||
this.host = info.data;
|
||||
});
|
||||
return this.hass.callApi("get", "hassio/host/info").then((info) => {
|
||||
this.host = info.data;
|
||||
});
|
||||
}
|
||||
|
||||
fetchHassInfo() {
|
||||
return this.hass.callApi('get', 'hassio/homeassistant/info')
|
||||
return this.hass
|
||||
.callApi("get", "hassio/homeassistant/info")
|
||||
.then((info) => {
|
||||
this.homeassistant = info.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-data', HassioData);
|
||||
customElements.define("hassio-data", HassioData);
|
||||
|
@@ -1,16 +1,17 @@
|
||||
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 "@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 './addon-view/hassio-addon-view.js';
|
||||
import './hassio-data.js';
|
||||
import './hassio-pages-with-tabs.js';
|
||||
import "../../src/layouts/hass-loading-screen.js";
|
||||
import "./addon-view/hassio-addon-view.js";
|
||||
import "./hassio-data.js";
|
||||
import "./hassio-pages-with-tabs.js";
|
||||
|
||||
import applyThemesOnElement from '../../src/common/dom/apply_themes_on_element.js';
|
||||
import NavigateMixin from '../../src/mixins/navigate-mixin.js';
|
||||
import applyThemesOnElement from "../../src/common/dom/apply_themes_on_element.js";
|
||||
import EventsMixin from "../../src/mixins/events-mixin.js";
|
||||
import NavigateMixin from "../../src/mixins/navigate-mixin.js";
|
||||
|
||||
class HassioMain extends NavigateMixin(PolymerElement) {
|
||||
class HassioMain extends EventsMixin(NavigateMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
return html`
|
||||
<app-route route="[[route]]" pattern="/:page" data="{{routeData}}"></app-route>
|
||||
@@ -40,11 +41,11 @@ class HassioMain extends NavigateMixin(PolymerElement) {
|
||||
type: Object,
|
||||
// Fake route object
|
||||
value: {
|
||||
prefix: '/hassio',
|
||||
path: '/dashboard',
|
||||
__queryParams: {}
|
||||
prefix: "/hassio",
|
||||
path: "/dashboard",
|
||||
__queryParams: {},
|
||||
},
|
||||
observer: 'routeChanged',
|
||||
observer: "routeChanged",
|
||||
},
|
||||
routeData: Object,
|
||||
supervisorInfo: Object,
|
||||
@@ -52,7 +53,7 @@ class HassioMain extends NavigateMixin(PolymerElement) {
|
||||
hassInfo: Object,
|
||||
loaded: {
|
||||
type: Boolean,
|
||||
computed: 'computeIsLoaded(supervisorInfo, hostInfo, hassInfo)',
|
||||
computed: "computeIsLoaded(supervisorInfo, hostInfo, hassInfo)",
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -60,7 +61,7 @@ class HassioMain extends NavigateMixin(PolymerElement) {
|
||||
ready() {
|
||||
super.ready();
|
||||
applyThemesOnElement(this, this.hass.themes, this.hass.selectedTheme, true);
|
||||
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
|
||||
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -73,7 +74,7 @@ class HassioMain extends NavigateMixin(PolymerElement) {
|
||||
let tries = 1;
|
||||
|
||||
const tryUpdate = () => {
|
||||
this.$.data.refresh().catch(function () {
|
||||
this.$.data.refresh().catch(function() {
|
||||
tries += 1;
|
||||
setTimeout(tryUpdate, Math.min(tries, 5) * 1000);
|
||||
});
|
||||
@@ -84,20 +85,19 @@ class HassioMain extends NavigateMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
computeIsLoaded(supervisorInfo, hostInfo, hassInfo) {
|
||||
return (supervisorInfo !== null &&
|
||||
hostInfo !== null &&
|
||||
hassInfo !== null);
|
||||
return supervisorInfo !== null && hostInfo !== null && hassInfo !== null;
|
||||
}
|
||||
|
||||
routeChanged(route) {
|
||||
if (route.path === '' && route.prefix === '/hassio') {
|
||||
this.navigate('/hassio/dashboard', true);
|
||||
if (route.path === "" && route.prefix === "/hassio") {
|
||||
this.navigate("/hassio/dashboard", true);
|
||||
}
|
||||
this.fire("iron-resize");
|
||||
}
|
||||
|
||||
equalsAddon(page) {
|
||||
return page && page === 'addon';
|
||||
return page && page === "addon";
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-main', HassioMain);
|
||||
customElements.define("hassio-main", HassioMain);
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
|
||||
import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
|
||||
import '@polymer/paper-dialog/paper-dialog.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 "@polymer/app-layout/app-toolbar/app-toolbar.js";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js";
|
||||
import "@polymer/paper-dialog/paper-dialog.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-markdown.js';
|
||||
import '../../src/resources/ha-style.js';
|
||||
import "../../src/components/ha-markdown.js";
|
||||
import "../../src/resources/ha-style.js";
|
||||
|
||||
class HassioMarkdownDialog extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -73,4 +73,4 @@ class HassioMarkdownDialog extends PolymerElement {
|
||||
this.$.dialog.open();
|
||||
}
|
||||
}
|
||||
customElements.define('hassio-markdown-dialog', HassioMarkdownDialog);
|
||||
customElements.define("hassio-markdown-dialog", HassioMarkdownDialog);
|
||||
|
@@ -1,24 +1,24 @@
|
||||
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 "@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 './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';
|
||||
import "../../src/components/ha-menu-button.js";
|
||||
import "../../src/resources/ha-style.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";
|
||||
|
||||
import scrollToTarget from '../../src/common/dom/scroll-to-target.js';
|
||||
import scrollToTarget from "../../src/common/dom/scroll-to-target.js";
|
||||
|
||||
import NavigateMixin from '../../src/mixins/navigate-mixin.js';
|
||||
import NavigateMixin from "../../src/mixins/navigate-mixin.js";
|
||||
|
||||
class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -87,18 +87,20 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
|
||||
markdownTitle: String,
|
||||
markdownContent: {
|
||||
type: String,
|
||||
value: '',
|
||||
value: "",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener('hassio-markdown-dialog', ev => this.openMarkdown(ev));
|
||||
this.addEventListener("hassio-markdown-dialog", (ev) =>
|
||||
this.openMarkdown(ev)
|
||||
);
|
||||
}
|
||||
|
||||
handlePageSelected(ev) {
|
||||
const newPage = ev.detail.item.getAttribute('page-name');
|
||||
const newPage = ev.detail.item.getAttribute("page-name");
|
||||
if (newPage !== this.page) {
|
||||
this.navigate(`/hassio/${newPage}`);
|
||||
}
|
||||
@@ -110,14 +112,14 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
showRefreshButton(page) {
|
||||
return page === 'store' || page === 'snapshots';
|
||||
return page === "store" || page === "snapshots";
|
||||
}
|
||||
|
||||
refreshClicked() {
|
||||
if (this.page === 'snapshots') {
|
||||
this.shadowRoot.querySelector('hassio-snapshots').refreshData();
|
||||
if (this.page === "snapshots") {
|
||||
this.shadowRoot.querySelector("hassio-snapshots").refreshData();
|
||||
} else {
|
||||
this.shadowRoot.querySelector('hassio-addon-store').refreshData();
|
||||
this.shadowRoot.querySelector("hassio-addon-store").refreshData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +128,8 @@ class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
|
||||
markdownTitle: ev.detail.title,
|
||||
markdownContent: ev.detail.content,
|
||||
});
|
||||
this.shadowRoot.querySelector('hassio-markdown-dialog').openDialog();
|
||||
this.shadowRoot.querySelector("hassio-markdown-dialog").openDialog();
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-pages-with-tabs', HassioPagesWithTabs);
|
||||
customElements.define("hassio-pages-with-tabs", HassioPagesWithTabs);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import '../../../src/components/ha-iconset-svg.js';
|
||||
import iconSetContent from '../../hassio-icons.html';
|
||||
import "../../../src/components/ha-iconset-svg.js";
|
||||
import iconSetContent from "../../hassio-icons.html";
|
||||
|
||||
const documentContainer = document.createElement('template');
|
||||
documentContainer.setAttribute('style', 'display: none;');
|
||||
const documentContainer = document.createElement("template");
|
||||
documentContainer.setAttribute("style", "display: none;");
|
||||
documentContainer.innerHTML = iconSetContent;
|
||||
document.head.appendChild(documentContainer.content);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
const documentContainer = document.createElement('template');
|
||||
documentContainer.setAttribute('style', 'display: none;');
|
||||
const documentContainer = document.createElement("template");
|
||||
documentContainer.setAttribute("style", "display: none;");
|
||||
|
||||
documentContainer.innerHTML = `<dom-module id="hassio-style">
|
||||
<template>
|
||||
|
@@ -1,14 +1,14 @@
|
||||
import '@polymer/app-layout/app-toolbar/app-toolbar.js';
|
||||
import '@polymer/paper-button/paper-button.js';
|
||||
import '@polymer/paper-checkbox/paper-checkbox.js';
|
||||
import '@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js';
|
||||
import '@polymer/paper-dialog/paper-dialog.js';
|
||||
import '@polymer/paper-icon-button/paper-icon-button.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 "@polymer/app-layout/app-toolbar/app-toolbar.js";
|
||||
import "@polymer/paper-button/paper-button.js";
|
||||
import "@polymer/paper-checkbox/paper-checkbox.js";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable.js";
|
||||
import "@polymer/paper-dialog/paper-dialog.js";
|
||||
import "@polymer/paper-icon-button/paper-icon-button.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/resources/ha-style.js';
|
||||
import "../../../src/resources/ha-style.js";
|
||||
|
||||
class HassioSnapshot extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -114,7 +114,7 @@ class HassioSnapshot extends PolymerElement {
|
||||
snapshotSlug: {
|
||||
type: String,
|
||||
notify: true,
|
||||
observer: '_snapshotSlugChanged',
|
||||
observer: "_snapshotSlugChanged",
|
||||
},
|
||||
snapshotDeleted: {
|
||||
type: Boolean,
|
||||
@@ -131,84 +131,124 @@ class HassioSnapshot extends PolymerElement {
|
||||
}
|
||||
|
||||
_snapshotSlugChanged(snapshotSlug) {
|
||||
if (!snapshotSlug || snapshotSlug === 'update') return;
|
||||
this.hass.callApi('get', `hassio/snapshots/${snapshotSlug}/info`)
|
||||
.then((info) => {
|
||||
if (!snapshotSlug || snapshotSlug === "update") return;
|
||||
this.hass.callApi("get", `hassio/snapshots/${snapshotSlug}/info`).then(
|
||||
(info) => {
|
||||
info.data.folders = this._computeFolders(info.data.folders);
|
||||
info.data.addons = this._computeAddons(info.data.addons);
|
||||
this.snapshot = info.data;
|
||||
this.$.dialog.open();
|
||||
}, () => {
|
||||
},
|
||||
() => {
|
||||
this.snapshot = null;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_computeFolders(folders) {
|
||||
const list = [];
|
||||
if (folders.includes('homeassistant')) list.push({ slug: 'homeassistant', name: 'Home Assistant configuration', checked: true });
|
||||
if (folders.includes('ssl')) list.push({ slug: 'ssl', name: 'SSL', checked: true });
|
||||
if (folders.includes('share')) list.push({ slug: 'share', name: 'Share', checked: true });
|
||||
if (folders.includes('addons/local')) list.push({ slug: 'addons/local', name: 'Local add-ons', checked: true });
|
||||
if (folders.includes("homeassistant"))
|
||||
list.push({
|
||||
slug: "homeassistant",
|
||||
name: "Home Assistant configuration",
|
||||
checked: true,
|
||||
});
|
||||
if (folders.includes("ssl"))
|
||||
list.push({ slug: "ssl", name: "SSL", checked: true });
|
||||
if (folders.includes("share"))
|
||||
list.push({ slug: "share", name: "Share", checked: true });
|
||||
if (folders.includes("addons/local"))
|
||||
list.push({ slug: "addons/local", name: "Local add-ons", checked: true });
|
||||
return list;
|
||||
}
|
||||
|
||||
_computeAddons(addons) {
|
||||
return addons.map(addon => (
|
||||
{ slug: addon.slug, name: addon.name, version: addon.version, checked: true }));
|
||||
return addons.map((addon) => ({
|
||||
slug: addon.slug,
|
||||
name: addon.name,
|
||||
version: addon.version,
|
||||
checked: true,
|
||||
}));
|
||||
}
|
||||
|
||||
_isFullSnapshot(type) {
|
||||
return type === 'full';
|
||||
return type === "full";
|
||||
}
|
||||
|
||||
_partialRestoreClicked() {
|
||||
if (!confirm('Are you sure you want to restore this snapshot?')) {
|
||||
if (!confirm("Are you sure you want to restore this snapshot?")) {
|
||||
return;
|
||||
}
|
||||
const addons = this.snapshot.addons.filter(addon => addon.checked).map(addon => addon.slug);
|
||||
const folders =
|
||||
this.snapshot.folders.filter(folder => folder.checked).map(folder => folder.slug);
|
||||
const addons = this.snapshot.addons
|
||||
.filter((addon) => addon.checked)
|
||||
.map((addon) => addon.slug);
|
||||
const folders = this.snapshot.folders
|
||||
.filter((folder) => folder.checked)
|
||||
.map((folder) => folder.slug);
|
||||
|
||||
const data = {
|
||||
homeassistant: this.restoreHass,
|
||||
addons: addons,
|
||||
folders: folders
|
||||
folders: folders,
|
||||
};
|
||||
if (this.snapshot.protected) data.password = this.snapshotPassword;
|
||||
|
||||
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/restore/partial`, data).then(() => {
|
||||
alert('Snapshot restored!');
|
||||
this.$.dialog.close();
|
||||
}, (error) => {
|
||||
this.error = error.body.message;
|
||||
});
|
||||
this.hass
|
||||
.callApi(
|
||||
"post",
|
||||
`hassio/snapshots/${this.snapshotSlug}/restore/partial`,
|
||||
data
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
alert("Snapshot restored!");
|
||||
this.$.dialog.close();
|
||||
},
|
||||
(error) => {
|
||||
this.error = error.body.message;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_fullRestoreClicked() {
|
||||
if (!confirm('Are you sure you want to restore this snapshot?')) {
|
||||
if (!confirm("Are you sure you want to restore this snapshot?")) {
|
||||
return;
|
||||
}
|
||||
const data = this.snapshot.protected ? { password: this.snapshotPassword } : null;
|
||||
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/restore/full`, data)
|
||||
.then(() => {
|
||||
alert('Snapshot restored!');
|
||||
this.$.dialog.close();
|
||||
}, (error) => {
|
||||
this.error = error.body.message;
|
||||
});
|
||||
const data = this.snapshot.protected
|
||||
? { password: this.snapshotPassword }
|
||||
: null;
|
||||
this.hass
|
||||
.callApi(
|
||||
"post",
|
||||
`hassio/snapshots/${this.snapshotSlug}/restore/full`,
|
||||
data
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
alert("Snapshot restored!");
|
||||
this.$.dialog.close();
|
||||
},
|
||||
(error) => {
|
||||
this.error = error.body.message;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_deleteClicked() {
|
||||
if (!confirm('Are you sure you want to delete this snapshot?')) {
|
||||
if (!confirm("Are you sure you want to delete this snapshot?")) {
|
||||
return;
|
||||
}
|
||||
this.hass.callApi('post', `hassio/snapshots/${this.snapshotSlug}/remove`)
|
||||
.then(() => {
|
||||
this.$.dialog.close();
|
||||
this.snapshotDeleted = true;
|
||||
}, (error) => {
|
||||
this.error = error.body.message;
|
||||
});
|
||||
this.hass
|
||||
.callApi("post", `hassio/snapshots/${this.snapshotSlug}/remove`)
|
||||
.then(
|
||||
() => {
|
||||
this.$.dialog.close();
|
||||
this.snapshotDeleted = true;
|
||||
},
|
||||
(error) => {
|
||||
this.error = error.body.message;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_computeDownloadUrl(snapshotSlug) {
|
||||
@@ -217,7 +257,7 @@ class HassioSnapshot extends PolymerElement {
|
||||
}
|
||||
|
||||
_computeDownloadName(snapshot) {
|
||||
const name = this._computeName(snapshot).replace(/[^a-z0-9]+/gi, '_');
|
||||
const name = this._computeName(snapshot).replace(/[^a-z0-9]+/gi, "_");
|
||||
return `Hass_io_${name}.tar`;
|
||||
}
|
||||
|
||||
@@ -226,11 +266,11 @@ class HassioSnapshot extends PolymerElement {
|
||||
}
|
||||
|
||||
_computeType(type) {
|
||||
return type === 'full' ? 'Full snapshot' : 'Partial snapshot';
|
||||
return type === "full" ? "Full snapshot" : "Partial snapshot";
|
||||
}
|
||||
|
||||
_computeSize(size) {
|
||||
return (Math.ceil(size * 10) / 10) + ' MB';
|
||||
return Math.ceil(size * 10) / 10 + " MB";
|
||||
}
|
||||
|
||||
_sortAddons(a, b) {
|
||||
@@ -239,12 +279,12 @@ class HassioSnapshot extends PolymerElement {
|
||||
|
||||
_formatDatetime(datetime) {
|
||||
return new Date(datetime).toLocaleDateString(navigator.language, {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit'
|
||||
weekday: "long",
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -252,4 +292,4 @@ class HassioSnapshot extends PolymerElement {
|
||||
this.snapshotSlug = null;
|
||||
}
|
||||
}
|
||||
customElements.define('hassio-snapshot', HassioSnapshot);
|
||||
customElements.define("hassio-snapshot", HassioSnapshot);
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import '@polymer/paper-button/paper-button.js';
|
||||
import '@polymer/paper-card/paper-card.js';
|
||||
import '@polymer/paper-checkbox/paper-checkbox.js';
|
||||
import '@polymer/paper-input/paper-input.js';
|
||||
import '@polymer/paper-radio-button/paper-radio-button.js';
|
||||
import '@polymer/paper-radio-group/paper-radio-group.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import "@polymer/paper-button/paper-button.js";
|
||||
import "@polymer/paper-card/paper-card.js";
|
||||
import "@polymer/paper-checkbox/paper-checkbox.js";
|
||||
import "@polymer/paper-input/paper-input.js";
|
||||
import "@polymer/paper-radio-button/paper-radio-button.js";
|
||||
import "@polymer/paper-radio-group/paper-radio-group.js";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/hassio-card-content.js';
|
||||
import '../resources/hassio-style.js';
|
||||
import EventsMixin from '../../../src/mixins/events-mixin.js';
|
||||
import "../components/hassio-card-content.js";
|
||||
import "../resources/hassio-style.js";
|
||||
import EventsMixin from "../../../src/mixins/events-mixin.js";
|
||||
|
||||
class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -105,16 +105,16 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
hass: Object,
|
||||
snapshotName: {
|
||||
type: String,
|
||||
value: '',
|
||||
value: "",
|
||||
},
|
||||
snapshotPassword: {
|
||||
type: String,
|
||||
value: '',
|
||||
value: "",
|
||||
},
|
||||
snapshotHasPassword: Boolean,
|
||||
snapshotType: {
|
||||
type: String,
|
||||
value: 'full',
|
||||
value: "full",
|
||||
},
|
||||
snapshots: {
|
||||
type: Array,
|
||||
@@ -122,16 +122,20 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
},
|
||||
installedAddons: {
|
||||
type: Array,
|
||||
observer: '_installedAddonsChanged',
|
||||
observer: "_installedAddonsChanged",
|
||||
},
|
||||
addonList: Array,
|
||||
folderList: {
|
||||
type: Array,
|
||||
value: [
|
||||
{ slug: 'homeassistant', name: 'Home Assistant configuration', checked: true },
|
||||
{ slug: 'ssl', name: 'SSL', checked: true },
|
||||
{ slug: 'share', name: 'Share', checked: true },
|
||||
{ slug: 'addons/local', name: 'Local add-ons', checked: true },
|
||||
{
|
||||
slug: "homeassistant",
|
||||
name: "Home Assistant configuration",
|
||||
checked: true,
|
||||
},
|
||||
{ slug: "ssl", name: "SSL", checked: true },
|
||||
{ slug: "share", name: "Share", checked: true },
|
||||
{ slug: "addons/local", name: "Local add-ons", checked: true },
|
||||
],
|
||||
},
|
||||
snapshotSlug: {
|
||||
@@ -141,7 +145,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
snapshotDeleted: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
observer: '_snapshotDeletedChanged',
|
||||
observer: "_snapshotDeletedChanged",
|
||||
},
|
||||
creatingSnapshot: Boolean,
|
||||
dialogOpened: Boolean,
|
||||
@@ -151,7 +155,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener('hass-api-called', ev => this._apiCalled(ev));
|
||||
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
|
||||
this._updateSnapshots();
|
||||
}
|
||||
|
||||
@@ -162,57 +166,70 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
_updateSnapshots() {
|
||||
this.hass.callApi('get', 'hassio/snapshots')
|
||||
.then((result) => {
|
||||
this.hass.callApi("get", "hassio/snapshots").then(
|
||||
(result) => {
|
||||
this.snapshots = result.data.snapshots;
|
||||
}, (error) => {
|
||||
},
|
||||
(error) => {
|
||||
this.error = error.message;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_createSnapshot() {
|
||||
this.error = '';
|
||||
this.error = "";
|
||||
if (this.snapshotHasPassword && !this.snapshotPassword.length) {
|
||||
this.error = 'Please enter a password.';
|
||||
this.error = "Please enter a password.";
|
||||
return;
|
||||
}
|
||||
this.creatingSnapshot = true;
|
||||
let name = this.snapshotName;
|
||||
if (!name.length) {
|
||||
name = new Date().toLocaleDateString(navigator.language, {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric' });
|
||||
weekday: "long",
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
});
|
||||
}
|
||||
let data;
|
||||
let path;
|
||||
if (this.snapshotType === 'full') {
|
||||
if (this.snapshotType === "full") {
|
||||
data = { name: name };
|
||||
path = 'hassio/snapshots/new/full';
|
||||
path = "hassio/snapshots/new/full";
|
||||
} else {
|
||||
const addons = this.addonList.filter(addon => addon.checked).map(addon => addon.slug);
|
||||
const folders = this.folderList.filter(folder => folder.checked).map(folder => folder.slug);
|
||||
const addons = this.addonList
|
||||
.filter((addon) => addon.checked)
|
||||
.map((addon) => addon.slug);
|
||||
const folders = this.folderList
|
||||
.filter((folder) => folder.checked)
|
||||
.map((folder) => folder.slug);
|
||||
|
||||
data = { name: name, folders: folders, addons: addons };
|
||||
path = 'hassio/snapshots/new/partial';
|
||||
path = "hassio/snapshots/new/partial";
|
||||
}
|
||||
if (this.snapshotHasPassword) {
|
||||
data.password = this.snapshotPassword;
|
||||
}
|
||||
|
||||
this.hass.callApi('post', path, data)
|
||||
.then(() => {
|
||||
this.hass.callApi("post", path, data).then(
|
||||
() => {
|
||||
this.creatingSnapshot = false;
|
||||
this.fire('hass-api-called', { success: true });
|
||||
}, (error) => {
|
||||
this.fire("hass-api-called", { success: true });
|
||||
},
|
||||
(error) => {
|
||||
this.creatingSnapshot = false;
|
||||
this.error = error.message;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_installedAddonsChanged(addons) {
|
||||
this.addonList = addons.map(addon => ({ slug: addon.slug, name: addon.name, checked: true }));
|
||||
this.addonList = addons.map((addon) => ({
|
||||
slug: addon.slug,
|
||||
name: addon.name,
|
||||
checked: true,
|
||||
}));
|
||||
}
|
||||
|
||||
_sortAddons(a, b) {
|
||||
@@ -228,12 +245,15 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
_computeDetails(snapshot) {
|
||||
const type = snapshot.type === 'full' ? 'Full snapshot' : 'Partial snapshot';
|
||||
const type =
|
||||
snapshot.type === "full" ? "Full snapshot" : "Partial snapshot";
|
||||
return snapshot.protected ? `${type}, password protected` : type;
|
||||
}
|
||||
|
||||
_computeIcon(type) {
|
||||
return type === 'full' ? 'hassio:package-variant-closed' : 'hassio:package-variant';
|
||||
return type === "full"
|
||||
? "hassio:package-variant-closed"
|
||||
: "hassio:package-variant";
|
||||
}
|
||||
|
||||
_snapshotClicked(ev) {
|
||||
@@ -241,7 +261,7 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
_fullSelected(type) {
|
||||
return type === 'full';
|
||||
return type === "full";
|
||||
}
|
||||
|
||||
_snapshotDeletedChanged(snapshotDeleted) {
|
||||
@@ -252,11 +272,10 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
refreshData() {
|
||||
this.hass.callApi('post', 'hassio/snapshots/reload')
|
||||
.then(() => {
|
||||
this._updateSnapshots();
|
||||
});
|
||||
this.hass.callApi("post", "hassio/snapshots/reload").then(() => {
|
||||
this._updateSnapshots();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-snapshots', HassioSnapshots);
|
||||
customElements.define("hassio-snapshots", HassioSnapshots);
|
||||
|
@@ -1,10 +1,10 @@
|
||||
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 "@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 EventsMixin from '../../../src/mixins/events-mixin.js';
|
||||
import "../../../src/components/buttons/ha-call-api-button.js";
|
||||
import EventsMixin from "../../../src/mixins/events-mixin.js";
|
||||
|
||||
class HassioHostInfo extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -17,6 +17,7 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
.card-content {
|
||||
height: 200px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
@media screen and (max-width: 830px) {
|
||||
paper-card {
|
||||
@@ -96,16 +97,16 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
|
||||
hass: Object,
|
||||
data: {
|
||||
type: Object,
|
||||
observer: '_dataChanged'
|
||||
observer: "_dataChanged",
|
||||
},
|
||||
errors: String,
|
||||
_hassOs: Object
|
||||
_hassOs: Object,
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
|
||||
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
||||
}
|
||||
|
||||
apiCalled(ev) {
|
||||
@@ -116,19 +117,18 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
|
||||
|
||||
var response = ev.detail.response;
|
||||
|
||||
if (typeof response.body === 'object') {
|
||||
this.errors = response.body.message || 'Unknown error';
|
||||
if (typeof response.body === "object") {
|
||||
this.errors = response.body.message || "Unknown error";
|
||||
} else {
|
||||
this.errors = response.body;
|
||||
}
|
||||
}
|
||||
|
||||
_dataChanged(data) {
|
||||
if (data.features && data.features.includes('hassos')) {
|
||||
this.hass.callApi('get', 'hassio/hassos/info')
|
||||
.then((resp) => {
|
||||
this._hassOs = resp.data;
|
||||
});
|
||||
if (data.features && data.features.includes("hassos")) {
|
||||
this.hass.callApi("get", "hassio/hassos/info").then((resp) => {
|
||||
this._hassOs = resp.data;
|
||||
});
|
||||
} else {
|
||||
this._hassOs = {};
|
||||
}
|
||||
@@ -143,28 +143,31 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
_showHardware() {
|
||||
this.hass.callApi('get', 'hassio/hardware/info')
|
||||
this.hass
|
||||
.callApi("get", "hassio/hardware/info")
|
||||
.then(
|
||||
resp => this._objectToMarkdown(resp.data)
|
||||
, () => 'Error getting hardware info'
|
||||
).then((content) => {
|
||||
this.fire('hassio-markdown-dialog', {
|
||||
title: 'Hardware',
|
||||
(resp) => this._objectToMarkdown(resp.data),
|
||||
() => "Error getting hardware info"
|
||||
)
|
||||
.then((content) => {
|
||||
this.fire("hassio-markdown-dialog", {
|
||||
title: "Hardware",
|
||||
content: content,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_objectToMarkdown(obj, indent = '') {
|
||||
let data = '';
|
||||
_objectToMarkdown(obj, indent = "") {
|
||||
let data = "";
|
||||
Object.keys(obj).forEach((key) => {
|
||||
if (typeof obj[key] !== 'object') {
|
||||
if (typeof obj[key] !== "object") {
|
||||
data += `${indent}- ${key}: ${obj[key]}\n`;
|
||||
} else {
|
||||
data += `${indent}- ${key}:\n`;
|
||||
if (Array.isArray(obj[key])) {
|
||||
if (obj[key].length) {
|
||||
data += `${indent} - ` + obj[key].join(`\n${indent} - `) + '\n';
|
||||
data +=
|
||||
`${indent} - ` + obj[key].join(`\n${indent} - `) + "\n";
|
||||
}
|
||||
} else {
|
||||
data += this._objectToMarkdown(obj[key], ` ${indent}`);
|
||||
@@ -176,11 +179,11 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
|
||||
|
||||
_changeHostnameClicked() {
|
||||
const curHostname = this.data.hostname;
|
||||
const hostname = prompt('Please enter a new hostname:', curHostname);
|
||||
const hostname = prompt("Please enter a new hostname:", curHostname);
|
||||
if (hostname && hostname !== curHostname) {
|
||||
this.hass.callApi('post', 'hassio/host/options', { hostname });
|
||||
this.hass.callApi("post", "hassio/host/options", { hostname });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-host-info', HassioHostInfo);
|
||||
customElements.define("hassio-host-info", HassioHostInfo);
|
||||
|
@@ -1,10 +1,10 @@
|
||||
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 "@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 EventsMixin from '../../../src/mixins/events-mixin.js';
|
||||
import "../../../src/components/buttons/ha-call-api-button.js";
|
||||
import EventsMixin from "../../../src/mixins/events-mixin.js";
|
||||
|
||||
class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -16,6 +16,7 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
.card-content {
|
||||
height: 200px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
@media screen and (max-width: 830px) {
|
||||
paper-card {
|
||||
@@ -84,14 +85,14 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
|
||||
errors: String,
|
||||
leaveBeta: {
|
||||
type: Object,
|
||||
value: { channel: 'stable' },
|
||||
value: { channel: "stable" },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener('hass-api-called', ev => this.apiCalled(ev));
|
||||
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
||||
}
|
||||
|
||||
apiCalled(ev) {
|
||||
@@ -102,8 +103,8 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
|
||||
|
||||
var response = ev.detail.response;
|
||||
|
||||
if (typeof response.body === 'object') {
|
||||
this.errors = response.body.message || 'Unknown error';
|
||||
if (typeof response.body === "object") {
|
||||
this.errors = response.body.message || "Unknown error";
|
||||
} else {
|
||||
this.errors = response.body;
|
||||
}
|
||||
@@ -118,18 +119,20 @@ class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
_joinBeta() {
|
||||
if (!confirm(`WARNING:
|
||||
if (
|
||||
!confirm(`WARNING:
|
||||
Beta releases are for testers and early adopters and can contain unstable code changes. Make sure you have backups of your data before you activate this feature.
|
||||
|
||||
This inludes beta releases for:
|
||||
- Home Assistant (Release Candidates)
|
||||
- Hass.io supervisor
|
||||
- Host system`)) {
|
||||
- Host system`)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const method = 'post';
|
||||
const path = 'hassio/supervisor/options';
|
||||
const data = { channel: 'beta' };
|
||||
const method = "post";
|
||||
const path = "hassio/supervisor/options";
|
||||
const data = { channel: "beta" };
|
||||
|
||||
const eventData = {
|
||||
method: method,
|
||||
@@ -137,17 +140,22 @@ This inludes beta releases for:
|
||||
data: data,
|
||||
};
|
||||
|
||||
this.hass.callApi(method, path, data)
|
||||
.then((resp) => {
|
||||
eventData.success = true;
|
||||
eventData.response = resp;
|
||||
}, (resp) => {
|
||||
eventData.success = false;
|
||||
eventData.response = resp;
|
||||
}).then(() => {
|
||||
this.fire('hass-api-called', eventData);
|
||||
this.hass
|
||||
.callApi(method, path, data)
|
||||
.then(
|
||||
(resp) => {
|
||||
eventData.success = true;
|
||||
eventData.response = resp;
|
||||
},
|
||||
(resp) => {
|
||||
eventData.success = false;
|
||||
eventData.response = resp;
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
this.fire("hass-api-called", eventData);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-supervisor-info', HassioSupervisorInfo);
|
||||
customElements.define("hassio-supervisor-info", HassioSupervisorInfo);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
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 "@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";
|
||||
|
||||
class HassioSupervisorLog extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -38,12 +38,14 @@ class HassioSupervisorLog extends PolymerElement {
|
||||
}
|
||||
|
||||
loadData() {
|
||||
this.hass.callApi('get', 'hassio/supervisor/logs')
|
||||
.then((info) => {
|
||||
this.hass.callApi("get", "hassio/supervisor/logs").then(
|
||||
(info) => {
|
||||
this.log = info;
|
||||
}, () => {
|
||||
this.log = 'Error fetching logs';
|
||||
});
|
||||
},
|
||||
() => {
|
||||
this.log = "Error fetching logs";
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
refreshTapped() {
|
||||
@@ -51,4 +53,4 @@ class HassioSupervisorLog extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-supervisor-log', HassioSupervisorLog);
|
||||
customElements.define("hassio-supervisor-log", HassioSupervisorLog);
|
||||
|
@@ -1,10 +1,10 @@
|
||||
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 "@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';
|
||||
import "./hassio-host-info.js";
|
||||
import "./hassio-supervisor-info.js";
|
||||
import "./hassio-supervisor-log.js";
|
||||
|
||||
class HassioSystem extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -40,4 +40,4 @@ class HassioSystem extends PolymerElement {
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hassio-system', HassioSystem);
|
||||
customElements.define("hassio-system", HassioSystem);
|
||||
|
@@ -1,69 +1,54 @@
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
|
||||
const CompressionPlugin = require("compression-webpack-plugin");
|
||||
const config = require('./config.js');
|
||||
const config = require("./config.js");
|
||||
const { babelLoaderConfig } = require("../config/babel.js");
|
||||
|
||||
const isProdBuild = process.env.NODE_ENV === 'production'
|
||||
const chunkFilename = isProdBuild ?
|
||||
'chunk.[chunkhash].js' : '[name].chunk.js';
|
||||
const isProdBuild = process.env.NODE_ENV === "production";
|
||||
const chunkFilename = isProdBuild ? "chunk.[chunkhash].js" : "[name].chunk.js";
|
||||
|
||||
module.exports = {
|
||||
mode: isProdBuild ? 'production' : 'development',
|
||||
devtool: isProdBuild ? 'source-map' : 'inline-source-map',
|
||||
mode: isProdBuild ? "production" : "development",
|
||||
devtool: isProdBuild ? "source-map" : "inline-source-map",
|
||||
entry: {
|
||||
entrypoint: './src/entrypoint.js',
|
||||
entrypoint: "./src/entrypoint.js",
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
[require('babel-preset-env').default, { modules: false }]
|
||||
],
|
||||
plugins: [
|
||||
// Only support the syntax, Webpack will handle it.
|
||||
"syntax-dynamic-import",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
babelLoaderConfig({ latestBuild: false }),
|
||||
{
|
||||
test: /\.(html)$/,
|
||||
use: {
|
||||
loader: 'html-loader',
|
||||
loader: "html-loader",
|
||||
options: {
|
||||
exportAsEs6Default: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
isProdBuild && new UglifyJsPlugin({
|
||||
extractComments: true,
|
||||
sourceMap: true,
|
||||
uglifyOptions: {
|
||||
// Disabling because it broke output
|
||||
mangle: false,
|
||||
}
|
||||
}),
|
||||
isProdBuild && new CompressionPlugin({
|
||||
cache: true,
|
||||
exclude: [
|
||||
/\.js\.map$/,
|
||||
/\.LICENSE$/,
|
||||
/\.py$/,
|
||||
/\.txt$/,
|
||||
]
|
||||
}),
|
||||
isProdBuild &&
|
||||
new UglifyJsPlugin({
|
||||
extractComments: true,
|
||||
sourceMap: true,
|
||||
uglifyOptions: {
|
||||
// Disabling because it broke output
|
||||
mangle: false,
|
||||
},
|
||||
}),
|
||||
isProdBuild &&
|
||||
new CompressionPlugin({
|
||||
cache: true,
|
||||
exclude: [/\.js\.map$/, /\.LICENSE$/, /\.py$/, /\.txt$/],
|
||||
}),
|
||||
].filter(Boolean),
|
||||
resolve: {
|
||||
extensions: [".ts", ".js", ".json"],
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
filename: "[name].js",
|
||||
chunkFilename,
|
||||
path: config.buildDir,
|
||||
publicPath: `${config.publicPath}/`,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
224
package.json
224
package.json
@@ -8,98 +8,109 @@
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "script/build_frontend",
|
||||
"lint": "eslint src hassio/src gallery/src test-mocha && polymer lint",
|
||||
"lint": "eslint src hassio/src gallery/src test-mocha && tslint -c tslint.json 'src/**/*.ts' 'hassio/src/**/*.ts' 'gallery/src/**/*.ts' 'test-mocha/**/*.ts' && polymer lint && tsc",
|
||||
"mocha": "node_modules/.bin/mocha --opts test-mocha/mocha.opts",
|
||||
"test": "npm run lint && npm run mocha"
|
||||
"test": "npm run lint && npm run mocha",
|
||||
"docker_build": "sh ./script/docker_run.sh build $npm_package_version",
|
||||
"bash": "sh ./script/docker_run.sh bash $npm_package_version"
|
||||
},
|
||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@mdi/svg": "^2.4.85",
|
||||
"@polymer/app-layout": "^3.0.0-pre.19",
|
||||
"@polymer/app-localize-behavior": "^3.0.0-pre.19",
|
||||
"@polymer/app-route": "^3.0.0-pre.19",
|
||||
"@polymer/app-storage": "^3.0.0-pre.19",
|
||||
"@polymer/font-roboto": "^3.0.0-pre.19",
|
||||
"@polymer/font-roboto-local": "^3.0.0-pre.19",
|
||||
"@polymer/iron-autogrow-textarea": "^3.0.0-pre.19",
|
||||
"@polymer/iron-flex-layout": "^3.0.0-pre.19",
|
||||
"@polymer/iron-icon": "^3.0.0-pre.19",
|
||||
"@polymer/iron-iconset-svg": "^3.0.0-pre.19",
|
||||
"@polymer/iron-image": "^3.0.0-pre.19",
|
||||
"@polymer/iron-input": "^3.0.0-pre.19",
|
||||
"@polymer/iron-label": "^3.0.0-pre.19",
|
||||
"@polymer/iron-media-query": "^3.0.0-pre.19",
|
||||
"@polymer/iron-pages": "^3.0.0-pre.19",
|
||||
"@polymer/iron-resizable-behavior": "^3.0.0-pre.19",
|
||||
"@polymer/neon-animation": "^3.0.0-pre.19",
|
||||
"@polymer/paper-button": "^3.0.0-pre.19",
|
||||
"@polymer/paper-card": "^3.0.0-pre.19",
|
||||
"@polymer/paper-checkbox": "^3.0.0-pre.19",
|
||||
"@polymer/paper-dialog": "^3.0.0-pre.19",
|
||||
"@polymer/paper-dialog-behavior": "^3.0.0-pre.19",
|
||||
"@polymer/paper-dialog-scrollable": "^3.0.0-pre.19",
|
||||
"@polymer/paper-drawer-panel": "^3.0.0-pre.19",
|
||||
"@polymer/paper-dropdown-menu": "^3.0.0-pre.19",
|
||||
"@polymer/paper-fab": "^3.0.0-pre.19",
|
||||
"@polymer/paper-icon-button": "^3.0.0-pre.19",
|
||||
"@polymer/paper-input": "^3.0.0-pre.19",
|
||||
"@polymer/paper-item": "^3.0.0-pre.19",
|
||||
"@polymer/paper-listbox": "^3.0.0-pre.19",
|
||||
"@polymer/paper-menu-button": "^3.0.0-pre.19",
|
||||
"@polymer/paper-progress": "^3.0.0-pre.19",
|
||||
"@polymer/paper-radio-button": "^3.0.0-pre.19",
|
||||
"@polymer/paper-radio-group": "^3.0.0-pre.19",
|
||||
"@polymer/paper-ripple": "^3.0.0-pre.19",
|
||||
"@polymer/paper-scroll-header-panel": "^3.0.0-pre.19",
|
||||
"@polymer/paper-slider": "^3.0.0-pre.19",
|
||||
"@polymer/paper-spinner": "^3.0.0-pre.19",
|
||||
"@polymer/paper-styles": "^3.0.0-pre.19",
|
||||
"@polymer/paper-tabs": "^3.0.0-pre.19",
|
||||
"@polymer/paper-toast": "^3.0.0-pre.19",
|
||||
"@polymer/paper-toggle-button": "^3.0.0-pre.19",
|
||||
"@polymer/polymer": "^3.0.2",
|
||||
"@vaadin/vaadin-combo-box": "4.1.0-alpha2",
|
||||
"@vaadin/vaadin-date-picker": "3.2.0-alpha3",
|
||||
"@webcomponents/shadycss": "^1.3.1",
|
||||
"@webcomponents/webcomponentsjs": "^2.0.2",
|
||||
"@material/mwc-ripple": "^0.3.1",
|
||||
"@mdi/svg": "^2.7.94",
|
||||
"@polymer/app-layout": "^3.0.1",
|
||||
"@polymer/app-localize-behavior": "^3.0.1",
|
||||
"@polymer/app-route": "^3.0.2",
|
||||
"@polymer/app-storage": "^3.0.2",
|
||||
"@polymer/font-roboto": "^3.0.2",
|
||||
"@polymer/font-roboto-local": "^3.0.2",
|
||||
"@polymer/iron-autogrow-textarea": "^3.0.1",
|
||||
"@polymer/iron-flex-layout": "^3.0.1",
|
||||
"@polymer/iron-icon": "^3.0.1",
|
||||
"@polymer/iron-iconset-svg": "^3.0.1",
|
||||
"@polymer/iron-image": "^3.0.1",
|
||||
"@polymer/iron-input": "^3.0.1",
|
||||
"@polymer/iron-label": "^3.0.1",
|
||||
"@polymer/iron-media-query": "^3.0.1",
|
||||
"@polymer/iron-pages": "^3.0.1",
|
||||
"@polymer/iron-resizable-behavior": "^3.0.1",
|
||||
"@polymer/lit-element": "^0.6.2",
|
||||
"@polymer/neon-animation": "^3.0.1",
|
||||
"@polymer/paper-button": "^3.0.1",
|
||||
"@polymer/paper-card": "^3.0.1",
|
||||
"@polymer/paper-checkbox": "^3.0.1",
|
||||
"@polymer/paper-dialog": "^3.0.1",
|
||||
"@polymer/paper-dialog-behavior": "^3.0.1",
|
||||
"@polymer/paper-dialog-scrollable": "^3.0.1",
|
||||
"@polymer/paper-drawer-panel": "^3.0.1",
|
||||
"@polymer/paper-dropdown-menu": "^3.0.1",
|
||||
"@polymer/paper-fab": "^3.0.1",
|
||||
"@polymer/paper-icon-button": "^3.0.1",
|
||||
"@polymer/paper-input": "^3.0.1",
|
||||
"@polymer/paper-item": "^3.0.1",
|
||||
"@polymer/paper-listbox": "^3.0.1",
|
||||
"@polymer/paper-menu-button": "^3.0.1",
|
||||
"@polymer/paper-progress": "^3.0.1",
|
||||
"@polymer/paper-radio-button": "^3.0.1",
|
||||
"@polymer/paper-radio-group": "^3.0.1",
|
||||
"@polymer/paper-ripple": "^3.0.1",
|
||||
"@polymer/paper-scroll-header-panel": "^3.0.1",
|
||||
"@polymer/paper-slider": "^3.0.1",
|
||||
"@polymer/paper-spinner": "^3.0.1",
|
||||
"@polymer/paper-styles": "^3.0.1",
|
||||
"@polymer/paper-tabs": "^3.0.1",
|
||||
"@polymer/paper-toast": "^3.0.1",
|
||||
"@polymer/paper-toggle-button": "^3.0.1",
|
||||
"@polymer/paper-tooltip": "^3.0.1",
|
||||
"@polymer/polymer": "^3.0.5",
|
||||
"@vaadin/vaadin-combo-box": "4.2.0-alpha3",
|
||||
"@vaadin/vaadin-date-picker": "3.3.0-alpha1",
|
||||
"@webcomponents/shadycss": "^1.5.2",
|
||||
"@webcomponents/webcomponentsjs": "^2.1.3",
|
||||
"chart.js": "~2.7.2",
|
||||
"chartjs-chart-timeline": "^0.2.1",
|
||||
"es6-object-assign": "^1.1.0",
|
||||
"eslint-import-resolver-webpack": "^0.10.0",
|
||||
"eslint-import-resolver-webpack": "^0.10.1",
|
||||
"fecha": "^2.3.3",
|
||||
"home-assistant-js-websocket": "^2.1.0",
|
||||
"home-assistant-js-websocket": "^3.1.4",
|
||||
"intl-messageformat": "^2.2.0",
|
||||
"js-yaml": "^3.12.0",
|
||||
"leaflet": "^1.3.1",
|
||||
"marked": "^0.4.0",
|
||||
"mdn-polyfills": "^5.8.0",
|
||||
"leaflet": "^1.3.4",
|
||||
"lit-html": "^0.12.0",
|
||||
"marked": "^0.5.0",
|
||||
"mdn-polyfills": "^5.12.0",
|
||||
"moment": "^2.22.2",
|
||||
"preact": "^8.2.9",
|
||||
"preact-compat": "^3.18.0",
|
||||
"react-big-calendar": "^0.19.1",
|
||||
"regenerator-runtime": "^0.11.1",
|
||||
"unfetch": "^3.0.0",
|
||||
"preact": "^8.3.1",
|
||||
"preact-compat": "^3.18.4",
|
||||
"react-big-calendar": "^0.19.2",
|
||||
"regenerator-runtime": "^0.12.1",
|
||||
"unfetch": "^4.0.1",
|
||||
"web-animations-js": "^2.3.1",
|
||||
"xss": "^1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-eslint": "^8.2.3",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-plugin-external-helpers": "^6.22.0",
|
||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||
"babel-plugin-transform-react-jsx": "^6.24.1",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"@babel/core": "^7.1.2",
|
||||
"@babel/plugin-external-helpers": "^7.0.0",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||
"@babel/plugin-transform-react-jsx": "^7.0.0",
|
||||
"@babel/preset-env": "^7.1.0",
|
||||
"@babel/preset-typescript": "7.0.0",
|
||||
"@gfx/zopfli": "^1.0.9",
|
||||
"babel-eslint": "^10",
|
||||
"babel-loader": "^8.0.4",
|
||||
"babel-minify-webpack-plugin": "^0.3.1",
|
||||
"chai": "^4.1.2",
|
||||
"compression-webpack-plugin": "^1.1.11",
|
||||
"copy-webpack-plugin": "^4.5.1",
|
||||
"compression-webpack-plugin": "^2.0.0",
|
||||
"copy-webpack-plugin": "^4.5.2",
|
||||
"del": "^3.0.0",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-plugin-import": "^2.12.0",
|
||||
"eslint-plugin-react": "^7.9.1",
|
||||
"eslint": "^5.6.0",
|
||||
"eslint-config-airbnb-base": "^13.1.0",
|
||||
"eslint-config-prettier": "^3.1.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-prettier": "^3.0.0",
|
||||
"eslint-plugin-react": "^7.11.1",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-foreach": "^0.1.0",
|
||||
"gulp-hash": "^4.2.2",
|
||||
@@ -107,36 +118,65 @@
|
||||
"gulp-json-transform": "^0.4.5",
|
||||
"gulp-jsonminify": "^1.1.0",
|
||||
"gulp-merge-json": "^1.3.1",
|
||||
"gulp-rename": "^1.3.0",
|
||||
"gulp-rename": "^1.4.0",
|
||||
"html-loader": "^0.5.5",
|
||||
"html-minifier": "^3.5.16",
|
||||
"html-minifier": "^3.5.20",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"husky": "^1.1.0",
|
||||
"lint-staged": "^7.3.0",
|
||||
"merge-stream": "^1.0.1",
|
||||
"mocha": "^5.2.0",
|
||||
"parse5": "^5.0.0",
|
||||
"polymer-analyzer": "^3.0.1",
|
||||
"polymer-bundler": "^4.0.1",
|
||||
"polymer-cli": "^1.7.4",
|
||||
"reify": "^0.16.2",
|
||||
"parse5": "^5.1.0",
|
||||
"polymer-analyzer": "^3.1.2",
|
||||
"polymer-bundler": "^4.0.2",
|
||||
"polymer-cli": "^1.8.0",
|
||||
"prettier": "^1.14.3",
|
||||
"raw-loader": "^0.5.1",
|
||||
"reify": "^0.17.3",
|
||||
"require-dir": "^1.0.0",
|
||||
"sinon": "^6.0.0",
|
||||
"uglifyjs-webpack-plugin": "^1.2.6",
|
||||
"sinon": "^6.3.4",
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-config-prettier": "^1.15.0",
|
||||
"tslint-eslint-rules": "^5.4.0",
|
||||
"typescript": "3.1.3",
|
||||
"wct-browser-legacy": "^1.0.1",
|
||||
"web-component-tester": "^6.7.0",
|
||||
"webpack": "^4.12.0",
|
||||
"webpack-cli": "^3.0.8",
|
||||
"webpack-dev-server": "^3.1.4",
|
||||
"workbox-webpack-plugin": "^3.3.0"
|
||||
"web-component-tester": "^6.8.0",
|
||||
"webpack": "^4.19.1",
|
||||
"webpack-cli": "^3.1.0",
|
||||
"webpack-dev-server": "^3.1.8",
|
||||
"workbox-webpack-plugin": "^3.5.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"inherits": "2.0.3",
|
||||
"samsam": "1.1.3",
|
||||
"supports-color": "3.1.2",
|
||||
"type-detect": "1.0.0",
|
||||
"@webcomponents/webcomponentsjs": "2.0.2",
|
||||
"@webcomponents/shadycss": "^1.3.1",
|
||||
"@vaadin/vaadin-overlay": "3.0.2-pre.2",
|
||||
"@polymer/polymer": "3.0.5",
|
||||
"@webcomponents/webcomponentsjs": "2.1.3",
|
||||
"@webcomponents/shadycss": "^1.5.2",
|
||||
"@vaadin/vaadin-overlay": "3.2.0-alpha3",
|
||||
"@vaadin/vaadin-lumo-styles": "1.2.0",
|
||||
"fecha": "https://github.com/balloob/fecha/archive/51d14fd0eb4781e2ecf265d1c3080706259133b5.tar.gz"
|
||||
},
|
||||
"main": "src/home-assistant.js"
|
||||
"main": "src/home-assistant.js",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"linters": {
|
||||
"*.{js,json,css,md}": [
|
||||
"prettier --write",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"ignore": [
|
||||
"translations/**"
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "always"
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@
|
||||
],
|
||||
"lint": {
|
||||
"rules": ["polymer-3"],
|
||||
"ignoreWarnings": ["could-not-resolve-reference"],
|
||||
"ignoreWarnings": ["could-not-resolve-reference", "could-not-load"],
|
||||
"filesToIgnore": [
|
||||
"**/*.html",
|
||||
"**/src/panels/config/js/**/*.js",
|
||||
|
14
script/docker_entrypoint.sh
Normal file
14
script/docker_entrypoint.sh
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# Docker entry point inspired by travis build and script/build_frontend
|
||||
|
||||
# Stop on errors
|
||||
set -e
|
||||
|
||||
# Build the frontend but not used the npm run build
|
||||
/bin/bash script/build_frontend
|
||||
|
||||
# TEST
|
||||
npm run test
|
||||
|
||||
#
|
||||
#xvfb-run wct
|
103
script/docker_run.sh
Executable file
103
script/docker_run.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
# Basic Docker Management scripts
|
||||
# With this script you can build software, or enter an agnostic development environment and run commands interactively.
|
||||
|
||||
|
||||
|
||||
check_mandatory_tools(){
|
||||
if [ "x$(which docker)" == "x" ]; then
|
||||
echo "UNKNOWN - Missing docker binary! Are you sure it is installed and reachable?"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
docker info > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "UNKNOWN - Unable to talk to the docker daemon! Maybe the docker daemon is not running"
|
||||
exit 3
|
||||
fi
|
||||
}
|
||||
|
||||
check_dev_image(){
|
||||
if [[ "$(docker images -q ${IMAGE_NAME}:$IMAGE_TAG 2> /dev/null)" == "" ]]; then
|
||||
echo "UNKNOWN - Can't find the development docker image ${IMAGE_NAME}:$IMAGE_TAG"
|
||||
while true; do
|
||||
read -p "Do you want to create it now?" yn
|
||||
case $yn in
|
||||
[Yy]* ) create_image; break;;
|
||||
[Nn]* ) exit 3;;
|
||||
* ) echo "Please answer y or n";;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Building the basic image for compiling the production frontend
|
||||
create_image(){
|
||||
docker build -t ${IMAGE_NAME}:${IMAGE_TAG} .
|
||||
}
|
||||
|
||||
#
|
||||
# Execute interactive bash on basic image
|
||||
#
|
||||
run_bash_on_docker(){
|
||||
|
||||
check_dev_image
|
||||
|
||||
docker run -it \
|
||||
-v $PWD/:/frontend/ \
|
||||
-v /frontend/node_modules \
|
||||
-v /frontend/bower_components \
|
||||
${IMAGE_NAME}:${IMAGE_TAG} /bin/bash
|
||||
}
|
||||
|
||||
#
|
||||
# Execute the basic image for compiling the production frontend
|
||||
#
|
||||
build_all(){
|
||||
|
||||
check_dev_image
|
||||
|
||||
docker run -it \
|
||||
-v $PWD/:/frontend/ \
|
||||
-v /frontend/node_modules \
|
||||
-v /frontend/bower_components \
|
||||
${IMAGE_NAME}:${IMAGE_TAG} /bin/bash script/build_frontend
|
||||
|
||||
}
|
||||
|
||||
# Init Global Variable
|
||||
IMAGE_NAME=home_assistant_fe_image
|
||||
IMAGE_TAG=${2:-latest}
|
||||
|
||||
check_mandatory_tools
|
||||
|
||||
case "$1" in
|
||||
setup_env)
|
||||
create_image
|
||||
;;
|
||||
bash)
|
||||
run_bash_on_docker
|
||||
;;
|
||||
build)
|
||||
build_all
|
||||
;;
|
||||
*)
|
||||
echo "NAME"
|
||||
echo " Docker Management."
|
||||
echo ""
|
||||
echo "SYNOPSIS"
|
||||
echo " ${0} command [version]"
|
||||
echo ""
|
||||
echo "DESCRIPTION"
|
||||
echo " With this script you can build software, or enter an agnostic development environment and run commands interactively."
|
||||
echo ""
|
||||
echo " The command are:"
|
||||
echo " setup_env Create develop images"
|
||||
echo " bash Run bash on develop enviroments"
|
||||
echo " build Run silent build"
|
||||
echo ""
|
||||
echo " The version is optional, if not inserted it assumes \"latest\". "
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit 0
|
@@ -28,7 +28,7 @@ mkdir -p ${LOCAL_DIR}
|
||||
|
||||
docker run \
|
||||
-v ${LOCAL_DIR}:/opt/dest/locale \
|
||||
lokalise/lokalise-cli@sha256:ddf5677f58551261008342df5849731c88bcdc152ab645b133b21819aede8218 lokalise \
|
||||
lokalise/lokalise-cli@sha256:b8329d20280263cad04f65b843e54b9e8e6909a348a678eac959550b5ef5c75f lokalise \
|
||||
--token ${LOKALISE_TOKEN} \
|
||||
export ${PROJECT_ID} \
|
||||
--export_empty skip \
|
||||
|
38
setup.py
38
setup.py
@@ -1,20 +1,22 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name='home-assistant-frontend',
|
||||
version='20180826.0',
|
||||
description='The Home Assistant frontend',
|
||||
url='https://github.com/home-assistant/home-assistant-polymer',
|
||||
author='The Home Assistant Authors',
|
||||
author_email='hello@home-assistant.io',
|
||||
license='Apache License 2.0',
|
||||
packages=find_packages(include=[
|
||||
'hass_frontend',
|
||||
'hass_frontend_es5',
|
||||
'hass_frontend.*',
|
||||
'hass_frontend_es5.*'
|
||||
]),
|
||||
install_requires=[
|
||||
'user-agents==1.1.0',
|
||||
],
|
||||
include_package_data=True,
|
||||
zip_safe=False)
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20181024.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
author_email="hello@home-assistant.io",
|
||||
license="Apache License 2.0",
|
||||
packages=find_packages(
|
||||
include=[
|
||||
"hass_frontend",
|
||||
"hass_frontend_es5",
|
||||
"hass_frontend.*",
|
||||
"hass_frontend_es5.*",
|
||||
]
|
||||
),
|
||||
install_requires=["user-agents==1.1.0"],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
)
|
||||
|
@@ -1,94 +1,151 @@
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import '@polymer/paper-button/paper-button.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import '../components/ha-form.js';
|
||||
import EventsMixin from '../mixins/events-mixin.js';
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
import "@polymer/paper-button/paper-button.js";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import "../components/ha-form.js";
|
||||
import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
*/
|
||||
class HaAuthFlow extends EventsMixin(PolymerElement) {
|
||||
class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
/* So we can set min-height to avoid jumping during loading */
|
||||
display: block;
|
||||
}
|
||||
.action {
|
||||
margin: 32px 0;
|
||||
margin: 24px 0 8px;
|
||||
text-align: center;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
<template is="dom-if" if="[[_equals(_state, "loading")]]">
|
||||
Please wait
|
||||
</template>
|
||||
<template is="dom-if" if="[[_equals(_state, "error")]]">
|
||||
Something went wrong
|
||||
</template>
|
||||
<template is="dom-if" if="[[_equals(_state, "step")]]">
|
||||
<template is="dom-if" if="[[_equals(_step.type, "abort")]]">
|
||||
Aborted
|
||||
<form>
|
||||
<template is="dom-if" if="[[_equals(_state, "loading")]]">
|
||||
[[localize('ui.panel.page-authorize.form.working')]]:
|
||||
</template>
|
||||
<template is="dom-if" if="[[_equals(_step.type, "create_entry")]]">
|
||||
Success!
|
||||
<template is="dom-if" if="[[_equals(_state, "error")]]">
|
||||
<div class='error'>Error: [[_errorMsg]]</div>
|
||||
</template>
|
||||
<template is="dom-if" if="[[_equals(_step.type, "form")]]">
|
||||
<ha-form data="{{_stepData}}" schema="[[_step.data_schema]]" error="[[_step.errors]]"></ha-form>
|
||||
<template is="dom-if" if="[[_equals(_state, "step")]]">
|
||||
<template is="dom-if" if="[[_equals(_step.type, "abort")]]">
|
||||
[[localize('ui.panel.page-authorize.abort_intro')]]:
|
||||
<ha-markdown content="[[_computeStepAbortedReason(localize, _step)]]"></ha-markdown>
|
||||
</template>
|
||||
|
||||
<template is="dom-if" if="[[_equals(_step.type, "form")]]">
|
||||
<template is="dom-if" if="[[_computeStepDescription(localize, _step)]]">
|
||||
<ha-markdown content="[[_computeStepDescription(localize, _step)]]" allow-svg></ha-markdown>
|
||||
</template>
|
||||
|
||||
<ha-form
|
||||
data="{{_stepData}}"
|
||||
schema="[[_step.data_schema]]"
|
||||
error="[[_step.errors]]"
|
||||
compute-label="[[_computeLabelCallback(localize, _step)]]"
|
||||
compute-error="[[_computeErrorCallback(localize, _step)]]"
|
||||
></ha-form>
|
||||
</template>
|
||||
<div class='action'>
|
||||
<paper-button
|
||||
raised
|
||||
on-click='_handleSubmit'
|
||||
>[[_computeSubmitCaption(_step.type)]]</paper-button>
|
||||
</div>
|
||||
</template>
|
||||
<div class='action'>
|
||||
<paper-button raised on-click="_handleSubmit">[[_computeSubmitCaption(_step.type)]]</paper-button>
|
||||
</div>
|
||||
</template>
|
||||
</form>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
authProvider: Object,
|
||||
authProvider: {
|
||||
type: Object,
|
||||
observer: "_providerChanged",
|
||||
},
|
||||
clientId: String,
|
||||
redirectUri: String,
|
||||
oauth2State: String,
|
||||
_state: {
|
||||
type: String,
|
||||
value: 'loading'
|
||||
value: "loading",
|
||||
},
|
||||
_stepData: {
|
||||
type: Object,
|
||||
value: () => ({}),
|
||||
},
|
||||
_step: Object,
|
||||
_step: {
|
||||
type: Object,
|
||||
notify: true,
|
||||
},
|
||||
_errorMsg: String,
|
||||
};
|
||||
}
|
||||
|
||||
async ready() {
|
||||
ready() {
|
||||
super.ready();
|
||||
|
||||
this.addEventListener('keypress', (ev) => {
|
||||
this.addEventListener("keypress", (ev) => {
|
||||
if (ev.keyCode === 13) {
|
||||
this._handleSubmit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
async _providerChanged(newProvider, oldProvider) {
|
||||
if (oldProvider && this._step && this._step.type === "form") {
|
||||
fetch(`/auth/login_flow/${this._step.flow_id}`, {
|
||||
method: "DELETE",
|
||||
credentials: "same-origin",
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
fetch('/auth/login_flow', {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
client_id: this.clientId,
|
||||
handler: [this.authProvider.type, this.authProvider.id],
|
||||
redirect_uri: this.redirectUri,
|
||||
})
|
||||
}).then((response) => {
|
||||
if (!response.ok) throw new Error();
|
||||
return response.json();
|
||||
}).then(step => this.setProperties({
|
||||
_step: step,
|
||||
_state: 'step',
|
||||
})).catch((err) => {
|
||||
try {
|
||||
const response = await fetch("/auth/login_flow", {
|
||||
method: "POST",
|
||||
credentials: "same-origin",
|
||||
body: JSON.stringify({
|
||||
client_id: this.clientId,
|
||||
handler: [newProvider.type, newProvider.id],
|
||||
redirect_uri: this.redirectUri,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
this._updateStep(data);
|
||||
} else {
|
||||
this.setProperties({
|
||||
_state: "error",
|
||||
_errorMsg: data.message,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.error('Error starting auth flow', err);
|
||||
this._state = 'error';
|
||||
});
|
||||
console.error("Error starting auth flow", err);
|
||||
this.setProperties({
|
||||
_state: "error",
|
||||
_errorMsg: this.localize("ui.panel.page-authorize.form.unknown_error"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_updateStep(step) {
|
||||
const props = {
|
||||
_step: step,
|
||||
_state: "step",
|
||||
};
|
||||
|
||||
if (
|
||||
this._step &&
|
||||
(step.flow_id !== this._step.flow_id ||
|
||||
step.step_id !== this._step.step_id)
|
||||
) {
|
||||
props._stepData = {};
|
||||
}
|
||||
|
||||
this.setProperties(props);
|
||||
}
|
||||
|
||||
_equals(a, b) {
|
||||
@@ -96,35 +153,80 @@ class HaAuthFlow extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
_computeSubmitCaption(stepType) {
|
||||
return stepType === 'form' ? 'Next' : 'Start over';
|
||||
return stepType === "form" ? "Next" : "Start over";
|
||||
}
|
||||
|
||||
_handleSubmit() {
|
||||
if (this._step.type !== 'form') {
|
||||
this.fire('reset');
|
||||
_computeStepAbortedReason(localize, step) {
|
||||
return localize(
|
||||
`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${
|
||||
step.reason
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
_computeStepDescription(localize, step) {
|
||||
const args = [
|
||||
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
|
||||
step.step_id
|
||||
}.description`,
|
||||
];
|
||||
const placeholders = step.description_placeholders || {};
|
||||
Object.keys(placeholders).forEach((key) => {
|
||||
args.push(key);
|
||||
args.push(placeholders[key]);
|
||||
});
|
||||
return localize(...args);
|
||||
}
|
||||
|
||||
_computeLabelCallback(localize, step) {
|
||||
// Returns a callback for ha-form to calculate labels per schema object
|
||||
return (schema) =>
|
||||
localize(
|
||||
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
|
||||
step.step_id
|
||||
}.data.${schema.name}`
|
||||
);
|
||||
}
|
||||
|
||||
_computeErrorCallback(localize, step) {
|
||||
// Returns a callback for ha-form to calculate error messages
|
||||
return (error) =>
|
||||
localize(
|
||||
`ui.panel.page-authorize.form.providers.${
|
||||
step.handler[0]
|
||||
}.error.${error}`
|
||||
);
|
||||
}
|
||||
|
||||
async _handleSubmit() {
|
||||
if (this._step.type !== "form") {
|
||||
this._providerChanged(this.authProvider, null);
|
||||
return;
|
||||
}
|
||||
this._state = 'loading';
|
||||
this._state = "loading";
|
||||
// To avoid a jumping UI.
|
||||
this.style.setProperty("min-height", `${this.offsetHeight}px`);
|
||||
|
||||
const postData = Object.assign({}, this._stepData, {
|
||||
client_id: this.clientId,
|
||||
});
|
||||
|
||||
fetch(`/auth/login_flow/${this._step.flow_id}`, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify(postData)
|
||||
}).then((response) => {
|
||||
if (!response.ok) throw new Error();
|
||||
return response.json();
|
||||
}).then((newStep) => {
|
||||
if (newStep.type === 'create_entry') {
|
||||
try {
|
||||
const response = await fetch(`/auth/login_flow/${this._step.flow_id}`, {
|
||||
method: "POST",
|
||||
credentials: "same-origin",
|
||||
body: JSON.stringify(postData),
|
||||
});
|
||||
|
||||
const newStep = await response.json();
|
||||
|
||||
if (newStep.type === "create_entry") {
|
||||
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI
|
||||
let url = this.redirectUri;
|
||||
if (!url.includes('?')) {
|
||||
url += '?';
|
||||
} else if (!url.endsWith('&')) {
|
||||
url += '&';
|
||||
if (!url.includes("?")) {
|
||||
url += "?";
|
||||
} else if (!url.endsWith("&")) {
|
||||
url += "&";
|
||||
}
|
||||
|
||||
url += `code=${encodeURIComponent(newStep.result)}`;
|
||||
@@ -136,20 +238,14 @@ class HaAuthFlow extends EventsMixin(PolymerElement) {
|
||||
document.location = url;
|
||||
return;
|
||||
}
|
||||
|
||||
const props = {
|
||||
_step: newStep,
|
||||
_state: 'step',
|
||||
};
|
||||
if (newStep.step_id !== this._step.step_id) {
|
||||
props._stepData = {};
|
||||
}
|
||||
this.setProperties(props);
|
||||
}).catch((err) => {
|
||||
this._updateStep(newStep);
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.error('Error loading auth providers', err);
|
||||
this._state = 'error-loading';
|
||||
});
|
||||
console.error("Error submitting step", err);
|
||||
this._state = "error-loading";
|
||||
} finally {
|
||||
this.style.setProperty("min-height", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
customElements.define('ha-auth-flow', HaAuthFlow);
|
||||
customElements.define("ha-auth-flow", HaAuthFlow);
|
||||
|
@@ -1,81 +1,82 @@
|
||||
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
|
||||
import '@polymer/polymer/lib/elements/dom-if.js';
|
||||
import '@polymer/polymer/lib/elements/dom-repeat.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import "@polymer/polymer/lib/elements/dom-if.js";
|
||||
import "@polymer/polymer/lib/elements/dom-repeat.js";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../auth/ha-auth-flow.js';
|
||||
import '../auth/ha-pick-auth-provider.js';
|
||||
import "../components/ha-markdown.js";
|
||||
|
||||
class HaAuthorize extends PolymerElement {
|
||||
import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
|
||||
|
||||
import "./ha-auth-flow.js";
|
||||
|
||||
class HaAuthorize extends LocalizeLiteMixin(PolymerElement) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style include="iron-flex iron-positioning"></style>
|
||||
<style>
|
||||
.content {
|
||||
padding: 20px 16px;
|
||||
max-width: 360px;
|
||||
margin: 0 auto;
|
||||
ha-markdown {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
font-size: 1.96em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 300;
|
||||
ha-markdown a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.header img {
|
||||
margin-right: 16px;
|
||||
ha-markdown p:last-child{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ha-pick-auth-provider {
|
||||
display: block;
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class="content layout vertical fit">
|
||||
<div class='header'>
|
||||
<img src="/static/icons/favicon-192x192.png" height="52">
|
||||
Home Assistant
|
||||
</div>
|
||||
|
||||
<p>Logging in to <b>[[clientId]]</b>.</p>
|
||||
<template is="dom-if" if="[[!_authProviders]]">
|
||||
<p>[[localize('ui.panel.page-authorize.initializing')]]</p>
|
||||
</template>
|
||||
|
||||
<template is="dom-if" if="[[_authProvider]]">
|
||||
<ha-auth-flow
|
||||
client-id="[[clientId]]"
|
||||
redirect-uri="[[redirectUri]]"
|
||||
oauth2-state="[[oauth2State]]"
|
||||
auth-provider="[[_authProvider]]"
|
||||
on-reset="_handleReset"
|
||||
></ha-auth-flow>
|
||||
</template>
|
||||
<template is="dom-if" if="[[!_authProvider]]">
|
||||
<template is="dom-if" if="[[_authProviders]]">
|
||||
<ha-markdown content='[[_computeIntro(localize, clientId, _authProvider)]]'></ha-markdown>
|
||||
|
||||
<ha-auth-flow
|
||||
resources="[[resources]]"
|
||||
client-id="[[clientId]]"
|
||||
redirect-uri="[[redirectUri]]"
|
||||
oauth2-state="[[oauth2State]]"
|
||||
auth-provider="[[_authProvider]]"
|
||||
step="{{step}}"
|
||||
></ha-auth-flow>
|
||||
|
||||
<template is="dom-if" if="[[_computeMultiple(_authProviders)]]">
|
||||
<ha-pick-auth-provider
|
||||
resources="[[resources]]"
|
||||
client-id="[[clientId]]"
|
||||
auth-providers="[[_computeInactiveProvders(_authProvider, _authProviders)]]"
|
||||
on-pick="_handleAuthProviderPick"
|
||||
></ha-pick-auth-provider>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
_authProvider: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
_authProvider: String,
|
||||
_authProviders: Array,
|
||||
clientId: String,
|
||||
redirectUri: String,
|
||||
oauth2State: String,
|
||||
translationFragment: {
|
||||
type: String,
|
||||
value: "page-authorize",
|
||||
},
|
||||
};
|
||||
}
|
||||
ready() {
|
||||
|
||||
async ready() {
|
||||
super.ready();
|
||||
const query = {};
|
||||
const values = location.search.substr(1).split('&');
|
||||
const values = location.search.substr(1).split("&");
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
const value = values[i].split('=');
|
||||
const value = values[i].split("=");
|
||||
if (value.length > 1) {
|
||||
query[decodeURIComponent(value[0])] = decodeURIComponent(value[1]);
|
||||
}
|
||||
@@ -85,12 +86,67 @@ class HaAuthorize extends PolymerElement {
|
||||
if (query.redirect_uri) props.redirectUri = query.redirect_uri;
|
||||
if (query.state) props.oauth2State = query.state;
|
||||
this.setProperties(props);
|
||||
|
||||
import(/* webpackChunkName: "pick-auth-provider" */ "../auth/ha-pick-auth-provider.js");
|
||||
|
||||
// Fetch auth providers
|
||||
try {
|
||||
const response = await window.providersPromise;
|
||||
const authProviders = await response.json();
|
||||
|
||||
// Forward to main screen which will redirect to right onboarding page.
|
||||
if (
|
||||
response.status === 400 &&
|
||||
authProviders.code === "onboarding_required"
|
||||
) {
|
||||
location.href = "/";
|
||||
return;
|
||||
}
|
||||
|
||||
if (authProviders.length === 0) {
|
||||
alert("No auth providers returned. Unable to finish login.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
_authProviders: authProviders,
|
||||
_authProvider: authProviders[0],
|
||||
});
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.error("Error loading auth providers", err);
|
||||
this._state = "error-loading";
|
||||
}
|
||||
}
|
||||
_handleAuthProviderPick(ev) {
|
||||
|
||||
_computeMultiple(array) {
|
||||
return array && array.length > 1;
|
||||
}
|
||||
|
||||
async _handleAuthProviderPick(ev) {
|
||||
this._authProvider = ev.detail;
|
||||
}
|
||||
_handleReset() {
|
||||
this._authProvider = null;
|
||||
|
||||
_computeInactiveProvders(curProvider, providers) {
|
||||
return providers.filter(
|
||||
(prv) => prv.type !== curProvider.type || prv.id !== curProvider.id
|
||||
);
|
||||
}
|
||||
|
||||
_computeIntro(localize, clientId, authProvider) {
|
||||
return (
|
||||
localize(
|
||||
"ui.panel.page-authorize.authorizing_client",
|
||||
"clientId",
|
||||
clientId
|
||||
) +
|
||||
"\n\n" +
|
||||
localize(
|
||||
"ui.panel.page-authorize.logging_in_with",
|
||||
"authProviderName",
|
||||
authProvider.name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
customElements.define('ha-authorize', HaAuthorize);
|
||||
customElements.define("ha-authorize", HaAuthorize);
|
||||
|
@@ -1,14 +1,17 @@
|
||||
import '@polymer/paper-item/paper-item.js';
|
||||
import '@polymer/paper-item/paper-item-body.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import "@polymer/paper-item/paper-item.js";
|
||||
import "@polymer/paper-item/paper-item-body.js";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import EventsMixin from '../mixins/events-mixin.js';
|
||||
import EventsMixin from "../mixins/events-mixin.js";
|
||||
import LocalizeLiteMixin from "../mixins/localize-lite-mixin.js";
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
*/
|
||||
class HaPickAuthProvider extends EventsMixin(PolymerElement) {
|
||||
class HaPickAuthProvider extends EventsMixin(
|
||||
LocalizeLiteMixin(PolymerElement)
|
||||
) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
@@ -19,23 +22,12 @@ class HaPickAuthProvider extends EventsMixin(PolymerElement) {
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
<template is="dom-if" if="[[_equal(_state, "loading")]]">
|
||||
Loading auth providers.
|
||||
</template>
|
||||
<template is="dom-if" if="[[_equal(_state, "no-results")]]">
|
||||
No auth providers found.
|
||||
</template>
|
||||
<template is="dom-if" if="[[_equal(_state, "error-loading")]]">
|
||||
Error loading
|
||||
</template>
|
||||
<template is="dom-if" if="[[_equal(_state, "pick")]]">
|
||||
<p>Pick an auth provider to log in with:</p>
|
||||
<template is="dom-repeat" items="[[authProviders]]">
|
||||
<paper-item on-click="_handlePick">
|
||||
<paper-item-body>[[item.name]]</paper-item-body>
|
||||
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||
</paper-item>
|
||||
</template>
|
||||
<p>[[localize('ui.panel.page-authorize.pick_auth_provider')]]:</p>
|
||||
<template is="dom-repeat" items="[[authProviders]]">
|
||||
<paper-item on-click="_handlePick">
|
||||
<paper-item-body>[[item.name]]</paper-item-body>
|
||||
<iron-icon icon="hass:chevron-right"></iron-icon>
|
||||
</paper-item>
|
||||
</template>
|
||||
`;
|
||||
}
|
||||
@@ -44,39 +36,18 @@ class HaPickAuthProvider extends EventsMixin(PolymerElement) {
|
||||
return {
|
||||
_state: {
|
||||
type: String,
|
||||
value: 'loading'
|
||||
value: "loading",
|
||||
},
|
||||
authProviders: Array,
|
||||
clientId: String,
|
||||
};
|
||||
}
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
fetch('/auth/providers', { credentials: 'same-origin' }).then((response) => {
|
||||
if (!response.ok) throw new Error();
|
||||
return response.json();
|
||||
}).then((authProviders) => {
|
||||
this.setProperties({
|
||||
authProviders,
|
||||
_state: 'pick',
|
||||
});
|
||||
if (authProviders.length === 1) {
|
||||
this.fire('pick', authProviders[0]);
|
||||
}
|
||||
}).catch((err) => {
|
||||
// eslint-disable-next-line
|
||||
console.error('Error loading auth providers', err);
|
||||
this._state = 'error-loading';
|
||||
});
|
||||
}
|
||||
|
||||
_handlePick(ev) {
|
||||
this.fire('pick', ev.model.item);
|
||||
this.fire("pick", ev.model.item);
|
||||
}
|
||||
|
||||
_equal(a, b) {
|
||||
return a === b;
|
||||
}
|
||||
}
|
||||
customElements.define('ha-pick-auth-provider', HaPickAuthProvider);
|
||||
customElements.define("ha-pick-auth-provider", HaPickAuthProvider);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/entity/ha-state-label-badge.js';
|
||||
import "../components/entity/ha-state-label-badge.js";
|
||||
|
||||
class HaBadgesCard extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -25,4 +25,4 @@ class HaBadgesCard extends PolymerElement {
|
||||
};
|
||||
}
|
||||
}
|
||||
customElements.define('ha-badges-card', HaBadgesCard);
|
||||
customElements.define("ha-badges-card", HaBadgesCard);
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import '@polymer/paper-styles/element-styles/paper-material-styles.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import "@polymer/paper-styles/element-styles/paper-material-styles.js";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
|
||||
import computeStateName from '../common/entity/compute_state_name.js';
|
||||
import EventsMixin from '../mixins/events-mixin.js';
|
||||
import LocalizeMixin from '../mixins/localize-mixin.js';
|
||||
import computeStateName from "../common/entity/compute_state_name.js";
|
||||
import EventsMixin from "../mixins/events-mixin.js";
|
||||
import LocalizeMixin from "../mixins/localize-mixin.js";
|
||||
|
||||
const UPDATE_INTERVAL = 10000; // ms
|
||||
/*
|
||||
@@ -67,11 +66,11 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
hass: Object,
|
||||
stateObj: {
|
||||
type: Object,
|
||||
observer: 'updateCameraFeedSrc',
|
||||
observer: "updateCameraFeedSrc",
|
||||
},
|
||||
cameraFeedSrc: {
|
||||
type: String,
|
||||
value: '',
|
||||
value: "",
|
||||
},
|
||||
imageLoaded: {
|
||||
type: Boolean,
|
||||
@@ -82,7 +81,7 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
|
||||
ready() {
|
||||
super.ready();
|
||||
this.addEventListener('click', () => this.cardTapped());
|
||||
this.addEventListener("click", () => this.cardTapped());
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -96,13 +95,13 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
}
|
||||
|
||||
cardTapped() {
|
||||
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
|
||||
this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
|
||||
}
|
||||
|
||||
async updateCameraFeedSrc() {
|
||||
try {
|
||||
const { content_type: contentType, content } = await this.hass.callWS({
|
||||
type: 'camera_thumbnail',
|
||||
type: "camera_thumbnail",
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
this.setProperties({
|
||||
@@ -118,4 +117,4 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
return computeStateName(stateObj);
|
||||
}
|
||||
}
|
||||
customElements.define('ha-camera-card', HaCameraCard);
|
||||
customElements.define("ha-camera-card", HaCameraCard);
|
||||
|
@@ -1,28 +1,29 @@
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import './ha-camera-card.js';
|
||||
import './ha-entities-card.js';
|
||||
import './ha-history_graph-card.js';
|
||||
import './ha-media_player-card.js';
|
||||
import './ha-persistent_notification-card.js';
|
||||
import './ha-plant-card.js';
|
||||
import './ha-weather-card.js';
|
||||
import "./ha-camera-card.js";
|
||||
import "./ha-entities-card.js";
|
||||
import "./ha-history_graph-card.js";
|
||||
import "./ha-media_player-card.js";
|
||||
import "./ha-persistent_notification-card.js";
|
||||
import "./ha-plant-card.js";
|
||||
import "./ha-weather-card.js";
|
||||
|
||||
import dynamicContentUpdater from '../common/dom/dynamic_content_updater.js';
|
||||
import dynamicContentUpdater from "../common/dom/dynamic_content_updater.js";
|
||||
|
||||
class HaCardChooser extends PolymerElement {
|
||||
static get properties() {
|
||||
return {
|
||||
cardData: {
|
||||
type: Object,
|
||||
observer: 'cardDataChanged',
|
||||
observer: "cardDataChanged",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_updateCard(newData) {
|
||||
dynamicContentUpdater(
|
||||
this, 'HA-' + newData.cardType.toUpperCase() + '-CARD',
|
||||
this,
|
||||
"HA-" + newData.cardType.toUpperCase() + "-CARD",
|
||||
newData
|
||||
);
|
||||
}
|
||||
@@ -32,7 +33,7 @@ class HaCardChooser extends PolymerElement {
|
||||
this.observer = new IntersectionObserver((entries) => {
|
||||
if (!entries.length) return;
|
||||
if (entries[0].isIntersecting) {
|
||||
this.style.height = '';
|
||||
this.style.height = "";
|
||||
if (this._detachedChild) {
|
||||
this.appendChild(this._detachedChild);
|
||||
this._detachedChild = null;
|
||||
@@ -59,13 +60,13 @@ class HaCardChooser extends PolymerElement {
|
||||
// ha-entities-card is exempt from observer as it doesn't load heavy resources.
|
||||
// and usually doesn't load external resources (except for entity_picture).
|
||||
const eligibleToObserver =
|
||||
(window.IntersectionObserver && newData.cardType !== 'entities');
|
||||
window.IntersectionObserver && newData.cardType !== "entities";
|
||||
if (!eligibleToObserver) {
|
||||
if (this.observer) {
|
||||
this.observer.unobserve(this);
|
||||
this.observer = null;
|
||||
}
|
||||
this.style.height = '';
|
||||
this.style.height = "";
|
||||
this._updateCard(newData);
|
||||
return;
|
||||
}
|
||||
@@ -77,4 +78,4 @@ class HaCardChooser extends PolymerElement {
|
||||
}
|
||||
}
|
||||
}
|
||||
customElements.define('ha-card-chooser', HaCardChooser);
|
||||
customElements.define("ha-card-chooser", HaCardChooser);
|
||||
|
@@ -1,18 +1,17 @@
|
||||
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 "@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 '../components/entity/ha-entity-toggle.js';
|
||||
import '../components/ha-card.js';
|
||||
import '../state-summary/state-card-content.js';
|
||||
import "../components/entity/ha-entity-toggle.js";
|
||||
import "../components/ha-card.js";
|
||||
import "../state-summary/state-card-content.js";
|
||||
|
||||
|
||||
import computeStateDomain from '../common/entity/compute_state_domain.js';
|
||||
import computeStateName from '../common/entity/compute_state_name.js';
|
||||
import stateMoreInfoType from '../common/entity/state_more_info_type.js';
|
||||
import canToggleState from '../common/entity/can_toggle_state.js';
|
||||
import EventsMixin from '../mixins/events-mixin.js';
|
||||
import LocalizeMixin from '../mixins/localize-mixin.js';
|
||||
import computeStateDomain from "../common/entity/compute_state_domain.js";
|
||||
import computeStateName from "../common/entity/compute_state_name.js";
|
||||
import stateMoreInfoType from "../common/entity/state_more_info_type.js";
|
||||
import canToggleState from "../common/entity/can_toggle_state.js";
|
||||
import EventsMixin from "../mixins/events-mixin.js";
|
||||
import LocalizeMixin from "../mixins/localize-mixin.js";
|
||||
|
||||
class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
@@ -74,7 +73,7 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
groupEntity: Object,
|
||||
title: {
|
||||
type: String,
|
||||
computed: 'computeTitle(states, groupEntity, localize)',
|
||||
computed: "computeTitle(states, groupEntity, localize)",
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -91,34 +90,40 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
return computeStateName(groupEntity).trim();
|
||||
}
|
||||
const domain = computeStateDomain(states[0]);
|
||||
return (localize && localize(`domain.${domain}`)) || domain.replace(/_/g, ' ');
|
||||
return (
|
||||
(localize && localize(`domain.${domain}`)) || domain.replace(/_/g, " ")
|
||||
);
|
||||
}
|
||||
|
||||
computeTitleClass(groupEntity) {
|
||||
let classes = 'header horizontal layout center ';
|
||||
let classes = "header horizontal layout center ";
|
||||
if (groupEntity) {
|
||||
classes += 'more-info';
|
||||
classes += "more-info";
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
computeStateClass(stateObj) {
|
||||
return stateMoreInfoType(stateObj) !== 'hidden' ? 'state more-info' : 'state';
|
||||
return stateMoreInfoType(stateObj) !== "hidden"
|
||||
? "state more-info"
|
||||
: "state";
|
||||
}
|
||||
|
||||
addTapEvents() {
|
||||
const cards = this.root.querySelectorAll('.state');
|
||||
const cards = this.root.querySelectorAll(".state");
|
||||
cards.forEach((card) => {
|
||||
if (card.classList.contains('more-info')) {
|
||||
card.addEventListener('click', this.entityTapped);
|
||||
if (card.classList.contains("more-info")) {
|
||||
card.addEventListener("click", this.entityTapped);
|
||||
} else {
|
||||
card.removeEventListener('click', this.entityTapped);
|
||||
card.removeEventListener("click", this.entityTapped);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
entityTapped(ev) {
|
||||
const item = this.root.querySelector('dom-repeat').itemForElement(ev.target);
|
||||
const item = this.root
|
||||
.querySelector("dom-repeat")
|
||||
.itemForElement(ev.target);
|
||||
let entityId;
|
||||
if (!item && !this.groupEntity) {
|
||||
return;
|
||||
@@ -130,12 +135,16 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
} else {
|
||||
entityId = this.groupEntity.entity_id;
|
||||
}
|
||||
this.fire('hass-more-info', { entityId: entityId });
|
||||
this.fire("hass-more-info", { entityId: entityId });
|
||||
}
|
||||
|
||||
showGroupToggle(groupEntity, states) {
|
||||
if (!groupEntity || !states || groupEntity.attributes.control === 'hidden' ||
|
||||
(groupEntity.state !== 'on' && groupEntity.state !== 'off')) {
|
||||
if (
|
||||
!groupEntity ||
|
||||
!states ||
|
||||
groupEntity.attributes.control === "hidden" ||
|
||||
(groupEntity.state !== "on" && groupEntity.state !== "off")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -156,4 +165,4 @@ class HaEntitiesCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
return canToggleCount > 1;
|
||||
}
|
||||
}
|
||||
customElements.define('ha-entities-card', HaEntitiesCard);
|
||||
customElements.define("ha-entities-card", HaEntitiesCard);
|
||||
|
@@ -1,13 +1,12 @@
|
||||
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 "@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 '../components/state-history-charts.js';
|
||||
import '../data/ha-state-history-data.js';
|
||||
import "../components/state-history-charts.js";
|
||||
import "../data/ha-state-history-data";
|
||||
|
||||
|
||||
import computeStateName from '../common/entity/compute_state_name.js';
|
||||
import EventsMixin from '../mixins/events-mixin.js';
|
||||
import computeStateName from "../common/entity/compute_state_name.js";
|
||||
import EventsMixin from "../mixins/events-mixin.js";
|
||||
|
||||
/*
|
||||
* @appliesMixin EventsMixin
|
||||
@@ -55,7 +54,7 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
|
||||
hass: Object,
|
||||
stateObj: {
|
||||
type: Object,
|
||||
observer: 'stateObjObserver',
|
||||
observer: "stateObjObserver",
|
||||
},
|
||||
inDialog: {
|
||||
type: Boolean,
|
||||
@@ -76,14 +75,19 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
|
||||
|
||||
stateObjObserver(stateObj) {
|
||||
if (!stateObj) return;
|
||||
if (this.cacheConfig.cacheKey !== stateObj.entity_id ||
|
||||
this.cacheConfig.refresh !== (stateObj.attributes.refresh || 0) ||
|
||||
this.cacheConfig.hoursToShow !== (stateObj.attributes.hours_to_show || 24)) {
|
||||
this.cacheConfig = Object.assign({}, {
|
||||
refresh: stateObj.attributes.refresh || 0,
|
||||
cacheKey: stateObj.entity_id,
|
||||
hoursToShow: stateObj.attributes.hours_to_show || 24
|
||||
});
|
||||
if (
|
||||
this.cacheConfig.cacheKey !== stateObj.entity_id ||
|
||||
this.cacheConfig.refresh !== (stateObj.attributes.refresh || 0) ||
|
||||
this.cacheConfig.hoursToShow !== (stateObj.attributes.hours_to_show || 24)
|
||||
) {
|
||||
this.cacheConfig = Object.assign(
|
||||
{},
|
||||
{
|
||||
refresh: stateObj.attributes.refresh || 0,
|
||||
cacheKey: stateObj.entity_id,
|
||||
hoursToShow: stateObj.attributes.hours_to_show || 24,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +96,7 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
computeContentClass(inDialog) {
|
||||
return inDialog ? '' : 'content';
|
||||
return inDialog ? "" : "content";
|
||||
}
|
||||
|
||||
computeHistoryEntities(stateObj) {
|
||||
@@ -104,11 +108,11 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
cardTapped(ev) {
|
||||
const mq = window.matchMedia('(min-width: 610px) and (min-height: 550px)');
|
||||
const mq = window.matchMedia("(min-width: 610px) and (min-height: 550px)");
|
||||
if (mq.matches) {
|
||||
ev.stopPropagation();
|
||||
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
|
||||
this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
|
||||
}
|
||||
}
|
||||
}
|
||||
customElements.define('ha-history_graph-card', HaHistoryGraphCard);
|
||||
customElements.define("ha-history_graph-card", HaHistoryGraphCard);
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import '@polymer/iron-flex-layout/iron-flex-layout-classes.js';
|
||||
import '@polymer/paper-icon-button/paper-icon-button.js';
|
||||
import '@polymer/paper-progress/paper-progress.js';
|
||||
import '@polymer/paper-styles/element-styles/paper-material-styles.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes.js";
|
||||
import "@polymer/paper-icon-button/paper-icon-button.js";
|
||||
import "@polymer/paper-progress/paper-progress.js";
|
||||
import "@polymer/paper-styles/element-styles/paper-material-styles.js";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import HassMediaPlayerEntity from '../util/hass-media-player-model.js';
|
||||
import HassMediaPlayerEntity from "../util/hass-media-player-model.js";
|
||||
|
||||
import computeStateName from '../common/entity/compute_state_name.js';
|
||||
import EventsMixin from '../mixins/events-mixin.js';
|
||||
import LocalizeMixin from '../mixins/localize-mixin.js';
|
||||
import computeStateName from "../common/entity/compute_state_name.js";
|
||||
import EventsMixin from "../mixins/events-mixin.js";
|
||||
import LocalizeMixin from "../mixins/localize-mixin.js";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
@@ -189,12 +189,12 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
stateObj: Object,
|
||||
playerObj: {
|
||||
type: Object,
|
||||
computed: 'computePlayerObj(hass, stateObj)',
|
||||
observer: 'playerObjChanged',
|
||||
computed: "computePlayerObj(hass, stateObj)",
|
||||
observer: "playerObjChanged",
|
||||
},
|
||||
playbackControlIcon: {
|
||||
type: String,
|
||||
computed: 'computePlaybackControlIcon(playerObj)',
|
||||
computed: "computePlaybackControlIcon(playerObj)",
|
||||
},
|
||||
playbackPosition: Number,
|
||||
};
|
||||
@@ -203,7 +203,10 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
async playerObjChanged(playerObj, oldPlayerObj) {
|
||||
if (playerObj.isPlaying && playerObj.showProgress) {
|
||||
if (!this._positionTracking) {
|
||||
this._positionTracking = setInterval(() => this.updatePlaybackPosition(), 1000);
|
||||
this._positionTracking = setInterval(
|
||||
() => this.updatePlaybackPosition(),
|
||||
1000
|
||||
);
|
||||
}
|
||||
} else if (this._positionTracking) {
|
||||
clearInterval(this._positionTracking);
|
||||
@@ -214,25 +217,27 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
}
|
||||
|
||||
const picture = playerObj.stateObj.attributes.entity_picture;
|
||||
const oldPicture = oldPlayerObj && oldPlayerObj.stateObj.attributes.entity_picture;
|
||||
const oldPicture =
|
||||
oldPlayerObj && oldPlayerObj.stateObj.attributes.entity_picture;
|
||||
|
||||
if (picture !== oldPicture && !picture) {
|
||||
this.$.cover.style.backgroundImage = '';
|
||||
this.$.cover.style.backgroundImage = "";
|
||||
return;
|
||||
} else if (picture === oldPicture) {
|
||||
}
|
||||
if (picture === oldPicture) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We have a new picture url
|
||||
try {
|
||||
const { content_type: contentType, content } = await this.hass.callWS({
|
||||
type: 'media_player_thumbnail',
|
||||
type: "media_player_thumbnail",
|
||||
entity_id: playerObj.stateObj.entity_id,
|
||||
});
|
||||
this.$.cover.style.backgroundImage = `url(data:${contentType};base64,${content})`;
|
||||
} catch (err) {
|
||||
this.$.cover.style.backgroundImage = '';
|
||||
this.$.cover.parentElement.classList.add('no-cover');
|
||||
this.$.cover.style.backgroundImage = "";
|
||||
this.$.cover.parentElement.classList.add("no-cover");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,14 +246,14 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
}
|
||||
|
||||
computeBannerClasses(playerObj) {
|
||||
var cls = 'banner';
|
||||
var cls = "banner";
|
||||
|
||||
if (playerObj.isOff || playerObj.isIdle) {
|
||||
cls += ' is-off no-cover';
|
||||
cls += " is-off no-cover";
|
||||
} else if (!playerObj.stateObj.attributes.entity_picture) {
|
||||
cls += ' no-cover';
|
||||
} else if (playerObj.stateObj.attributes.media_content_type === 'music') {
|
||||
cls += ' content-type-music';
|
||||
cls += " no-cover";
|
||||
} else if (playerObj.stateObj.attributes.media_content_type === "music") {
|
||||
cls += " content-type-music";
|
||||
}
|
||||
|
||||
return cls;
|
||||
@@ -259,7 +264,9 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
}
|
||||
|
||||
computeHidePowerButton(playerObj) {
|
||||
return playerObj.isOff ? !playerObj.supportsTurnOn : !playerObj.supportsTurnOff;
|
||||
return playerObj.isOff
|
||||
? !playerObj.supportsTurnOn
|
||||
: !playerObj.supportsTurnOff;
|
||||
}
|
||||
|
||||
computePlayerObj(hass, stateObj) {
|
||||
@@ -267,21 +274,29 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
}
|
||||
|
||||
computePrimaryText(localize, playerObj) {
|
||||
return playerObj.primaryTitle
|
||||
|| localize(`state.media_player.${playerObj.stateObj.state}`)
|
||||
|| localize(`state.default.${playerObj.stateObj.state}`) || playerObj.stateObj.state;
|
||||
return (
|
||||
playerObj.primaryTitle ||
|
||||
localize(`state.media_player.${playerObj.stateObj.state}`) ||
|
||||
localize(`state.default.${playerObj.stateObj.state}`) ||
|
||||
playerObj.stateObj.state
|
||||
);
|
||||
}
|
||||
|
||||
computePlaybackControlIcon(playerObj) {
|
||||
if (playerObj.isPlaying) {
|
||||
return playerObj.supportsPause ? 'hass:pause' : 'hass:stop';
|
||||
} else if (playerObj.hasMediaControl || playerObj.isOff || playerObj.isIdle) {
|
||||
if (playerObj.hasMediaControl && playerObj.supportsPause && !playerObj.isPaused) {
|
||||
return 'hass:play-pause';
|
||||
}
|
||||
return playerObj.supportsPlay ? 'hass:play' : null;
|
||||
return playerObj.supportsPause ? "hass:pause" : "hass:stop";
|
||||
}
|
||||
return '';
|
||||
if (playerObj.hasMediaControl || playerObj.isOff || playerObj.isIdle) {
|
||||
if (
|
||||
playerObj.hasMediaControl &&
|
||||
playerObj.supportsPause &&
|
||||
!playerObj.isPaused
|
||||
) {
|
||||
return "hass:play-pause";
|
||||
}
|
||||
return playerObj.supportsPlay ? "hass:play" : null;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
_computeStateName(stateObj) {
|
||||
@@ -295,7 +310,7 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
|
||||
handleOpenMoreInfo(ev) {
|
||||
ev.stopPropagation();
|
||||
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
|
||||
this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
|
||||
}
|
||||
|
||||
handlePlaybackControl(ev) {
|
||||
@@ -313,4 +328,4 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
this.playerObj.togglePower();
|
||||
}
|
||||
}
|
||||
customElements.define('ha-media_player-card', HaMediaPlayerCard);
|
||||
customElements.define("ha-media_player-card", HaMediaPlayerCard);
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import '@polymer/paper-button/paper-button.js';
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import "@polymer/paper-button/paper-button.js";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/ha-card.js';
|
||||
import '../components/ha-markdown.js';
|
||||
import "../components/ha-card.js";
|
||||
import "../components/ha-markdown.js";
|
||||
|
||||
|
||||
import computeStateName from '../common/entity/compute_state_name.js';
|
||||
import LocalizeMixin from '../mixins/localize-mixin.js';
|
||||
import computeStateName from "../common/entity/compute_state_name.js";
|
||||
import LocalizeMixin from "../mixins/localize-mixin.js";
|
||||
import computeObjectId from "../common/entity/compute_object_id";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
@@ -59,13 +59,17 @@ class HaPersistentNotificationCard extends LocalizeMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
computeTitle(stateObj) {
|
||||
return (stateObj.attributes.title ||
|
||||
computeStateName(stateObj));
|
||||
return stateObj.attributes.title || computeStateName(stateObj);
|
||||
}
|
||||
|
||||
dismissTap(ev) {
|
||||
ev.preventDefault();
|
||||
this.hass.callApi('DELETE', 'states/' + this.stateObj.entity_id);
|
||||
this.hass.callService("persistent_notification", "dismiss", {
|
||||
notification_id: computeObjectId(this.stateObj.entity_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
customElements.define('ha-persistent_notification-card', HaPersistentNotificationCard);
|
||||
customElements.define(
|
||||
"ha-persistent_notification-card",
|
||||
HaPersistentNotificationCard
|
||||
);
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/ha-card.js';
|
||||
import '../components/ha-icon.js';
|
||||
import "../components/ha-card.js";
|
||||
import "../components/ha-icon.js";
|
||||
|
||||
import computeStateName from '../common/entity/compute_state_name.js';
|
||||
import EventsMixin from '../mixins/events-mixin.js';
|
||||
import computeStateName from "../common/entity/compute_state_name.js";
|
||||
import EventsMixin from "../mixins/events-mixin.js";
|
||||
|
||||
class HaPlantCard extends EventsMixin(PolymerElement) {
|
||||
static get template() {
|
||||
@@ -85,18 +85,18 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
stateObj: Object
|
||||
stateObj: Object,
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.sensors = {
|
||||
moisture: 'hass:water',
|
||||
temperature: 'hass:thermometer',
|
||||
brightness: 'hass:white-balance-sunny',
|
||||
conductivity: 'hass:emoticon-poop',
|
||||
battery: 'hass:battery'
|
||||
moisture: "hass:water",
|
||||
temperature: "hass:thermometer",
|
||||
brightness: "hass:white-balance-sunny",
|
||||
conductivity: "hass:emoticon-poop",
|
||||
battery: "hass:battery",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -105,16 +105,17 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
computeAttributes(data) {
|
||||
return Object.keys(this.sensors).filter(key => key in data);
|
||||
return Object.keys(this.sensors).filter((key) => key in data);
|
||||
}
|
||||
|
||||
computeIcon(attr, batLvl) {
|
||||
const icon = this.sensors[attr];
|
||||
if (attr === 'battery') {
|
||||
if (attr === "battery") {
|
||||
if (batLvl <= 5) {
|
||||
return `${icon}-alert`;
|
||||
} else if (batLvl < 95) {
|
||||
return `${icon}-${Math.round((batLvl / 10) - 0.01) * 10}`;
|
||||
}
|
||||
if (batLvl < 95) {
|
||||
return `${icon}-${Math.round(batLvl / 10 - 0.01) * 10}`;
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
@@ -125,20 +126,22 @@ class HaPlantCard extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
|
||||
computeUom(dict, attr) {
|
||||
return dict[attr] || '';
|
||||
return dict[attr] || "";
|
||||
}
|
||||
|
||||
computeAttributeClass(problem, attr) {
|
||||
return problem.indexOf(attr) === -1 ? '' : 'problem';
|
||||
return problem.indexOf(attr) === -1 ? "" : "problem";
|
||||
}
|
||||
|
||||
computeImageClass(entityPicture) {
|
||||
return entityPicture ? 'has-plant-image' : '';
|
||||
return entityPicture ? "has-plant-image" : "";
|
||||
}
|
||||
|
||||
attributeClicked(ev) {
|
||||
this.fire('hass-more-info', { entityId: this.stateObj.attributes.sensors[ev.model.item] });
|
||||
this.fire("hass-more-info", {
|
||||
entityId: this.stateObj.attributes.sensors[ev.model.item],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ha-plant-card', HaPlantCard);
|
||||
customElements.define("ha-plant-card", HaPlantCard);
|
||||
|
@@ -1,17 +1,16 @@
|
||||
import { html } from '@polymer/polymer/lib/utils/html-tag.js';
|
||||
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag.js";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element.js";
|
||||
|
||||
import '../components/ha-card.js';
|
||||
import '../components/ha-icon.js';
|
||||
import "../components/ha-card.js";
|
||||
import "../components/ha-icon.js";
|
||||
|
||||
import EventsMixin from '../mixins/events-mixin.js';
|
||||
import LocalizeMixin from '../mixins/localize-mixin.js';
|
||||
import EventsMixin from "../mixins/events-mixin.js";
|
||||
import LocalizeMixin from "../mixins/localize-mixin.js";
|
||||
|
||||
/*
|
||||
* @appliesMixin LocalizeMixin
|
||||
*/
|
||||
class HaWeatherCard extends
|
||||
LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
static get template() {
|
||||
return html`
|
||||
<style>
|
||||
@@ -129,11 +128,11 @@ class HaWeatherCard extends
|
||||
<template is="dom-repeat" items="[[forecast]]">
|
||||
<div>
|
||||
<div class="weekday">[[computeDate(item.datetime)]]<br>
|
||||
<template is="dom-if" if="[[!item.templow]]">
|
||||
<template is="dom-if" if="[[!_showValue(item.templow)]]">
|
||||
[[computeTime(item.datetime)]]
|
||||
</template>
|
||||
</div>
|
||||
<template is="dom-if" if="[[item.condition]]">
|
||||
<template is="dom-if" if="[[_showValue(item.condition)]]">
|
||||
<div class="icon">
|
||||
<ha-icon icon="[[getWeatherIcon(item.condition)]]"></ha-icon>
|
||||
</div>
|
||||
@@ -160,42 +159,57 @@ class HaWeatherCard extends
|
||||
stateObj: Object,
|
||||
forecast: {
|
||||
type: Array,
|
||||
computed: 'computeForecast(stateObj.attributes.forecast)'
|
||||
}
|
||||
computed: "computeForecast(stateObj.attributes.forecast)",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.cardinalDirections = [
|
||||
'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
|
||||
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'
|
||||
"N",
|
||||
"NNE",
|
||||
"NE",
|
||||
"ENE",
|
||||
"E",
|
||||
"ESE",
|
||||
"SE",
|
||||
"SSE",
|
||||
"S",
|
||||
"SSW",
|
||||
"SW",
|
||||
"WSW",
|
||||
"W",
|
||||
"WNW",
|
||||
"NW",
|
||||
"NNW",
|
||||
"N",
|
||||
];
|
||||
this.weatherIcons = {
|
||||
'clear-night': 'hass:weather-night',
|
||||
cloudy: 'hass:weather-cloudy',
|
||||
fog: 'hass:weather-fog',
|
||||
hail: 'hass:weather-hail',
|
||||
lightning: 'mid:weather-lightning',
|
||||
'lightning-rainy': 'hass:weather-lightning-rainy',
|
||||
partlycloudy: 'hass:weather-partlycloudy',
|
||||
pouring: 'hass:weather-pouring',
|
||||
rainy: 'hass:weather-rainy',
|
||||
snowy: 'hass:weather-snowy',
|
||||
'snowy-rainy': 'hass:weather-snowy-rainy',
|
||||
sunny: 'hass:weather-sunny',
|
||||
windy: 'hass:weather-windy',
|
||||
'windy-variant': 'hass:weather-windy-variant'
|
||||
"clear-night": "hass:weather-night",
|
||||
cloudy: "hass:weather-cloudy",
|
||||
fog: "hass:weather-fog",
|
||||
hail: "hass:weather-hail",
|
||||
lightning: "hass:weather-lightning",
|
||||
"lightning-rainy": "hass:weather-lightning-rainy",
|
||||
partlycloudy: "hass:weather-partlycloudy",
|
||||
pouring: "hass:weather-pouring",
|
||||
rainy: "hass:weather-rainy",
|
||||
snowy: "hass:weather-snowy",
|
||||
"snowy-rainy": "hass:weather-snowy-rainy",
|
||||
sunny: "hass:weather-sunny",
|
||||
windy: "hass:weather-windy",
|
||||
"windy-variant": "hass:weather-windy-variant",
|
||||
};
|
||||
}
|
||||
|
||||
ready() {
|
||||
this.addEventListener('click', this._onClick);
|
||||
this.addEventListener("click", this._onClick);
|
||||
super.ready();
|
||||
}
|
||||
|
||||
_onClick() {
|
||||
this.fire('hass-more-info', { entityId: this.stateObj.entity_id });
|
||||
this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
|
||||
}
|
||||
|
||||
computeForecast(forecast) {
|
||||
@@ -203,16 +217,16 @@ class HaWeatherCard extends
|
||||
}
|
||||
|
||||
getUnit(measure) {
|
||||
const lengthUnit = this.hass.config.core.unit_system.length || '';
|
||||
const lengthUnit = this.hass.config.unit_system.length || "";
|
||||
switch (measure) {
|
||||
case 'air_pressure':
|
||||
return lengthUnit === 'km' ? 'hPa' : 'inHg';
|
||||
case 'length':
|
||||
case "air_pressure":
|
||||
return lengthUnit === "km" ? "hPa" : "inHg";
|
||||
case "length":
|
||||
return lengthUnit;
|
||||
case 'precipitation':
|
||||
return lengthUnit === 'km' ? 'mm' : 'in';
|
||||
case "precipitation":
|
||||
return lengthUnit === "km" ? "mm" : "in";
|
||||
default:
|
||||
return this.hass.config.core.unit_system[measure] || '';
|
||||
return this.hass.config.unit_system[measure] || "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,20 +253,22 @@ class HaWeatherCard extends
|
||||
getWind(speed, bearing, localize) {
|
||||
if (bearing != null) {
|
||||
const cardinalDirection = this.windBearingToText(bearing);
|
||||
return `${speed} ${this.getUnit('length')}/h (${localize(`ui.card.weather.cardinal_direction.${cardinalDirection.toLowerCase()}`) || cardinalDirection})`;
|
||||
return `${speed} ${this.getUnit("length")}/h (${localize(
|
||||
`ui.card.weather.cardinal_direction.${cardinalDirection.toLowerCase()}`
|
||||
) || cardinalDirection})`;
|
||||
}
|
||||
return `${speed} ${this.getUnit('length')}/h`;
|
||||
return `${speed} ${this.getUnit("length")}/h`;
|
||||
}
|
||||
|
||||
_showValue(item) {
|
||||
return typeof item !== 'undefined' && item !== null;
|
||||
return typeof item !== "undefined" && item !== null;
|
||||
}
|
||||
|
||||
computeDate(data) {
|
||||
const date = new Date(data);
|
||||
return date.toLocaleDateString(
|
||||
this.hass.selectedLanguage || this.hass.language,
|
||||
{ weekday: 'short' }
|
||||
{ weekday: "short" }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -260,8 +276,8 @@ class HaWeatherCard extends
|
||||
const date = new Date(data);
|
||||
return date.toLocaleTimeString(
|
||||
this.hass.selectedLanguage || this.hass.language,
|
||||
{ hour: 'numeric' }
|
||||
{ hour: "numeric" }
|
||||
);
|
||||
}
|
||||
}
|
||||
customElements.define('ha-weather-card', HaWeatherCard);
|
||||
customElements.define("ha-weather-card", HaWeatherCard);
|
||||
|
78
src/common/auth/external_auth.js
Normal file
78
src/common/auth/external_auth.js
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Auth class that connects to a native app for authentication.
|
||||
*/
|
||||
import { Auth } from "home-assistant-js-websocket";
|
||||
|
||||
const CALLBACK_SET_TOKEN = "externalAuthSetToken";
|
||||
const CALLBACK_REVOKE_TOKEN = "externalAuthRevokeToken";
|
||||
|
||||
if (!window.externalApp && !window.webkit) {
|
||||
throw new Error(
|
||||
"External auth requires either externalApp or webkit defined on Window object."
|
||||
);
|
||||
}
|
||||
|
||||
export default class ExternalAuth extends Auth {
|
||||
constructor(hassUrl) {
|
||||
super();
|
||||
|
||||
this.data = {
|
||||
hassUrl,
|
||||
access_token: "",
|
||||
// This will trigger connection to do a refresh right away
|
||||
expires: 0,
|
||||
};
|
||||
}
|
||||
|
||||
async refreshAccessToken() {
|
||||
const responseProm = new Promise((resolve, reject) => {
|
||||
window[CALLBACK_SET_TOKEN] = (success, data) =>
|
||||
success ? resolve(data) : reject(data);
|
||||
});
|
||||
|
||||
// Allow promise to set resolve on window object.
|
||||
await 0;
|
||||
|
||||
const callbackPayload = { callback: CALLBACK_SET_TOKEN };
|
||||
|
||||
if (window.externalApp) {
|
||||
window.externalApp.getExternalAuth(callbackPayload);
|
||||
} else {
|
||||
window.webkit.messageHandlers.getExternalAuth.postMessage(
|
||||
callbackPayload
|
||||
);
|
||||
}
|
||||
|
||||
// Response we expect back:
|
||||
// {
|
||||
// "access_token": "qwere",
|
||||
// "expires_in": 1800
|
||||
// }
|
||||
const tokens = await responseProm;
|
||||
|
||||
this.data.access_token = tokens.access_token;
|
||||
this.data.expires = tokens.expires_in * 1000 + Date.now();
|
||||
}
|
||||
|
||||
async revoke() {
|
||||
const responseProm = new Promise((resolve, reject) => {
|
||||
window[CALLBACK_REVOKE_TOKEN] = (success, data) =>
|
||||
success ? resolve(data) : reject(data);
|
||||
});
|
||||
|
||||
// Allow promise to set resolve on window object.
|
||||
await 0;
|
||||
|
||||
const callbackPayload = { callback: CALLBACK_REVOKE_TOKEN };
|
||||
|
||||
if (window.externalApp) {
|
||||
window.externalApp.revokeExternalAuth(callbackPayload);
|
||||
} else {
|
||||
window.webkit.messageHandlers.revokeExternalAuth.postMessage(
|
||||
callbackPayload
|
||||
);
|
||||
}
|
||||
|
||||
await responseProm;
|
||||
}
|
||||
}
|
@@ -1,76 +0,0 @@
|
||||
import { storeTokens, loadTokens } from './token_storage.js';
|
||||
|
||||
function genClientId() {
|
||||
return `${location.protocol}//${location.host}/`;
|
||||
}
|
||||
|
||||
|
||||
export function redirectLogin() {
|
||||
document.location.href = `/auth/authorize?response_type=code&client_id=${encodeURIComponent(genClientId())}&redirect_uri=${encodeURIComponent(location.toString())}`;
|
||||
return new Promise((() => {}));
|
||||
}
|
||||
|
||||
|
||||
function fetchTokenRequest(code) {
|
||||
const data = new FormData();
|
||||
data.append('client_id', genClientId());
|
||||
data.append('grant_type', 'authorization_code');
|
||||
data.append('code', code);
|
||||
return fetch('/auth/token', {
|
||||
credentials: 'same-origin',
|
||||
method: 'POST',
|
||||
body: data,
|
||||
}).then((resp) => {
|
||||
if (!resp.ok) throw new Error('Unable to fetch tokens');
|
||||
return resp.json().then((tokens) => {
|
||||
tokens.expires = (tokens.expires_in * 1000) + Date.now();
|
||||
return tokens;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function refreshTokenRequest(tokens) {
|
||||
const data = new FormData();
|
||||
data.append('client_id', genClientId());
|
||||
data.append('grant_type', 'refresh_token');
|
||||
data.append('refresh_token', tokens.refresh_token);
|
||||
return fetch('/auth/token', {
|
||||
credentials: 'same-origin',
|
||||
method: 'POST',
|
||||
body: data,
|
||||
}).then((resp) => {
|
||||
if (!resp.ok) throw new Error('Unable to fetch tokens');
|
||||
return resp.json().then((newTokens) => {
|
||||
newTokens.expires = (newTokens.expires_in * 1000) + Date.now();
|
||||
return newTokens;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveCode(code) {
|
||||
return fetchTokenRequest(code).then((tokens) => {
|
||||
storeTokens(tokens);
|
||||
history.replaceState(null, null, location.pathname);
|
||||
return tokens;
|
||||
}, (err) => {
|
||||
// eslint-disable-next-line
|
||||
console.error('Resolve token failed', err);
|
||||
alert('Unable to fetch tokens');
|
||||
redirectLogin();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function refreshToken() {
|
||||
const tokens = loadTokens();
|
||||
|
||||
if (tokens === null) {
|
||||
return redirectLogin();
|
||||
}
|
||||
|
||||
return refreshTokenRequest(tokens).then((accessTokenResp) => {
|
||||
const newTokens = Object.assign({}, tokens, accessTokenResp);
|
||||
storeTokens(newTokens);
|
||||
return newTokens;
|
||||
}, () => redirectLogin());
|
||||
}
|
@@ -10,27 +10,31 @@ if (!tokenCache) {
|
||||
}
|
||||
|
||||
export function askWrite() {
|
||||
return tokenCache.tokens !== undefined && tokenCache.writeEnabled === undefined;
|
||||
return (
|
||||
tokenCache.tokens !== undefined && tokenCache.writeEnabled === undefined
|
||||
);
|
||||
}
|
||||
|
||||
export function storeTokens(tokens) {
|
||||
export function saveTokens(tokens) {
|
||||
tokenCache.tokens = tokens;
|
||||
if (tokenCache.writeEnabled) {
|
||||
try {
|
||||
storage.tokens = JSON.stringify(tokens);
|
||||
} catch (err) {} // eslint-disable-line
|
||||
storage.hassTokens = JSON.stringify(tokens);
|
||||
} catch (err) {} // eslint-disable-line
|
||||
}
|
||||
}
|
||||
|
||||
export function enableWrite() {
|
||||
tokenCache.writeEnabled = true;
|
||||
storeTokens(tokenCache.tokens);
|
||||
saveTokens(tokenCache.tokens);
|
||||
}
|
||||
|
||||
export function loadTokens() {
|
||||
if (tokenCache.tokens === undefined) {
|
||||
try {
|
||||
const tokens = storage.tokens;
|
||||
// Delete the old token cache.
|
||||
delete storage.tokens;
|
||||
const tokens = storage.hassTokens;
|
||||
if (tokens) {
|
||||
tokenCache.tokens = JSON.parse(tokens);
|
||||
tokenCache.writeEnabled = true;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/** Return if a component is loaded. */
|
||||
export default function isComponentLoaded(hass, component) {
|
||||
return hass && hass.config.core.components.indexOf(component) !== -1;
|
||||
return hass && hass.config.components.indexOf(component) !== -1;
|
||||
}
|
||||
|
4
src/common/config/is_pwa.js
Normal file
4
src/common/config/is_pwa.js
Normal file
@@ -0,0 +1,4 @@
|
||||
/** Return if the displaymode is in standalone mode (PWA). */
|
||||
export default function isPwa() {
|
||||
return window.matchMedia("(display-mode: standalone)").matches;
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
/** Get the location name from a hass object. */
|
||||
export default function computeLocationName(hass) {
|
||||
return hass && hass.config.core.location_name;
|
||||
return hass && hass.config.location_name;
|
||||
}
|
||||
|
@@ -5,82 +5,80 @@
|
||||
// Each constant should have a description what it is supposed to be used for.
|
||||
|
||||
/** Icon to use when no icon specified for domain. */
|
||||
export const DEFAULT_DOMAIN_ICON = 'hass:bookmark';
|
||||
export const DEFAULT_DOMAIN_ICON = "hass:bookmark";
|
||||
|
||||
/** Domains that have a state card. */
|
||||
export const DOMAINS_WITH_CARD = [
|
||||
'climate',
|
||||
'cover',
|
||||
'configurator',
|
||||
'input_select',
|
||||
'input_number',
|
||||
'input_text',
|
||||
'lock',
|
||||
'media_player',
|
||||
'scene',
|
||||
'script',
|
||||
'timer',
|
||||
'vacuum',
|
||||
'weblink',
|
||||
"climate",
|
||||
"cover",
|
||||
"configurator",
|
||||
"input_select",
|
||||
"input_number",
|
||||
"input_text",
|
||||
"lock",
|
||||
"media_player",
|
||||
"scene",
|
||||
"script",
|
||||
"timer",
|
||||
"vacuum",
|
||||
"water_heater",
|
||||
"weblink",
|
||||
];
|
||||
|
||||
/** Domains with separate more info dialog. */
|
||||
export const DOMAINS_WITH_MORE_INFO = [
|
||||
'alarm_control_panel',
|
||||
'automation',
|
||||
'camera',
|
||||
'climate',
|
||||
'configurator',
|
||||
'cover',
|
||||
'fan',
|
||||
'group',
|
||||
'history_graph',
|
||||
'input_datetime',
|
||||
'light',
|
||||
'lock',
|
||||
'media_player',
|
||||
'script',
|
||||
'sun',
|
||||
'updater',
|
||||
'vacuum',
|
||||
'weather'
|
||||
"alarm_control_panel",
|
||||
"automation",
|
||||
"camera",
|
||||
"climate",
|
||||
"configurator",
|
||||
"cover",
|
||||
"fan",
|
||||
"group",
|
||||
"history_graph",
|
||||
"input_datetime",
|
||||
"light",
|
||||
"lock",
|
||||
"media_player",
|
||||
"script",
|
||||
"sun",
|
||||
"updater",
|
||||
"vacuum",
|
||||
"water_heater",
|
||||
"weather",
|
||||
];
|
||||
|
||||
/** Domains that show no more info dialog. */
|
||||
export const DOMAINS_HIDE_MORE_INFO = [
|
||||
'input_number',
|
||||
'input_select',
|
||||
'input_text',
|
||||
'scene',
|
||||
'weblink'
|
||||
"input_number",
|
||||
"input_select",
|
||||
"input_text",
|
||||
"scene",
|
||||
"weblink",
|
||||
];
|
||||
|
||||
/** Domains that should have the history hidden in the more info dialog. */
|
||||
export const DOMAINS_MORE_INFO_NO_HISTORY = [
|
||||
'camera',
|
||||
'configurator',
|
||||
'history_graph',
|
||||
'scene',
|
||||
"camera",
|
||||
"configurator",
|
||||
"history_graph",
|
||||
"scene",
|
||||
];
|
||||
|
||||
/** States that we consider "off". */
|
||||
export const STATES_OFF = [
|
||||
'closed',
|
||||
'locked',
|
||||
'off'
|
||||
];
|
||||
export const STATES_OFF = ["closed", "locked", "off"];
|
||||
|
||||
/** Domains where we allow toggle in Lovelace. */
|
||||
export const DOMAINS_TOGGLE = new Set([
|
||||
'fan',
|
||||
'input_boolean',
|
||||
'light',
|
||||
'switch'
|
||||
"fan",
|
||||
"input_boolean",
|
||||
"light",
|
||||
"switch",
|
||||
]);
|
||||
|
||||
/** Temperature units. */
|
||||
export const UNIT_C = '°C';
|
||||
export const UNIT_F = '°F';
|
||||
export const UNIT_C = "°C";
|
||||
export const UNIT_F = "°F";
|
||||
|
||||
/** Entity ID of the default view. */
|
||||
export const DEFAULT_VIEW_ENTITY_ID = 'group.default_view';
|
||||
export const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
|
||||
|
@@ -1,4 +1,4 @@
|
||||
export default function durationToSeconds(duration) {
|
||||
const parts = duration.split(':').map(Number);
|
||||
return (parts[0] * 3600) + (parts[1] * 60) + parts[2];
|
||||
const parts = duration.split(":").map(Number);
|
||||
return parts[0] * 3600 + parts[1] * 60 + parts[2];
|
||||
}
|
||||
|
@@ -1,21 +1,21 @@
|
||||
import fecha from 'fecha';
|
||||
import fecha from "fecha";
|
||||
|
||||
// Check for support of native locale string options
|
||||
function toLocaleDateStringSupportsOptions() {
|
||||
try {
|
||||
new Date().toLocaleDateString('i');
|
||||
new Date().toLocaleDateString("i");
|
||||
} catch (e) {
|
||||
return e.name === 'RangeError';
|
||||
return e.name === "RangeError";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default (toLocaleDateStringSupportsOptions() ?
|
||||
function (dateObj, locales) {
|
||||
return dateObj.toLocaleDateString(
|
||||
locales,
|
||||
{ year: 'numeric', month: 'long', day: 'numeric' },
|
||||
);
|
||||
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars
|
||||
return fecha.format(dateObj, 'mediumDate');
|
||||
});
|
||||
export default (toLocaleDateStringSupportsOptions()
|
||||
? (dateObj, locales) =>
|
||||
dateObj.toLocaleDateString(locales, {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
})
|
||||
: // eslint-disable-next-line no-unused-vars
|
||||
(dateObj, locales) => fecha.format(dateObj, "mediumDate"));
|
||||
|
@@ -1,24 +1,23 @@
|
||||
import fecha from 'fecha';
|
||||
import fecha from "fecha";
|
||||
|
||||
// Check for support of native locale string options
|
||||
function toLocaleStringSupportsOptions() {
|
||||
try {
|
||||
new Date().toLocaleString('i');
|
||||
new Date().toLocaleString("i");
|
||||
} catch (e) {
|
||||
return e.name === 'RangeError';
|
||||
return e.name === "RangeError";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default (toLocaleStringSupportsOptions() ?
|
||||
function (dateObj, locales) {
|
||||
return dateObj.toLocaleString(locales, {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
});
|
||||
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars
|
||||
return fecha.format(dateObj, 'haDateTime');
|
||||
});
|
||||
export default (toLocaleStringSupportsOptions()
|
||||
? (dateObj, locales) =>
|
||||
dateObj.toLocaleString(locales, {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
})
|
||||
: // eslint-disable-next-line no-unused-vars
|
||||
(dateObj, locales) => fecha.format(dateObj, "haDateTime"));
|
||||
|
@@ -1,21 +1,20 @@
|
||||
import fecha from 'fecha';
|
||||
import fecha from "fecha";
|
||||
|
||||
// Check for support of native locale string options
|
||||
function toLocaleTimeStringSupportsOptions() {
|
||||
try {
|
||||
new Date().toLocaleTimeString('i');
|
||||
new Date().toLocaleTimeString("i");
|
||||
} catch (e) {
|
||||
return e.name === 'RangeError';
|
||||
return e.name === "RangeError";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export default (toLocaleTimeStringSupportsOptions() ?
|
||||
function (dateObj, locales) {
|
||||
return dateObj.toLocaleTimeString(
|
||||
locales,
|
||||
{ hour: 'numeric', minute: '2-digit' }
|
||||
);
|
||||
} : function (dateObj, locales) { // eslint-disable-line no-unused-vars
|
||||
return fecha.format(dateObj, 'shortTime');
|
||||
});
|
||||
export default (toLocaleTimeStringSupportsOptions()
|
||||
? (dateObj, locales) =>
|
||||
dateObj.toLocaleTimeString(locales, {
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
})
|
||||
: // eslint-disable-next-line no-unused-vars
|
||||
(dateObj, locales) => fecha.format(dateObj, "shortTime"));
|
||||
|
@@ -1,30 +1,33 @@
|
||||
/** Calculate a string representing a date object as relative time from now.
|
||||
*
|
||||
* Example output: 5 minutes ago, in 3 days.
|
||||
*/
|
||||
const tests = [
|
||||
60, 'second',
|
||||
60, 'minute',
|
||||
24, 'hour',
|
||||
7, 'day',
|
||||
];
|
||||
*/
|
||||
const tests = [60, "second", 60, "minute", 24, "hour", 7, "day"];
|
||||
|
||||
export default function relativeTime(dateObj, localize) {
|
||||
let delta = (new Date() - dateObj) / 1000;
|
||||
const tense = delta >= 0 ? 'past' : 'future';
|
||||
const tense = delta >= 0 ? "past" : "future";
|
||||
delta = Math.abs(delta);
|
||||
|
||||
for (let i = 0; i < tests.length; i += 2) {
|
||||
if (delta < tests[i]) {
|
||||
delta = Math.floor(delta);
|
||||
const time = localize(`ui.components.relative_time.duration.${tests[i + 1]}`, 'count', delta);
|
||||
return localize(`ui.components.relative_time.${tense}`, 'time', time);
|
||||
const time = localize(
|
||||
`ui.components.relative_time.duration.${tests[i + 1]}`,
|
||||
"count",
|
||||
delta
|
||||
);
|
||||
return localize(`ui.components.relative_time.${tense}`, "time", time);
|
||||
}
|
||||
|
||||
delta /= tests[i];
|
||||
}
|
||||
|
||||
delta = Math.floor(delta);
|
||||
const time = localize('ui.components.relative_time.duration.week', 'count', delta);
|
||||
return localize(`ui.components.relative_time.${tense}`, 'time', time);
|
||||
const time = localize(
|
||||
"ui.components.relative_time.duration.week",
|
||||
"count",
|
||||
delta
|
||||
);
|
||||
return localize(`ui.components.relative_time.${tense}`, "time", time);
|
||||
}
|
||||
|
@@ -1,16 +1,18 @@
|
||||
const leftPad = number => (number < 10 ? `0${number}` : number);
|
||||
const leftPad = (number) => (number < 10 ? `0${number}` : number);
|
||||
|
||||
export default function secondsToDuration(d) {
|
||||
const h = Math.floor(d / 3600);
|
||||
const m = Math.floor((d % 3600) / 60);
|
||||
const s = Math.floor(d % 3600 % 60);
|
||||
const s = Math.floor((d % 3600) % 60);
|
||||
|
||||
if (h > 0) {
|
||||
return `${h}:${leftPad(m)}:${leftPad(s)}`;
|
||||
} else if (m > 0) {
|
||||
}
|
||||
if (m > 0) {
|
||||
return `${m}:${leftPad(s)}`;
|
||||
} else if (s > 0) {
|
||||
return '' + s;
|
||||
}
|
||||
if (s > 0) {
|
||||
return "" + s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user