diff --git a/build-scripts/gulp/app.js b/build-scripts/gulp/app.js new file mode 100644 index 0000000000..0536b14a30 --- /dev/null +++ b/build-scripts/gulp/app.js @@ -0,0 +1,51 @@ +// Run HA develop mode +const gulp = require("gulp"); + +require("./clean.js"); +require("./translations.js"); +require("./gen-icons.js"); +require("./gather-static.js"); +require("./webpack.js"); +require("./service-worker.js"); +require("./entry-html.js"); + +gulp.task( + "develop-app", + gulp.series( + async function setEnv() { + process.env.NODE_ENV = "development"; + }, + "clean", + gulp.parallel( + "gen-service-worker-dev", + "gen-icons", + "gen-pages-dev", + "gen-index-html-dev", + "build-translations" + ), + "copy-static", + "webpack-watch-app" + ) +); + +gulp.task( + "build-app", + gulp.series( + async function setEnv() { + process.env.NODE_ENV = "production"; + }, + "clean", + gulp.parallel("gen-icons", "build-translations"), + "copy-static", + gulp.parallel( + "webpack-prod-app", + // Do not compress static files in CI, it's SLOW. + ...(process.env.CI === "true" ? [] : ["compress-static"]) + ), + gulp.parallel( + "gen-pages-prod", + "gen-index-html-prod", + "gen-service-worker-prod" + ) + ) +); diff --git a/build-scripts/gulp/clean.js b/build-scripts/gulp/clean.js index d3eaed526a..d1226c198e 100644 --- a/build-scripts/gulp/clean.js +++ b/build-scripts/gulp/clean.js @@ -3,3 +3,4 @@ const gulp = require("gulp"); const config = require("../paths"); gulp.task("clean", () => del([config.root, config.build_dir])); +gulp.task("clean-demo", () => del([config.demo_root, config.build_dir])); diff --git a/build-scripts/gulp/demo.js b/build-scripts/gulp/demo.js new file mode 100644 index 0000000000..cbe23e326c --- /dev/null +++ b/build-scripts/gulp/demo.js @@ -0,0 +1,36 @@ +// Run HA develop mode +const gulp = require("gulp"); + +require("./clean.js"); +require("./translations.js"); +require("./gen-icons.js"); +require("./gather-static.js"); +require("./webpack.js"); +require("./service-worker.js"); +require("./entry-html.js"); + +gulp.task( + "develop-demo", + gulp.series( + async function setEnv() { + process.env.NODE_ENV = "development"; + }, + "clean-demo", + gulp.parallel("gen-icons", "gen-icons-demo", "build-translations"), + "copy-static-demo", + "webpack-dev-server-demo" + ) +); + +gulp.task( + "build-demo", + gulp.series( + async function setEnv() { + process.env.NODE_ENV = "production"; + }, + "clean-demo", + gulp.parallel("gen-icons", "gen-icons-demo", "build-translations"), + "copy-static-demo", + "webpack-prod-demo" + ) +); diff --git a/build-scripts/gulp/develop.js b/build-scripts/gulp/develop.js deleted file mode 100644 index 2dbcbaac45..0000000000 --- a/build-scripts/gulp/develop.js +++ /dev/null @@ -1,29 +0,0 @@ -// Run HA develop mode -const gulp = require("gulp"); - -require("./clean.js"); -require("./translations.js"); -require("./gen-icons.js"); -require("./gather-static.js"); -require("./webpack.js"); -require("./service-worker.js"); -require("./entry-html.js"); - -gulp.task( - "develop", - gulp.series( - async function setEnv() { - process.env.NODE_ENV = "development"; - }, - "clean", - gulp.parallel( - "copy-static", - "gen-service-worker-dev", - "gen-icons", - "gen-pages-dev", - "gen-index-html-dev", - gulp.series("build-translations", "copy-translations") - ), - "webpack-watch" - ) -); diff --git a/build-scripts/gulp/gather-static.js b/build-scripts/gulp/gather-static.js index 733c0e876c..9008b63f58 100644 --- a/build-scripts/gulp/gather-static.js +++ b/build-scripts/gulp/gather-static.js @@ -5,17 +5,21 @@ const path = require("path"); const fs = require("fs-extra"); const zopfli = require("gulp-zopfli-green"); const merge = require("merge-stream"); -const config = require("../paths"); +const paths = require("../paths"); const npmPath = (...parts) => - path.resolve(config.polymer_dir, "node_modules", ...parts); -const polyPath = (...parts) => path.resolve(config.polymer_dir, ...parts); -const staticPath = (...parts) => path.resolve(config.root, "static", ...parts); + path.resolve(paths.polymer_dir, "node_modules", ...parts); +const polyPath = (...parts) => path.resolve(paths.polymer_dir, ...parts); const copyFileDir = (fromFile, toDir) => fs.copySync(fromFile, path.join(toDir, path.basename(fromFile))); -function copyTranslations() { +const genStaticPath = (staticDir) => (...parts) => + path.resolve(staticDir, ...parts); + +function copyTranslations(staticDir) { + const staticPath = genStaticPath(staticDir); + // Translation output fs.copySync( polyPath("build-translations/output"), @@ -23,9 +27,8 @@ function copyTranslations() { ); } -function copyStatic() { - // Basic static files - fs.copySync(polyPath("public"), config.root); +function copyPolyfills(staticDir) { + const staticPath = genStaticPath(staticDir); // Web Component polyfills and adapters copyFileDir( @@ -40,31 +43,16 @@ function copyStatic() { npmPath("@webcomponents/webcomponentsjs/webcomponents-bundle.js.map"), staticPath("polyfills/") ); - - // Local fonts - fs.copySync(npmPath("@polymer/font-roboto-local/fonts"), staticPath("fonts")); - - // External dependency assets - copyFileDir( - npmPath("react-big-calendar/lib/css/react-big-calendar.css"), - staticPath("panels/calendar/") - ); - copyFileDir( - npmPath("leaflet/dist/leaflet.css"), - staticPath("images/leaflet/") - ); - fs.copySync( - npmPath("leaflet/dist/images"), - staticPath("images/leaflet/images/") - ); } -gulp.task("copy-static", (done) => { - copyStatic(); - done(); -}); +function copyFonts(staticDir) { + const staticPath = genStaticPath(staticDir); + // Local fonts + fs.copySync(npmPath("@polymer/font-roboto-local/fonts"), staticPath("fonts")); +} -gulp.task("compress-static", () => { +function compressStatic(staticDir) { + const staticPath = genStaticPath(staticDir); const fonts = gulp .src(staticPath("fonts/**/*.ttf")) .pipe(zopfli()) @@ -79,9 +67,44 @@ gulp.task("compress-static", () => { .pipe(gulp.dest(staticPath("translations"))); return merge(fonts, polyfills, translations); -}); +} -gulp.task("copy-translations", (done) => { - copyTranslations(); +gulp.task("copy-static", (done) => { + const staticDir = paths.static; + const staticPath = genStaticPath(paths.static); + // Basic static files + fs.copySync(polyPath("public"), paths.root); + + copyPolyfills(staticDir); + copyFonts(staticDir); + copyTranslations(staticDir); + + // Panel assets + copyFileDir( + npmPath("react-big-calendar/lib/css/react-big-calendar.css"), + staticPath("panels/calendar/") + ); + copyFileDir( + npmPath("leaflet/dist/leaflet.css"), + staticPath("images/leaflet/") + ); + fs.copySync( + npmPath("leaflet/dist/images"), + staticPath("images/leaflet/images/") + ); + done(); +}); + +gulp.task("compress-static", () => compressStatic(paths.static)); + +gulp.task("copy-static-demo", (done) => { + // Copy app static files + fs.copySync(polyPath("public"), paths.demo_root); + // Copy demo static files + fs.copySync(path.resolve(paths.demo_dir, "public"), paths.demo_root); + + copyPolyfills(paths.demo_static); + copyFonts(paths.demo_static); + copyTranslations(paths.demo_static); done(); }); diff --git a/build-scripts/gulp/gen-icons.js b/build-scripts/gulp/gen-icons.js index 6563b9a8f1..bfa7d7cc77 100644 --- a/build-scripts/gulp/gen-icons.js +++ b/build-scripts/gulp/gen-icons.js @@ -1,6 +1,7 @@ const gulp = require("gulp"); const path = require("path"); const fs = require("fs"); +const paths = require("../paths"); const ICON_PACKAGE_PATH = path.resolve( __dirname, @@ -118,6 +119,15 @@ gulp.task("gen-icons-hass", (done) => { }); gulp.task("gen-icons", gulp.series("gen-icons-hass", "gen-icons-mdi")); +gulp.task("gen-icons-demo", (done) => { + const iconNames = findIcons(path.resolve(paths.demo_dir, "./src"), "hademo"); + fs.writeFileSync( + path.resolve(paths.demo_dir, "hademo-icons.html"), + generateIconset("hademo", iconNames) + ); + done(); +}); + module.exports = { findIcons, generateIconset, diff --git a/build-scripts/gulp/release.js b/build-scripts/gulp/release.js deleted file mode 100644 index f7e26b45ca..0000000000 --- a/build-scripts/gulp/release.js +++ /dev/null @@ -1,31 +0,0 @@ -// Run HA develop mode -const gulp = require("gulp"); - -require("./clean.js"); -require("./translations.js"); -require("./gen-icons.js"); -require("./gather-static.js"); -require("./webpack.js"); -require("./service-worker.js"); -require("./entry-html.js"); - -gulp.task( - "build-release", - gulp.series( - async function setEnv() { - process.env.NODE_ENV = "production"; - }, - "clean", - gulp.parallel( - "copy-static", - "gen-icons", - gulp.series("build-translations", "copy-translations") - ), - gulp.parallel("webpack-prod", "compress-static"), - gulp.parallel( - "gen-pages-prod", - "gen-index-html-prod", - "gen-service-worker-prod" - ) - ) -); diff --git a/build-scripts/gulp/webpack.js b/build-scripts/gulp/webpack.js index 6ba6fa1e4a..2a21a14011 100644 --- a/build-scripts/gulp/webpack.js +++ b/build-scripts/gulp/webpack.js @@ -1,7 +1,11 @@ // Tasks to run webpack. const gulp = require("gulp"); +const path = require("path"); const webpack = require("webpack"); -const { createAppConfig } = require("../webpack"); +const WebpackDevServer = require("webpack-dev-server"); +const log = require("fancy-log"); +const paths = require("../paths"); +const { createAppConfig, createDemoConfig } = require("../webpack"); const handler = (done) => (err, stats) => { if (err) { @@ -12,7 +16,7 @@ const handler = (done) => (err, stats) => { return; } - console.log(`Build done @ ${new Date().toLocaleTimeString()}`); + log(`Build done @ ${new Date().toLocaleTimeString()}`); if (stats.hasErrors() || stats.hasWarnings()) { console.log(stats.toString("minimal")); @@ -23,7 +27,7 @@ const handler = (done) => (err, stats) => { } }; -gulp.task("webpack-watch", () => { +gulp.task("webpack-watch-app", () => { const compiler = webpack([ createAppConfig({ isProdBuild: false, @@ -41,7 +45,7 @@ gulp.task("webpack-watch", () => { }); gulp.task( - "webpack-prod", + "webpack-prod-app", () => new Promise((resolve) => webpack( @@ -61,3 +65,52 @@ gulp.task( ) ) ); + +gulp.task("webpack-dev-server-demo", () => { + const compiler = webpack([ + createDemoConfig({ + isProdBuild: false, + latestBuild: false, + isStatsBuild: false, + }), + createDemoConfig({ + isProdBuild: false, + latestBuild: true, + isStatsBuild: false, + }), + ]); + + new WebpackDevServer(compiler, { + open: true, + watchContentBase: true, + contentBase: path.resolve(paths.demo_dir, "dist"), + }).listen(8080, "localhost", function(err) { + if (err) { + throw err; + } + // Server listening + log("[webpack-dev-server]", "http://localhost:8080"); + }); +}); + +gulp.task( + "webpack-prod-demo", + () => + new Promise((resolve) => + webpack( + [ + createDemoConfig({ + isProdBuild: true, + latestBuild: false, + isStatsBuild: false, + }), + createDemoConfig({ + isProdBuild: true, + latestBuild: true, + isStatsBuild: false, + }), + ], + handler(resolve) + ) + ) +); diff --git a/build-scripts/paths.js b/build-scripts/paths.js index 28d553717b..f078c80da9 100644 --- a/build-scripts/paths.js +++ b/build-scripts/paths.js @@ -2,9 +2,16 @@ var path = require("path"); module.exports = { polymer_dir: path.resolve(__dirname, ".."), + build_dir: path.resolve(__dirname, "../build"), root: path.resolve(__dirname, "../hass_frontend"), static: path.resolve(__dirname, "../hass_frontend/static"), output: path.resolve(__dirname, "../hass_frontend/frontend_latest"), output_es5: path.resolve(__dirname, "../hass_frontend/frontend_es5"), + + demo_dir: path.resolve(__dirname, "../demo"), + demo_root: path.resolve(__dirname, "../demo/dist"), + demo_static: path.resolve(__dirname, "../demo/dist/static"), + demo_output: path.resolve(__dirname, "../demo/dist/frontend_latest"), + demo_output_es5: path.resolve(__dirname, "../demo/frontend_es5"), }; diff --git a/build-scripts/webpack.js b/build-scripts/webpack.js index 1a48454661..a29e6ec85a 100644 --- a/build-scripts/webpack.js +++ b/build-scripts/webpack.js @@ -17,6 +17,12 @@ if (!version) { } version = version[0]; +const genMode = (isProdBuild) => (isProdBuild ? "production" : "development"); +const genDevTool = (isProdBuild) => + isProdBuild ? "cheap-source-map" : "inline-cheap-module-source-map"; +const genChunkFilename = (isProdBuild, isStatsBuild) => + isProdBuild && !isStatsBuild ? "chunk.[chunkhash].js" : "[name].chunk.js"; + const resolve = { extensions: [".ts", ".js", ".json", ".tsx"], alias: { @@ -29,6 +35,20 @@ const resolve = { }, }; +const cssLoader = { + test: /\.css$/, + use: "raw-loader", +}; +const htmlLoader = { + test: /\.(html)$/, + use: { + loader: "html-loader", + options: { + exportAsEs6Default: true, + }, + }, +}; + const plugins = [ // Ignore moment.js locales new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), @@ -75,8 +95,6 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { ] = `build-translations/output/${key}.json`; }); - const publicPath = latestBuild ? "/frontend_latest/" : "/frontend_es5/"; - const entry = { app: "./src/entrypoints/app.ts", authorize: "./src/entrypoints/authorize.ts", @@ -88,28 +106,11 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { }; return { - mode: isProdBuild ? "production" : "development", - devtool: isProdBuild - ? "cheap-source-map " - : "inline-cheap-module-source-map", + mode: genMode(isProdBuild), + devtool: genDevTool(isProdBuild), entry, module: { - rules: [ - babelLoaderConfig({ latestBuild }), - { - test: /\.css$/, - use: "raw-loader", - }, - { - test: /\.(html)$/, - use: { - loader: "html-loader", - options: { - exportAsEs6Default: true, - }, - }, - }, - ], + rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader], }, optimization: optimization(latestBuild), plugins: [ @@ -165,20 +166,56 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { if (!isProdBuild || dontHash.has(chunk.name)) return `${chunk.name}.js`; return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`; }, - chunkFilename: - isProdBuild && !isStatsBuild - ? "chunk.[chunkhash].js" - : "[name].chunk.js", + chunkFilename: genChunkFilename(isProdBuild, isStatsBuild), path: latestBuild ? paths.output : paths.output_es5, - publicPath, + publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/", }, resolve, }; }; +const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { + return { + mode: genMode(isProdBuild), + devtool: genDevTool(isProdBuild), + entry: { + main: "./demo/src/entrypoint.ts", + compatibility: "./src/entrypoints/compatibility.ts", + }, + module: { + rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader], + }, + optimization: optimization(latestBuild), + plugins: [ + new webpack.DefinePlugin({ + __DEV__: !isProdBuild, + __BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"), + __VERSION__: JSON.stringify("DEMO"), + __DEMO__: true, + __STATIC_PATH__: "/static/", + "process.env.NODE_ENV": JSON.stringify( + isProdBuild ? "production" : "development" + ), + }), + ...plugins, + ].filter(Boolean), + resolve, + output: { + filename: "[name].js", + chunkFilename: genChunkFilename(isProdBuild, isStatsBuild), + path: path.resolve( + paths.demo_root, + latestBuild ? "frontend_latest" : "frontend_es5" + ), + publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/", + }, + }; +}; + module.exports = { resolve, plugins, optimization, createAppConfig, + createDemoConfig, }; diff --git a/demo/public/index.html b/demo/public/index.html index 5a9e3e49a7..4878fe8d43 100644 --- a/demo/public/index.html +++ b/demo/public/index.html @@ -74,9 +74,6 @@ content="https://www.home-assistant.io/images/default-social.png" /> Home Assistant Demo - - -
- +
-

