mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 11:46:42 +00:00
commit
e78fb35593
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": ["airbnb-base", "prettier"],
|
"extends": ["airbnb-base", "prettier"],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "2020",
|
||||||
"ecmaFeatures": {
|
"ecmaFeatures": {
|
||||||
"jsx": true,
|
"jsx": true,
|
||||||
"modules": true
|
"modules": true
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
{
|
{
|
||||||
"extends": "./.eslintrc-hound.json",
|
"extends": "./.eslintrc-hound.json",
|
||||||
"plugins": [
|
"plugins": ["react"],
|
||||||
"react"
|
|
||||||
],
|
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true
|
"browser": true
|
||||||
},
|
},
|
||||||
"parser": "babel-eslint",
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"import/no-unresolved": 2,
|
"import/no-unresolved": 2,
|
||||||
"linebreak-style": 0,
|
"linebreak-style": 0,
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
module.exports.babelLoaderConfig = ({ latestBuild }) => {
|
|
||||||
if (latestBuild === undefined) {
|
|
||||||
throw Error("latestBuild not defined for babel loader config");
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
test: /\.m?js$|\.tsx?$/,
|
|
||||||
use: {
|
|
||||||
loader: "babel-loader",
|
|
||||||
options: {
|
|
||||||
presets: [
|
|
||||||
!latestBuild && [
|
|
||||||
require("@babel/preset-env").default,
|
|
||||||
{ modules: false },
|
|
||||||
],
|
|
||||||
[
|
|
||||||
require("@babel/preset-typescript").default,
|
|
||||||
{
|
|
||||||
jsxPragma: "h",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
].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",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
require("@babel/plugin-proposal-decorators").default,
|
|
||||||
{ decoratorsBeforeExport: true },
|
|
||||||
],
|
|
||||||
[
|
|
||||||
require("@babel/plugin-proposal-class-properties").default,
|
|
||||||
{ loose: true },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
73
build-scripts/gulp/download_translations.js
Normal file
73
build-scripts/gulp/download_translations.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
const del = require("del");
|
||||||
|
const gulp = require("gulp");
|
||||||
|
const mapStream = require("map-stream");
|
||||||
|
|
||||||
|
const inDir = "translations";
|
||||||
|
const downloadDir = inDir + "/downloads";
|
||||||
|
|
||||||
|
const tasks = [];
|
||||||
|
|
||||||
|
function hasHtml(data) {
|
||||||
|
return /<[a-z][\s\S]*>/i.test(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function recursiveCheckHasHtml(file, data, errors, recKey) {
|
||||||
|
Object.keys(data).forEach(function(key) {
|
||||||
|
if (typeof data[key] === "object") {
|
||||||
|
nextRecKey = recKey ? `${recKey}.${key}` : key;
|
||||||
|
recursiveCheckHasHtml(file, data[key], errors, nextRecKey);
|
||||||
|
} else if (hasHtml(data[key])) {
|
||||||
|
errors.push(`HTML found in ${file.path} at key ${recKey}.${key}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkHtml() {
|
||||||
|
let errors = [];
|
||||||
|
|
||||||
|
return mapStream(function(file, cb) {
|
||||||
|
const content = file.contents;
|
||||||
|
let error;
|
||||||
|
if (content) {
|
||||||
|
if (hasHtml(String(content))) {
|
||||||
|
const data = JSON.parse(String(content));
|
||||||
|
recursiveCheckHasHtml(file, data, errors);
|
||||||
|
if (errors.length > 0) {
|
||||||
|
error = errors.join("\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb(error, file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let taskName = "clean-downloaded-translations";
|
||||||
|
gulp.task(taskName, function() {
|
||||||
|
return del([`${downloadDir}/**`]);
|
||||||
|
});
|
||||||
|
tasks.push(taskName);
|
||||||
|
|
||||||
|
taskName = "check-translations-html";
|
||||||
|
gulp.task(taskName, function() {
|
||||||
|
return gulp.src(`${downloadDir}/*.json`).pipe(checkHtml());
|
||||||
|
});
|
||||||
|
tasks.push(taskName);
|
||||||
|
|
||||||
|
taskName = "move-downloaded-translations";
|
||||||
|
gulp.task(taskName, function() {
|
||||||
|
return gulp.src(`${downloadDir}/*.json`).pipe(gulp.dest(inDir));
|
||||||
|
});
|
||||||
|
tasks.push(taskName);
|
||||||
|
|
||||||
|
taskName = "check-downloaded-translations";
|
||||||
|
gulp.task(
|
||||||
|
taskName,
|
||||||
|
gulp.series(
|
||||||
|
"check-translations-html",
|
||||||
|
"move-downloaded-translations",
|
||||||
|
"clean-downloaded-translations"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
tasks.push(taskName);
|
||||||
|
|
||||||
|
module.exports = tasks;
|
@ -7,7 +7,6 @@ const CompressionPlugin = require("compression-webpack-plugin");
|
|||||||
const zopfli = require("@gfx/zopfli");
|
const zopfli = require("@gfx/zopfli");
|
||||||
const ManifestPlugin = require("webpack-manifest-plugin");
|
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
const { babelLoaderConfig } = require("./babel.js");
|
|
||||||
|
|
||||||
let version = fs
|
let version = fs
|
||||||
.readFileSync(path.resolve(paths.polymer_dir, "setup.py"), "utf8")
|
.readFileSync(path.resolve(paths.polymer_dir, "setup.py"), "utf8")
|
||||||
@ -41,6 +40,20 @@ const resolve = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tsLoader = (latestBuild) => ({
|
||||||
|
test: /\.ts|tsx$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "ts-loader",
|
||||||
|
options: {
|
||||||
|
compilerOptions: latestBuild
|
||||||
|
? { noEmit: false }
|
||||||
|
: { target: "es5", noEmit: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
const cssLoader = {
|
const cssLoader = {
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: "raw-loader",
|
use: "raw-loader",
|
||||||
@ -118,7 +131,7 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
|||||||
devtool: genDevTool(isProdBuild),
|
devtool: genDevTool(isProdBuild),
|
||||||
entry,
|
entry,
|
||||||
module: {
|
module: {
|
||||||
rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader],
|
rules: [tsLoader(latestBuild), cssLoader, htmlLoader],
|
||||||
},
|
},
|
||||||
optimization: optimization(latestBuild),
|
optimization: optimization(latestBuild),
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -186,7 +199,7 @@ const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
|||||||
compatibility: "./src/entrypoints/compatibility.ts",
|
compatibility: "./src/entrypoints/compatibility.ts",
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader],
|
rules: [tsLoader(latestBuild), cssLoader, htmlLoader],
|
||||||
},
|
},
|
||||||
optimization: optimization(latestBuild),
|
optimization: optimization(latestBuild),
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -233,7 +246,7 @@ const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
|||||||
devtool: genDevTool(isProdBuild),
|
devtool: genDevTool(isProdBuild),
|
||||||
entry,
|
entry,
|
||||||
module: {
|
module: {
|
||||||
rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader],
|
rules: [tsLoader(latestBuild), cssLoader, htmlLoader],
|
||||||
},
|
},
|
||||||
optimization: optimization(latestBuild),
|
optimization: optimization(latestBuild),
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -134,7 +134,13 @@ export class HcMain extends HassElement {
|
|||||||
this._error = err;
|
this._error = err;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const connection = await createConnection({ auth });
|
let connection;
|
||||||
|
try {
|
||||||
|
connection = await createConnection({ auth });
|
||||||
|
} catch (err) {
|
||||||
|
this._error = err;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
this.hass.connection.close();
|
this.hass.connection.close();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
const { babelLoaderConfig } = require("../build-scripts/babel.js");
|
|
||||||
const webpackBase = require("../build-scripts/webpack.js");
|
const webpackBase = require("../build-scripts/webpack.js");
|
||||||
|
|
||||||
const isProd = process.env.NODE_ENV === "production";
|
const isProd = process.env.NODE_ENV === "production";
|
||||||
@ -17,7 +16,20 @@ module.exports = {
|
|||||||
entry: "./src/entrypoint.js",
|
entry: "./src/entrypoint.js",
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
babelLoaderConfig({ latestBuild }),
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "ts-loader",
|
||||||
|
options: {
|
||||||
|
compilerOptions: latestBuild
|
||||||
|
? { noEmit: false }
|
||||||
|
: { target: "es5", noEmit: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: "raw-loader",
|
use: "raw-loader",
|
||||||
|
@ -102,7 +102,7 @@ export function parseTextToColoredPre(text) {
|
|||||||
|
|
||||||
if (match[1] === undefined) continue;
|
if (match[1] === undefined) continue;
|
||||||
|
|
||||||
for (const colorCode of match[1].split(";")) {
|
match[1].split(";").forEach((colorCode) => {
|
||||||
switch (parseInt(colorCode)) {
|
switch (parseInt(colorCode)) {
|
||||||
case 0:
|
case 0:
|
||||||
// reset
|
// reset
|
||||||
@ -195,7 +195,7 @@ export function parseTextToColoredPre(text) {
|
|||||||
state.backgroundColor = null;
|
state.backgroundColor = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
addSpan(text.substring(i));
|
addSpan(text.substring(i));
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
window.loadES5Adapter().then(() => {
|
window.loadES5Adapter().then(() => {
|
||||||
|
// eslint-disable-next-line
|
||||||
import(/* webpackChunkName: "hassio-icons" */ "./resources/hassio-icons");
|
import(/* webpackChunkName: "hassio-icons" */ "./resources/hassio-icons");
|
||||||
|
// eslint-disable-next-line
|
||||||
import(/* webpackChunkName: "hassio-main" */ "./hassio-main");
|
import(/* webpackChunkName: "hassio-main" */ "./hassio-main");
|
||||||
});
|
});
|
||||||
const styleEl = document.createElement("style");
|
const styleEl = document.createElement("style");
|
||||||
|
@ -3,7 +3,6 @@ const CompressionPlugin = require("compression-webpack-plugin");
|
|||||||
const zopfli = require("@gfx/zopfli");
|
const zopfli = require("@gfx/zopfli");
|
||||||
|
|
||||||
const config = require("./config.js");
|
const config = require("./config.js");
|
||||||
const { babelLoaderConfig } = require("../build-scripts/babel.js");
|
|
||||||
const webpackBase = require("../build-scripts/webpack.js");
|
const webpackBase = require("../build-scripts/webpack.js");
|
||||||
|
|
||||||
const isProdBuild = process.env.NODE_ENV === "production";
|
const isProdBuild = process.env.NODE_ENV === "production";
|
||||||
@ -19,7 +18,20 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
babelLoaderConfig({ latestBuild }),
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "ts-loader",
|
||||||
|
options: {
|
||||||
|
compilerOptions: latestBuild
|
||||||
|
? { noEmit: false }
|
||||||
|
: { target: "es5", noEmit: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.(html)$/,
|
test: /\.(html)$/,
|
||||||
use: {
|
use: {
|
||||||
|
47
package.json
47
package.json
@ -8,7 +8,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "script/build_frontend",
|
"build": "script/build_frontend",
|
||||||
"lint": "eslint src hassio/src gallery/src && tslint 'src/**/*.ts' 'hassio/src/**/*.ts' 'gallery/src/**/*.ts' 'cast/src/**/*.ts' 'test-mocha/**/*.ts' && polymer lint && tsc",
|
"lint": "eslint src hassio/src gallery/src && tslint 'src/**/*.ts' 'src/**/*.tsx' 'hassio/src/**/*.ts' 'gallery/src/**/*.ts' 'cast/src/**/*.ts' 'test-mocha/**/*.ts' && tsc",
|
||||||
"mocha": "node_modules/.bin/ts-mocha -p test-mocha/tsconfig.test.json --opts test-mocha/mocha.opts",
|
"mocha": "node_modules/.bin/ts-mocha -p test-mocha/tsconfig.test.json --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",
|
"docker_build": "sh ./script/docker_run.sh build $npm_package_version",
|
||||||
@ -17,9 +17,11 @@
|
|||||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material/mwc-base": "^0.6.0",
|
"@material/mwc-base": "^0.8.0",
|
||||||
"@material/mwc-button": "^0.6.0",
|
"@material/mwc-button": "^0.8.0",
|
||||||
"@material/mwc-ripple": "^0.6.0",
|
"@material/mwc-checkbox": "^0.8.0",
|
||||||
|
"@material/mwc-fab": "^0.8.0",
|
||||||
|
"@material/mwc-ripple": "0.8.0",
|
||||||
"@mdi/svg": "4.3.95",
|
"@mdi/svg": "4.3.95",
|
||||||
"@polymer/app-layout": "^3.0.2",
|
"@polymer/app-layout": "^3.0.2",
|
||||||
"@polymer/app-localize-behavior": "^3.0.1",
|
"@polymer/app-localize-behavior": "^3.0.1",
|
||||||
@ -45,7 +47,6 @@
|
|||||||
"@polymer/paper-dialog-scrollable": "^3.0.1",
|
"@polymer/paper-dialog-scrollable": "^3.0.1",
|
||||||
"@polymer/paper-drawer-panel": "^3.0.1",
|
"@polymer/paper-drawer-panel": "^3.0.1",
|
||||||
"@polymer/paper-dropdown-menu": "^3.0.1",
|
"@polymer/paper-dropdown-menu": "^3.0.1",
|
||||||
"@polymer/paper-fab": "^3.0.1",
|
|
||||||
"@polymer/paper-icon-button": "^3.0.2",
|
"@polymer/paper-icon-button": "^3.0.2",
|
||||||
"@polymer/paper-input": "^3.0.1",
|
"@polymer/paper-input": "^3.0.1",
|
||||||
"@polymer/paper-item": "^3.0.1",
|
"@polymer/paper-item": "^3.0.1",
|
||||||
@ -79,12 +80,12 @@
|
|||||||
"fuse.js": "^3.4.4",
|
"fuse.js": "^3.4.4",
|
||||||
"google-timezones-json": "^1.0.2",
|
"google-timezones-json": "^1.0.2",
|
||||||
"hls.js": "^0.12.4",
|
"hls.js": "^0.12.4",
|
||||||
"home-assistant-js-websocket": "4.3.1",
|
"home-assistant-js-websocket": "^4.4.0",
|
||||||
"intl-messageformat": "^2.2.0",
|
"intl-messageformat": "^2.2.0",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.4.0",
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"leaflet": "^1.4.0",
|
"leaflet": "^1.4.0",
|
||||||
"lit-element": "^2.2.0",
|
"lit-element": "^2.2.1",
|
||||||
"lit-html": "^1.1.0",
|
"lit-html": "^1.1.0",
|
||||||
"marked": "^0.6.1",
|
"marked": "^0.6.1",
|
||||||
"mdn-polyfills": "^5.16.0",
|
"mdn-polyfills": "^5.16.0",
|
||||||
@ -103,15 +104,6 @@
|
|||||||
"xss": "^1.0.6"
|
"xss": "^1.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.4.0",
|
|
||||||
"@babel/plugin-external-helpers": "^7.2.0",
|
|
||||||
"@babel/plugin-proposal-class-properties": "^7.4.0",
|
|
||||||
"@babel/plugin-proposal-decorators": "^7.4.0",
|
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.4.0",
|
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
|
||||||
"@babel/plugin-transform-react-jsx": "^7.3.0",
|
|
||||||
"@babel/preset-env": "^7.4.2",
|
|
||||||
"@babel/preset-typescript": "^7.3.3",
|
|
||||||
"@gfx/zopfli": "^1.0.11",
|
"@gfx/zopfli": "^1.0.11",
|
||||||
"@types/chai": "^4.1.7",
|
"@types/chai": "^4.1.7",
|
||||||
"@types/chromecast-caf-receiver": "^3.0.12",
|
"@types/chromecast-caf-receiver": "^3.0.12",
|
||||||
@ -120,19 +112,17 @@
|
|||||||
"@types/leaflet": "^1.4.3",
|
"@types/leaflet": "^1.4.3",
|
||||||
"@types/memoize-one": "4.1.0",
|
"@types/memoize-one": "4.1.0",
|
||||||
"@types/mocha": "^5.2.6",
|
"@types/mocha": "^5.2.6",
|
||||||
"babel-eslint": "^10",
|
|
||||||
"babel-loader": "^8.0.5",
|
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"compression-webpack-plugin": "^2.0.0",
|
"compression-webpack-plugin": "^2.0.0",
|
||||||
"copy-webpack-plugin": "^5.0.2",
|
"copy-webpack-plugin": "^5.0.2",
|
||||||
"del": "^4.0.0",
|
"del": "^4.0.0",
|
||||||
"eslint": "^5.15.3",
|
"eslint": "^6.3.0",
|
||||||
"eslint-config-airbnb-base": "^13.1.0",
|
"eslint-config-airbnb-base": "^14.0.0",
|
||||||
"eslint-config-prettier": "^4.1.0",
|
"eslint-config-prettier": "^6.2.0",
|
||||||
"eslint-import-resolver-webpack": "^0.11.0",
|
"eslint-import-resolver-webpack": "^0.11.1",
|
||||||
"eslint-plugin-import": "^2.16.0",
|
"eslint-plugin-import": "^2.18.2",
|
||||||
"eslint-plugin-prettier": "^3.0.1",
|
"eslint-plugin-prettier": "^3.1.0",
|
||||||
"eslint-plugin-react": "^7.12.4",
|
"eslint-plugin-react": "^7.14.3",
|
||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
"gulp": "^4.0.0",
|
"gulp": "^4.0.0",
|
||||||
"gulp-foreach": "^0.1.0",
|
"gulp-foreach": "^0.1.0",
|
||||||
@ -148,17 +138,18 @@
|
|||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"husky": "^1.3.1",
|
"husky": "^1.3.1",
|
||||||
"lint-staged": "^8.1.5",
|
"lint-staged": "^8.1.5",
|
||||||
"lodash.template": "^4.4.0",
|
"lodash.template": "^4.5.0",
|
||||||
|
"map-stream": "^0.0.7",
|
||||||
"merge-stream": "^1.0.1",
|
"merge-stream": "^1.0.1",
|
||||||
"mocha": "^6.0.2",
|
"mocha": "^6.0.2",
|
||||||
"parse5": "^5.1.0",
|
"parse5": "^5.1.0",
|
||||||
"polymer-cli": "^1.9.7",
|
|
||||||
"prettier": "^1.16.4",
|
"prettier": "^1.16.4",
|
||||||
"raw-loader": "^2.0.0",
|
"raw-loader": "^2.0.0",
|
||||||
"reify": "^0.18.1",
|
"reify": "^0.18.1",
|
||||||
"require-dir": "^1.2.0",
|
"require-dir": "^1.2.0",
|
||||||
"sinon": "^7.3.1",
|
"sinon": "^7.3.1",
|
||||||
"terser-webpack-plugin": "^1.2.3",
|
"terser-webpack-plugin": "^1.2.3",
|
||||||
|
"ts-loader": "^6.0.4",
|
||||||
"ts-mocha": "^6.0.0",
|
"ts-mocha": "^6.0.0",
|
||||||
"tslint": "^5.14.0",
|
"tslint": "^5.14.0",
|
||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
|
@ -21,7 +21,7 @@ fi
|
|||||||
[ -z "${LOKALISE_TOKEN-}" ] && LOKALISE_TOKEN="$(<.lokalise_token)"
|
[ -z "${LOKALISE_TOKEN-}" ] && LOKALISE_TOKEN="$(<.lokalise_token)"
|
||||||
|
|
||||||
PROJECT_ID="3420425759f6d6d241f598.13594006"
|
PROJECT_ID="3420425759f6d6d241f598.13594006"
|
||||||
LOCAL_DIR="$(pwd)/translations"
|
LOCAL_DIR="$(pwd)/translations/downloads"
|
||||||
FILE_FORMAT=json
|
FILE_FORMAT=json
|
||||||
|
|
||||||
mkdir -p ${LOCAL_DIR}
|
mkdir -p ${LOCAL_DIR}
|
||||||
@ -35,3 +35,5 @@ docker run \
|
|||||||
--export_empty skip \
|
--export_empty skip \
|
||||||
--type json \
|
--type json \
|
||||||
--unzip_to /opt/dest
|
--unzip_to /opt/dest
|
||||||
|
|
||||||
|
./node_modules/.bin/gulp check-downloaded-translations
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20190908.0",
|
version="20190911.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -97,14 +97,11 @@ class HaHistoryGraphCard extends EventsMixin(PolymerElement) {
|
|||||||
this.cacheConfig.refresh !== (stateObj.attributes.refresh || 0) ||
|
this.cacheConfig.refresh !== (stateObj.attributes.refresh || 0) ||
|
||||||
this.cacheConfig.hoursToShow !== (stateObj.attributes.hours_to_show || 24)
|
this.cacheConfig.hoursToShow !== (stateObj.attributes.hours_to_show || 24)
|
||||||
) {
|
) {
|
||||||
this.cacheConfig = Object.assign(
|
this.cacheConfig = {
|
||||||
{},
|
refresh: stateObj.attributes.refresh || 0,
|
||||||
{
|
cacheKey: stateObj.entity_id,
|
||||||
refresh: stateObj.attributes.refresh || 0,
|
hoursToShow: stateObj.attributes.hours_to_show || 24,
|
||||||
cacheKey: stateObj.entity_id,
|
};
|
||||||
hoursToShow: stateObj.attributes.hours_to_show || 24,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ export interface GetStatusMessage extends BaseCastMessage {
|
|||||||
export interface ConnectMessage extends BaseCastMessage {
|
export interface ConnectMessage extends BaseCastMessage {
|
||||||
type: "connect";
|
type: "connect";
|
||||||
refreshToken: string;
|
refreshToken: string;
|
||||||
clientId: string;
|
clientId: string | null;
|
||||||
hassUrl: string;
|
hassUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
interface OnChangeComponent {
|
// interface OnChangeComponent {
|
||||||
props: {
|
// props: {
|
||||||
index: number;
|
// index: number;
|
||||||
onChange(index: number, data: object);
|
// onChange(index: number, data: object);
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function onChangeEvent(this: OnChangeComponent, prop, ev) {
|
// export function onChangeEvent(this: OnChangeComponent, prop, ev) {
|
||||||
|
export function onChangeEvent(this: any, prop, ev) {
|
||||||
const origData = this.props[prop];
|
const origData = this.props[prop];
|
||||||
|
|
||||||
if (ev.target.value === origData[ev.target.name]) {
|
if (ev.target.value === origData[ev.target.name]) {
|
||||||
|
32
src/components/device/ha-device-action-picker.ts
Normal file
32
src/components/device/ha-device-action-picker.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { customElement } from "lit-element";
|
||||||
|
import {
|
||||||
|
DeviceAction,
|
||||||
|
fetchDeviceActions,
|
||||||
|
localizeDeviceAutomationAction,
|
||||||
|
} from "../../data/device_automation";
|
||||||
|
import "../../components/ha-paper-dropdown-menu";
|
||||||
|
import { HaDeviceAutomationPicker } from "./ha-device-automation-picker";
|
||||||
|
|
||||||
|
@customElement("ha-device-action-picker")
|
||||||
|
class HaDeviceActionPicker extends HaDeviceAutomationPicker<DeviceAction> {
|
||||||
|
protected NO_AUTOMATION_TEXT = "No actions";
|
||||||
|
protected UNKNOWN_AUTOMATION_TEXT = "Unknown action";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(
|
||||||
|
localizeDeviceAutomationAction,
|
||||||
|
fetchDeviceActions,
|
||||||
|
(deviceId?: string) => ({
|
||||||
|
device_id: deviceId || "",
|
||||||
|
domain: "",
|
||||||
|
entity_id: "",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-device-action-picker": HaDeviceActionPicker;
|
||||||
|
}
|
||||||
|
}
|
@ -287,11 +287,12 @@ class HaChartBase extends mixinBehaviors(
|
|||||||
}
|
}
|
||||||
positionX += this._chart.canvas.offsetLeft;
|
positionX += this._chart.canvas.offsetLeft;
|
||||||
// Display, position, and set styles for font
|
// Display, position, and set styles for font
|
||||||
this.tooltip = Object.assign({}, this.tooltip, {
|
this.tooltip = {
|
||||||
|
...this.tooltip,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
left: `${positionX}px`,
|
left: `${positionX}px`,
|
||||||
top: `${positionY}px`,
|
top: `${positionY}px`,
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_legendClick(event) {
|
_legendClick(event) {
|
||||||
|
@ -21,6 +21,7 @@ class StateBadge extends LitElement {
|
|||||||
public hass?: HomeAssistant;
|
public hass?: HomeAssistant;
|
||||||
@property() public stateObj?: HassEntity;
|
@property() public stateObj?: HassEntity;
|
||||||
@property() public overrideIcon?: string;
|
@property() public overrideIcon?: string;
|
||||||
|
@property() public overrideImage?: string;
|
||||||
@query("ha-icon") private _icon!: HaIcon;
|
@query("ha-icon") private _icon!: HaIcon;
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
@ -55,8 +56,11 @@ class StateBadge extends LitElement {
|
|||||||
};
|
};
|
||||||
if (stateObj) {
|
if (stateObj) {
|
||||||
// hide icon if we have entity picture
|
// hide icon if we have entity picture
|
||||||
if (stateObj.attributes.entity_picture && !this.overrideIcon) {
|
if (
|
||||||
let imageUrl = stateObj.attributes.entity_picture;
|
(stateObj.attributes.entity_picture && !this.overrideIcon) ||
|
||||||
|
this.overrideImage
|
||||||
|
) {
|
||||||
|
let imageUrl = this.overrideImage || stateObj.attributes.entity_picture;
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
imageUrl = this.hass.hassUrl(imageUrl);
|
imageUrl = this.hass.hassUrl(imageUrl);
|
||||||
}
|
}
|
||||||
|
20
src/components/ha-checkbox.ts
Normal file
20
src/components/ha-checkbox.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { Constructor, customElement } from "lit-element";
|
||||||
|
import "@material/mwc-checkbox";
|
||||||
|
// tslint:disable-next-line
|
||||||
|
import { Checkbox } from "@material/mwc-checkbox";
|
||||||
|
// tslint:disable-next-line
|
||||||
|
const MwcCheckbox = customElements.get("mwc-checkbox") as Constructor<Checkbox>;
|
||||||
|
|
||||||
|
@customElement("ha-checkbox")
|
||||||
|
export class HaCheckbox extends MwcCheckbox {
|
||||||
|
protected firstUpdated() {
|
||||||
|
super.firstUpdated();
|
||||||
|
this.style.setProperty("--mdc-theme-secondary", "var(--primary-color)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-checkbox": HaCheckbox;
|
||||||
|
}
|
||||||
|
}
|
49
src/components/ha-fab.ts
Normal file
49
src/components/ha-fab.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import {
|
||||||
|
classMap,
|
||||||
|
html,
|
||||||
|
customElement,
|
||||||
|
Constructor,
|
||||||
|
} from "@material/mwc-base/base-element";
|
||||||
|
import { ripple } from "@material/mwc-ripple/ripple-directive.js";
|
||||||
|
|
||||||
|
import "@material/mwc-fab";
|
||||||
|
// tslint:disable-next-line
|
||||||
|
import { Fab } from "@material/mwc-fab";
|
||||||
|
// tslint:disable-next-line
|
||||||
|
const MwcFab = customElements.get("mwc-fab") as Constructor<Fab>;
|
||||||
|
|
||||||
|
@customElement("ha-fab")
|
||||||
|
export class HaFab extends MwcFab {
|
||||||
|
// We override the render method because we don't have an icon font and mwc-fab doesn't support our svg-icon sets.
|
||||||
|
// Based on version mwc-fab 0.8
|
||||||
|
protected render() {
|
||||||
|
const classes = {
|
||||||
|
"mdc-fab--mini": this.mini,
|
||||||
|
"mdc-fab--exited": this.exited,
|
||||||
|
"mdc-fab--extended": this.extended,
|
||||||
|
};
|
||||||
|
const showLabel = this.label !== "" && this.extended;
|
||||||
|
return html`
|
||||||
|
<button
|
||||||
|
.ripple="${ripple()}"
|
||||||
|
class="mdc-fab ${classMap(classes)}"
|
||||||
|
?disabled="${this.disabled}"
|
||||||
|
aria-label="${this.label || this.icon}"
|
||||||
|
>
|
||||||
|
${showLabel && this.showIconAtEnd ? this.label : ""}
|
||||||
|
${this.icon
|
||||||
|
? html`
|
||||||
|
<ha-icon .icon=${this.icon}></ha-icon>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${showLabel && !this.showIconAtEnd ? this.label : ""}
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-fab": HaFab;
|
||||||
|
}
|
||||||
|
}
|
@ -49,13 +49,17 @@ class HaMarkdown extends UpdatingElement {
|
|||||||
|
|
||||||
// Open external links in a new window
|
// Open external links in a new window
|
||||||
if (
|
if (
|
||||||
node.nodeName === "A" &&
|
node instanceof HTMLAnchorElement &&
|
||||||
(node as HTMLAnchorElement).host !== document.location.host
|
node.host !== document.location.host
|
||||||
) {
|
) {
|
||||||
(node as HTMLAnchorElement).target = "_blank";
|
node.target = "_blank";
|
||||||
|
|
||||||
|
// protect referrer on external links and deny window.opener access for security reasons
|
||||||
|
// (see https://mathiasbynens.github.io/rel-noopener/)
|
||||||
|
node.rel = "noreferrer noopener";
|
||||||
|
|
||||||
// Fire a resize event when images loaded to notify content resized
|
// Fire a resize event when images loaded to notify content resized
|
||||||
} else if (node.nodeName === "IMG") {
|
} else if (node) {
|
||||||
node.addEventListener("load", this._resize);
|
node.addEventListener("load", this._resize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,9 @@ export interface DeviceAutomation {
|
|||||||
event?: string;
|
event?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line: no-empty-interface
|
||||||
|
export interface DeviceAction extends DeviceAutomation {}
|
||||||
|
|
||||||
export interface DeviceCondition extends DeviceAutomation {
|
export interface DeviceCondition extends DeviceAutomation {
|
||||||
condition: string;
|
condition: string;
|
||||||
}
|
}
|
||||||
@ -18,6 +21,12 @@ export interface DeviceTrigger extends DeviceAutomation {
|
|||||||
platform: string;
|
platform: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fetchDeviceActions = (hass: HomeAssistant, deviceId: string) =>
|
||||||
|
hass.callWS<DeviceAction[]>({
|
||||||
|
type: "device_automation/action/list",
|
||||||
|
device_id: deviceId,
|
||||||
|
});
|
||||||
|
|
||||||
export const fetchDeviceConditions = (hass: HomeAssistant, deviceId: string) =>
|
export const fetchDeviceConditions = (hass: HomeAssistant, deviceId: string) =>
|
||||||
hass.callWS<DeviceCondition[]>({
|
hass.callWS<DeviceCondition[]>({
|
||||||
type: "device_automation/condition/list",
|
type: "device_automation/condition/list",
|
||||||
@ -52,6 +61,24 @@ export const deviceAutomationsEqual = (
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const localizeDeviceAutomationAction = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
action: DeviceAction
|
||||||
|
) => {
|
||||||
|
const state = action.entity_id ? hass.states[action.entity_id] : undefined;
|
||||||
|
return hass.localize(
|
||||||
|
`component.${action.domain}.device_automation.action_type.${action.type}`,
|
||||||
|
"entity_name",
|
||||||
|
state ? compute_state_name(state) : "<unknown>",
|
||||||
|
"subtype",
|
||||||
|
hass.localize(
|
||||||
|
`component.${action.domain}.device_automation.action_subtype.${
|
||||||
|
action.subtype
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const localizeDeviceAutomationCondition = (
|
export const localizeDeviceAutomationCondition = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
condition: DeviceCondition
|
condition: DeviceCondition
|
||||||
|
@ -163,7 +163,7 @@ class HaStateHistoryData extends LocalizeMixin(PolymerElement) {
|
|||||||
localize,
|
localize,
|
||||||
language
|
language
|
||||||
).then((stateHistory) => {
|
).then((stateHistory) => {
|
||||||
this._setData(Object.assign({}, stateHistory));
|
this._setData({ ...stateHistory });
|
||||||
});
|
});
|
||||||
}, cacheConfig.refresh * 1000);
|
}, cacheConfig.refresh * 1000);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,12 @@ export interface EventAction {
|
|||||||
event_data_template?: { [key: string]: any };
|
event_data_template?: { [key: string]: any };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DeviceAction {
|
||||||
|
device_id: string;
|
||||||
|
domain: string;
|
||||||
|
entity_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const triggerScript = (
|
export const triggerScript = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entityId: string,
|
entityId: string,
|
||||||
|
@ -79,10 +79,11 @@ class MoreInfoGroup extends PolymerElement {
|
|||||||
// Groups need to be filtered out or we'll show content of
|
// Groups need to be filtered out or we'll show content of
|
||||||
// first child above the children of the current group
|
// first child above the children of the current group
|
||||||
if (groupDomain !== "group") {
|
if (groupDomain !== "group") {
|
||||||
groupDomainStateObj = Object.assign({}, baseStateObj, {
|
groupDomainStateObj = {
|
||||||
|
...baseStateObj,
|
||||||
entity_id: stateObj.entity_id,
|
entity_id: stateObj.entity_id,
|
||||||
attributes: Object.assign({}, baseStateObj.attributes),
|
attributes: { ...baseStateObj.attributes },
|
||||||
});
|
};
|
||||||
|
|
||||||
for (let i = 0; i < states.length; i++) {
|
for (let i = 0; i < states.length; i++) {
|
||||||
if (groupDomain !== computeStateDomain(states[i])) {
|
if (groupDomain !== computeStateDomain(states[i])) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
import "@polymer/paper-listbox/paper-listbox";
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
|
@ -193,9 +193,10 @@ class MoreInfoControls extends EventsMixin(PolymerElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._cacheConfig.cacheKey !== `more_info.${newVal.entity_id}`) {
|
if (this._cacheConfig.cacheKey !== `more_info.${newVal.entity_id}`) {
|
||||||
this._cacheConfig = Object.assign({}, this._cacheConfig, {
|
this._cacheConfig = {
|
||||||
|
...this._cacheConfig,
|
||||||
cacheKey: `more_info.${newVal.entity_id}`,
|
cacheKey: `more_info.${newVal.entity_id}`,
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,11 +80,7 @@ function initPushNotifications() {
|
|||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
self.registration
|
self.registration
|
||||||
.getNotifications({ tag: data.tag })
|
.getNotifications({ tag: data.tag })
|
||||||
.then(function(notifications) {
|
.then((notifications) => notifications.forEach((n) => n.close()))
|
||||||
for (const n of notifications) {
|
|
||||||
n.close();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import { HassElement } from "../state/hass-element";
|
|||||||
|
|
||||||
export class HomeAssistantAppEl extends HassElement {
|
export class HomeAssistantAppEl extends HassElement {
|
||||||
@property() private _route?: Route;
|
@property() private _route?: Route;
|
||||||
@property() private _error?: boolean;
|
@property() private _error = false;
|
||||||
@property() private _panelUrl?: string;
|
@property() private _panelUrl?: string;
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
@ -49,6 +49,7 @@ export class HomeAssistantAppEl extends HassElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues): void {
|
protected updated(changedProps: PropertyValues): void {
|
||||||
|
super.updated(changedProps);
|
||||||
if (changedProps.has("_panelUrl")) {
|
if (changedProps.has("_panelUrl")) {
|
||||||
this.panelUrlChanged(this._panelUrl!);
|
this.panelUrlChanged(this._panelUrl!);
|
||||||
this._updateHass({ panelUrl: this._panelUrl });
|
this._updateHass({ panelUrl: this._panelUrl });
|
||||||
@ -70,7 +71,11 @@ export class HomeAssistantAppEl extends HassElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _routeChanged(ev) {
|
private async _routeChanged(ev) {
|
||||||
|
// routeChangged event listener is called while we're doing the fist render,
|
||||||
|
// causing the update to be ignored. So delay it to next task (Lit render is sync).
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
|
|
||||||
const route = ev.detail.value as Route;
|
const route = ev.detail.value as Route;
|
||||||
// If it's the first route that we process,
|
// If it's the first route that we process,
|
||||||
// check if we should navigate away from /
|
// check if we should navigate away from /
|
||||||
|
@ -8,7 +8,6 @@ import {
|
|||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
|
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import {
|
import {
|
||||||
@ -19,6 +18,7 @@ import {
|
|||||||
subscribeAreaRegistry,
|
subscribeAreaRegistry,
|
||||||
} from "../../../data/area_registry";
|
} from "../../../data/area_registry";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-fab";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import "../../../layouts/hass-loading-screen";
|
import "../../../layouts/hass-loading-screen";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
@ -100,7 +100,7 @@ class HaConfigAreaRegistry extends LitElement {
|
|||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
|
|
||||||
<paper-fab
|
<ha-fab
|
||||||
?is-wide=${this.isWide}
|
?is-wide=${this.isWide}
|
||||||
icon="hass:plus"
|
icon="hass:plus"
|
||||||
title="${this.hass.localize(
|
title="${this.hass.localize(
|
||||||
@ -110,7 +110,7 @@ class HaConfigAreaRegistry extends LitElement {
|
|||||||
class="${classMap({
|
class="${classMap({
|
||||||
rtl: computeRTL(this.hass),
|
rtl: computeRTL(this.hass),
|
||||||
})}"
|
})}"
|
||||||
></paper-fab>
|
></ha-fab>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,24 +183,24 @@ All devices in this area will become unassigned.`)
|
|||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
}
|
}
|
||||||
paper-fab {
|
ha-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide] {
|
ha-fab[is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab.rtl {
|
ha-fab.rtl {
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide].rtl {
|
ha-fab[is-wide].rtl {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
|
@ -10,11 +10,11 @@ import {
|
|||||||
import "@polymer/app-layout/app-header/app-header";
|
import "@polymer/app-layout/app-header/app-header";
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
import { classMap } from "lit-html/directives/class-map";
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
|
|
||||||
import { h, render } from "preact";
|
import { h, render } from "preact";
|
||||||
|
|
||||||
|
import "../../../components/ha-fab";
|
||||||
import "../../../components/ha-paper-icon-button-arrow-prev";
|
import "../../../components/ha-paper-icon-button-arrow-prev";
|
||||||
import "../../../layouts/ha-app-layout";
|
import "../../../layouts/ha-app-layout";
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ class HaAutomationEditor extends LitElement {
|
|||||||
})}"
|
})}"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<paper-fab
|
<ha-fab
|
||||||
slot="fab"
|
slot="fab"
|
||||||
?is-wide="${this.isWide}"
|
?is-wide="${this.isWide}"
|
||||||
?dirty="${this._dirty}"
|
?dirty="${this._dirty}"
|
||||||
@ -125,7 +125,7 @@ class HaAutomationEditor extends LitElement {
|
|||||||
class="${classMap({
|
class="${classMap({
|
||||||
rtl: computeRTL(this.hass),
|
rtl: computeRTL(this.hass),
|
||||||
})}"
|
})}"
|
||||||
></paper-fab>
|
></ha-fab>
|
||||||
</ha-app-layout>
|
</ha-app-layout>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ class HaAutomationEditor extends LitElement {
|
|||||||
span[slot="introduction"] a {
|
span[slot="introduction"] a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
paper-fab {
|
ha-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
@ -310,21 +310,21 @@ class HaAutomationEditor extends LitElement {
|
|||||||
transition: margin-bottom 0.3s;
|
transition: margin-bottom 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide] {
|
ha-fab[is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[dirty] {
|
ha-fab[dirty] {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab.rtl {
|
ha-fab.rtl {
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide].rtl {
|
ha-fab[is-wide].rtl {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
|
@ -8,13 +8,13 @@ import {
|
|||||||
customElement,
|
customElement,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
import "@polymer/paper-tooltip/paper-tooltip";
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
|
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-fab";
|
||||||
import "../../../components/entity/ha-entity-toggle";
|
import "../../../components/entity/ha-entity-toggle";
|
||||||
|
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
@ -136,7 +136,7 @@ class HaAutomationPicker extends LitElement {
|
|||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
|
|
||||||
<a href="/config/automation/new">
|
<a href="/config/automation/new">
|
||||||
<paper-fab
|
<ha-fab
|
||||||
slot="fab"
|
slot="fab"
|
||||||
?is-wide=${this.isWide}
|
?is-wide=${this.isWide}
|
||||||
icon="hass:plus"
|
icon="hass:plus"
|
||||||
@ -144,7 +144,7 @@ class HaAutomationPicker extends LitElement {
|
|||||||
"ui.panel.config.automation.picker.add_automation"
|
"ui.panel.config.automation.picker.add_automation"
|
||||||
)}
|
)}
|
||||||
?rtl=${computeRTL(this.hass)}
|
?rtl=${computeRTL(this.hass)}
|
||||||
></paper-fab
|
></ha-fab
|
||||||
></a>
|
></a>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
@ -186,24 +186,24 @@ class HaAutomationPicker extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab {
|
ha-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide] {
|
ha-fab[is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[rtl] {
|
ha-fab[rtl] {
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[rtl][is-wide] {
|
ha-fab[rtl][is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
|
@ -48,9 +48,9 @@ class HaCustomizeAttribute extends PolymerElement {
|
|||||||
|
|
||||||
tapButton() {
|
tapButton() {
|
||||||
if (this.item.secondary) {
|
if (this.item.secondary) {
|
||||||
this.item = Object.assign({}, this.item, { secondary: false });
|
this.item = { ...this.item, secondary: false };
|
||||||
} else {
|
} else {
|
||||||
this.item = Object.assign({}, this.item, { closed: true });
|
this.item = { ...this.item, closed: true };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ class HaCustomizeAttribute extends PolymerElement {
|
|||||||
this.$.child = child = document.createElement(tag.toLowerCase());
|
this.$.child = child = document.createElement(tag.toLowerCase());
|
||||||
child.className = "form-control";
|
child.className = "form-control";
|
||||||
child.addEventListener("item-changed", () => {
|
child.addEventListener("item-changed", () => {
|
||||||
this.item = Object.assign({}, child.item);
|
this.item = { ...child.item };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
child.setProperties({ item: this.item });
|
child.setProperties({ item: this.item });
|
||||||
|
@ -141,17 +141,15 @@ class HaFormCustomize extends PolymerElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_initOpenObject(key, value, secondary, config) {
|
_initOpenObject(key, value, secondary, config) {
|
||||||
return Object.assign(
|
return {
|
||||||
{
|
attribute: key,
|
||||||
attribute: key,
|
value: value,
|
||||||
value: value,
|
closed: false,
|
||||||
closed: false,
|
domain: computeStateDomain(this.entity),
|
||||||
domain: computeStateDomain(this.entity),
|
secondary: secondary,
|
||||||
secondary: secondary,
|
description: key,
|
||||||
description: key,
|
...config,
|
||||||
},
|
};
|
||||||
config
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadEntity(entity) {
|
loadEntity(entity) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||||
import "@polymer/paper-tooltip/paper-tooltip";
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
import "@polymer/iron-icon/iron-icon";
|
import "@polymer/iron-icon/iron-icon";
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
@ -9,6 +8,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-fab";
|
||||||
import "../../../components/entity/ha-state-icon";
|
import "../../../components/entity/ha-state-icon";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import "../../../resources/ha-style";
|
import "../../../resources/ha-style";
|
||||||
@ -53,24 +53,24 @@ class HaConfigManagerDashboard extends LocalizeMixin(
|
|||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
paper-fab {
|
ha-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide] {
|
ha-fab[is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[rtl] {
|
ha-fab[rtl] {
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[rtl][is-wide] {
|
ha-fab[rtl][is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
@ -141,13 +141,13 @@ class HaConfigManagerDashboard extends LocalizeMixin(
|
|||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
|
|
||||||
<paper-fab
|
<ha-fab
|
||||||
icon="hass:plus"
|
icon="hass:plus"
|
||||||
title="[[localize('ui.panel.config.integrations.new')]]"
|
title="[[localize('ui.panel.config.integrations.new')]]"
|
||||||
on-click="_createFlow"
|
on-click="_createFlow"
|
||||||
is-wide$="[[isWide]]"
|
is-wide$="[[isWide]]"
|
||||||
rtl$="[[rtl]]"
|
rtl$="[[rtl]]"
|
||||||
></paper-fab>
|
></ha-fab>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import Trigger from "./trigger/index";
|
|||||||
import Condition from "./condition/index";
|
import Condition from "./condition/index";
|
||||||
import Script from "./script/index";
|
import Script from "./script/index";
|
||||||
|
|
||||||
export default class Automation extends Component {
|
export default class Automation extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -18,29 +18,26 @@ export default class Automation extends Component {
|
|||||||
this.actionChanged = this.actionChanged.bind(this);
|
this.actionChanged = this.actionChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(ev) {
|
public onChange(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange({
|
||||||
Object.assign({}, this.props.automation, {
|
...this.props.automation,
|
||||||
[ev.target.name]: ev.target.value,
|
[ev.target.name]: ev.target.value,
|
||||||
})
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerChanged(trigger) {
|
public triggerChanged(trigger) {
|
||||||
this.props.onChange(Object.assign({}, this.props.automation, { trigger }));
|
this.props.onChange({ ...this.props.automation, trigger });
|
||||||
}
|
}
|
||||||
|
|
||||||
conditionChanged(condition) {
|
public conditionChanged(condition) {
|
||||||
this.props.onChange(
|
this.props.onChange({ ...this.props.automation, condition });
|
||||||
Object.assign({}, this.props.automation, { condition })
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actionChanged(action) {
|
public actionChanged(action) {
|
||||||
this.props.onChange(Object.assign({}, this.props.automation, { action }));
|
this.props.onChange({ ...this.props.automation, action });
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ automation, isWide, hass, localize }) {
|
public render({ automation, isWide, hass, localize }) {
|
||||||
const { alias, trigger, condition, action } = automation;
|
const { alias, trigger, condition, action } = automation;
|
||||||
|
|
||||||
return (
|
return (
|
@ -23,25 +23,26 @@ const TYPES = {
|
|||||||
|
|
||||||
const OPTIONS = Object.keys(TYPES).sort();
|
const OPTIONS = Object.keys(TYPES).sort();
|
||||||
|
|
||||||
export default class ConditionRow extends Component {
|
export default class ConditionRow extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.typeChanged = this.typeChanged.bind(this);
|
this.typeChanged = this.typeChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
typeChanged(ev) {
|
public typeChanged(ev) {
|
||||||
const type = ev.target.selectedItem.attributes.condition.value;
|
const type = ev.target.selectedItem.attributes.condition.value;
|
||||||
|
|
||||||
if (type !== this.props.condition.condition) {
|
if (type !== this.props.condition.condition) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
condition: type,
|
||||||
Object.assign({ condition: type }, TYPES[type].defaultConfig)
|
...TYPES[type].defaultConfig,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ index, condition, onChange, hass, localize }) {
|
public render({ index, condition, onChange, hass, localize }) {
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
const Comp = TYPES[condition.condition];
|
const Comp = TYPES[condition.condition];
|
||||||
const selected = OPTIONS.indexOf(condition.condition);
|
const selected = OPTIONS.indexOf(condition.condition);
|
||||||
|
|
@ -7,14 +7,14 @@ import "../../../../components/ha-card";
|
|||||||
|
|
||||||
import ConditionEdit from "./condition_edit";
|
import ConditionEdit from "./condition_edit";
|
||||||
|
|
||||||
export default class ConditionRow extends Component {
|
export default class ConditionRow extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onDelete = this.onDelete.bind(this);
|
this.onDelete = this.onDelete.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelete() {
|
public onDelete() {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
if (
|
if (
|
||||||
confirm(
|
confirm(
|
||||||
@ -27,7 +27,7 @@ export default class ConditionRow extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(props) {
|
public render(props) {
|
||||||
return (
|
return (
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
@ -3,32 +3,28 @@ import { h, Component } from "preact";
|
|||||||
import "../../../../components/device/ha-device-picker";
|
import "../../../../components/device/ha-device-picker";
|
||||||
import "../../../../components/device/ha-device-condition-picker";
|
import "../../../../components/device/ha-device-condition-picker";
|
||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
export default class DeviceCondition extends Component<any, any> {
|
||||||
|
|
||||||
export default class DeviceCondition extends Component {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.onChange = onChangeEvent.bind(this, "condition");
|
|
||||||
this.devicePicked = this.devicePicked.bind(this);
|
this.devicePicked = this.devicePicked.bind(this);
|
||||||
this.deviceConditionPicked = this.deviceConditionPicked.bind(this);
|
this.deviceConditionPicked = this.deviceConditionPicked.bind(this);
|
||||||
this.state.device_id = undefined;
|
this.state = { device_id: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
devicePicked(ev) {
|
public devicePicked(ev) {
|
||||||
this.setState({ device_id: ev.target.value });
|
this.setState({ device_id: ev.target.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceConditionPicked(ev) {
|
public deviceConditionPicked(ev) {
|
||||||
const deviceCondition = ev.target.value;
|
const deviceCondition = ev.target.value;
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, deviceCondition);
|
||||||
this.props.index,
|
|
||||||
(this.props.condition = deviceCondition)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ condition, hass }, { device_id }) {
|
public render({ condition, hass }, { device_id }) {
|
||||||
if (device_id === undefined) device_id = condition.device_id;
|
if (device_id === undefined) {
|
||||||
|
device_id = condition.device_id;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -50,7 +46,7 @@ export default class DeviceCondition extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceCondition.defaultConfig = {
|
(DeviceCondition as any).defaultConfig = {
|
||||||
device_id: "",
|
device_id: "",
|
||||||
domain: "",
|
domain: "",
|
||||||
entity_id: "",
|
entity_id: "",
|
@ -4,7 +4,7 @@ import "../../../../components/ha-card";
|
|||||||
|
|
||||||
import ConditionRow from "./condition_row";
|
import ConditionRow from "./condition_row";
|
||||||
|
|
||||||
export default class Condition extends Component {
|
export default class Condition extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ export default class Condition extends Component {
|
|||||||
this.conditionChanged = this.conditionChanged.bind(this);
|
this.conditionChanged = this.conditionChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
addCondition() {
|
public addCondition() {
|
||||||
const condition = this.props.condition.concat({
|
const condition = this.props.condition.concat({
|
||||||
condition: "state",
|
condition: "state",
|
||||||
});
|
});
|
||||||
@ -20,7 +20,7 @@ export default class Condition extends Component {
|
|||||||
this.props.onChange(condition);
|
this.props.onChange(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
conditionChanged(index, newValue) {
|
public conditionChanged(index, newValue) {
|
||||||
const condition = this.props.condition.concat();
|
const condition = this.props.condition.concat();
|
||||||
|
|
||||||
if (newValue === null) {
|
if (newValue === null) {
|
||||||
@ -32,7 +32,7 @@ export default class Condition extends Component {
|
|||||||
this.props.onChange(condition);
|
this.props.onChange(condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ condition, hass, localize }) {
|
public render({ condition, hass, localize }) {
|
||||||
return (
|
return (
|
||||||
<div class="triggers">
|
<div class="triggers">
|
||||||
{condition.map((cnd, idx) => (
|
{condition.map((cnd, idx) => (
|
@ -5,7 +5,8 @@ import "../../../../components/entity/ha-entity-picker";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class NumericStateCondition extends Component {
|
export default class NumericStateCondition extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -13,15 +14,15 @@ export default class NumericStateCondition extends Component {
|
|||||||
this.entityPicked = this.entityPicked.bind(this);
|
this.entityPicked = this.entityPicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityPicked(ev) {
|
public entityPicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.condition,
|
||||||
Object.assign({}, this.props.condition, { entity_id: ev.target.value })
|
entity_id: ev.target.value,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ condition, hass, localize }) {
|
public render({ condition, hass, localize }) {
|
||||||
const { value_template, entity_id, below, above } = condition;
|
const { value_template, entity_id, below, above } = condition;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -61,6 +62,6 @@ export default class NumericStateCondition extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NumericStateCondition.defaultConfig = {
|
(NumericStateCondition as any).defaultConfig = {
|
||||||
entity_id: "",
|
entity_id: "",
|
||||||
};
|
};
|
@ -4,7 +4,8 @@ import "../../../../components/entity/ha-entity-picker";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class StateCondition extends Component {
|
export default class StateCondition extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -12,15 +13,15 @@ export default class StateCondition extends Component {
|
|||||||
this.entityPicked = this.entityPicked.bind(this);
|
this.entityPicked = this.entityPicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityPicked(ev) {
|
public entityPicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.condition,
|
||||||
Object.assign({}, this.props.condition, { entity_id: ev.target.value })
|
entity_id: ev.target.value,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ condition, hass, localize }) {
|
public render({ condition, hass, localize }) {
|
||||||
const { entity_id, state } = condition;
|
const { entity_id, state } = condition;
|
||||||
const cndFor = condition.for;
|
const cndFor = condition.for;
|
||||||
return (
|
return (
|
||||||
@ -45,7 +46,7 @@ export default class StateCondition extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StateCondition.defaultConfig = {
|
(StateCondition as any).defaultConfig = {
|
||||||
entity_id: "",
|
entity_id: "",
|
||||||
state: "",
|
state: "",
|
||||||
};
|
};
|
@ -5,7 +5,11 @@ import "@polymer/paper-radio-group/paper-radio-group";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class SunCondition extends Component {
|
export default class SunCondition extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
|
private afterPicked: (obj: any) => void;
|
||||||
|
private beforePicked: (obj: any) => void;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -14,8 +18,8 @@ export default class SunCondition extends Component {
|
|||||||
this.beforePicked = this.radioGroupPicked.bind(this, "before");
|
this.beforePicked = this.radioGroupPicked.bind(this, "before");
|
||||||
}
|
}
|
||||||
|
|
||||||
radioGroupPicked(key, ev) {
|
public radioGroupPicked(key, ev) {
|
||||||
const condition = Object.assign({}, this.props.condition);
|
const condition = { ...this.props.condition };
|
||||||
|
|
||||||
if (ev.target.selected) {
|
if (ev.target.selected) {
|
||||||
condition[key] = ev.target.selected;
|
condition[key] = ev.target.selected;
|
||||||
@ -26,7 +30,7 @@ export default class SunCondition extends Component {
|
|||||||
this.props.onChange(this.props.index, condition);
|
this.props.onChange(this.props.index, condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ condition, localize }) {
|
public render({ condition, localize }) {
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
const { after, after_offset, before, before_offset } = condition;
|
const { after, after_offset, before, before_offset } = condition;
|
||||||
return (
|
return (
|
||||||
@ -101,4 +105,4 @@ export default class SunCondition extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SunCondition.defaultConfig = {};
|
(SunCondition as any).defaultConfig = {};
|
@ -3,14 +3,15 @@ import "../../../../components/ha-textarea";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class TemplateCondition extends Component {
|
export default class TemplateCondition extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onChange = onChangeEvent.bind(this, "condition");
|
this.onChange = onChangeEvent.bind(this, "condition");
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ condition, localize }) {
|
public render({ condition, localize }) {
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
const { value_template } = condition;
|
const { value_template } = condition;
|
||||||
return (
|
return (
|
||||||
@ -29,6 +30,6 @@ export default class TemplateCondition extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateCondition.defaultConfig = {
|
(TemplateCondition as any).defaultConfig = {
|
||||||
value_template: "",
|
value_template: "",
|
||||||
};
|
};
|
@ -3,7 +3,8 @@ import "@polymer/paper-input/paper-input";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class TimeCondition extends Component {
|
export default class TimeCondition extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ export default class TimeCondition extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ condition, localize }) {
|
public render({ condition, localize }) {
|
||||||
const { after, before } = condition;
|
const { after, before } = condition;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -36,4 +37,4 @@ export default class TimeCondition extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeCondition.defaultConfig = {};
|
(TimeCondition as any).defaultConfig = {};
|
@ -1,6 +1,5 @@
|
|||||||
import { h, Component } from "preact";
|
import { h, Component } from "preact";
|
||||||
import "../../../../components/entity/ha-entity-picker";
|
import "../../../../components/entity/ha-entity-picker";
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
|
||||||
import hasLocation from "../../../../common/entity/has_location";
|
import hasLocation from "../../../../common/entity/has_location";
|
||||||
import computeStateDomain from "../../../../common/entity/compute_state_domain";
|
import computeStateDomain from "../../../../common/entity/compute_state_domain";
|
||||||
|
|
||||||
@ -8,31 +7,30 @@ function zoneAndLocationFilter(stateObj) {
|
|||||||
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";
|
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ZoneCondition extends Component {
|
export default class ZoneCondition extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onChange = onChangeEvent.bind(this, "condition");
|
|
||||||
this.entityPicked = this.entityPicked.bind(this);
|
this.entityPicked = this.entityPicked.bind(this);
|
||||||
this.zonePicked = this.zonePicked.bind(this);
|
this.zonePicked = this.zonePicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityPicked(ev) {
|
public entityPicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.condition,
|
||||||
Object.assign({}, this.props.condition, { entity_id: ev.target.value })
|
entity_id: ev.target.value,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
zonePicked(ev) {
|
public zonePicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.condition,
|
||||||
Object.assign({}, this.props.condition, { zone: ev.target.value })
|
zone: ev.target.value,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ condition, hass, localize }) {
|
public render({ condition, hass, localize }) {
|
||||||
const { entity_id, zone } = condition;
|
const { entity_id, zone } = condition;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -61,7 +59,7 @@ export default class ZoneCondition extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneCondition.defaultConfig = {
|
(ZoneCondition as any).defaultConfig = {
|
||||||
entity_id: "",
|
entity_id: "",
|
||||||
zone: "",
|
zone: "",
|
||||||
};
|
};
|
@ -1,15 +1,18 @@
|
|||||||
import { h, Component } from "preact";
|
import { h, Component } from "preact";
|
||||||
import "../../../components/ha-textarea";
|
import "../../../components/ha-textarea";
|
||||||
|
|
||||||
export default class JSONTextArea extends Component {
|
export default class JSONTextArea extends Component<any, any> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state.isValid = true;
|
this.state = {
|
||||||
this.state.value = JSON.stringify(props.value || {}, null, 2);
|
isvalid: true,
|
||||||
|
value: JSON.stringify(props.value || {}, null, 2),
|
||||||
|
};
|
||||||
|
|
||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(ev) {
|
public onChange(ev) {
|
||||||
const value = ev.target.value;
|
const value = ev.target.value;
|
||||||
let parsed;
|
let parsed;
|
||||||
let isValid;
|
let isValid;
|
||||||
@ -31,16 +34,18 @@ export default class JSONTextArea extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps({ value }) {
|
public componentWillReceiveProps({ value }) {
|
||||||
if (value === this.props.value) return;
|
if (value === this.props.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
value: JSON.stringify(value, null, 2),
|
value: JSON.stringify(value, null, 2),
|
||||||
isValid: true,
|
isValid: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ label }, { value, isValid }) {
|
public render({ label }, { value, isValid }) {
|
||||||
const style = {
|
const style: any = {
|
||||||
minWidth: 300,
|
minWidth: 300,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
};
|
};
|
@ -7,6 +7,23 @@ declare global {
|
|||||||
namespace JSX {
|
namespace JSX {
|
||||||
interface IntrinsicElements {
|
interface IntrinsicElements {
|
||||||
"paper-input": Partial<PaperInputElement>;
|
"paper-input": Partial<PaperInputElement>;
|
||||||
|
"ha-config-section": any;
|
||||||
|
"ha-card": any;
|
||||||
|
"paper-radio-button": any;
|
||||||
|
"paper-radio-group": any;
|
||||||
|
"ha-entity-picker": any;
|
||||||
|
"paper-listbox": any;
|
||||||
|
"paper-item": any;
|
||||||
|
"paper-menu-button": any;
|
||||||
|
"paper-dropdown-menu-light": any;
|
||||||
|
"paper-icon-button": any;
|
||||||
|
"ha-device-picker": any;
|
||||||
|
"ha-device-condition-picker": any;
|
||||||
|
"ha-textarea": any;
|
||||||
|
"ha-service-picker": any;
|
||||||
|
"mwc-button": any;
|
||||||
|
"ha-device-trigger-picker": any;
|
||||||
|
"ha-device-action-picker": any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,13 @@ import "../../../components/ha-card";
|
|||||||
|
|
||||||
import Script from "./script/index";
|
import Script from "./script/index";
|
||||||
|
|
||||||
export default class ScriptEditor extends Component {
|
export default class ScriptEditor extends Component<{
|
||||||
|
onChange: (...args: any[]) => any;
|
||||||
|
script: any;
|
||||||
|
isWide: any;
|
||||||
|
hass: any;
|
||||||
|
localize: any;
|
||||||
|
}> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -14,19 +20,19 @@ export default class ScriptEditor extends Component {
|
|||||||
this.sequenceChanged = this.sequenceChanged.bind(this);
|
this.sequenceChanged = this.sequenceChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(ev) {
|
public onChange(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange({
|
||||||
Object.assign({}, this.props.script, {
|
...this.props.script,
|
||||||
[ev.target.name]: ev.target.value,
|
[ev.target.name]: ev.target.value,
|
||||||
})
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sequenceChanged(sequence) {
|
public sequenceChanged(sequence) {
|
||||||
this.props.onChange(Object.assign({}, this.props.script, { sequence }));
|
this.props.onChange({ ...this.props.script, sequence });
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ script, isWide, hass, localize }) {
|
// @ts-ignore
|
||||||
|
public render({ script, isWide, hass, localize }) {
|
||||||
const { alias, sequence } = script;
|
const { alias, sequence } = script;
|
||||||
|
|
||||||
return (
|
return (
|
@ -6,6 +6,7 @@ import "@polymer/paper-item/paper-item";
|
|||||||
import CallServiceAction from "./call_service";
|
import CallServiceAction from "./call_service";
|
||||||
import ConditionAction from "./condition";
|
import ConditionAction from "./condition";
|
||||||
import DelayAction from "./delay";
|
import DelayAction from "./delay";
|
||||||
|
import DeviceAction from "./device";
|
||||||
import EventAction from "./event";
|
import EventAction from "./event";
|
||||||
import WaitAction from "./wait";
|
import WaitAction from "./wait";
|
||||||
|
|
||||||
@ -15,12 +16,14 @@ const TYPES = {
|
|||||||
wait_template: WaitAction,
|
wait_template: WaitAction,
|
||||||
condition: ConditionAction,
|
condition: ConditionAction,
|
||||||
event: EventAction,
|
event: EventAction,
|
||||||
|
device_id: DeviceAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
const OPTIONS = Object.keys(TYPES).sort();
|
const OPTIONS = Object.keys(TYPES).sort();
|
||||||
|
|
||||||
function getType(action) {
|
function getType(action) {
|
||||||
const keys = Object.keys(TYPES);
|
const keys = Object.keys(TYPES);
|
||||||
|
// tslint:disable-next-line: prefer-for-of
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
if (keys[i] in action) {
|
if (keys[i] in action) {
|
||||||
return keys[i];
|
return keys[i];
|
||||||
@ -29,14 +32,14 @@ function getType(action) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Action extends Component {
|
export default class Action extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.typeChanged = this.typeChanged.bind(this);
|
this.typeChanged = this.typeChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
typeChanged(ev) {
|
public typeChanged(ev) {
|
||||||
const newType = ev.target.selectedItem.attributes.action.value;
|
const newType = ev.target.selectedItem.attributes.action.value;
|
||||||
const oldType = getType(this.props.action);
|
const oldType = getType(this.props.action);
|
||||||
|
|
||||||
@ -45,9 +48,11 @@ export default class Action extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ index, action, onChange, hass, localize }) {
|
public render({ index, action, onChange, hass, localize }) {
|
||||||
const type = getType(action);
|
const type = getType(action);
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
const Comp = type && TYPES[type];
|
const Comp = type && TYPES[type];
|
||||||
|
// @ts-ignore
|
||||||
const selected = OPTIONS.indexOf(type);
|
const selected = OPTIONS.indexOf(type);
|
||||||
|
|
||||||
if (!Comp) {
|
if (!Comp) {
|
@ -7,14 +7,14 @@ import "../../../../components/ha-card";
|
|||||||
|
|
||||||
import ActionEdit from "./action_edit";
|
import ActionEdit from "./action_edit";
|
||||||
|
|
||||||
export default class Action extends Component {
|
export default class Action extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onDelete = this.onDelete.bind(this);
|
this.onDelete = this.onDelete.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelete() {
|
public onDelete() {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
if (
|
if (
|
||||||
confirm(
|
confirm(
|
||||||
@ -27,7 +27,7 @@ export default class Action extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(props) {
|
public render(props) {
|
||||||
return (
|
return (
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
@ -3,7 +3,7 @@ import "../../../../components/ha-service-picker";
|
|||||||
|
|
||||||
import JSONTextArea from "../json_textarea";
|
import JSONTextArea from "../json_textarea";
|
||||||
|
|
||||||
export default class CallServiceAction extends Component {
|
export default class CallServiceAction extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -11,21 +11,18 @@ export default class CallServiceAction extends Component {
|
|||||||
this.serviceDataChanged = this.serviceDataChanged.bind(this);
|
this.serviceDataChanged = this.serviceDataChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceChanged(ev) {
|
public serviceChanged(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.action,
|
||||||
Object.assign({}, this.props.action, { service: ev.target.value })
|
service: ev.target.value,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceDataChanged(data) {
|
public serviceDataChanged(data) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, { ...this.props.action, data });
|
||||||
this.props.index,
|
|
||||||
Object.assign({}, this.props.action, { data })
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ action, hass, localize }) {
|
public render({ action, hass, localize }) {
|
||||||
const { service, data } = action;
|
const { service, data } = action;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -47,7 +44,7 @@ export default class CallServiceAction extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CallServiceAction.defaultConfig = {
|
(CallServiceAction as any).defaultConfig = {
|
||||||
alias: "",
|
alias: "",
|
||||||
service: "",
|
service: "",
|
||||||
data: {},
|
data: {},
|
@ -3,9 +3,9 @@ import { h, Component } from "preact";
|
|||||||
import StateCondition from "../condition/state";
|
import StateCondition from "../condition/state";
|
||||||
import ConditionEdit from "../condition/condition_edit";
|
import ConditionEdit from "../condition/condition_edit";
|
||||||
|
|
||||||
export default class ConditionAction extends Component {
|
export default class ConditionAction extends Component<any> {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
render({ action, index, onChange, hass, localize }) {
|
public render({ action, index, onChange, hass, localize }) {
|
||||||
return (
|
return (
|
||||||
<ConditionEdit
|
<ConditionEdit
|
||||||
condition={action}
|
condition={action}
|
||||||
@ -18,7 +18,7 @@ export default class ConditionAction extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConditionAction.defaultConfig = Object.assign(
|
(ConditionAction as any).defaultConfig = {
|
||||||
{ condition: "state" },
|
condition: "state",
|
||||||
StateCondition.defaultConfig
|
...(StateCondition as any).defaultConfig,
|
||||||
);
|
};
|
@ -2,14 +2,15 @@ import { h, Component } from "preact";
|
|||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class DelayAction extends Component {
|
export default class DelayAction extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onChange = onChangeEvent.bind(this, "action");
|
this.onChange = onChangeEvent.bind(this, "action");
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ action, localize }) {
|
public render({ action, localize }) {
|
||||||
const { delay } = action;
|
const { delay } = action;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -26,6 +27,6 @@ export default class DelayAction extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DelayAction.defaultConfig = {
|
(DelayAction as any).defaultConfig = {
|
||||||
delay: "",
|
delay: "",
|
||||||
};
|
};
|
63
src/panels/config/js/script/device.tsx
Normal file
63
src/panels/config/js/script/device.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { h, Component } from "preact";
|
||||||
|
|
||||||
|
import "../../../../components/device/ha-device-picker";
|
||||||
|
import "../../../../components/device/ha-device-action-picker";
|
||||||
|
import { HomeAssistant } from "../../../../types";
|
||||||
|
import { DeviceAction } from "../../../../data/script";
|
||||||
|
|
||||||
|
export default class DeviceActionEditor extends Component<
|
||||||
|
{
|
||||||
|
index: number;
|
||||||
|
action: DeviceAction;
|
||||||
|
hass: HomeAssistant;
|
||||||
|
onChange(index: number, action: DeviceAction);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
device_id: string | undefined;
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
public static defaultConfig: DeviceAction = {
|
||||||
|
device_id: "",
|
||||||
|
domain: "",
|
||||||
|
entity_id: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.devicePicked = this.devicePicked.bind(this);
|
||||||
|
this.deviceActionPicked = this.deviceActionPicked.bind(this);
|
||||||
|
this.state = { device_id: undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const { action, hass } = this.props;
|
||||||
|
const deviceId = this.state.device_id || action.device_id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ha-device-picker
|
||||||
|
value={deviceId}
|
||||||
|
onChange={this.devicePicked}
|
||||||
|
hass={hass}
|
||||||
|
label="Device"
|
||||||
|
/>
|
||||||
|
<ha-device-action-picker
|
||||||
|
value={action}
|
||||||
|
deviceId={deviceId}
|
||||||
|
onChange={this.deviceActionPicked}
|
||||||
|
hass={hass}
|
||||||
|
label="Action"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private devicePicked(ev) {
|
||||||
|
this.setState({ device_id: ev.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
private deviceActionPicked(ev) {
|
||||||
|
const deviceAction = { ...ev.target.value };
|
||||||
|
this.props.onChange(this.props.index, deviceAction);
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ import "../../../../components/ha-card";
|
|||||||
|
|
||||||
import ActionRow from "./action_row";
|
import ActionRow from "./action_row";
|
||||||
|
|
||||||
export default class Script extends Component {
|
export default class Script extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ export default class Script extends Component {
|
|||||||
this.actionChanged = this.actionChanged.bind(this);
|
this.actionChanged = this.actionChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
addAction() {
|
public addAction() {
|
||||||
const script = this.props.script.concat({
|
const script = this.props.script.concat({
|
||||||
service: "",
|
service: "",
|
||||||
});
|
});
|
||||||
@ -20,7 +20,7 @@ export default class Script extends Component {
|
|||||||
this.props.onChange(script);
|
this.props.onChange(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
actionChanged(index, newValue) {
|
public actionChanged(index, newValue) {
|
||||||
const script = this.props.script.concat();
|
const script = this.props.script.concat();
|
||||||
|
|
||||||
if (newValue === null) {
|
if (newValue === null) {
|
||||||
@ -32,7 +32,7 @@ export default class Script extends Component {
|
|||||||
this.props.onChange(script);
|
this.props.onChange(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ script, hass, localize }) {
|
public render({ script, hass, localize }) {
|
||||||
return (
|
return (
|
||||||
<div class="script">
|
<div class="script">
|
||||||
{script.map((act, idx) => (
|
{script.map((act, idx) => (
|
@ -5,7 +5,8 @@ import "../../../../components/ha-textarea";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class WaitAction extends Component {
|
export default class WaitAction extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -15,16 +16,14 @@ export default class WaitAction extends Component {
|
|||||||
|
|
||||||
// Gets fired on mount. If empty, onChangeEvent removes attribute.
|
// Gets fired on mount. If empty, onChangeEvent removes attribute.
|
||||||
// Without the attribute this action is no longer matched to this component.
|
// Without the attribute this action is no longer matched to this component.
|
||||||
onTemplateChange(ev) {
|
public onTemplateChange(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.action,
|
||||||
Object.assign({}, this.props.action, {
|
[ev.target.getAttribute("name")]: ev.target.value,
|
||||||
[ev.target.getAttribute("name")]: ev.target.value,
|
});
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ action, localize }) {
|
public render({ action, localize }) {
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
const { wait_template, timeout } = action;
|
const { wait_template, timeout } = action;
|
||||||
return (
|
return (
|
||||||
@ -51,7 +50,7 @@ export default class WaitAction extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitAction.defaultConfig = {
|
(WaitAction as any).defaultConfig = {
|
||||||
wait_template: "",
|
wait_template: "",
|
||||||
timeout: "",
|
timeout: "",
|
||||||
};
|
};
|
@ -2,31 +2,29 @@ import { h, Component } from "preact";
|
|||||||
|
|
||||||
import "../../../../components/device/ha-device-picker";
|
import "../../../../components/device/ha-device-picker";
|
||||||
import "../../../../components/device/ha-device-trigger-picker";
|
import "../../../../components/device/ha-device-trigger-picker";
|
||||||
import "../../../../components/device/ha-device-automation-picker";
|
|
||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
export default class DeviceTrigger extends Component<any, any> {
|
||||||
|
|
||||||
export default class DeviceTrigger extends Component {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.onChange = onChangeEvent.bind(this, "trigger");
|
|
||||||
this.devicePicked = this.devicePicked.bind(this);
|
this.devicePicked = this.devicePicked.bind(this);
|
||||||
this.deviceTriggerPicked = this.deviceTriggerPicked.bind(this);
|
this.deviceTriggerPicked = this.deviceTriggerPicked.bind(this);
|
||||||
this.state.device_id = undefined;
|
this.state = { device_id: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
devicePicked(ev) {
|
public devicePicked(ev) {
|
||||||
this.setState({ device_id: ev.target.value });
|
this.setState({ device_id: ev.target.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceTriggerPicked(ev) {
|
public deviceTriggerPicked(ev) {
|
||||||
const deviceTrigger = ev.target.value;
|
const deviceTrigger = ev.target.value;
|
||||||
this.props.onChange(this.props.index, (this.props.trigger = deviceTrigger));
|
this.props.onChange(this.props.index, deviceTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, hass }, { device_id }) {
|
public render({ trigger, hass }, { device_id }) {
|
||||||
if (device_id === undefined) device_id = trigger.device_id;
|
if (device_id === undefined) {
|
||||||
|
device_id = trigger.device_id;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -48,7 +46,7 @@ export default class DeviceTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceTrigger.defaultConfig = {
|
(DeviceTrigger as any).defaultConfig = {
|
||||||
device_id: "",
|
device_id: "",
|
||||||
domain: "",
|
domain: "",
|
||||||
entity_id: "",
|
entity_id: "",
|
@ -4,7 +4,8 @@ import "@polymer/paper-input/paper-input";
|
|||||||
import JSONTextArea from "../json_textarea";
|
import JSONTextArea from "../json_textarea";
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class EventTrigger extends Component {
|
export default class EventTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -13,14 +14,15 @@ export default class EventTrigger extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
eventDataChanged(event_data) {
|
// tslint:disable-next-line: variable-name
|
||||||
this.props.onChange(
|
public eventDataChanged(event_data) {
|
||||||
this.props.index,
|
this.props.onChange(this.props.index, {
|
||||||
Object.assign({}, this.props.trigger, { event_data })
|
...this.props.trigger,
|
||||||
);
|
event_data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ trigger, localize }) {
|
public render({ trigger, localize }) {
|
||||||
const { event_type, event_data } = trigger;
|
const { event_type, event_data } = trigger;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -44,7 +46,7 @@ export default class EventTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventTrigger.defaultConfig = {
|
(EventTrigger as any).defaultConfig = {
|
||||||
event_type: "",
|
event_type: "",
|
||||||
event_data: {},
|
event_data: {},
|
||||||
};
|
};
|
@ -5,7 +5,8 @@ import "../../../../components/entity/ha-entity-picker";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class GeolocationTrigger extends Component {
|
export default class GeolocationTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -14,22 +15,22 @@ export default class GeolocationTrigger extends Component {
|
|||||||
this.radioGroupPicked = this.radioGroupPicked.bind(this);
|
this.radioGroupPicked = this.radioGroupPicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
zonePicked(ev) {
|
public zonePicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.trigger,
|
||||||
Object.assign({}, this.props.trigger, { zone: ev.target.value })
|
zone: ev.target.value,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
radioGroupPicked(ev) {
|
public radioGroupPicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.trigger,
|
||||||
Object.assign({}, this.props.trigger, { event: ev.target.selected })
|
event: ev.target.selected,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, hass, localize }) {
|
public render({ trigger, hass, localize }) {
|
||||||
const { source, zone, event } = trigger;
|
const { source, zone, event } = trigger;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -78,7 +79,7 @@ export default class GeolocationTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GeolocationTrigger.defaultConfig = {
|
(GeolocationTrigger as any).defaultConfig = {
|
||||||
source: "",
|
source: "",
|
||||||
zone: "",
|
zone: "",
|
||||||
event: "enter",
|
event: "enter",
|
@ -2,22 +2,22 @@ import { h, Component } from "preact";
|
|||||||
import "@polymer/paper-radio-button/paper-radio-button";
|
import "@polymer/paper-radio-button/paper-radio-button";
|
||||||
import "@polymer/paper-radio-group/paper-radio-group";
|
import "@polymer/paper-radio-group/paper-radio-group";
|
||||||
|
|
||||||
export default class HassTrigger extends Component {
|
export default class HassTrigger extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.radioGroupPicked = this.radioGroupPicked.bind(this);
|
this.radioGroupPicked = this.radioGroupPicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
radioGroupPicked(ev) {
|
public radioGroupPicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.trigger,
|
||||||
Object.assign({}, this.props.trigger, { event: ev.target.selected })
|
event: ev.target.selected,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, localize }) {
|
public render({ trigger, localize }) {
|
||||||
const { event } = trigger;
|
const { event } = trigger;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -47,6 +47,6 @@ export default class HassTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HassTrigger.defaultConfig = {
|
(HassTrigger as any).defaultConfig = {
|
||||||
event: "start",
|
event: "start",
|
||||||
};
|
};
|
@ -5,7 +5,7 @@ import "../../../../components/ha-card";
|
|||||||
import TriggerRow from "./trigger_row";
|
import TriggerRow from "./trigger_row";
|
||||||
import StateTrigger from "./state";
|
import StateTrigger from "./state";
|
||||||
|
|
||||||
export default class Trigger extends Component {
|
export default class Trigger extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -13,15 +13,16 @@ export default class Trigger extends Component {
|
|||||||
this.triggerChanged = this.triggerChanged.bind(this);
|
this.triggerChanged = this.triggerChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTrigger() {
|
public addTrigger() {
|
||||||
const trigger = this.props.trigger.concat(
|
const trigger = this.props.trigger.concat({
|
||||||
Object.assign({ platform: "state" }, StateTrigger.defaultConfig)
|
platform: "state",
|
||||||
);
|
...(StateTrigger as any).defaultConfig,
|
||||||
|
});
|
||||||
|
|
||||||
this.props.onChange(trigger);
|
this.props.onChange(trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerChanged(index, newValue) {
|
public triggerChanged(index, newValue) {
|
||||||
const trigger = this.props.trigger.concat();
|
const trigger = this.props.trigger.concat();
|
||||||
|
|
||||||
if (newValue === null) {
|
if (newValue === null) {
|
||||||
@ -33,7 +34,7 @@ export default class Trigger extends Component {
|
|||||||
this.props.onChange(trigger);
|
this.props.onChange(trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ trigger, hass, localize }) {
|
public render({ trigger, hass, localize }) {
|
||||||
return (
|
return (
|
||||||
<div class="triggers">
|
<div class="triggers">
|
||||||
{trigger.map((trg, idx) => (
|
{trigger.map((trg, idx) => (
|
@ -3,7 +3,8 @@ import "@polymer/paper-input/paper-input";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class MQTTTrigger extends Component {
|
export default class MQTTTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ export default class MQTTTrigger extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, localize }) {
|
public render({ trigger, localize }) {
|
||||||
const { topic, payload } = trigger;
|
const { topic, payload } = trigger;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -36,6 +37,6 @@ export default class MQTTTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MQTTTrigger.defaultConfig = {
|
(MQTTTrigger as any).defaultConfig = {
|
||||||
topic: "",
|
topic: "",
|
||||||
};
|
};
|
@ -6,7 +6,8 @@ import "../../../../components/entity/ha-entity-picker";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class NumericStateTrigger extends Component {
|
export default class NumericStateTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -14,15 +15,15 @@ export default class NumericStateTrigger extends Component {
|
|||||||
this.entityPicked = this.entityPicked.bind(this);
|
this.entityPicked = this.entityPicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityPicked(ev) {
|
public entityPicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.trigger,
|
||||||
Object.assign({}, this.props.trigger, { entity_id: ev.target.value })
|
entity_id: ev.target.value,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, hass, localize }) {
|
public render({ trigger, hass, localize }) {
|
||||||
const { value_template, entity_id, below, above } = trigger;
|
const { value_template, entity_id, below, above } = trigger;
|
||||||
let trgFor = trigger.for;
|
let trgFor = trigger.for;
|
||||||
|
|
||||||
@ -82,6 +83,6 @@ export default class NumericStateTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NumericStateTrigger.defaultConfig = {
|
(NumericStateTrigger as any).defaultConfig = {
|
||||||
entity_id: "",
|
entity_id: "",
|
||||||
};
|
};
|
@ -5,7 +5,8 @@ import "../../../../components/entity/ha-entity-picker";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class StateTrigger extends Component {
|
export default class StateTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -13,15 +14,15 @@ export default class StateTrigger extends Component {
|
|||||||
this.entityPicked = this.entityPicked.bind(this);
|
this.entityPicked = this.entityPicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityPicked(ev) {
|
public entityPicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.trigger,
|
||||||
Object.assign({}, this.props.trigger, { entity_id: ev.target.value })
|
entity_id: ev.target.value,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, hass, localize }) {
|
public render({ trigger, hass, localize }) {
|
||||||
const { entity_id, to } = trigger;
|
const { entity_id, to } = trigger;
|
||||||
const trgFrom = trigger.from;
|
const trgFrom = trigger.from;
|
||||||
let trgFor = trigger.for;
|
let trgFor = trigger.for;
|
||||||
@ -73,6 +74,6 @@ export default class StateTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StateTrigger.defaultConfig = {
|
(StateTrigger as any).defaultConfig = {
|
||||||
entity_id: "",
|
entity_id: "",
|
||||||
};
|
};
|
@ -6,7 +6,8 @@ import "@polymer/paper-radio-group/paper-radio-group";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class SunTrigger extends Component {
|
export default class SunTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -14,15 +15,15 @@ export default class SunTrigger extends Component {
|
|||||||
this.radioGroupPicked = this.radioGroupPicked.bind(this);
|
this.radioGroupPicked = this.radioGroupPicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
radioGroupPicked(ev) {
|
public radioGroupPicked(ev) {
|
||||||
this.props.onChange(
|
this.props.onChange(this.props.index, {
|
||||||
this.props.index,
|
...this.props.trigger,
|
||||||
Object.assign({}, this.props.trigger, { event: ev.target.selected })
|
event: ev.target.selected,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, localize }) {
|
public render({ trigger, localize }) {
|
||||||
const { offset, event } = trigger;
|
const { offset, event } = trigger;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -61,6 +62,6 @@ export default class SunTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SunTrigger.defaultConfig = {
|
(SunTrigger as any).defaultConfig = {
|
||||||
event: "sunrise",
|
event: "sunrise",
|
||||||
};
|
};
|
@ -4,14 +4,15 @@ import "../../../../components/ha-textarea";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class TemplateTrigger extends Component {
|
export default class TemplateTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onChange = onChangeEvent.bind(this, "trigger");
|
this.onChange = onChangeEvent.bind(this, "trigger");
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ trigger, localize }) {
|
public render({ trigger, localize }) {
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
const { value_template } = trigger;
|
const { value_template } = trigger;
|
||||||
return (
|
return (
|
||||||
@ -30,6 +31,6 @@ export default class TemplateTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateTrigger.defaultConfig = {
|
(TemplateTrigger as any).defaultConfig = {
|
||||||
value_template: "",
|
value_template: "",
|
||||||
};
|
};
|
@ -4,7 +4,8 @@ import "@polymer/paper-input/paper-input";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class TimeTrigger extends Component {
|
export default class TimeTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ export default class TimeTrigger extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, localize }) {
|
public render({ trigger, localize }) {
|
||||||
const { at } = trigger;
|
const { at } = trigger;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -29,6 +30,6 @@ export default class TimeTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeTrigger.defaultConfig = {
|
(TimeTrigger as any).defaultConfig = {
|
||||||
at: "",
|
at: "",
|
||||||
};
|
};
|
@ -4,7 +4,8 @@ import "@polymer/paper-input/paper-input";
|
|||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
|
||||||
export default class TimePatternTrigger extends Component {
|
export default class TimePatternTrigger extends Component<any> {
|
||||||
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ export default class TimePatternTrigger extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, localize }) {
|
public render({ trigger, localize }) {
|
||||||
const { hours, minutes, seconds } = trigger;
|
const { hours, minutes, seconds } = trigger;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -45,7 +46,7 @@ export default class TimePatternTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimePatternTrigger.defaultConfig = {
|
(TimePatternTrigger as any).defaultConfig = {
|
||||||
hours: "",
|
hours: "",
|
||||||
minutes: "",
|
minutes: "",
|
||||||
seconds: "",
|
seconds: "",
|
@ -36,25 +36,15 @@ const TYPES = {
|
|||||||
|
|
||||||
const OPTIONS = Object.keys(TYPES).sort();
|
const OPTIONS = Object.keys(TYPES).sort();
|
||||||
|
|
||||||
export default class TriggerEdit extends Component {
|
export default class TriggerEdit extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.typeChanged = this.typeChanged.bind(this);
|
this.typeChanged = this.typeChanged.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
typeChanged(ev) {
|
public render({ index, trigger, onChange, hass, localize }) {
|
||||||
const type = ev.target.selectedItem.attributes.platform.value;
|
// tslint:disable-next-line: variable-name
|
||||||
|
|
||||||
if (type !== this.props.trigger.platform) {
|
|
||||||
this.props.onChange(
|
|
||||||
this.props.index,
|
|
||||||
Object.assign({ platform: type }, TYPES[type].defaultConfig)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render({ index, trigger, onChange, hass, localize }) {
|
|
||||||
const Comp = TYPES[trigger.platform];
|
const Comp = TYPES[trigger.platform];
|
||||||
const selected = OPTIONS.indexOf(trigger.platform);
|
const selected = OPTIONS.indexOf(trigger.platform);
|
||||||
|
|
||||||
@ -102,4 +92,15 @@ export default class TriggerEdit extends Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private typeChanged(ev) {
|
||||||
|
const type = ev.target.selectedItem.attributes.platform.value;
|
||||||
|
|
||||||
|
if (type !== this.props.trigger.platform) {
|
||||||
|
this.props.onChange(this.props.index, {
|
||||||
|
platform: type,
|
||||||
|
...TYPES[type].defaultConfig,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,27 +7,14 @@ import "../../../../components/ha-card";
|
|||||||
|
|
||||||
import TriggerEdit from "./trigger_edit";
|
import TriggerEdit from "./trigger_edit";
|
||||||
|
|
||||||
export default class TriggerRow extends Component {
|
export default class TriggerRow extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onDelete = this.onDelete.bind(this);
|
this.onDelete = this.onDelete.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelete() {
|
public render(props) {
|
||||||
// eslint-disable-next-line
|
|
||||||
if (
|
|
||||||
confirm(
|
|
||||||
this.props.localize(
|
|
||||||
"ui.panel.config.automation.editor.triggers.delete_confirm"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
this.props.onChange(this.props.index, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render(props) {
|
|
||||||
return (
|
return (
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
@ -61,4 +48,17 @@ export default class TriggerRow extends Component {
|
|||||||
</ha-card>
|
</ha-card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onDelete() {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
if (
|
||||||
|
confirm(
|
||||||
|
this.props.localize(
|
||||||
|
"ui.panel.config.automation.editor.triggers.delete_confirm"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.props.onChange(this.props.index, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,15 +2,15 @@ import { h, Component } from "preact";
|
|||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
import { onChangeEvent } from "../../../../common/preact/event";
|
||||||
|
export default class WebhookTrigger extends Component<any> {
|
||||||
export default class WebhookTrigger extends Component {
|
private onChange: (obj: any) => void;
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onChange = onChangeEvent.bind(this, "trigger");
|
this.onChange = onChangeEvent.bind(this, "trigger");
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ trigger, localize }) {
|
public render({ trigger, localize }) {
|
||||||
const { webhook_id: webhookId } = trigger;
|
const { webhook_id: webhookId } = trigger;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -27,6 +27,6 @@ export default class WebhookTrigger extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WebhookTrigger.defaultConfig = {
|
(WebhookTrigger as any).defaultConfig = {
|
||||||
webhook_id: "",
|
webhook_id: "",
|
||||||
};
|
};
|
@ -3,7 +3,6 @@ import "@polymer/paper-radio-button/paper-radio-button";
|
|||||||
import "@polymer/paper-radio-group/paper-radio-group";
|
import "@polymer/paper-radio-group/paper-radio-group";
|
||||||
import "../../../../components/entity/ha-entity-picker";
|
import "../../../../components/entity/ha-entity-picker";
|
||||||
|
|
||||||
import { onChangeEvent } from "../../../../common/preact/event";
|
|
||||||
import hasLocation from "../../../../common/entity/has_location";
|
import hasLocation from "../../../../common/entity/has_location";
|
||||||
import computeStateDomain from "../../../../common/entity/compute_state_domain";
|
import computeStateDomain from "../../../../common/entity/compute_state_domain";
|
||||||
|
|
||||||
@ -11,39 +10,17 @@ function zoneAndLocationFilter(stateObj) {
|
|||||||
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";
|
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ZoneTrigger extends Component {
|
export default class ZoneTrigger extends Component<any> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.onChange = onChangeEvent.bind(this, "trigger");
|
|
||||||
this.radioGroupPicked = this.radioGroupPicked.bind(this);
|
this.radioGroupPicked = this.radioGroupPicked.bind(this);
|
||||||
this.entityPicked = this.entityPicked.bind(this);
|
this.entityPicked = this.entityPicked.bind(this);
|
||||||
this.zonePicked = this.zonePicked.bind(this);
|
this.zonePicked = this.zonePicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityPicked(ev) {
|
|
||||||
this.props.onChange(
|
|
||||||
this.props.index,
|
|
||||||
Object.assign({}, this.props.trigger, { entity_id: ev.target.value })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
zonePicked(ev) {
|
|
||||||
this.props.onChange(
|
|
||||||
this.props.index,
|
|
||||||
Object.assign({}, this.props.trigger, { zone: ev.target.value })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
radioGroupPicked(ev) {
|
|
||||||
this.props.onChange(
|
|
||||||
this.props.index,
|
|
||||||
Object.assign({}, this.props.trigger, { event: ev.target.selected })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
render({ trigger, hass, localize }) {
|
public render({ trigger, hass, localize }) {
|
||||||
const { entity_id, zone, event } = trigger;
|
const { entity_id, zone, event } = trigger;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -91,9 +68,30 @@ export default class ZoneTrigger extends Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private entityPicked(ev) {
|
||||||
|
this.props.onChange(this.props.index, {
|
||||||
|
...this.props.trigger,
|
||||||
|
entity_id: ev.target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private zonePicked(ev) {
|
||||||
|
this.props.onChange(this.props.index, {
|
||||||
|
...this.props.trigger,
|
||||||
|
zone: ev.target.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private radioGroupPicked(ev) {
|
||||||
|
this.props.onChange(this.props.index, {
|
||||||
|
...this.props.trigger,
|
||||||
|
event: ev.target.selected,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneTrigger.defaultConfig = {
|
(ZoneTrigger as any).defaultConfig = {
|
||||||
entity_id: "",
|
entity_id: "",
|
||||||
zone: "",
|
zone: "",
|
||||||
event: "enter",
|
event: "enter",
|
@ -8,7 +8,6 @@ import {
|
|||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
|
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import {
|
import {
|
||||||
@ -19,6 +18,7 @@ import {
|
|||||||
createPerson,
|
createPerson,
|
||||||
} from "../../../data/person";
|
} from "../../../data/person";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-fab";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import "../../../layouts/hass-loading-screen";
|
import "../../../layouts/hass-loading-screen";
|
||||||
import { compare } from "../../../common/string/compare";
|
import { compare } from "../../../common/string/compare";
|
||||||
@ -109,12 +109,12 @@ class HaConfigPerson extends LitElement {
|
|||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
|
|
||||||
<paper-fab
|
<ha-fab
|
||||||
?is-wide=${this.isWide}
|
?is-wide=${this.isWide}
|
||||||
icon="hass:plus"
|
icon="hass:plus"
|
||||||
title="Add Person"
|
title="Add Person"
|
||||||
@click=${this._createPerson}
|
@click=${this._createPerson}
|
||||||
></paper-fab>
|
></ha-fab>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,14 +221,14 @@ All devices belonging to this person will become unassigned.`)
|
|||||||
ha-card.storage paper-item {
|
ha-card.storage paper-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
paper-fab {
|
ha-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide] {
|
ha-fab[is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import "@polymer/app-layout/app-header/app-header";
|
import "@polymer/app-layout/app-header/app-header";
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import { h, render } from "preact";
|
import { h, render } from "preact";
|
||||||
|
|
||||||
import "../../../layouts/ha-app-layout";
|
import "../../../layouts/ha-app-layout";
|
||||||
import "../../../components/ha-paper-icon-button-arrow-prev";
|
import "../../../components/ha-paper-icon-button-arrow-prev";
|
||||||
|
import "../../../components/ha-fab";
|
||||||
|
|
||||||
import Script from "../js/script";
|
import Script from "../js/script";
|
||||||
import unmountPreact from "../../../common/preact/unmount";
|
import unmountPreact from "../../../common/preact/unmount";
|
||||||
@ -65,7 +65,7 @@ class HaScriptEditor extends LocalizeMixin(NavigateMixin(PolymerElement)) {
|
|||||||
span[slot="introduction"] a {
|
span[slot="introduction"] a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
paper-fab {
|
ha-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
@ -74,21 +74,21 @@ class HaScriptEditor extends LocalizeMixin(NavigateMixin(PolymerElement)) {
|
|||||||
transition: margin-bottom 0.3s;
|
transition: margin-bottom 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide] {
|
ha-fab[is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[dirty] {
|
ha-fab[dirty] {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[rtl] {
|
ha-fab[rtl] {
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[rtl][is-wide] {
|
ha-fab[rtl][is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
@ -115,7 +115,7 @@ class HaScriptEditor extends LocalizeMixin(NavigateMixin(PolymerElement)) {
|
|||||||
</template>
|
</template>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</div>
|
</div>
|
||||||
<paper-fab
|
<ha-fab
|
||||||
slot="fab"
|
slot="fab"
|
||||||
is-wide$="[[isWide]]"
|
is-wide$="[[isWide]]"
|
||||||
dirty$="[[dirty]]"
|
dirty$="[[dirty]]"
|
||||||
@ -123,7 +123,7 @@ class HaScriptEditor extends LocalizeMixin(NavigateMixin(PolymerElement)) {
|
|||||||
title="Save"
|
title="Save"
|
||||||
on-click="saveScript"
|
on-click="saveScript"
|
||||||
rtl$="[[rtl]]"
|
rtl$="[[rtl]]"
|
||||||
></paper-fab>
|
></ha-fab>
|
||||||
</ha-app-layout>
|
</ha-app-layout>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import {
|
|||||||
property,
|
property,
|
||||||
customElement,
|
customElement,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
@ -17,6 +16,7 @@ import "../../../layouts/hass-subpage";
|
|||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
|
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-fab";
|
||||||
|
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
|
|
||||||
@ -81,13 +81,13 @@ class HaScriptPicker extends LitElement {
|
|||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
|
|
||||||
<a href="/config/script/new">
|
<a href="/config/script/new">
|
||||||
<paper-fab
|
<ha-fab
|
||||||
slot="fab"
|
slot="fab"
|
||||||
?is-wide=${this.isWide}
|
?is-wide=${this.isWide}
|
||||||
icon="hass:plus"
|
icon="hass:plus"
|
||||||
title="Add Script"
|
title="Add Script"
|
||||||
?rtl=${computeRTL(this.hass)}
|
?rtl=${computeRTL(this.hass)}
|
||||||
></paper-fab>
|
></ha-fab>
|
||||||
</a>
|
</a>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
@ -135,24 +135,24 @@ class HaScriptPicker extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab {
|
ha-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[is-wide] {
|
ha-fab[is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[rtl] {
|
ha-fab[rtl] {
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-fab[rtl][is-wide] {
|
ha-fab[rtl][is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
@ -7,6 +6,7 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import "../../../components/ha-icon-next";
|
import "../../../components/ha-icon-next";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-fab";
|
||||||
|
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import NavigateMixin from "../../../mixins/navigate-mixin";
|
import NavigateMixin from "../../../mixins/navigate-mixin";
|
||||||
@ -27,21 +27,21 @@ class HaUserPicker extends EventsMixin(
|
|||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
paper-fab {
|
ha-fab {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
paper-fab[is-wide] {
|
ha-fab[is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
}
|
}
|
||||||
paper-fab[rtl] {
|
ha-fab[rtl] {
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 16px;
|
left: 16px;
|
||||||
}
|
}
|
||||||
paper-fab[rtl][is-wide] {
|
ha-fab[rtl][is-wide] {
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
@ -78,13 +78,13 @@ class HaUserPicker extends EventsMixin(
|
|||||||
</template>
|
</template>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
|
||||||
<paper-fab
|
<ha-fab
|
||||||
is-wide$="[[isWide]]"
|
is-wide$="[[isWide]]"
|
||||||
icon="hass:plus"
|
icon="hass:plus"
|
||||||
title="[[localize('ui.panel.config.users.picker.add_user')]]"
|
title="[[localize('ui.panel.config.users.picker.add_user')]]"
|
||||||
on-click="_addUser"
|
on-click="_addUser"
|
||||||
rtl$="[[rtl]]"
|
rtl$="[[rtl]]"
|
||||||
></paper-fab>
|
></ha-fab>
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ export class HaPanelCustom extends UpdatingElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const props = {};
|
const props = {};
|
||||||
|
// @ts-ignore
|
||||||
for (const key of changedProps.keys()) {
|
for (const key of changedProps.keys()) {
|
||||||
props[key] = this[key];
|
props[key] = this[key];
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ class HaPanelDevService extends PolymerElement {
|
|||||||
|
|
||||||
const fields = serviceDomains[domain][service].fields;
|
const fields = serviceDomains[domain][service].fields;
|
||||||
return Object.keys(fields).map(function(field) {
|
return Object.keys(fields).map(function(field) {
|
||||||
return Object.assign({ key: field }, fields[field]);
|
return { key: field, ...fields[field] };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,9 +282,9 @@ class HaPanelDevService extends PolymerElement {
|
|||||||
|
|
||||||
_fillExampleData() {
|
_fillExampleData() {
|
||||||
const example = {};
|
const example = {};
|
||||||
for (const attribute of this._attributes) {
|
this._attributes.forEach((attribute) => {
|
||||||
example[attribute.key] = attribute.example;
|
example[attribute.key] = attribute.example;
|
||||||
}
|
});
|
||||||
this.serviceData = JSON.stringify(example, null, 2);
|
this.serviceData = JSON.stringify(example, null, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static getStubConfig() {
|
public static getStubConfig() {
|
||||||
return { states: ["arm_home", "arm_away"] };
|
return { states: ["arm_home", "arm_away"], entity: "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
|
@ -37,7 +37,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
return document.createElement("hui-gauge-card-editor");
|
return document.createElement("hui-gauge-card-editor");
|
||||||
}
|
}
|
||||||
public static getStubConfig(): object {
|
public static getStubConfig(): object {
|
||||||
return {};
|
return { entity: "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
|
@ -202,6 +202,7 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.stateObj=${stateObj}
|
.stateObj=${stateObj}
|
||||||
.overrideIcon=${entityConf.icon}
|
.overrideIcon=${entityConf.icon}
|
||||||
|
.overrideImage=${entityConf.image}
|
||||||
></state-badge>
|
></state-badge>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
@ -8,6 +8,10 @@ import "../../../data/ha-state-history-data";
|
|||||||
import { processConfigEntities } from "../common/process-config-entities";
|
import { processConfigEntities } from "../common/process-config-entities";
|
||||||
|
|
||||||
class HuiHistoryGraphCard extends PolymerElement {
|
class HuiHistoryGraphCard extends PolymerElement {
|
||||||
|
static getStubConfig() {
|
||||||
|
return { entities: [] };
|
||||||
|
}
|
||||||
|
|
||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
@ -66,12 +70,12 @@ class HuiHistoryGraphCard extends PolymerElement {
|
|||||||
|
|
||||||
const _entities = [];
|
const _entities = [];
|
||||||
const _names = {};
|
const _names = {};
|
||||||
for (const entity of entities) {
|
entities.forEach((entity) => {
|
||||||
_entities.push(entity.entity);
|
_entities.push(entity.entity);
|
||||||
if (entity.name) {
|
if (entity.name) {
|
||||||
_names[entity.entity] = entity.name;
|
_names[entity.entity] = entity.name;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
_cacheConfig: {
|
_cacheConfig: {
|
||||||
|
@ -33,7 +33,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
|||||||
return document.createElement("hui-light-card-editor");
|
return document.createElement("hui-light-card-editor");
|
||||||
}
|
}
|
||||||
public static getStubConfig(): object {
|
public static getStubConfig(): object {
|
||||||
return {};
|
return { entity: "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
@ -96,25 +96,23 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
|||||||
@value-changing=${this._dragEvent}
|
@value-changing=${this._dragEvent}
|
||||||
@value-changed=${this._setBrightness}
|
@value-changed=${this._setBrightness}
|
||||||
></round-slider>
|
></round-slider>
|
||||||
|
<ha-icon
|
||||||
|
class="light-icon"
|
||||||
|
data-state="${stateObj.state}"
|
||||||
|
.icon="${stateIcon(stateObj)}"
|
||||||
|
style="${styleMap({
|
||||||
|
filter: this._computeBrightness(stateObj),
|
||||||
|
color: this._computeColor(stateObj),
|
||||||
|
})}"
|
||||||
|
@click="${this._handleTap}"
|
||||||
|
></ha-icon>
|
||||||
</div>
|
</div>
|
||||||
<div id="tooltip">
|
<div id="tooltip">
|
||||||
<div class="icon-state">
|
<div class="brightness" @ha-click="${this._handleTap}">
|
||||||
<ha-icon
|
${brightness} %
|
||||||
class="light-icon"
|
</div>
|
||||||
data-state="${stateObj.state}"
|
<div class="name">
|
||||||
.icon="${stateIcon(stateObj)}"
|
${this._config.name || computeStateName(stateObj)}
|
||||||
style="${styleMap({
|
|
||||||
filter: this._computeBrightness(stateObj),
|
|
||||||
color: this._computeColor(stateObj),
|
|
||||||
})}"
|
|
||||||
@click="${this._handleTap}"
|
|
||||||
></ha-icon>
|
|
||||||
<div class="brightness" @ha-click="${this._handleTap}">
|
|
||||||
${brightness} %
|
|
||||||
</div>
|
|
||||||
<div class="name">
|
|
||||||
${this._config.name || computeStateName(stateObj)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
@ -165,19 +163,10 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
|||||||
right: 0;
|
right: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
z-index: 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-state {
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
transform: translate(0, 25%);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#light {
|
#light {
|
||||||
margin: 0 auto;
|
margin: auto;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
padding-bottom: 32px;
|
padding-bottom: 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -187,19 +176,21 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
|||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
#light round-slider {
|
#light round-slider {
|
||||||
z-index: 20 !important;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
--round-slider-path-color: var(--disabled-text-color);
|
--round-slider-path-color: var(--disabled-text-color);
|
||||||
--round-slider-bar-color: var(--primary-color);
|
--round-slider-bar-color: var(--primary-color);
|
||||||
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
.light-icon {
|
.light-icon {
|
||||||
margin: auto;
|
position: absolute;
|
||||||
|
margin: 0 auto;
|
||||||
width: 76px;
|
width: 76px;
|
||||||
height: 76px;
|
height: 76px;
|
||||||
color: var(--paper-item-icon-color, #44739e);
|
color: var(--paper-item-icon-color, #44739e);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
.light-icon[data-state="on"] {
|
.light-icon[data-state="on"] {
|
||||||
@ -211,7 +202,10 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
padding-top: 32px;
|
position: absolute;
|
||||||
|
top: 160px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%);
|
||||||
font-size: var(--name-font-size);
|
font-size: var(--name-font-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,8 +213,8 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
|
|||||||
font-size: var(--brightness-font-size);
|
font-size: var(--brightness-font-size);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
top: 135px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
top: 45%;
|
|
||||||
transform: translate(-50%);
|
transform: translate(-50%);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.5s ease-in-out;
|
transition: opacity 0.5s ease-in-out;
|
||||||
|
@ -9,7 +9,7 @@ class HuiMediaControlCard extends LegacyWrapperCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getStubConfig() {
|
static getStubConfig() {
|
||||||
return {};
|
return { entity: "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -22,7 +22,9 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
set hass(hass: HomeAssistant) {
|
set hass(hass: HomeAssistant) {
|
||||||
this._hass = hass;
|
this._hass = hass;
|
||||||
for (const el of this.shadowRoot!.querySelectorAll("#root > *")) {
|
for (const el of Array.from(
|
||||||
|
this.shadowRoot!.querySelectorAll("#root > *")
|
||||||
|
)) {
|
||||||
const element = el as LovelaceElement;
|
const element = el as LovelaceElement;
|
||||||
element.hass = this._hass;
|
element.hass = this._hass;
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static getStubConfig(): object {
|
public static getStubConfig(): object {
|
||||||
return {};
|
return { entity: "" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@property() public hass?: HomeAssistant;
|
@property() public hass?: HomeAssistant;
|
||||||
|
@ -84,6 +84,7 @@ export interface ConfigEntity extends EntityConfig {
|
|||||||
|
|
||||||
export interface GlanceConfigEntity extends ConfigEntity {
|
export interface GlanceConfigEntity extends ConfigEntity {
|
||||||
show_last_changed?: boolean;
|
show_last_changed?: boolean;
|
||||||
|
image?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GlanceCardConfig extends LovelaceCardConfig {
|
export interface GlanceCardConfig extends LovelaceCardConfig {
|
||||||
|
@ -36,6 +36,7 @@ const SPECIAL_TYPES = new Set([
|
|||||||
"section",
|
"section",
|
||||||
"weblink",
|
"weblink",
|
||||||
"cast",
|
"cast",
|
||||||
|
"select",
|
||||||
]);
|
]);
|
||||||
const DOMAIN_TO_ELEMENT_TYPE = {
|
const DOMAIN_TO_ELEMENT_TYPE = {
|
||||||
alert: "toggle",
|
alert: "toggle",
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import { directive, PropertyPart } from "lit-html";
|
import { directive, PropertyPart } from "lit-html";
|
||||||
// See https://github.com/home-assistant/home-assistant-polymer/pull/2457
|
import "@material/mwc-ripple";
|
||||||
// on how to undo mwc -> paper migration
|
|
||||||
// import "@material/mwc-ripple";
|
|
||||||
import "@polymer/paper-ripple";
|
|
||||||
|
|
||||||
const isTouch =
|
const isTouch =
|
||||||
"ontouchstart" in window ||
|
"ontouchstart" in window ||
|
||||||
@ -19,7 +16,7 @@ interface LongPressElement extends Element {
|
|||||||
|
|
||||||
class LongPress extends HTMLElement implements LongPress {
|
class LongPress extends HTMLElement implements LongPress {
|
||||||
public holdTime: number;
|
public holdTime: number;
|
||||||
protected ripple: any;
|
public ripple: any;
|
||||||
protected timer: number | undefined;
|
protected timer: number | undefined;
|
||||||
protected held: boolean;
|
protected held: boolean;
|
||||||
protected cooldownStart: boolean;
|
protected cooldownStart: boolean;
|
||||||
@ -28,7 +25,7 @@ class LongPress extends HTMLElement implements LongPress {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.holdTime = 500;
|
this.holdTime = 500;
|
||||||
this.ripple = document.createElement("paper-ripple");
|
this.ripple = document.createElement("mwc-ripple");
|
||||||
this.timer = undefined;
|
this.timer = undefined;
|
||||||
this.held = false;
|
this.held = false;
|
||||||
this.cooldownStart = false;
|
this.cooldownStart = false;
|
||||||
@ -37,7 +34,6 @@ class LongPress extends HTMLElement implements LongPress {
|
|||||||
|
|
||||||
public connectedCallback() {
|
public connectedCallback() {
|
||||||
Object.assign(this.style, {
|
Object.assign(this.style, {
|
||||||
borderRadius: "50%", // paper-ripple
|
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
width: isTouch ? "100px" : "50px",
|
width: isTouch ? "100px" : "50px",
|
||||||
height: isTouch ? "100px" : "50px",
|
height: isTouch ? "100px" : "50px",
|
||||||
@ -46,9 +42,7 @@ class LongPress extends HTMLElement implements LongPress {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.appendChild(this.ripple);
|
this.appendChild(this.ripple);
|
||||||
this.ripple.style.color = "#03a9f4"; // paper-ripple
|
this.ripple.primary = true;
|
||||||
this.ripple.style.color = "var(--primary-color)"; // paper-ripple
|
|
||||||
// this.ripple.primary = true;
|
|
||||||
|
|
||||||
[
|
[
|
||||||
"touchcancel",
|
"touchcancel",
|
||||||
@ -154,17 +148,14 @@ class LongPress extends HTMLElement implements LongPress {
|
|||||||
top: `${y}px`,
|
top: `${y}px`,
|
||||||
display: null,
|
display: null,
|
||||||
});
|
});
|
||||||
this.ripple.holdDown = true; // paper-ripple
|
this.ripple.disabled = false;
|
||||||
this.ripple.simulatedRipple(); // paper-ripple
|
this.ripple.active = true;
|
||||||
// this.ripple.disabled = false;
|
this.ripple.unbounded = true;
|
||||||
// this.ripple.active = true;
|
|
||||||
// this.ripple.unbounded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private stopAnimation() {
|
private stopAnimation() {
|
||||||
this.ripple.holdDown = false; // paper-ripple
|
this.ripple.active = false;
|
||||||
// this.ripple.active = false;
|
this.ripple.disabled = true;
|
||||||
// this.ripple.disabled = true;
|
|
||||||
this.style.display = "none";
|
this.style.display = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ export class HuiDialogEditCard extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<hui-card-picker
|
<hui-card-picker
|
||||||
.hass="${this.hass}"
|
.hass="${this.hass}"
|
||||||
@config-changed="${this._handleConfigChanged}"
|
@config-changed="${this._handleCardPicked}"
|
||||||
></hui-card-picker>
|
></hui-card-picker>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
@ -220,6 +220,18 @@ export class HuiDialogEditCard extends LitElement {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleCardPicked(ev) {
|
||||||
|
this._cardConfig = ev.detail.config;
|
||||||
|
if (this._params!.entities && this._params!.entities.length > 0) {
|
||||||
|
if (Object.keys(this._cardConfig!).includes("entities")) {
|
||||||
|
this._cardConfig!.entities = this._params!.entities;
|
||||||
|
} else if (Object.keys(this._cardConfig!).includes("entity")) {
|
||||||
|
this._cardConfig!.entity = this._params!.entities[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._error = ev.detail.error;
|
||||||
|
}
|
||||||
|
|
||||||
private _handleConfigChanged(ev) {
|
private _handleConfigChanged(ev) {
|
||||||
this._cardConfig = ev.detail.config;
|
this._cardConfig = ev.detail.config;
|
||||||
this._error = ev.detail.error;
|
this._error = ev.detail.error;
|
||||||
|
@ -15,6 +15,7 @@ const dialogTag = "hui-dialog-edit-card";
|
|||||||
export interface EditCardDialogParams {
|
export interface EditCardDialogParams {
|
||||||
lovelace: Lovelace;
|
lovelace: Lovelace;
|
||||||
path: [number] | [number, number];
|
path: [number] | [number, number];
|
||||||
|
entities?: string[]; // We can pass entity id's that will be added to the config when a card is picked
|
||||||
}
|
}
|
||||||
|
|
||||||
const registerEditCardDialog = (element: HTMLElement): Event =>
|
const registerEditCardDialog = (element: HTMLElement): Event =>
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
import {
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
customElement,
|
||||||
|
property,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
|
import "../../../../components/dialog/ha-paper-dialog";
|
||||||
|
import { toggleAttribute } from "../../../../common/dom/toggle_attribute";
|
||||||
|
import "../../components/hui-views-list";
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-duplicate-imports
|
||||||
|
import { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialog";
|
||||||
|
|
||||||
|
import { SelectViewDialogParams } from "./show-select-view-dialog";
|
||||||
|
import { PolymerChangedEvent } from "../../../../polymer-types";
|
||||||
|
|
||||||
|
@customElement("hui-dialog-select-view")
|
||||||
|
export class HuiDialogSelectView extends LitElement {
|
||||||
|
@property() private _params?: SelectViewDialogParams;
|
||||||
|
|
||||||
|
public async showDialog(params: SelectViewDialogParams): Promise<void> {
|
||||||
|
this._params = params;
|
||||||
|
await this.updateComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
toggleAttribute(
|
||||||
|
this,
|
||||||
|
"hide-icons",
|
||||||
|
this._params!.lovelace!.config
|
||||||
|
? !this._params!.lovelace!.config.views.some((view) => view.icon)
|
||||||
|
: true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult | void {
|
||||||
|
if (!this._params) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-paper-dialog
|
||||||
|
with-backdrop
|
||||||
|
opened
|
||||||
|
@opened-changed="${this._openedChanged}"
|
||||||
|
>
|
||||||
|
<h2>Choose a view</h2>
|
||||||
|
<hui-views-list
|
||||||
|
.lovelaceConfig=${this._params!.lovelace.config}
|
||||||
|
@view-selected=${this._selectView}>
|
||||||
|
</hui-view-list>
|
||||||
|
</ha-paper-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _dialog(): HaPaperDialog {
|
||||||
|
return this.shadowRoot!.querySelector("ha-paper-dialog")!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _selectView(e: CustomEvent): void {
|
||||||
|
const view: number = e.detail.view;
|
||||||
|
this._params!.viewSelectedCallback(view);
|
||||||
|
this._dialog.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _openedChanged(ev: PolymerChangedEvent<boolean>): void {
|
||||||
|
if (!(ev.detail as any).value) {
|
||||||
|
this._params = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-dialog-select-view": HuiDialogSelectView;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import { Lovelace } from "../../types";
|
||||||
|
|
||||||
|
export interface SelectViewDialogParams {
|
||||||
|
lovelace: Lovelace;
|
||||||
|
viewSelectedCallback: (view: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showSelectViewDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
selectViewDialogParams: SelectViewDialogParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "hui-dialog-select-view",
|
||||||
|
dialogImport: () =>
|
||||||
|
import(/* webpackChunkName: "hui-dialog-select-view" */ "./hui-dialog-select-view"),
|
||||||
|
dialogParams: selectViewDialogParams,
|
||||||
|
});
|
||||||
|
};
|
151
src/panels/lovelace/editor/unused-entities/hui-select-row.ts
Normal file
151
src/panels/lovelace/editor/unused-entities/hui-select-row.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import {
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
customElement,
|
||||||
|
property,
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
|
import { Checkbox } from "@material/mwc-checkbox";
|
||||||
|
import { HomeAssistant } from "../../../../types";
|
||||||
|
import computeStateName from "../../../../common/entity/compute_state_name";
|
||||||
|
import computeDomain from "../../../../common/entity/compute_domain";
|
||||||
|
|
||||||
|
import "../../../../components/ha-checkbox";
|
||||||
|
import "../../../../components/entity/state-badge";
|
||||||
|
import "../../../../components/ha-relative-time";
|
||||||
|
import "../../../../components/ha-icon";
|
||||||
|
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// for fire event
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"entity-selection-changed": EntitySelectionChangedEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EntitySelectionChangedEvent {
|
||||||
|
entity: string;
|
||||||
|
selected: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("hui-select-row")
|
||||||
|
class HuiSelectRow extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public entity?: string;
|
||||||
|
|
||||||
|
@property() public selectable = true;
|
||||||
|
|
||||||
|
protected render(): TemplateResult | void {
|
||||||
|
if (!this.entity) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateObj = this.entity ? this.hass.states[this.entity] : undefined;
|
||||||
|
|
||||||
|
if (!stateObj) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="flex-row" role="rowgroup">
|
||||||
|
<div class="flex-cell" role="cell">
|
||||||
|
${this.selectable
|
||||||
|
? html`
|
||||||
|
<ha-checkbox @change=${this._handleSelect}></ha-checkbox>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<state-badge .hass=${this.hass} .stateObj=${stateObj}></state-badge>
|
||||||
|
${computeStateName(stateObj)}
|
||||||
|
</div>
|
||||||
|
<div class="flex-cell" role="cell">${stateObj.entity_id}</div>
|
||||||
|
<div class="flex-cell" role="cell">
|
||||||
|
${computeDomain(stateObj.entity_id)}
|
||||||
|
</div>
|
||||||
|
<div class="flex-cell" role="cell">
|
||||||
|
<ha-relative-time
|
||||||
|
.hass=${this.hass}
|
||||||
|
.datetime=${stateObj.last_changed}
|
||||||
|
></ha-relative-time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleSelect(ev: Event): void {
|
||||||
|
const checkbox = ev.currentTarget as Checkbox;
|
||||||
|
fireEvent(this, "entity-selection-changed", {
|
||||||
|
entity: this.entity!,
|
||||||
|
selected: checkbox.checked as boolean,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
div {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row:hover {
|
||||||
|
background: var(--table-row-alternative-background-color, #eee);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-cell {
|
||||||
|
width: calc(100% / 4);
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (max-width: 767px) {
|
||||||
|
.flex-cell {
|
||||||
|
width: calc(100% / 3);
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.flex-cell:first-child {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 12px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (max-width: 430px) {
|
||||||
|
.flex-cell {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-cell:first-child {
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-cell:last-child {
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-cell {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-select-row": HuiSelectRow;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,213 @@
|
|||||||
|
import {
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
PropertyValues,
|
||||||
|
property,
|
||||||
|
customElement,
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
|
import "../../../../components/ha-fab";
|
||||||
|
|
||||||
|
import "./hui-select-row";
|
||||||
|
|
||||||
|
import { computeRTL } from "../../../../common/util/compute_rtl";
|
||||||
|
import { computeUnusedEntities } from "../../common/compute-unused-entities";
|
||||||
|
import { showSelectViewDialog } from "../select-view/show-select-view-dialog";
|
||||||
|
import { showEditCardDialog } from "../card-editor/show-edit-card-dialog";
|
||||||
|
|
||||||
|
import { HomeAssistant } from "../../../../types";
|
||||||
|
import { Lovelace } from "../../types";
|
||||||
|
import { LovelaceConfig } from "../../../../data/lovelace";
|
||||||
|
|
||||||
|
@customElement("hui-unused-entities")
|
||||||
|
export class HuiUnusedEntities extends LitElement {
|
||||||
|
@property() public lovelace?: Lovelace;
|
||||||
|
|
||||||
|
@property() public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property() private _unusedEntities: string[] = [];
|
||||||
|
|
||||||
|
private _selectedEntities: string[] = [];
|
||||||
|
|
||||||
|
private get _config(): LovelaceConfig {
|
||||||
|
return this.lovelace!.config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProperties: PropertyValues): void {
|
||||||
|
super.updated(changedProperties);
|
||||||
|
|
||||||
|
if (changedProperties.has("lovelace")) {
|
||||||
|
this._getUnusedEntities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult | void {
|
||||||
|
if (!this.hass || !this.lovelace) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lovelace.mode === "storage" && this.lovelace.editMode === false) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-card header="Unused entities">
|
||||||
|
<div class="card-content">
|
||||||
|
These are the entities that you have available, but are not in your
|
||||||
|
Lovelace UI yet.
|
||||||
|
${this.lovelace.mode === "storage"
|
||||||
|
? html`
|
||||||
|
<br />Select the entities you want to add to a card and then
|
||||||
|
click the add card button.
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="table-container"
|
||||||
|
role="table"
|
||||||
|
aria-label="Unused Entities"
|
||||||
|
@entity-selection-changed=${this._handleSelectionChanged}
|
||||||
|
>
|
||||||
|
<div class="flex-row header" role="rowgroup">
|
||||||
|
<div class="flex-cell" role="columnheader">Entity</div>
|
||||||
|
<div class="flex-cell" role="columnheader">Entity id</div>
|
||||||
|
<div class="flex-cell" role="columnheader">Domain</div>
|
||||||
|
<div class="flex-cell" role="columnheader">Last Changed</div>
|
||||||
|
</div>
|
||||||
|
${this._unusedEntities.map((entity) => {
|
||||||
|
return html`
|
||||||
|
<hui-select-row
|
||||||
|
.selectable=${this.lovelace!.mode === "storage"}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entity=${entity}
|
||||||
|
></hui-select-row>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
${this.lovelace.mode === "storage"
|
||||||
|
? html`
|
||||||
|
<ha-fab
|
||||||
|
class="${classMap({
|
||||||
|
rtl: computeRTL(this.hass),
|
||||||
|
})}"
|
||||||
|
icon="hass:plus"
|
||||||
|
label="${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.edit_card.add"
|
||||||
|
)}"
|
||||||
|
@click="${this._selectView}"
|
||||||
|
></ha-fab>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getUnusedEntities(): void {
|
||||||
|
if (!this.hass || !this.lovelace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._selectedEntities = [];
|
||||||
|
this._unusedEntities = computeUnusedEntities(this.hass, this._config!);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleSelectionChanged(ev: any): void {
|
||||||
|
if (ev.detail.selected) {
|
||||||
|
this._selectedEntities.push(ev.detail.entity);
|
||||||
|
} else {
|
||||||
|
const index = this._selectedEntities.indexOf(ev.detail.entity);
|
||||||
|
if (index !== -1) {
|
||||||
|
this._selectedEntities.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _selectView(): void {
|
||||||
|
showSelectViewDialog(this, {
|
||||||
|
lovelace: this.lovelace!,
|
||||||
|
viewSelectedCallback: (view) => this._addCard(view),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addCard(view: number): void {
|
||||||
|
showEditCardDialog(this, {
|
||||||
|
lovelace: this.lovelace!,
|
||||||
|
path: [view],
|
||||||
|
entities: this._selectedEntities,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
background: var(--lovelace-background);
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
ha-fab {
|
||||||
|
position: sticky;
|
||||||
|
float: right;
|
||||||
|
bottom: 16px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
ha-fab.rtl {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
}
|
||||||
|
.flex-row .flex-cell {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-cell {
|
||||||
|
width: calc(100% / 4);
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (max-width: 767px) {
|
||||||
|
.flex-cell {
|
||||||
|
width: calc(100% / 3);
|
||||||
|
}
|
||||||
|
.flex-cell:first-child {
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media all and (max-width: 430px) {
|
||||||
|
.flex-cell {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-cell:last-child {
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-cell {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-unused-entities": HuiUnusedEntities;
|
||||||
|
}
|
||||||
|
}
|
@ -116,6 +116,20 @@ class HUIRoot extends LitElement {
|
|||||||
@iron-select="${this._deselect}"
|
@iron-select="${this._deselect}"
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
>
|
>
|
||||||
|
${__DEMO__ /* No unused entities available in the demo */
|
||||||
|
? ""
|
||||||
|
: html`
|
||||||
|
<paper-item
|
||||||
|
aria-label=${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.menu.unused_entities"
|
||||||
|
)}
|
||||||
|
@tap="${this._handleUnusedEntities}"
|
||||||
|
>
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.menu.unused_entities"
|
||||||
|
)}
|
||||||
|
</paper-item>
|
||||||
|
`}
|
||||||
<paper-item @tap="${this.lovelace!.enableFullEditMode}">
|
<paper-item @tap="${this.lovelace!.enableFullEditMode}">
|
||||||
${this.hass!.localize(
|
${this.hass!.localize(
|
||||||
"ui.panel.lovelace.editor.menu.raw_editor"
|
"ui.panel.lovelace.editor.menu.raw_editor"
|
||||||
@ -160,11 +174,6 @@ class HUIRoot extends LitElement {
|
|||||||
"ui.panel.lovelace.menu.refresh"
|
"ui.panel.lovelace.menu.refresh"
|
||||||
)}
|
)}
|
||||||
</paper-item>
|
</paper-item>
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${__DEMO__ /* No unused entities available in the demo */
|
|
||||||
? ""
|
|
||||||
: html`
|
|
||||||
<paper-item
|
<paper-item
|
||||||
aria-label=${this.hass!.localize(
|
aria-label=${this.hass!.localize(
|
||||||
"ui.panel.lovelace.menu.unused_entities"
|
"ui.panel.lovelace.menu.unused_entities"
|
||||||
@ -175,17 +184,22 @@ class HUIRoot extends LitElement {
|
|||||||
"ui.panel.lovelace.menu.unused_entities"
|
"ui.panel.lovelace.menu.unused_entities"
|
||||||
)}
|
)}
|
||||||
</paper-item>
|
</paper-item>
|
||||||
`}
|
`
|
||||||
<paper-item
|
: ""}
|
||||||
aria-label=${this.hass!.localize(
|
${this.hass!.user!.is_admin
|
||||||
"ui.panel.lovelace.menu.configure_ui"
|
? html`
|
||||||
)}
|
<paper-item
|
||||||
@tap="${this._editModeEnable}"
|
aria-label=${this.hass!.localize(
|
||||||
>
|
"ui.panel.lovelace.menu.configure_ui"
|
||||||
${this.hass!.localize(
|
)}
|
||||||
"ui.panel.lovelace.menu.configure_ui"
|
@tap="${this._editModeEnable}"
|
||||||
)}
|
>
|
||||||
</paper-item>
|
${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.menu.configure_ui"
|
||||||
|
)}
|
||||||
|
</paper-item>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
<paper-item
|
<paper-item
|
||||||
aria-label=${this.hass!.localize(
|
aria-label=${this.hass!.localize(
|
||||||
"ui.panel.lovelace.menu.help"
|
"ui.panel.lovelace.menu.help"
|
||||||
@ -422,6 +436,15 @@ class HUIRoot extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!oldLovelace || oldLovelace.editMode !== this.lovelace!.editMode) {
|
if (!oldLovelace || oldLovelace.editMode !== this.lovelace!.editMode) {
|
||||||
|
// Leave unused entities when leaving edit mode
|
||||||
|
if (
|
||||||
|
this.lovelace!.mode === "storage" &&
|
||||||
|
this._routeData!.view === "hass-unused-entities"
|
||||||
|
) {
|
||||||
|
const views = this.config && this.config.views;
|
||||||
|
navigate(this, `/lovelace/${views[0].path || 0}`);
|
||||||
|
newSelectView = 0;
|
||||||
|
}
|
||||||
// On edit mode change, recreate the current view from scratch
|
// On edit mode change, recreate the current view from scratch
|
||||||
force = true;
|
force = true;
|
||||||
// Recalculate to see if we need to adjust content area for tab bar
|
// Recalculate to see if we need to adjust content area for tab bar
|
||||||
@ -562,10 +585,10 @@ class HUIRoot extends LitElement {
|
|||||||
if (viewIndex === "hass-unused-entities") {
|
if (viewIndex === "hass-unused-entities") {
|
||||||
const unusedEntities = document.createElement("hui-unused-entities");
|
const unusedEntities = document.createElement("hui-unused-entities");
|
||||||
// Wait for promise to resolve so that the element has been upgraded.
|
// Wait for promise to resolve so that the element has been upgraded.
|
||||||
import(/* webpackChunkName: "hui-unused-entities" */ "./hui-unused-entities").then(
|
import(/* webpackChunkName: "hui-unused-entities" */ "./editor/unused-entities/hui-unused-entities").then(
|
||||||
() => {
|
() => {
|
||||||
unusedEntities.setConfig(this.config);
|
|
||||||
unusedEntities.hass = this.hass!;
|
unusedEntities.hass = this.hass!;
|
||||||
|
unusedEntities.lovelace = this.lovelace!;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (this.config.background) {
|
if (this.config.background) {
|
||||||
|
@ -1,112 +0,0 @@
|
|||||||
import {
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
PropertyDeclarations,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
|
|
||||||
import "./cards/hui-entities-card";
|
|
||||||
|
|
||||||
import { computeUnusedEntities } from "./common/compute-unused-entities";
|
|
||||||
import { createCardElement } from "./common/create-card-element";
|
|
||||||
import { HomeAssistant } from "../../types";
|
|
||||||
import { LovelaceCard } from "./types";
|
|
||||||
import { LovelaceConfig } from "../../data/lovelace";
|
|
||||||
import computeDomain from "../../common/entity/compute_domain";
|
|
||||||
|
|
||||||
export class HuiUnusedEntities extends LitElement {
|
|
||||||
private _hass?: HomeAssistant;
|
|
||||||
private _config?: LovelaceConfig;
|
|
||||||
private _elements?: LovelaceCard[];
|
|
||||||
|
|
||||||
static get properties(): PropertyDeclarations {
|
|
||||||
return {
|
|
||||||
_hass: {},
|
|
||||||
_config: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
set hass(hass: HomeAssistant) {
|
|
||||||
this._hass = hass;
|
|
||||||
if (!this._elements) {
|
|
||||||
this._createElements();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (const element of this._elements) {
|
|
||||||
element.hass = this._hass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public setConfig(config: LovelaceConfig): void {
|
|
||||||
this._config = config;
|
|
||||||
this._createElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
|
||||||
if (!this._config || !this._hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
${this.renderStyle()}
|
|
||||||
<div id="root">${this._elements}</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderStyle(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
:host {
|
|
||||||
background: var(--lovelace-background);
|
|
||||||
}
|
|
||||||
#root {
|
|
||||||
padding: 4px;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
hui-entities-card {
|
|
||||||
max-width: 400px;
|
|
||||||
padding: 4px;
|
|
||||||
flex: 1 auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _createElements(): void {
|
|
||||||
if (!this._hass) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const domains: { [domain: string]: string[] } = {};
|
|
||||||
computeUnusedEntities(this._hass, this._config!).forEach((entity) => {
|
|
||||||
const domain = computeDomain(entity);
|
|
||||||
|
|
||||||
if (!(domain in domains)) {
|
|
||||||
domains[domain] = [];
|
|
||||||
}
|
|
||||||
domains[domain].push(entity);
|
|
||||||
});
|
|
||||||
this._elements = Object.keys(domains)
|
|
||||||
.sort()
|
|
||||||
.map((domain) => {
|
|
||||||
const el = createCardElement({
|
|
||||||
type: "entities",
|
|
||||||
title: this._hass!.localize(`domain.${domain}`) || domain,
|
|
||||||
entities: domains[domain].map((entity) => ({
|
|
||||||
entity,
|
|
||||||
secondary_info: "entity-id",
|
|
||||||
})),
|
|
||||||
show_header_toggle: false,
|
|
||||||
});
|
|
||||||
el.hass = this._hass;
|
|
||||||
return el;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"hui-unused-entities": HuiUnusedEntities;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
customElements.define("hui-unused-entities", HuiUnusedEntities);
|
|
@ -1,3 +1,3 @@
|
|||||||
// hui-view dependencies for when in edit mode.
|
// hui-view dependencies for when in edit mode.
|
||||||
import "@polymer/paper-fab/paper-fab";
|
|
||||||
import "./components/hui-card-options";
|
import "./components/hui-card-options";
|
||||||
|
import "../../components/ha-fab";
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user