Forgot your password?

Enter your email address and we will send you a link to reset your password. @@ -72,7 +70,7 @@ class HaConfigCloudForgotPassword extends EventsMixin(PolymerElement) { >Send reset email

-
+
`; diff --git a/src/panels/config/cloud/ha-config-cloud-login.js b/src/panels/config/cloud/ha-config-cloud-login.js index 7445a2769b..51687e5b9b 100644 --- a/src/panels/config/cloud/ha-config-cloud-login.js +++ b/src/panels/config/cloud/ha-config-cloud-login.js @@ -1,5 +1,4 @@ import "@material/mwc-button"; -import "@polymer/paper-card/paper-card"; import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item-body"; @@ -8,12 +7,13 @@ import "@polymer/paper-ripple/paper-ripple"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import "../../../components/ha-card"; import "../../../components/buttons/ha-progress-button"; import "../../../layouts/hass-subpage"; import "../../../resources/ha-style"; import "../ha-config-section"; -import EventsMixin from "../../../mixins/events-mixin"; +import { EventsMixin } from "../../../mixins/events-mixin"; import NavigateMixin from "../../../mixins/navigate-mixin"; import "../../../components/ha-icon-next"; /* @@ -34,14 +34,14 @@ class HaConfigCloudLogin extends NavigateMixin(EventsMixin(PolymerElement)) { [slot="introduction"] a { color: var(--primary-color); } - paper-card { - display: block; - } paper-item { cursor: pointer; } - paper-card:last-child { - margin-top: 24px; + ha-card { + overflow: hidden; + } + ha-card .card-header { + margin-bottom: -8px; } h1 { @apply --paper-font-headline; @@ -97,7 +97,7 @@ class HaConfigCloudLogin extends NavigateMixin(EventsMixin(PolymerElement)) {

- +
[[flashMessage]]
-
+ - +
-

Sign In

[[_error]]
-
+ - + Start your free 1 month trial @@ -152,7 +151,7 @@ class HaConfigCloudLogin extends NavigateMixin(EventsMixin(PolymerElement)) { - + diff --git a/src/panels/config/cloud/ha-config-cloud-register.js b/src/panels/config/cloud/ha-config-cloud-register.js index b387e18d01..9b9c1fc31c 100644 --- a/src/panels/config/cloud/ha-config-cloud-register.js +++ b/src/panels/config/cloud/ha-config-cloud-register.js @@ -1,13 +1,13 @@ -import "@polymer/paper-card/paper-card"; import "@polymer/paper-input/paper-input"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import "../../../components/ha-card"; import "../../../components/buttons/ha-progress-button"; import "../../../layouts/hass-subpage"; import "../../../resources/ha-style"; import "../ha-config-section"; -import EventsMixin from "../../../mixins/events-mixin"; +import { EventsMixin } from "../../../mixins/events-mixin"; /* * @appliesMixin EventsMixin @@ -29,15 +29,9 @@ class HaConfigCloudRegister extends EventsMixin(PolymerElement) { a { color: var(--primary-color); } - paper-card { - display: block; - } paper-item { cursor: pointer; } - paper-card:last-child { - margin-top: 24px; - } h1 { @apply --paper-font-headline; margin: 0; @@ -84,10 +78,9 @@ class HaConfigCloudRegister extends EventsMixin(PolymerElement) {

- +
-

Create Account

[[_error]]
@@ -97,7 +90,7 @@ class HaConfigCloudRegister extends EventsMixin(PolymerElement) { Start trial
-
+ diff --git a/src/panels/config/core/ha-config-section-core.js b/src/panels/config/core/ha-config-section-core.js index ee9c3547d0..4824b74fc5 100644 --- a/src/panels/config/core/ha-config-section-core.js +++ b/src/panels/config/core/ha-config-section-core.js @@ -1,9 +1,9 @@ import "@material/mwc-button"; -import "@polymer/paper-card/paper-card"; import "@polymer/paper-input/paper-input"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import "../../../components/ha-card"; import "../../../components/buttons/ha-call-service-button"; import "../../../resources/ha-style"; @@ -57,8 +57,8 @@ class HaConfigSectionCore extends LocalizeMixin(PolymerElement) { >[[localize('ui.panel.config.core.section.core.introduction')]] -
[[localize('ui.panel.config.core.section.core.validation.introduction')]] @@ -91,10 +91,10 @@ class HaConfigSectionCore extends LocalizeMixin(PolymerElement) {
[[validateLog]]
-
+ -
[[localize('ui.panel.config.core.section.core.reloading.introduction')]] @@ -128,10 +128,10 @@ class HaConfigSectionCore extends LocalizeMixin(PolymerElement) { >[[localize('ui.panel.config.core.section.core.reloading.script')]]
-
+ -
[[localize('ui.panel.config.core.section.core.server_management.introduction')]] @@ -152,7 +152,7 @@ class HaConfigSectionCore extends LocalizeMixin(PolymerElement) { >[[localize('ui.panel.config.core.section.core.server_management.stop')]]
-
+ `; } diff --git a/src/panels/config/customize/types/ha-customize-array.js b/src/panels/config/customize/types/ha-customize-array.js index 2991a9edc6..c300a8ed91 100644 --- a/src/panels/config/customize/types/ha-customize-array.js +++ b/src/panels/config/customize/types/ha-customize-array.js @@ -4,7 +4,7 @@ import "@polymer/paper-listbox/paper-listbox"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; -import EventsMixin from "../../../../mixins/events-mixin"; +import { EventsMixin } from "../../../../mixins/events-mixin"; /* * @appliesMixin EventsMixin diff --git a/src/panels/config/dashboard/ha-config-dashboard.js b/src/panels/config/dashboard/ha-config-dashboard.js index 41d6226f71..8c4a40a721 100644 --- a/src/panels/config/dashboard/ha-config-dashboard.js +++ b/src/panels/config/dashboard/ha-config-dashboard.js @@ -2,12 +2,12 @@ import "@polymer/app-layout/app-header-layout/app-header-layout"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/iron-icon/iron-icon"; -import "@polymer/paper-card/paper-card"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-item/paper-item"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import "../../../components/ha-card"; import "../../../components/ha-menu-button"; import "../../../components/ha-icon-next"; @@ -25,12 +25,12 @@ class HaConfigDashboard extends NavigateMixin(LocalizeMixin(PolymerElement)) { static get template() { return html` - + - + `; } diff --git a/src/panels/config/entity_registry/ha-config-entity-registry.ts b/src/panels/config/entity_registry/ha-config-entity-registry.ts index 8e5bd8b375..86f4dd1e78 100644 --- a/src/panels/config/entity_registry/ha-config-entity-registry.ts +++ b/src/panels/config/entity_registry/ha-config-entity-registry.ts @@ -4,24 +4,23 @@ import { html, css, CSSResult, - PropertyDeclarations, + property, } from "lit-element"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; -import "@polymer/paper-card/paper-card"; import { HomeAssistant } from "../../../types"; import { EntityRegistryEntry, - fetchEntityRegistry, computeEntityRegistryName, updateEntityRegistryEntry, removeEntityRegistryEntry, + subscribeEntityRegistry, } from "../../../data/entity_registry"; import "../../../layouts/hass-subpage"; import "../../../layouts/hass-loading-screen"; +import "../../../components/ha-card"; import "../../../components/ha-icon"; -import compare from "../../../common/string/compare"; import domainIcon from "../../../common/entity/domain_icon"; import stateIcon from "../../../common/entity/state_icon"; import computeDomain from "../../../common/entity/compute_domain"; @@ -30,22 +29,24 @@ import { showEntityRegistryDetailDialog, loadEntityRegistryDetailDialog, } from "./show-dialog-entity-registry-detail"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; +import { compare } from "../../../common/string/compare"; class HaConfigEntityRegistry extends LitElement { - public hass?: HomeAssistant; - public isWide?: boolean; - private _items?: EntityRegistryEntry[]; + @property() public hass!: HomeAssistant; + @property() public isWide?: boolean; + @property() private _entities?: EntityRegistryEntry[]; + private _unsubEntities?: UnsubscribeFunc; - static get properties(): PropertyDeclarations { - return { - hass: {}, - isWide: {}, - _items: {}, - }; + public disconnectedCallback() { + super.disconnectedCallback(); + if (this._unsubEntities) { + this._unsubEntities(); + } } protected render(): TemplateResult | void { - if (!this.hass || this._items === undefined) { + if (!this.hass || this._entities === undefined) { return html` `; @@ -77,8 +78,8 @@ class HaConfigEntityRegistry extends LitElement { )} - - ${this._items.map((entry) => { + + ${this._entities.map((entry) => { const state = this.hass!.states[entry.entity_id]; return html` @@ -103,7 +104,7 @@ class HaConfigEntityRegistry extends LitElement { `; })} - + `; @@ -111,14 +112,18 @@ class HaConfigEntityRegistry extends LitElement { protected firstUpdated(changedProps): void { super.firstUpdated(changedProps); - this._fetchData(); loadEntityRegistryDetailDialog(); } - private async _fetchData(): Promise { - this._items = (await fetchEntityRegistry(this.hass!)).sort((ent1, ent2) => - compare(ent1.entity_id, ent2.entity_id) - ); + protected updated(changedProps) { + super.updated(changedProps); + if (!this._unsubEntities) { + this._unsubEntities = subscribeEntityRegistry(this.hass, (entities) => { + this._entities = entities.sort((ent1, ent2) => + compare(ent1.entity_id, ent2.entity_id) + ); + }); + } } private _openEditEntry(ev: MouseEvent): void { @@ -131,7 +136,7 @@ class HaConfigEntityRegistry extends LitElement { entry.entity_id, updates ); - this._items = this._items!.map((ent) => + this._entities = this._entities!.map((ent) => ent === entry ? updated : ent ); }, @@ -148,7 +153,7 @@ Deleting an entry will not remove the entity from Home Assistant. To do this, yo try { await removeEntityRegistryEntry(this.hass!, entry.entity_id); - this._items = this._items!.filter((ent) => ent !== entry); + this._entities = this._entities!.filter((ent) => ent !== entry); return true; } catch (err) { return false; @@ -162,9 +167,9 @@ Deleting an entry will not remove the entity from Home Assistant. To do this, yo a { color: var(--primary-color); } - paper-card { - display: block; + ha-card { direction: ltr; + overflow: hidden; } paper-icon-item { cursor: pointer; diff --git a/src/panels/config/ha-entity-config.js b/src/panels/config/ha-entity-config.js index f2e0386871..15661b5c62 100644 --- a/src/panels/config/ha-entity-config.js +++ b/src/panels/config/ha-entity-config.js @@ -1,11 +1,11 @@ import "@material/mwc-button"; -import "@polymer/paper-card/paper-card"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-spinner/paper-spinner"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import "../../components/ha-card"; import computeStateName from "../../common/entity/compute_state_name"; @@ -13,8 +13,7 @@ class HaEntityConfig extends PolymerElement { static get template() { return html` - +
- + `; } diff --git a/src/panels/config/integrations/ha-ce-entities-card.js b/src/panels/config/integrations/ha-ce-entities-card.js index c06a75d525..49b9ea3454 100644 --- a/src/panels/config/integrations/ha-ce-entities-card.js +++ b/src/panels/config/integrations/ha-ce-entities-card.js @@ -1,12 +1,12 @@ import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; -import "@polymer/paper-card/paper-card"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import "../../../components/ha-card"; import "../../../layouts/hass-subpage"; -import EventsMixin from "../../../mixins/events-mixin"; +import { EventsMixin } from "../../../mixins/events-mixin"; import LocalizeMixIn from "../../../mixins/localize-mixin"; import "../../../components/entity/state-badge"; import { computeEntityRegistryName } from "../../../data/entity_registry"; @@ -19,7 +19,7 @@ class HaCeEntitiesCard extends LocalizeMixIn(EventsMixin(PolymerElement)) { static get template() { return html` - + - + `; } diff --git a/src/panels/config/integrations/ha-config-entries-dashboard.js b/src/panels/config/integrations/ha-config-entries-dashboard.js index e7582b6c91..937fcc21f8 100644 --- a/src/panels/config/integrations/ha-config-entries-dashboard.js +++ b/src/panels/config/integrations/ha-config-entries-dashboard.js @@ -2,13 +2,13 @@ import "@polymer/iron-flex-layout/iron-flex-layout-classes"; import "@polymer/paper-tooltip/paper-tooltip"; import "@material/mwc-button"; import "@polymer/paper-fab/paper-fab"; -import "@polymer/paper-card/paper-card"; import "@polymer/iron-icon/iron-icon"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import "../../../components/ha-card"; import "../../../components/entity/ha-state-icon"; import "../../../layouts/hass-subpage"; import "../../../resources/ha-style"; @@ -16,13 +16,14 @@ import "../../../components/ha-icon-next"; import { computeRTL } from "../../../common/util/compute_rtl"; import "../ha-config-section"; -import EventsMixin from "../../../mixins/events-mixin"; +import { EventsMixin } from "../../../mixins/events-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin"; import computeStateName from "../../../common/entity/compute_state_name"; import { loadConfigFlowDialog, showConfigFlowDialog, } from "../../../dialogs/config-flow/show-dialog-config-flow"; +import { localizeConfigFlowTitle } from "../../../data/config_entries"; /* * @appliesMixin LocalizeMixin @@ -34,13 +35,13 @@ class HaConfigManagerDashboard extends LocalizeMixin( static get template() { return html` - +