mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-02 14:07:55 +00:00
Merge pull request #6093 from home-assistant/dev
This commit is contained in:
commit
5d5d6b247f
14
.github/workflows/release-drafter.yaml
vendored
Normal file
14
.github/workflows/release-drafter.yaml
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
name: Release Drafter
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update_release_draft:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: release-drafter/release-drafter@v5
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
@ -2,79 +2,139 @@
|
|||||||
|
|
||||||
## Our Pledge
|
## Our Pledge
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
contributors and maintainers pledge to making participation in our project and
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
our community a harassment-free experience for everyone, regardless of age, body
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
nationality, personal appearance, race, religion, or sexual identity and
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
orientation.
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
## Our Standards
|
## Our Standards
|
||||||
|
|
||||||
Examples of behavior that contributes to creating a positive environment
|
Examples of behavior that contributes to a positive environment for our
|
||||||
include:
|
community include:
|
||||||
|
|
||||||
* Using welcoming and inclusive language
|
* Demonstrating empathy and kindness toward other people
|
||||||
* Being respectful of differing viewpoints and experiences
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
* Gracefully accepting constructive criticism
|
* Giving and gracefully accepting constructive feedback
|
||||||
* Focusing on what is best for the community
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
* Showing empathy towards other community members
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
advances
|
advances of any kind
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
* Public or private harassment
|
* Public or private harassment
|
||||||
* Publishing others' private information, such as a physical or electronic
|
* Publishing others' private information, such as a physical or email
|
||||||
address, without explicit permission
|
address, without their explicit permission
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
professional setting
|
professional setting
|
||||||
|
|
||||||
## Our Responsibilities
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying the standards of acceptable
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
behavior and are expected to take appropriate and fair corrective action in
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
response to any instances of unacceptable behavior.
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
Project maintainers have the right and responsibility to remove, edit, or
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
permanently any contributor for other behaviors that they deem inappropriate,
|
decisions when appropriate.
|
||||||
threatening, offensive, or harmful.
|
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
This Code of Conduct applies both within project spaces and in public spaces
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
when an individual is representing the project or its community. Examples of
|
an individual is officially representing the community in public spaces.
|
||||||
representing a project or community include using an official project e-mail
|
Examples of representing our community include using an official e-mail address,
|
||||||
address, posting via an official social media account, or acting as an appointed
|
posting via an official social media account, or acting as an appointed
|
||||||
representative at an online or offline event. Representation of a project may be
|
representative at an online or offline event.
|
||||||
further defined and clarified by project maintainers.
|
|
||||||
|
|
||||||
## Enforcement
|
## Enforcement
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported by contacting the project team at [safety@home-assistant.io][email]. All
|
reported to the community leaders responsible for enforcement at
|
||||||
complaints will be reviewed and investigated and will result in a response that
|
[safety@home-assistant.io][email] or by using the report/flag feature of
|
||||||
is deemed necessary and appropriate to the circumstances. The project team is
|
the medium used. All complaints will be reviewed and investigated promptly and
|
||||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
fairly.
|
||||||
Further details of specific enforcement policies may be posted separately.
|
|
||||||
|
|
||||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
faith may face temporary or permanent repercussions as determined by other
|
reporter of any incident.
|
||||||
members of the project's leadership.
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
## Attribution
|
## Attribution
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
available [here][version].
|
version 2.0, available [here][version].
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder][mozilla].
|
||||||
|
|
||||||
## Adoption
|
## Adoption
|
||||||
|
|
||||||
This Code of Conduct was first adopted January 21st, 2017 and announced in [this][coc-blog] blog post.
|
This Code of Conduct was first adopted January 21st, 2017 and announced in
|
||||||
|
[this][coc-blog] blog post and has been updated on May 25th, 2020 to version
|
||||||
|
2.0 of the [Contributor Covenant][homepage] as announced in [this][coc2-blog]
|
||||||
|
blog post.
|
||||||
|
|
||||||
[homepage]: http://contributor-covenant.org
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
[version]: http://contributor-covenant.org/version/1/4/
|
<https://www.contributor-covenant.org/faq>. Translations are available at
|
||||||
|
<https://www.contributor-covenant.org/translations>.
|
||||||
|
|
||||||
|
[coc-blog]: /blog/2017/01/21/home-assistant-governance/
|
||||||
|
[coc2-blog]: /blog/2020/05/25/code-of-conduct-updated/
|
||||||
[email]: mailto:safety@home-assistant.io
|
[email]: mailto:safety@home-assistant.io
|
||||||
[coc-blog]: https://home-assistant.io/blog/2017/01/21/home-assistant-governance/
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[mozilla]: https://github.com/mozilla/diversity
|
||||||
|
[version]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
const options = ({ latestBuild }) => ({
|
|
||||||
presets: [
|
|
||||||
!latestBuild && [require("@babel/preset-env").default, { modules: false }],
|
|
||||||
require("@babel/preset-typescript").default,
|
|
||||||
].filter(Boolean),
|
|
||||||
plugins: [
|
|
||||||
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
|
||||||
[
|
|
||||||
"@babel/plugin-proposal-object-rest-spread",
|
|
||||||
{ loose: true, useBuiltIns: true },
|
|
||||||
],
|
|
||||||
// Only support the syntax, Webpack will handle it.
|
|
||||||
"@babel/syntax-dynamic-import",
|
|
||||||
"@babel/plugin-proposal-optional-chaining",
|
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
|
||||||
[
|
|
||||||
require("@babel/plugin-proposal-decorators").default,
|
|
||||||
{ decoratorsBeforeExport: true },
|
|
||||||
],
|
|
||||||
[
|
|
||||||
require("@babel/plugin-proposal-class-properties").default,
|
|
||||||
{ loose: true },
|
|
||||||
],
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.babelLoaderConfig = ({ latestBuild }) => {
|
|
||||||
if (latestBuild === undefined) {
|
|
||||||
throw Error("latestBuild not defined for babel loader config");
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
test: /\.m?js$|\.tsx?$/,
|
|
||||||
exclude: [require.resolve("@mdi/js/mdi.js"), require.resolve("hls.js")],
|
|
||||||
use: {
|
|
||||||
loader: "babel-loader",
|
|
||||||
options: options({ latestBuild }),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
199
build-scripts/bundle.js
Normal file
199
build-scripts/bundle.js
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const env = require("./env.js");
|
||||||
|
const paths = require("./paths.js");
|
||||||
|
|
||||||
|
// Files from NPM Packages that should not be imported
|
||||||
|
module.exports.ignorePackages = ({ latestBuild }) => [
|
||||||
|
// Bloats bundle and it's not used.
|
||||||
|
path.resolve(require.resolve("moment"), "../locale"),
|
||||||
|
// Part of yaml.js and only used for !!js functions that we don't use
|
||||||
|
require.resolve("esprima"),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Files from NPM packages that we should replace with empty file
|
||||||
|
module.exports.emptyPackages = ({ latestBuild }) =>
|
||||||
|
[
|
||||||
|
// Contains all color definitions for all material color sets.
|
||||||
|
// We don't use it
|
||||||
|
require.resolve("@polymer/paper-styles/color.js"),
|
||||||
|
require.resolve("@polymer/paper-styles/default-theme.js"),
|
||||||
|
// Loads stuff from a CDN
|
||||||
|
require.resolve("@polymer/font-roboto/roboto.js"),
|
||||||
|
require.resolve("@vaadin/vaadin-material-styles/font-roboto.js"),
|
||||||
|
// Compatibility not needed for latest builds
|
||||||
|
latestBuild &&
|
||||||
|
// wrapped in require.resolve so it blows up if file no longer exists
|
||||||
|
require.resolve(
|
||||||
|
path.resolve(paths.polymer_dir, "src/resources/compatibility.ts")
|
||||||
|
),
|
||||||
|
// This polyfill is loaded in workers to support ES5, filter it out.
|
||||||
|
latestBuild && require.resolve("proxy-polyfill/src/index.js"),
|
||||||
|
].filter(Boolean);
|
||||||
|
|
||||||
|
module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
|
||||||
|
__DEV__: !isProdBuild,
|
||||||
|
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
||||||
|
__VERSION__: JSON.stringify(env.version()),
|
||||||
|
__DEMO__: false,
|
||||||
|
__BACKWARDS_COMPAT__: false,
|
||||||
|
__STATIC_PATH__: "/static/",
|
||||||
|
"process.env.NODE_ENV": JSON.stringify(
|
||||||
|
isProdBuild ? "production" : "development"
|
||||||
|
),
|
||||||
|
...defineOverlay,
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports.terserOptions = (latestBuild) => ({
|
||||||
|
safari10: true,
|
||||||
|
ecma: latestBuild ? undefined : 5,
|
||||||
|
output: { comments: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports.babelOptions = ({ latestBuild }) => ({
|
||||||
|
babelrc: false,
|
||||||
|
presets: [
|
||||||
|
!latestBuild && [require("@babel/preset-env").default, { modules: false }],
|
||||||
|
require("@babel/preset-typescript").default,
|
||||||
|
].filter(Boolean),
|
||||||
|
plugins: [
|
||||||
|
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
||||||
|
[
|
||||||
|
"@babel/plugin-proposal-object-rest-spread",
|
||||||
|
{ loose: true, useBuiltIns: true },
|
||||||
|
],
|
||||||
|
// Only support the syntax, Webpack will handle it.
|
||||||
|
"@babel/syntax-dynamic-import",
|
||||||
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
|
[
|
||||||
|
require("@babel/plugin-proposal-decorators").default,
|
||||||
|
{ decoratorsBeforeExport: true },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
require("@babel/plugin-proposal-class-properties").default,
|
||||||
|
{ loose: true },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Are already ES5, cause warnings when babelified.
|
||||||
|
module.exports.babelExclude = () => [
|
||||||
|
require.resolve("@mdi/js/mdi.js"),
|
||||||
|
require.resolve("hls.js"),
|
||||||
|
];
|
||||||
|
|
||||||
|
const outputPath = (outputRoot, latestBuild) =>
|
||||||
|
path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5");
|
||||||
|
|
||||||
|
const publicPath = (latestBuild) =>
|
||||||
|
latestBuild ? "/frontend_latest/" : "/frontend_es5/";
|
||||||
|
|
||||||
|
/*
|
||||||
|
BundleConfig {
|
||||||
|
// Object with entrypoints that need to be bundled
|
||||||
|
entry: { [name: string]: pathToFile },
|
||||||
|
// Folder where bundled files need to be written
|
||||||
|
outputPath: string,
|
||||||
|
// absolute url-path where bundled files can be found
|
||||||
|
publicPath: string,
|
||||||
|
// extra definitions that we need to replace in source
|
||||||
|
defineOverlay: {[name: string]: value },
|
||||||
|
// if this is a production build
|
||||||
|
isProdBuild: boolean,
|
||||||
|
// If we're targeting latest browsers
|
||||||
|
latestBuild: boolean,
|
||||||
|
// If we're doing a stats build (create nice chunk names)
|
||||||
|
isStatsBuild: boolean,
|
||||||
|
// Names of entrypoints that should not be hashed
|
||||||
|
dontHash: Set<string>
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports.config = {
|
||||||
|
app({ isProdBuild, latestBuild, isStatsBuild }) {
|
||||||
|
return {
|
||||||
|
entry: {
|
||||||
|
service_worker: "./src/entrypoints/service_worker.ts",
|
||||||
|
app: "./src/entrypoints/app.ts",
|
||||||
|
authorize: "./src/entrypoints/authorize.ts",
|
||||||
|
onboarding: "./src/entrypoints/onboarding.ts",
|
||||||
|
core: "./src/entrypoints/core.ts",
|
||||||
|
"custom-panel": "./src/entrypoints/custom-panel.ts",
|
||||||
|
},
|
||||||
|
outputPath: outputPath(paths.app_output_root, latestBuild),
|
||||||
|
publicPath: publicPath(latestBuild),
|
||||||
|
isProdBuild,
|
||||||
|
latestBuild,
|
||||||
|
isStatsBuild,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
demo({ isProdBuild, latestBuild, isStatsBuild }) {
|
||||||
|
return {
|
||||||
|
entry: {
|
||||||
|
main: path.resolve(paths.demo_dir, "src/entrypoint.ts"),
|
||||||
|
},
|
||||||
|
outputPath: outputPath(paths.demo_output_root, latestBuild),
|
||||||
|
publicPath: publicPath(latestBuild),
|
||||||
|
defineOverlay: {
|
||||||
|
__VERSION__: JSON.stringify(`DEMO-${env.version()}`),
|
||||||
|
__DEMO__: true,
|
||||||
|
},
|
||||||
|
isProdBuild,
|
||||||
|
latestBuild,
|
||||||
|
isStatsBuild,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
cast({ isProdBuild, latestBuild }) {
|
||||||
|
const entry = {
|
||||||
|
launcher: path.resolve(paths.cast_dir, "src/launcher/entrypoint.ts"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (latestBuild) {
|
||||||
|
entry.receiver = path.resolve(
|
||||||
|
paths.cast_dir,
|
||||||
|
"src/receiver/entrypoint.ts"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
entry,
|
||||||
|
outputPath: outputPath(paths.cast_output_root, latestBuild),
|
||||||
|
publicPath: publicPath(latestBuild),
|
||||||
|
isProdBuild,
|
||||||
|
latestBuild,
|
||||||
|
defineOverlay: {
|
||||||
|
__BACKWARDS_COMPAT__: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
hassio({ isProdBuild, latestBuild }) {
|
||||||
|
if (latestBuild) {
|
||||||
|
throw new Error("Hass.io does not support latest build!");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
entry: {
|
||||||
|
entrypoint: path.resolve(paths.hassio_dir, "src/entrypoint.ts"),
|
||||||
|
},
|
||||||
|
outputPath: paths.hassio_output_root,
|
||||||
|
publicPath: paths.hassio_publicPath,
|
||||||
|
isProdBuild,
|
||||||
|
latestBuild,
|
||||||
|
dontHash: new Set(["entrypoint"]),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
gallery({ isProdBuild, latestBuild }) {
|
||||||
|
return {
|
||||||
|
entry: {
|
||||||
|
entrypoint: path.resolve(paths.gallery_dir, "src/entrypoint.js"),
|
||||||
|
},
|
||||||
|
outputPath: outputPath(paths.gallery_output_root, latestBuild),
|
||||||
|
publicPath: publicPath(latestBuild),
|
||||||
|
isProdBuild,
|
||||||
|
latestBuild,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
@ -3,8 +3,13 @@ const path = require("path");
|
|||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
useRollup() {
|
||||||
|
return process.env.ROLLUP === "1";
|
||||||
|
},
|
||||||
isProdBuild() {
|
isProdBuild() {
|
||||||
return process.env.NODE_ENV === "production";
|
return (
|
||||||
|
process.env.NODE_ENV === "production" || module.exports.isStatsBuild()
|
||||||
|
);
|
||||||
},
|
},
|
||||||
isStatsBuild() {
|
isStatsBuild() {
|
||||||
return process.env.STATS === "1";
|
return process.env.STATS === "1";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Run HA develop mode
|
// Run HA develop mode
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
|
|
||||||
const envVars = require("../env");
|
const env = require("../env");
|
||||||
|
|
||||||
require("./clean.js");
|
require("./clean.js");
|
||||||
require("./translations.js");
|
require("./translations.js");
|
||||||
@ -11,6 +11,7 @@ require("./compress.js");
|
|||||||
require("./webpack.js");
|
require("./webpack.js");
|
||||||
require("./service-worker.js");
|
require("./service-worker.js");
|
||||||
require("./entry-html.js");
|
require("./entry-html.js");
|
||||||
|
require("./rollup.js");
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-app",
|
"develop-app",
|
||||||
@ -26,8 +27,8 @@ gulp.task(
|
|||||||
"gen-index-app-dev",
|
"gen-index-app-dev",
|
||||||
"build-translations"
|
"build-translations"
|
||||||
),
|
),
|
||||||
"copy-static",
|
"copy-static-app",
|
||||||
"webpack-watch-app"
|
env.useRollup() ? "rollup-watch-app" : "webpack-watch-app"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -39,10 +40,10 @@ gulp.task(
|
|||||||
},
|
},
|
||||||
"clean",
|
"clean",
|
||||||
gulp.parallel("gen-icons-json", "build-translations"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static",
|
"copy-static-app",
|
||||||
"webpack-prod-app",
|
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
|
||||||
...// Don't compress running tests
|
...// Don't compress running tests
|
||||||
(envVars.isTest() ? [] : ["compress-app"]),
|
(env.isTest() ? [] : ["compress-app"]),
|
||||||
gulp.parallel(
|
gulp.parallel(
|
||||||
"gen-pages-prod",
|
"gen-pages-prod",
|
||||||
"gen-index-app-prod",
|
"gen-index-app-prod",
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
|
|
||||||
|
const env = require("../env");
|
||||||
|
|
||||||
require("./clean.js");
|
require("./clean.js");
|
||||||
require("./translations.js");
|
require("./translations.js");
|
||||||
require("./gather-static.js");
|
require("./gather-static.js");
|
||||||
require("./webpack.js");
|
require("./webpack.js");
|
||||||
require("./service-worker.js");
|
require("./service-worker.js");
|
||||||
require("./entry-html.js");
|
require("./entry-html.js");
|
||||||
|
require("./rollup.js");
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-cast",
|
"develop-cast",
|
||||||
@ -17,7 +20,7 @@ gulp.task(
|
|||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel("gen-icons-json", "build-translations"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-cast",
|
"copy-static-cast",
|
||||||
"webpack-dev-server-cast"
|
env.useRollup() ? "rollup-dev-server-cast" : "webpack-dev-server-cast"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -31,7 +34,7 @@ gulp.task(
|
|||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel("gen-icons-json", "build-translations"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-cast",
|
"copy-static-cast",
|
||||||
"webpack-prod-cast",
|
env.useRollup() ? "rollup-prod-cast" : "webpack-prod-cast",
|
||||||
"gen-index-cast-prod"
|
"gen-index-cast-prod"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -1,39 +1,36 @@
|
|||||||
const del = require("del");
|
const del = require("del");
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const config = require("../paths");
|
const paths = require("../paths");
|
||||||
require("./translations");
|
require("./translations");
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean",
|
"clean",
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||||
return del([config.root, config.build_dir]);
|
return del([paths.app_output_root, paths.build_dir]);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-demo",
|
"clean-demo",
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||||
return del([config.demo_root, config.build_dir]);
|
return del([paths.demo_output_root, paths.build_dir]);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-cast",
|
"clean-cast",
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||||
return del([config.cast_root, config.build_dir]);
|
return del([paths.cast_output_root, paths.build_dir]);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task("clean-hassio", function cleanOutputAndBuildDir() {
|
||||||
"clean-hassio",
|
return del([paths.hassio_output_root, paths.build_dir]);
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
});
|
||||||
return del([config.hassio_root, config.build_dir]);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-gallery",
|
"clean-gallery",
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||||
return del([config.gallery_root, config.build_dir]);
|
return del([paths.gallery_output_root, paths.build_dir]);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -8,36 +8,36 @@ const paths = require("../paths");
|
|||||||
|
|
||||||
gulp.task("compress-app", function compressApp() {
|
gulp.task("compress-app", function compressApp() {
|
||||||
const jsLatest = gulp
|
const jsLatest = gulp
|
||||||
.src(path.resolve(paths.output, "**/*.js"))
|
.src(path.resolve(paths.app_output_latest, "**/*.js"))
|
||||||
.pipe(zopfli({ threshold: 150 }))
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(paths.output));
|
.pipe(gulp.dest(paths.app_output_latest));
|
||||||
|
|
||||||
const jsEs5 = gulp
|
const jsEs5 = gulp
|
||||||
.src(path.resolve(paths.output_es5, "**/*.js"))
|
.src(path.resolve(paths.app_output_es5, "**/*.js"))
|
||||||
.pipe(zopfli({ threshold: 150 }))
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(paths.output_es5));
|
.pipe(gulp.dest(paths.app_output_es5));
|
||||||
|
|
||||||
const polyfills = gulp
|
const polyfills = gulp
|
||||||
.src(path.resolve(paths.static, "polyfills/*.js"))
|
.src(path.resolve(paths.app_output_static, "polyfills/*.js"))
|
||||||
.pipe(zopfli({ threshold: 150 }))
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(path.resolve(paths.static, "polyfills")));
|
.pipe(gulp.dest(path.resolve(paths.app_output_static, "polyfills")));
|
||||||
|
|
||||||
const translations = gulp
|
const translations = gulp
|
||||||
.src(path.resolve(paths.static, "translations/**/*.json"))
|
.src(path.resolve(paths.app_output_static, "translations/**/*.json"))
|
||||||
.pipe(zopfli({ threshold: 150 }))
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(path.resolve(paths.static, "translations")));
|
.pipe(gulp.dest(path.resolve(paths.app_output_static, "translations")));
|
||||||
|
|
||||||
const icons = gulp
|
const icons = gulp
|
||||||
.src(path.resolve(paths.static, "mdi/*.json"))
|
.src(path.resolve(paths.app_output_static, "mdi/*.json"))
|
||||||
.pipe(zopfli({ threshold: 150 }))
|
.pipe(zopfli({ threshold: 150 }))
|
||||||
.pipe(gulp.dest(path.resolve(paths.static, "mdi")));
|
.pipe(gulp.dest(path.resolve(paths.app_output_static, "mdi")));
|
||||||
|
|
||||||
return merge(jsLatest, jsEs5, polyfills, translations, icons);
|
return merge(jsLatest, jsEs5, polyfills, translations, icons);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("compress-hassio", function compressApp() {
|
gulp.task("compress-hassio", function compressApp() {
|
||||||
return gulp
|
return gulp
|
||||||
.src(path.resolve(paths.hassio_root, "**/*.js"))
|
.src(path.resolve(paths.hassio_output_root, "**/*.js"))
|
||||||
.pipe(zopfli())
|
.pipe(zopfli())
|
||||||
.pipe(gulp.dest(paths.hassio_root));
|
.pipe(gulp.dest(paths.hassio_output_root));
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Run demo develop mode
|
// Run demo develop mode
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
|
|
||||||
|
const env = require("../env");
|
||||||
|
|
||||||
require("./clean.js");
|
require("./clean.js");
|
||||||
require("./translations.js");
|
require("./translations.js");
|
||||||
require("./gen-icons-json.js");
|
require("./gen-icons-json.js");
|
||||||
@ -8,6 +10,7 @@ require("./gather-static.js");
|
|||||||
require("./webpack.js");
|
require("./webpack.js");
|
||||||
require("./service-worker.js");
|
require("./service-worker.js");
|
||||||
require("./entry-html.js");
|
require("./entry-html.js");
|
||||||
|
require("./rollup.js");
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-demo",
|
"develop-demo",
|
||||||
@ -19,7 +22,7 @@ gulp.task(
|
|||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel("gen-icons-json", "gen-index-demo-dev", "build-translations"),
|
gulp.parallel("gen-icons-json", "gen-index-demo-dev", "build-translations"),
|
||||||
"copy-static-demo",
|
"copy-static-demo",
|
||||||
"webpack-dev-server-demo"
|
env.useRollup() ? "rollup-dev-server-demo" : "webpack-dev-server-demo"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -34,7 +37,7 @@ gulp.task(
|
|||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel("gen-icons-json", "build-translations"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-demo",
|
"copy-static-demo",
|
||||||
"webpack-prod-demo",
|
env.useRollup() ? "rollup-prod-demo" : "webpack-prod-demo",
|
||||||
"gen-index-demo-prod"
|
"gen-index-demo-prod"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -6,31 +6,36 @@ const fs = require("fs-extra");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const template = require("lodash.template");
|
const template = require("lodash.template");
|
||||||
const minify = require("html-minifier").minify;
|
const minify = require("html-minifier").minify;
|
||||||
const config = require("../paths.js");
|
const paths = require("../paths.js");
|
||||||
|
const env = require("../env.js");
|
||||||
|
|
||||||
const templatePath = (tpl) =>
|
const templatePath = (tpl) =>
|
||||||
path.resolve(config.polymer_dir, "src/html/", `${tpl}.html.template`);
|
path.resolve(paths.polymer_dir, "src/html/", `${tpl}.html.template`);
|
||||||
|
|
||||||
const readFile = (pth) => fs.readFileSync(pth).toString();
|
const readFile = (pth) => fs.readFileSync(pth).toString();
|
||||||
|
|
||||||
const renderTemplate = (pth, data = {}, pathFunc = templatePath) => {
|
const renderTemplate = (pth, data = {}, pathFunc = templatePath) => {
|
||||||
const compiled = template(readFile(pathFunc(pth)));
|
const compiled = template(readFile(pathFunc(pth)));
|
||||||
return compiled({ ...data, renderTemplate });
|
return compiled({
|
||||||
|
...data,
|
||||||
|
useRollup: env.useRollup(),
|
||||||
|
renderTemplate,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderDemoTemplate = (pth, data = {}) =>
|
const renderDemoTemplate = (pth, data = {}) =>
|
||||||
renderTemplate(pth, data, (tpl) =>
|
renderTemplate(pth, data, (tpl) =>
|
||||||
path.resolve(config.demo_dir, "src/html/", `${tpl}.html.template`)
|
path.resolve(paths.demo_dir, "src/html/", `${tpl}.html.template`)
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderCastTemplate = (pth, data = {}) =>
|
const renderCastTemplate = (pth, data = {}) =>
|
||||||
renderTemplate(pth, data, (tpl) =>
|
renderTemplate(pth, data, (tpl) =>
|
||||||
path.resolve(config.cast_dir, "src/html/", `${tpl}.html.template`)
|
path.resolve(paths.cast_dir, "src/html/", `${tpl}.html.template`)
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderGalleryTemplate = (pth, data = {}) =>
|
const renderGalleryTemplate = (pth, data = {}) =>
|
||||||
renderTemplate(pth, data, (tpl) =>
|
renderTemplate(pth, data, (tpl) =>
|
||||||
path.resolve(config.gallery_dir, "src/html/", `${tpl}.html.template`)
|
path.resolve(paths.gallery_dir, "src/html/", `${tpl}.html.template`)
|
||||||
);
|
);
|
||||||
|
|
||||||
const minifyHtml = (content) =>
|
const minifyHtml = (content) =>
|
||||||
@ -48,29 +53,36 @@ gulp.task("gen-pages-dev", (done) => {
|
|||||||
const content = renderTemplate(page, {
|
const content = renderTemplate(page, {
|
||||||
latestPageJS: `/frontend_latest/${page}.js`,
|
latestPageJS: `/frontend_latest/${page}.js`,
|
||||||
|
|
||||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
|
||||||
es5PageJS: `/frontend_es5/${page}.js`,
|
es5PageJS: `/frontend_es5/${page}.js`,
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.outputFileSync(path.resolve(config.root, `${page}.html`), content);
|
fs.outputFileSync(
|
||||||
|
path.resolve(paths.app_output_root, `${page}.html`),
|
||||||
|
content
|
||||||
|
);
|
||||||
}
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("gen-pages-prod", (done) => {
|
gulp.task("gen-pages-prod", (done) => {
|
||||||
const latestManifest = require(path.resolve(config.output, "manifest.json"));
|
const latestManifest = require(path.resolve(
|
||||||
const es5Manifest = require(path.resolve(config.output_es5, "manifest.json"));
|
paths.app_output_latest,
|
||||||
|
"manifest.json"
|
||||||
|
));
|
||||||
|
const es5Manifest = require(path.resolve(
|
||||||
|
paths.app_output_es5,
|
||||||
|
"manifest.json"
|
||||||
|
));
|
||||||
|
|
||||||
for (const page of PAGES) {
|
for (const page of PAGES) {
|
||||||
const content = renderTemplate(page, {
|
const content = renderTemplate(page, {
|
||||||
latestPageJS: latestManifest[`${page}.js`],
|
latestPageJS: latestManifest[`${page}.js`],
|
||||||
|
|
||||||
es5Compatibility: es5Manifest["compatibility.js"],
|
|
||||||
es5PageJS: es5Manifest[`${page}.js`],
|
es5PageJS: es5Manifest[`${page}.js`],
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.outputFileSync(
|
fs.outputFileSync(
|
||||||
path.resolve(config.root, `${page}.html`),
|
path.resolve(paths.app_output_root, `${page}.html`),
|
||||||
minifyHtml(content)
|
minifyHtml(content)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -85,32 +97,39 @@ gulp.task("gen-index-app-dev", (done) => {
|
|||||||
latestCoreJS: "/frontend_latest/core.js",
|
latestCoreJS: "/frontend_latest/core.js",
|
||||||
latestCustomPanelJS: "/frontend_latest/custom-panel.js",
|
latestCustomPanelJS: "/frontend_latest/custom-panel.js",
|
||||||
|
|
||||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
|
||||||
es5AppJS: "/frontend_es5/app.js",
|
es5AppJS: "/frontend_es5/app.js",
|
||||||
es5CoreJS: "/frontend_es5/core.js",
|
es5CoreJS: "/frontend_es5/core.js",
|
||||||
es5CustomPanelJS: "/frontend_es5/custom-panel.js",
|
es5CustomPanelJS: "/frontend_es5/custom-panel.js",
|
||||||
}).replace(/#THEMEC/g, "{{ theme_color }}");
|
}).replace(/#THEMEC/g, "{{ theme_color }}");
|
||||||
|
|
||||||
fs.outputFileSync(path.resolve(config.root, "index.html"), content);
|
fs.outputFileSync(path.resolve(paths.app_output_root, "index.html"), content);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("gen-index-app-prod", (done) => {
|
gulp.task("gen-index-app-prod", (done) => {
|
||||||
const latestManifest = require(path.resolve(config.output, "manifest.json"));
|
const latestManifest = require(path.resolve(
|
||||||
const es5Manifest = require(path.resolve(config.output_es5, "manifest.json"));
|
paths.app_output_latest,
|
||||||
|
"manifest.json"
|
||||||
|
));
|
||||||
|
const es5Manifest = require(path.resolve(
|
||||||
|
paths.app_output_es5,
|
||||||
|
"manifest.json"
|
||||||
|
));
|
||||||
const content = renderTemplate("index", {
|
const content = renderTemplate("index", {
|
||||||
latestAppJS: latestManifest["app.js"],
|
latestAppJS: latestManifest["app.js"],
|
||||||
latestCoreJS: latestManifest["core.js"],
|
latestCoreJS: latestManifest["core.js"],
|
||||||
latestCustomPanelJS: latestManifest["custom-panel.js"],
|
latestCustomPanelJS: latestManifest["custom-panel.js"],
|
||||||
|
|
||||||
es5Compatibility: es5Manifest["compatibility.js"],
|
|
||||||
es5AppJS: es5Manifest["app.js"],
|
es5AppJS: es5Manifest["app.js"],
|
||||||
es5CoreJS: es5Manifest["core.js"],
|
es5CoreJS: es5Manifest["core.js"],
|
||||||
es5CustomPanelJS: es5Manifest["custom-panel.js"],
|
es5CustomPanelJS: es5Manifest["custom-panel.js"],
|
||||||
});
|
});
|
||||||
const minified = minifyHtml(content).replace(/#THEMEC/g, "{{ theme_color }}");
|
const minified = minifyHtml(content).replace(/#THEMEC/g, "{{ theme_color }}");
|
||||||
|
|
||||||
fs.outputFileSync(path.resolve(config.root, "index.html"), minified);
|
fs.outputFileSync(
|
||||||
|
path.resolve(paths.app_output_root, "index.html"),
|
||||||
|
minified
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -119,7 +138,7 @@ gulp.task("gen-index-cast-dev", (done) => {
|
|||||||
latestReceiverJS: "/frontend_latest/receiver.js",
|
latestReceiverJS: "/frontend_latest/receiver.js",
|
||||||
});
|
});
|
||||||
fs.outputFileSync(
|
fs.outputFileSync(
|
||||||
path.resolve(config.cast_root, "receiver.html"),
|
path.resolve(paths.cast_output_root, "receiver.html"),
|
||||||
contentReceiver
|
contentReceiver
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -127,14 +146,17 @@ gulp.task("gen-index-cast-dev", (done) => {
|
|||||||
latestLauncherJS: "/frontend_latest/launcher.js",
|
latestLauncherJS: "/frontend_latest/launcher.js",
|
||||||
es5LauncherJS: "/frontend_es5/launcher.js",
|
es5LauncherJS: "/frontend_es5/launcher.js",
|
||||||
});
|
});
|
||||||
fs.outputFileSync(path.resolve(config.cast_root, "faq.html"), contentFAQ);
|
fs.outputFileSync(
|
||||||
|
path.resolve(paths.cast_output_root, "faq.html"),
|
||||||
|
contentFAQ
|
||||||
|
);
|
||||||
|
|
||||||
const contentLauncher = renderCastTemplate("launcher", {
|
const contentLauncher = renderCastTemplate("launcher", {
|
||||||
latestLauncherJS: "/frontend_latest/launcher.js",
|
latestLauncherJS: "/frontend_latest/launcher.js",
|
||||||
es5LauncherJS: "/frontend_es5/launcher.js",
|
es5LauncherJS: "/frontend_es5/launcher.js",
|
||||||
});
|
});
|
||||||
fs.outputFileSync(
|
fs.outputFileSync(
|
||||||
path.resolve(config.cast_root, "index.html"),
|
path.resolve(paths.cast_output_root, "index.html"),
|
||||||
contentLauncher
|
contentLauncher
|
||||||
);
|
);
|
||||||
done();
|
done();
|
||||||
@ -142,11 +164,11 @@ gulp.task("gen-index-cast-dev", (done) => {
|
|||||||
|
|
||||||
gulp.task("gen-index-cast-prod", (done) => {
|
gulp.task("gen-index-cast-prod", (done) => {
|
||||||
const latestManifest = require(path.resolve(
|
const latestManifest = require(path.resolve(
|
||||||
config.cast_output,
|
paths.cast_output_latest,
|
||||||
"manifest.json"
|
"manifest.json"
|
||||||
));
|
));
|
||||||
const es5Manifest = require(path.resolve(
|
const es5Manifest = require(path.resolve(
|
||||||
config.cast_output_es5,
|
paths.cast_output_es5,
|
||||||
"manifest.json"
|
"manifest.json"
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -154,7 +176,7 @@ gulp.task("gen-index-cast-prod", (done) => {
|
|||||||
latestReceiverJS: latestManifest["receiver.js"],
|
latestReceiverJS: latestManifest["receiver.js"],
|
||||||
});
|
});
|
||||||
fs.outputFileSync(
|
fs.outputFileSync(
|
||||||
path.resolve(config.cast_root, "receiver.html"),
|
path.resolve(paths.cast_output_root, "receiver.html"),
|
||||||
contentReceiver
|
contentReceiver
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -162,14 +184,17 @@ gulp.task("gen-index-cast-prod", (done) => {
|
|||||||
latestLauncherJS: latestManifest["launcher.js"],
|
latestLauncherJS: latestManifest["launcher.js"],
|
||||||
es5LauncherJS: es5Manifest["launcher.js"],
|
es5LauncherJS: es5Manifest["launcher.js"],
|
||||||
});
|
});
|
||||||
fs.outputFileSync(path.resolve(config.cast_root, "faq.html"), contentFAQ);
|
fs.outputFileSync(
|
||||||
|
path.resolve(paths.cast_output_root, "faq.html"),
|
||||||
|
contentFAQ
|
||||||
|
);
|
||||||
|
|
||||||
const contentLauncher = renderCastTemplate("launcher", {
|
const contentLauncher = renderCastTemplate("launcher", {
|
||||||
latestLauncherJS: latestManifest["launcher.js"],
|
latestLauncherJS: latestManifest["launcher.js"],
|
||||||
es5LauncherJS: es5Manifest["launcher.js"],
|
es5LauncherJS: es5Manifest["launcher.js"],
|
||||||
});
|
});
|
||||||
fs.outputFileSync(
|
fs.outputFileSync(
|
||||||
path.resolve(config.cast_root, "index.html"),
|
path.resolve(paths.cast_output_root, "index.html"),
|
||||||
contentLauncher
|
contentLauncher
|
||||||
);
|
);
|
||||||
done();
|
done();
|
||||||
@ -181,32 +206,36 @@ gulp.task("gen-index-demo-dev", (done) => {
|
|||||||
const content = renderDemoTemplate("index", {
|
const content = renderDemoTemplate("index", {
|
||||||
latestDemoJS: "/frontend_latest/main.js",
|
latestDemoJS: "/frontend_latest/main.js",
|
||||||
|
|
||||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
|
||||||
es5DemoJS: "/frontend_es5/main.js",
|
es5DemoJS: "/frontend_es5/main.js",
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.outputFileSync(path.resolve(config.demo_root, "index.html"), content);
|
fs.outputFileSync(
|
||||||
|
path.resolve(paths.demo_output_root, "index.html"),
|
||||||
|
content
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("gen-index-demo-prod", (done) => {
|
gulp.task("gen-index-demo-prod", (done) => {
|
||||||
const latestManifest = require(path.resolve(
|
const latestManifest = require(path.resolve(
|
||||||
config.demo_output,
|
paths.demo_output_latest,
|
||||||
"manifest.json"
|
"manifest.json"
|
||||||
));
|
));
|
||||||
const es5Manifest = require(path.resolve(
|
const es5Manifest = require(path.resolve(
|
||||||
config.demo_output_es5,
|
paths.demo_output_es5,
|
||||||
"manifest.json"
|
"manifest.json"
|
||||||
));
|
));
|
||||||
const content = renderDemoTemplate("index", {
|
const content = renderDemoTemplate("index", {
|
||||||
latestDemoJS: latestManifest["main.js"],
|
latestDemoJS: latestManifest["main.js"],
|
||||||
|
|
||||||
es5Compatibility: es5Manifest["compatibility.js"],
|
|
||||||
es5DemoJS: es5Manifest["main.js"],
|
es5DemoJS: es5Manifest["main.js"],
|
||||||
});
|
});
|
||||||
const minified = minifyHtml(content);
|
const minified = minifyHtml(content);
|
||||||
|
|
||||||
fs.outputFileSync(path.resolve(config.demo_root, "index.html"), minified);
|
fs.outputFileSync(
|
||||||
|
path.resolve(paths.demo_output_root, "index.html"),
|
||||||
|
minified
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -217,13 +246,16 @@ gulp.task("gen-index-gallery-dev", (done) => {
|
|||||||
latestGalleryJS: "./frontend_latest/entrypoint.js",
|
latestGalleryJS: "./frontend_latest/entrypoint.js",
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.outputFileSync(path.resolve(config.gallery_root, "index.html"), content);
|
fs.outputFileSync(
|
||||||
|
path.resolve(paths.gallery_output_root, "index.html"),
|
||||||
|
content
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("gen-index-gallery-prod", (done) => {
|
gulp.task("gen-index-gallery-prod", (done) => {
|
||||||
const latestManifest = require(path.resolve(
|
const latestManifest = require(path.resolve(
|
||||||
config.gallery_output,
|
paths.gallery_output_latest,
|
||||||
"manifest.json"
|
"manifest.json"
|
||||||
));
|
));
|
||||||
const content = renderGalleryTemplate("index", {
|
const content = renderGalleryTemplate("index", {
|
||||||
@ -231,6 +263,9 @@ gulp.task("gen-index-gallery-prod", (done) => {
|
|||||||
});
|
});
|
||||||
const minified = minifyHtml(content);
|
const minified = minifyHtml(content);
|
||||||
|
|
||||||
fs.outputFileSync(path.resolve(config.gallery_root, "index.html"), minified);
|
fs.outputFileSync(
|
||||||
|
path.resolve(paths.gallery_output_root, "index.html"),
|
||||||
|
minified
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Run demo develop mode
|
// Run demo develop mode
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
|
|
||||||
|
const env = require("../env");
|
||||||
|
|
||||||
require("./clean.js");
|
require("./clean.js");
|
||||||
require("./translations.js");
|
require("./translations.js");
|
||||||
require("./gen-icons-json.js");
|
require("./gen-icons-json.js");
|
||||||
@ -8,6 +10,7 @@ require("./gather-static.js");
|
|||||||
require("./webpack.js");
|
require("./webpack.js");
|
||||||
require("./service-worker.js");
|
require("./service-worker.js");
|
||||||
require("./entry-html.js");
|
require("./entry-html.js");
|
||||||
|
require("./rollup.js");
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-gallery",
|
"develop-gallery",
|
||||||
@ -20,7 +23,7 @@ gulp.task(
|
|||||||
gulp.parallel("gen-icons-json", "build-translations"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-gallery",
|
"copy-static-gallery",
|
||||||
"gen-index-gallery-dev",
|
"gen-index-gallery-dev",
|
||||||
"webpack-dev-server-gallery"
|
env.useRollup() ? "rollup-dev-server-gallery" : "webpack-dev-server-gallery"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -34,7 +37,7 @@ gulp.task(
|
|||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel("gen-icons-json", "build-translations"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-gallery",
|
"copy-static-gallery",
|
||||||
"webpack-prod-gallery",
|
env.useRollup() ? "rollup-prod-gallery" : "webpack-prod-gallery",
|
||||||
"gen-index-gallery-prod"
|
"gen-index-gallery-prod"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -51,6 +51,12 @@ function copyPolyfills(staticDir) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function copyLoaderJS(staticDir) {
|
||||||
|
const staticPath = genStaticPath(staticDir);
|
||||||
|
copyFileDir(npmPath("systemjs/dist/s.min.js"), staticPath("js"));
|
||||||
|
copyFileDir(npmPath("systemjs/dist/s.min.js.map"), staticPath("js"));
|
||||||
|
}
|
||||||
|
|
||||||
function copyFonts(staticDir) {
|
function copyFonts(staticDir) {
|
||||||
const staticPath = genStaticPath(staticDir);
|
const staticPath = genStaticPath(staticDir);
|
||||||
// Local fonts
|
// Local fonts
|
||||||
@ -72,17 +78,17 @@ function copyMapPanel(staticDir) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task("copy-translations", (done) => {
|
gulp.task("copy-translations-app", async () => {
|
||||||
const staticDir = paths.static;
|
const staticDir = paths.app_output_static;
|
||||||
copyTranslations(staticDir);
|
copyTranslations(staticDir);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("copy-static", (done) => {
|
gulp.task("copy-static-app", async () => {
|
||||||
const staticDir = paths.static;
|
const staticDir = paths.app_output_static;
|
||||||
// Basic static files
|
// Basic static files
|
||||||
fs.copySync(polyPath("public"), paths.root);
|
fs.copySync(polyPath("public"), paths.app_output_root);
|
||||||
|
|
||||||
|
copyLoaderJS(staticDir);
|
||||||
copyPolyfills(staticDir);
|
copyPolyfills(staticDir);
|
||||||
copyFonts(staticDir);
|
copyFonts(staticDir);
|
||||||
copyTranslations(staticDir);
|
copyTranslations(staticDir);
|
||||||
@ -90,48 +96,50 @@ gulp.task("copy-static", (done) => {
|
|||||||
|
|
||||||
// Panel assets
|
// Panel assets
|
||||||
copyMapPanel(staticDir);
|
copyMapPanel(staticDir);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("copy-static-demo", (done) => {
|
gulp.task("copy-static-demo", async () => {
|
||||||
// Copy app static files
|
// Copy app static files
|
||||||
fs.copySync(
|
fs.copySync(
|
||||||
polyPath("public/static"),
|
polyPath("public/static"),
|
||||||
path.resolve(paths.demo_root, "static")
|
path.resolve(paths.demo_output_root, "static")
|
||||||
);
|
);
|
||||||
// Copy demo static files
|
// Copy demo static files
|
||||||
fs.copySync(path.resolve(paths.demo_dir, "public"), paths.demo_root);
|
fs.copySync(path.resolve(paths.demo_dir, "public"), paths.demo_output_root);
|
||||||
|
|
||||||
copyPolyfills(paths.demo_static);
|
copyLoaderJS(paths.demo_output_static);
|
||||||
copyMapPanel(paths.demo_static);
|
copyPolyfills(paths.demo_output_static);
|
||||||
copyFonts(paths.demo_static);
|
copyMapPanel(paths.demo_output_static);
|
||||||
copyTranslations(paths.demo_static);
|
copyFonts(paths.demo_output_static);
|
||||||
copyMdiIcons(paths.demo_static);
|
copyTranslations(paths.demo_output_static);
|
||||||
done();
|
copyMdiIcons(paths.demo_output_static);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("copy-static-cast", (done) => {
|
gulp.task("copy-static-cast", async () => {
|
||||||
// Copy app static files
|
// Copy app static files
|
||||||
fs.copySync(polyPath("public/static"), paths.cast_static);
|
fs.copySync(polyPath("public/static"), paths.cast_output_static);
|
||||||
// Copy cast static files
|
// Copy cast static files
|
||||||
fs.copySync(path.resolve(paths.cast_dir, "public"), paths.cast_root);
|
fs.copySync(path.resolve(paths.cast_dir, "public"), paths.cast_output_root);
|
||||||
|
|
||||||
copyMapPanel(paths.cast_static);
|
copyLoaderJS(paths.cast_output_static);
|
||||||
copyFonts(paths.cast_static);
|
copyPolyfills(paths.cast_output_static);
|
||||||
copyTranslations(paths.cast_static);
|
copyMapPanel(paths.cast_output_static);
|
||||||
copyMdiIcons(paths.cast_static);
|
copyFonts(paths.cast_output_static);
|
||||||
done();
|
copyTranslations(paths.cast_output_static);
|
||||||
|
copyMdiIcons(paths.cast_output_static);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("copy-static-gallery", (done) => {
|
gulp.task("copy-static-gallery", async () => {
|
||||||
// Copy app static files
|
// Copy app static files
|
||||||
fs.copySync(polyPath("public/static"), paths.gallery_static);
|
fs.copySync(polyPath("public/static"), paths.gallery_output_static);
|
||||||
// Copy gallery static files
|
// Copy gallery static files
|
||||||
fs.copySync(path.resolve(paths.gallery_dir, "public"), paths.gallery_root);
|
fs.copySync(
|
||||||
|
path.resolve(paths.gallery_dir, "public"),
|
||||||
|
paths.gallery_output_root
|
||||||
|
);
|
||||||
|
|
||||||
copyMapPanel(paths.gallery_static);
|
copyMapPanel(paths.gallery_output_static);
|
||||||
copyFonts(paths.gallery_static);
|
copyFonts(paths.gallery_output_static);
|
||||||
copyTranslations(paths.gallery_static);
|
copyTranslations(paths.gallery_output_static);
|
||||||
copyMdiIcons(paths.gallery_static);
|
copyMdiIcons(paths.gallery_output_static);
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
|
|
||||||
const envVars = require("../env");
|
const env = require("../env");
|
||||||
|
|
||||||
require("./clean.js");
|
require("./clean.js");
|
||||||
require("./gen-icons-json.js");
|
require("./gen-icons-json.js");
|
||||||
require("./webpack.js");
|
require("./webpack.js");
|
||||||
require("./compress.js");
|
require("./compress.js");
|
||||||
|
require("./rollup.js");
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-hassio",
|
"develop-hassio",
|
||||||
@ -15,7 +16,7 @@ gulp.task(
|
|||||||
},
|
},
|
||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"webpack-watch-hassio"
|
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -27,8 +28,8 @@ gulp.task(
|
|||||||
},
|
},
|
||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"webpack-prod-hassio",
|
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
|
||||||
...// Don't compress running tests
|
...// Don't compress running tests
|
||||||
(envVars.isTest() ? [] : ["compress-hassio"])
|
(env.isTest() ? [] : ["compress-hassio"])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
155
build-scripts/gulp/rollup.js
Normal file
155
build-scripts/gulp/rollup.js
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// Tasks to run Rollup
|
||||||
|
const path = require("path");
|
||||||
|
const gulp = require("gulp");
|
||||||
|
const rollup = require("rollup");
|
||||||
|
const handler = require("serve-handler");
|
||||||
|
const http = require("http");
|
||||||
|
const log = require("fancy-log");
|
||||||
|
const rollupConfig = require("../rollup");
|
||||||
|
const paths = require("../paths");
|
||||||
|
const open = require("open");
|
||||||
|
|
||||||
|
const bothBuilds = (createConfigFunc, params) =>
|
||||||
|
gulp.series(
|
||||||
|
async function buildLatest() {
|
||||||
|
await buildRollup(
|
||||||
|
createConfigFunc({
|
||||||
|
...params,
|
||||||
|
latestBuild: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
async function buildES5() {
|
||||||
|
await buildRollup(
|
||||||
|
createConfigFunc({
|
||||||
|
...params,
|
||||||
|
latestBuild: false,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function createServer(serveOptions) {
|
||||||
|
const server = http.createServer((request, response) => {
|
||||||
|
return handler(request, response, {
|
||||||
|
public: serveOptions.root,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
server.listen(
|
||||||
|
serveOptions.port,
|
||||||
|
serveOptions.networkAccess ? "0.0.0.0" : undefined,
|
||||||
|
() => {
|
||||||
|
log.info(`Available at http://localhost:${serveOptions.port}`);
|
||||||
|
open(`http://localhost:${serveOptions.port}`);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function watchRollup(createConfig, extraWatchSrc = [], serveOptions) {
|
||||||
|
const { inputOptions, outputOptions } = createConfig({
|
||||||
|
isProdBuild: false,
|
||||||
|
latestBuild: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const watcher = rollup.watch({
|
||||||
|
...inputOptions,
|
||||||
|
output: [outputOptions],
|
||||||
|
watch: {
|
||||||
|
include: ["src/**"] + extraWatchSrc,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let startedHttp = false;
|
||||||
|
|
||||||
|
watcher.on("event", (event) => {
|
||||||
|
if (event.code === "BUNDLE_END") {
|
||||||
|
log(`Build done @ ${new Date().toLocaleTimeString()}`);
|
||||||
|
} else if (event.code === "ERROR") {
|
||||||
|
log.error(event.error);
|
||||||
|
} else if (event.code === "END") {
|
||||||
|
if (startedHttp || !serveOptions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startedHttp = true;
|
||||||
|
createServer(serveOptions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.watch(
|
||||||
|
path.join(paths.translations_src, "en.json"),
|
||||||
|
gulp.series("build-translations", "copy-translations-app")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildRollup(config) {
|
||||||
|
const bundle = await rollup.rollup(config.inputOptions);
|
||||||
|
await bundle.write(config.outputOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task("rollup-watch-app", () => {
|
||||||
|
watchRollup(rollupConfig.createAppConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("rollup-watch-hassio", () => {
|
||||||
|
watchRollup(
|
||||||
|
// Force latestBuild = false for hassio config.
|
||||||
|
(conf) => rollupConfig.createHassioConfig({ ...conf, latestBuild: false }),
|
||||||
|
["hassio/src/**"]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("rollup-dev-server-demo", () => {
|
||||||
|
watchRollup(rollupConfig.createDemoConfig, ["demo/src/**"], {
|
||||||
|
root: paths.demo_output_root,
|
||||||
|
port: 8090,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("rollup-dev-server-cast", () => {
|
||||||
|
watchRollup(rollupConfig.createCastConfig, ["cast/src/**"], {
|
||||||
|
root: paths.cast_output_root,
|
||||||
|
port: 8080,
|
||||||
|
networkAccess: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("rollup-dev-server-gallery", () => {
|
||||||
|
watchRollup(rollupConfig.createGalleryConfig, ["gallery/src/**"], {
|
||||||
|
root: paths.gallery_output_root,
|
||||||
|
port: 8100,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task(
|
||||||
|
"rollup-prod-app",
|
||||||
|
bothBuilds(rollupConfig.createAppConfig, { isProdBuild: true })
|
||||||
|
);
|
||||||
|
|
||||||
|
gulp.task(
|
||||||
|
"rollup-prod-demo",
|
||||||
|
bothBuilds(rollupConfig.createDemoConfig, { isProdBuild: true })
|
||||||
|
);
|
||||||
|
|
||||||
|
gulp.task(
|
||||||
|
"rollup-prod-cast",
|
||||||
|
bothBuilds(rollupConfig.createCastConfig, { isProdBuild: true })
|
||||||
|
);
|
||||||
|
|
||||||
|
gulp.task("rollup-prod-hassio", () =>
|
||||||
|
buildRollup(
|
||||||
|
rollupConfig.createHassioConfig({
|
||||||
|
isProdBuild: true,
|
||||||
|
latestBuild: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
gulp.task("rollup-prod-gallery", () =>
|
||||||
|
buildRollup(
|
||||||
|
rollupConfig.createGalleryConfig({
|
||||||
|
isProdBuild: true,
|
||||||
|
latestBuild: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
@ -9,7 +9,7 @@ const workboxBuild = require("workbox-build");
|
|||||||
const sourceMapUrl = require("source-map-url");
|
const sourceMapUrl = require("source-map-url");
|
||||||
const paths = require("../paths.js");
|
const paths = require("../paths.js");
|
||||||
|
|
||||||
const swDest = path.resolve(paths.root, "service_worker.js");
|
const swDest = path.resolve(paths.app_output_root, "service_worker.js");
|
||||||
|
|
||||||
const writeSW = (content) => fs.outputFileSync(swDest, content.trim() + "\n");
|
const writeSW = (content) => fs.outputFileSync(swDest, content.trim() + "\n");
|
||||||
|
|
||||||
@ -31,32 +31,38 @@ self.addEventListener('install', (event) => {
|
|||||||
gulp.task("gen-service-worker-app-prod", async () => {
|
gulp.task("gen-service-worker-app-prod", async () => {
|
||||||
// Read bundled source file
|
// Read bundled source file
|
||||||
const bundleManifestLatest = require(path.resolve(
|
const bundleManifestLatest = require(path.resolve(
|
||||||
paths.output,
|
paths.app_output_latest,
|
||||||
"manifest.json"
|
"manifest.json"
|
||||||
));
|
));
|
||||||
let serviceWorkerContent = fs.readFileSync(
|
let serviceWorkerContent = fs.readFileSync(
|
||||||
paths.root + bundleManifestLatest["service_worker.js"],
|
paths.app_output_root + bundleManifestLatest["service_worker.js"],
|
||||||
"utf-8"
|
"utf-8"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Delete old file from frontend_latest so manifest won't pick it up
|
// Delete old file from frontend_latest so manifest won't pick it up
|
||||||
fs.removeSync(paths.root + bundleManifestLatest["service_worker.js"]);
|
fs.removeSync(
|
||||||
fs.removeSync(paths.root + bundleManifestLatest["service_worker.js.map"]);
|
paths.app_output_root + bundleManifestLatest["service_worker.js"]
|
||||||
|
);
|
||||||
|
fs.removeSync(
|
||||||
|
paths.app_output_root + bundleManifestLatest["service_worker.js.map"]
|
||||||
|
);
|
||||||
|
|
||||||
// Remove ES5
|
// Remove ES5
|
||||||
const bundleManifestES5 = require(path.resolve(
|
const bundleManifestES5 = require(path.resolve(
|
||||||
paths.output_es5,
|
paths.app_output_es5,
|
||||||
"manifest.json"
|
"manifest.json"
|
||||||
));
|
));
|
||||||
fs.removeSync(paths.root + bundleManifestES5["service_worker.js"]);
|
fs.removeSync(paths.app_output_root + bundleManifestES5["service_worker.js"]);
|
||||||
fs.removeSync(paths.root + bundleManifestES5["service_worker.js.map"]);
|
fs.removeSync(
|
||||||
|
paths.app_output_root + bundleManifestES5["service_worker.js.map"]
|
||||||
|
);
|
||||||
|
|
||||||
const workboxManifest = await workboxBuild.getManifest({
|
const workboxManifest = await workboxBuild.getManifest({
|
||||||
// Files that mach this pattern will be considered unique and skip revision check
|
// Files that mach this pattern will be considered unique and skip revision check
|
||||||
// ignore JS files + translation files
|
// ignore JS files + translation files
|
||||||
dontCacheBustURLsMatching: /(frontend_latest\/.+|static\/translations\/.+)/,
|
dontCacheBustURLsMatching: /(frontend_latest\/.+|static\/translations\/.+)/,
|
||||||
|
|
||||||
globDirectory: paths.root,
|
globDirectory: paths.app_output_root,
|
||||||
globPatterns: [
|
globPatterns: [
|
||||||
"frontend_latest/*.js",
|
"frontend_latest/*.js",
|
||||||
// Cache all English translations because we catch them as fallback
|
// Cache all English translations because we catch them as fallback
|
||||||
|
@ -38,9 +38,9 @@ const runDevServer = ({
|
|||||||
|
|
||||||
const handler = (done) => (err, stats) => {
|
const handler = (done) => (err, stats) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err.stack || err);
|
log.error(err.stack || err);
|
||||||
if (err.details) {
|
if (err.details) {
|
||||||
console.log(err.details);
|
log.error(err.details);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ const handler = (done) => (err, stats) => {
|
|||||||
log(`Build done @ ${new Date().toLocaleTimeString()}`);
|
log(`Build done @ ${new Date().toLocaleTimeString()}`);
|
||||||
|
|
||||||
if (stats.hasErrors() || stats.hasWarnings()) {
|
if (stats.hasErrors() || stats.hasWarnings()) {
|
||||||
console.log(stats.toString("minimal"));
|
log.warn(stats.toString("minimal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
@ -64,7 +64,7 @@ gulp.task("webpack-watch-app", () => {
|
|||||||
);
|
);
|
||||||
gulp.watch(
|
gulp.watch(
|
||||||
path.join(paths.translations_src, "en.json"),
|
path.join(paths.translations_src, "en.json"),
|
||||||
gulp.series("build-translations", "copy-translations")
|
gulp.series("build-translations", "copy-translations-app")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ gulp.task(
|
|||||||
gulp.task("webpack-dev-server-demo", () => {
|
gulp.task("webpack-dev-server-demo", () => {
|
||||||
runDevServer({
|
runDevServer({
|
||||||
compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })),
|
compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })),
|
||||||
contentBase: paths.demo_root,
|
contentBase: paths.demo_output_root,
|
||||||
port: 8090,
|
port: 8090,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -103,7 +103,7 @@ gulp.task(
|
|||||||
gulp.task("webpack-dev-server-cast", () => {
|
gulp.task("webpack-dev-server-cast", () => {
|
||||||
runDevServer({
|
runDevServer({
|
||||||
compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })),
|
compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })),
|
||||||
contentBase: paths.cast_root,
|
contentBase: paths.cast_output_root,
|
||||||
port: 8080,
|
port: 8080,
|
||||||
// Accessible from the network, because that's how Cast hits it.
|
// Accessible from the network, because that's how Cast hits it.
|
||||||
listenHost: "0.0.0.0",
|
listenHost: "0.0.0.0",
|
||||||
@ -152,7 +152,7 @@ gulp.task("webpack-dev-server-gallery", () => {
|
|||||||
runDevServer({
|
runDevServer({
|
||||||
// We don't use the es5 build, but the dev server will fuck up the publicPath if we don't
|
// We don't use the es5 build, but the dev server will fuck up the publicPath if we don't
|
||||||
compiler: webpack(bothBuilds(createGalleryConfig, { isProdBuild: false })),
|
compiler: webpack(bothBuilds(createGalleryConfig, { isProdBuild: false })),
|
||||||
contentBase: paths.gallery_root,
|
contentBase: paths.gallery_output_root,
|
||||||
port: 8100,
|
port: 8100,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,30 +4,36 @@ module.exports = {
|
|||||||
polymer_dir: path.resolve(__dirname, ".."),
|
polymer_dir: path.resolve(__dirname, ".."),
|
||||||
|
|
||||||
build_dir: path.resolve(__dirname, "../build"),
|
build_dir: path.resolve(__dirname, "../build"),
|
||||||
root: path.resolve(__dirname, "../hass_frontend"),
|
app_output_root: path.resolve(__dirname, "../hass_frontend"),
|
||||||
static: path.resolve(__dirname, "../hass_frontend/static"),
|
app_output_static: path.resolve(__dirname, "../hass_frontend/static"),
|
||||||
output: path.resolve(__dirname, "../hass_frontend/frontend_latest"),
|
app_output_latest: path.resolve(
|
||||||
output_es5: path.resolve(__dirname, "../hass_frontend/frontend_es5"),
|
__dirname,
|
||||||
|
"../hass_frontend/frontend_latest"
|
||||||
|
),
|
||||||
|
app_output_es5: path.resolve(__dirname, "../hass_frontend/frontend_es5"),
|
||||||
|
|
||||||
demo_dir: path.resolve(__dirname, "../demo"),
|
demo_dir: path.resolve(__dirname, "../demo"),
|
||||||
demo_root: path.resolve(__dirname, "../demo/dist"),
|
demo_output_root: path.resolve(__dirname, "../demo/dist"),
|
||||||
demo_static: path.resolve(__dirname, "../demo/dist/static"),
|
demo_output_static: path.resolve(__dirname, "../demo/dist/static"),
|
||||||
demo_output: path.resolve(__dirname, "../demo/dist/frontend_latest"),
|
demo_output_latest: path.resolve(__dirname, "../demo/dist/frontend_latest"),
|
||||||
demo_output_es5: path.resolve(__dirname, "../demo/dist/frontend_es5"),
|
demo_output_es5: path.resolve(__dirname, "../demo/dist/frontend_es5"),
|
||||||
|
|
||||||
cast_dir: path.resolve(__dirname, "../cast"),
|
cast_dir: path.resolve(__dirname, "../cast"),
|
||||||
cast_root: path.resolve(__dirname, "../cast/dist"),
|
cast_output_root: path.resolve(__dirname, "../cast/dist"),
|
||||||
cast_static: path.resolve(__dirname, "../cast/dist/static"),
|
cast_output_static: path.resolve(__dirname, "../cast/dist/static"),
|
||||||
cast_output: path.resolve(__dirname, "../cast/dist/frontend_latest"),
|
cast_output_latest: path.resolve(__dirname, "../cast/dist/frontend_latest"),
|
||||||
cast_output_es5: path.resolve(__dirname, "../cast/dist/frontend_es5"),
|
cast_output_es5: path.resolve(__dirname, "../cast/dist/frontend_es5"),
|
||||||
|
|
||||||
gallery_dir: path.resolve(__dirname, "../gallery"),
|
gallery_dir: path.resolve(__dirname, "../gallery"),
|
||||||
gallery_root: path.resolve(__dirname, "../gallery/dist"),
|
gallery_output_root: path.resolve(__dirname, "../gallery/dist"),
|
||||||
gallery_output: path.resolve(__dirname, "../gallery/dist/frontend_latest"),
|
gallery_output_latest: path.resolve(
|
||||||
gallery_static: path.resolve(__dirname, "../gallery/dist/static"),
|
__dirname,
|
||||||
|
"../gallery/dist/frontend_latest"
|
||||||
|
),
|
||||||
|
gallery_output_static: path.resolve(__dirname, "../gallery/dist/static"),
|
||||||
|
|
||||||
hassio_dir: path.resolve(__dirname, "../hassio"),
|
hassio_dir: path.resolve(__dirname, "../hassio"),
|
||||||
hassio_root: path.resolve(__dirname, "../hassio/build"),
|
hassio_output_root: path.resolve(__dirname, "../hassio/build"),
|
||||||
hassio_publicPath: "/api/hassio/app/",
|
hassio_publicPath: "/api/hassio/app/",
|
||||||
|
|
||||||
translations_src: path.resolve(__dirname, "../src/translations"),
|
translations_src: path.resolve(__dirname, "../src/translations"),
|
||||||
|
14
build-scripts/rollup-plugins/dont-hash-plugin.js
Normal file
14
build-scripts/rollup-plugins/dont-hash-plugin.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module.exports = function (opts = {}) {
|
||||||
|
const dontHash = opts.dontHash || new Set();
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "dont-hash",
|
||||||
|
renderChunk(_code, chunk, _options) {
|
||||||
|
if (!chunk.isEntry || !dontHash.has(chunk.name)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
chunk.fileName = `${chunk.name}.js`;
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
26
build-scripts/rollup-plugins/ignore-plugin.js
Normal file
26
build-scripts/rollup-plugins/ignore-plugin.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
module.exports = function (userOptions = {}) {
|
||||||
|
// Files need to be absolute paths.
|
||||||
|
// This only works if the file has no exports
|
||||||
|
// and only is imported for its side effects
|
||||||
|
const files = userOptions.files || [];
|
||||||
|
|
||||||
|
if (files.length === 0) {
|
||||||
|
return {
|
||||||
|
name: "ignore",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "ignore",
|
||||||
|
|
||||||
|
load(id) {
|
||||||
|
return files.some((toIgnorePath) => id.startsWith(toIgnorePath))
|
||||||
|
? {
|
||||||
|
code: "",
|
||||||
|
}
|
||||||
|
: null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
34
build-scripts/rollup-plugins/manifest-plugin.js
Normal file
34
build-scripts/rollup-plugins/manifest-plugin.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const url = require("url");
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
publicPath: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = function (userOptions = {}) {
|
||||||
|
const options = { ...defaultOptions, ...userOptions };
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "manifest",
|
||||||
|
generateBundle(outputOptions, bundle) {
|
||||||
|
const manifest = {};
|
||||||
|
|
||||||
|
for (const chunk of Object.values(bundle)) {
|
||||||
|
if (!chunk.isEntry) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Add js extension to mimic Webpack manifest.
|
||||||
|
manifest[`${chunk.name}.js`] = url.resolve(
|
||||||
|
options.publicPath,
|
||||||
|
chunk.fileName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emitFile({
|
||||||
|
type: "asset",
|
||||||
|
source: JSON.stringify(manifest, undefined, 2),
|
||||||
|
name: "manifest.json",
|
||||||
|
fileName: "manifest.json",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
149
build-scripts/rollup-plugins/worker-plugin.js
Normal file
149
build-scripts/rollup-plugins/worker-plugin.js
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// Worker plugin
|
||||||
|
// Each worker will include all of its dependencies
|
||||||
|
// instead of relying on an importer.
|
||||||
|
|
||||||
|
// Forked from v.1.4.1
|
||||||
|
// https://github.com/surma/rollup-plugin-off-main-thread
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Google Inc. All Rights Reserved.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const rollup = require("rollup");
|
||||||
|
const path = require("path");
|
||||||
|
const MagicString = require("magic-string");
|
||||||
|
|
||||||
|
const defaultOpts = {
|
||||||
|
// A RegExp to find `new Workers()` calls. The second capture group _must_
|
||||||
|
// capture the provided file name without the quotes.
|
||||||
|
workerRegexp: /new Worker\((["'])(.+?)\1(,[^)]+)?\)/g,
|
||||||
|
plugins: ["node-resolve", "commonjs", "babel", "terser", "ignore"],
|
||||||
|
};
|
||||||
|
|
||||||
|
async function getBundledWorker(workerPath, rollupOptions) {
|
||||||
|
const bundle = await rollup.rollup({
|
||||||
|
...rollupOptions,
|
||||||
|
input: {
|
||||||
|
worker: workerPath,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { output } = await bundle.generate({
|
||||||
|
// Generates cleanest output, we shouldn't have any imports/exports
|
||||||
|
// that would be incompatible with ES5.
|
||||||
|
format: "es",
|
||||||
|
// We should not export anything. This will fail build if we are.
|
||||||
|
exports: "none",
|
||||||
|
});
|
||||||
|
|
||||||
|
let code;
|
||||||
|
|
||||||
|
for (const chunkOrAsset of output) {
|
||||||
|
if (chunkOrAsset.name === "worker") {
|
||||||
|
code = chunkOrAsset.code;
|
||||||
|
} else if (chunkOrAsset.type !== "asset") {
|
||||||
|
throw new Error("Unexpected extra output");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (opts = {}) {
|
||||||
|
opts = { ...defaultOpts, ...opts };
|
||||||
|
|
||||||
|
let rollupOptions;
|
||||||
|
let refIds;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "hass-worker",
|
||||||
|
|
||||||
|
async buildStart(options) {
|
||||||
|
refIds = {};
|
||||||
|
rollupOptions = {
|
||||||
|
plugins: options.plugins.filter((plugin) =>
|
||||||
|
opts.plugins.includes(plugin.name)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
async transform(code, id) {
|
||||||
|
// Copy the regexp as they are stateful and this hook is async.
|
||||||
|
const workerRegexp = new RegExp(
|
||||||
|
opts.workerRegexp.source,
|
||||||
|
opts.workerRegexp.flags
|
||||||
|
);
|
||||||
|
if (!workerRegexp.test(code)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ms = new MagicString(code);
|
||||||
|
// Reset the regexp
|
||||||
|
workerRegexp.lastIndex = 0;
|
||||||
|
while (true) {
|
||||||
|
const match = workerRegexp.exec(code);
|
||||||
|
if (!match) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const workerFile = match[2];
|
||||||
|
let optionsObject = {};
|
||||||
|
// Parse the optional options object
|
||||||
|
if (match[3] && match[3].length > 0) {
|
||||||
|
// FIXME: ooooof!
|
||||||
|
optionsObject = new Function(`return ${match[3].slice(1)};`)();
|
||||||
|
}
|
||||||
|
delete optionsObject.type;
|
||||||
|
|
||||||
|
if (!new RegExp("^.*/").test(workerFile)) {
|
||||||
|
this.warn(
|
||||||
|
`Paths passed to the Worker constructor must be relative or absolute, i.e. start with /, ./ or ../ (just like dynamic import!). Ignoring "${workerFile}".`
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find worker file and store it as a chunk with ID prefixed for our loader
|
||||||
|
const resolvedWorkerFile = (await this.resolve(workerFile, id)).id;
|
||||||
|
let chunkRefId;
|
||||||
|
if (resolvedWorkerFile in refIds) {
|
||||||
|
chunkRefId = refIds[resolvedWorkerFile];
|
||||||
|
} else {
|
||||||
|
this.addWatchFile(resolvedWorkerFile);
|
||||||
|
const source = await getBundledWorker(
|
||||||
|
resolvedWorkerFile,
|
||||||
|
rollupOptions
|
||||||
|
);
|
||||||
|
chunkRefId = refIds[resolvedWorkerFile] = this.emitFile({
|
||||||
|
name: path.basename(resolvedWorkerFile),
|
||||||
|
source,
|
||||||
|
type: "asset",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const workerParametersStartIndex = match.index + "new Worker(".length;
|
||||||
|
const workerParametersEndIndex =
|
||||||
|
match.index + match[0].length - ")".length;
|
||||||
|
|
||||||
|
ms.overwrite(
|
||||||
|
workerParametersStartIndex,
|
||||||
|
workerParametersEndIndex,
|
||||||
|
`import.meta.ROLLUP_FILE_URL_${chunkRefId}, ${JSON.stringify(
|
||||||
|
optionsObject
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: ms.toString(),
|
||||||
|
map: ms.generateMap({ hires: true }),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
151
build-scripts/rollup.js
Normal file
151
build-scripts/rollup.js
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const commonjs = require("@rollup/plugin-commonjs");
|
||||||
|
const resolve = require("@rollup/plugin-node-resolve");
|
||||||
|
const json = require("@rollup/plugin-json");
|
||||||
|
const babel = require("rollup-plugin-babel");
|
||||||
|
const replace = require("@rollup/plugin-replace");
|
||||||
|
const visualizer = require("rollup-plugin-visualizer");
|
||||||
|
const { string } = require("rollup-plugin-string");
|
||||||
|
const { terser } = require("rollup-plugin-terser");
|
||||||
|
const manifest = require("./rollup-plugins/manifest-plugin");
|
||||||
|
const worker = require("./rollup-plugins/worker-plugin");
|
||||||
|
const dontHashPlugin = require("./rollup-plugins/dont-hash-plugin");
|
||||||
|
const ignore = require("./rollup-plugins/ignore-plugin");
|
||||||
|
|
||||||
|
const bundle = require("./bundle");
|
||||||
|
const paths = require("./paths");
|
||||||
|
|
||||||
|
const extensions = [".js", ".ts"];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} arg
|
||||||
|
* @param { import("rollup").InputOption } arg.input
|
||||||
|
*/
|
||||||
|
const createRollupConfig = ({
|
||||||
|
entry,
|
||||||
|
outputPath,
|
||||||
|
defineOverlay,
|
||||||
|
isProdBuild,
|
||||||
|
latestBuild,
|
||||||
|
isStatsBuild,
|
||||||
|
publicPath,
|
||||||
|
dontHash,
|
||||||
|
}) => {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* @type { import("rollup").InputOptions }
|
||||||
|
*/
|
||||||
|
inputOptions: {
|
||||||
|
input: entry,
|
||||||
|
// Some entry points contain no JavaScript. This setting silences a warning about that.
|
||||||
|
// https://rollupjs.org/guide/en/#preserveentrysignatures
|
||||||
|
preserveEntrySignatures: false,
|
||||||
|
plugins: [
|
||||||
|
ignore({
|
||||||
|
files: bundle.emptyPackages({ latestBuild }),
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
extensions,
|
||||||
|
preferBuiltins: false,
|
||||||
|
browser: true,
|
||||||
|
rootDir: paths.polymer_dir,
|
||||||
|
}),
|
||||||
|
commonjs({
|
||||||
|
namedExports: {
|
||||||
|
"js-yaml": ["safeDump", "safeLoad"],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
json(),
|
||||||
|
babel({
|
||||||
|
...bundle.babelOptions({ latestBuild }),
|
||||||
|
extensions,
|
||||||
|
exclude: bundle.babelExclude(),
|
||||||
|
}),
|
||||||
|
string({
|
||||||
|
// Import certain extensions as strings
|
||||||
|
include: [path.join(paths.polymer_dir, "node_modules/**/*.css")],
|
||||||
|
}),
|
||||||
|
replace(
|
||||||
|
bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })
|
||||||
|
),
|
||||||
|
manifest({
|
||||||
|
publicPath,
|
||||||
|
}),
|
||||||
|
worker(),
|
||||||
|
dontHashPlugin({ dontHash }),
|
||||||
|
isProdBuild && terser(bundle.terserOptions(latestBuild)),
|
||||||
|
isStatsBuild &&
|
||||||
|
visualizer({
|
||||||
|
// https://github.com/btd/rollup-plugin-visualizer#options
|
||||||
|
open: true,
|
||||||
|
sourcemap: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @type { import("rollup").OutputOptions }
|
||||||
|
*/
|
||||||
|
outputOptions: {
|
||||||
|
// https://rollupjs.org/guide/en/#outputdir
|
||||||
|
dir: outputPath,
|
||||||
|
// https://rollupjs.org/guide/en/#outputformat
|
||||||
|
format: latestBuild ? "es" : "systemjs",
|
||||||
|
// https://rollupjs.org/guide/en/#outputexternallivebindings
|
||||||
|
externalLiveBindings: false,
|
||||||
|
// https://rollupjs.org/guide/en/#outputentryfilenames
|
||||||
|
// https://rollupjs.org/guide/en/#outputchunkfilenames
|
||||||
|
// https://rollupjs.org/guide/en/#outputassetfilenames
|
||||||
|
entryFileNames:
|
||||||
|
isProdBuild && !isStatsBuild ? "[name]-[hash].js" : "[name].js",
|
||||||
|
chunkFileNames:
|
||||||
|
isProdBuild && !isStatsBuild ? "c.[hash].js" : "[name].js",
|
||||||
|
assetFileNames:
|
||||||
|
isProdBuild && !isStatsBuild ? "a.[hash].js" : "[name].js",
|
||||||
|
// https://rollupjs.org/guide/en/#outputsourcemap
|
||||||
|
sourcemap: isProdBuild ? true : "inline",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
|
return createRollupConfig(
|
||||||
|
bundle.config.app({
|
||||||
|
isProdBuild,
|
||||||
|
latestBuild,
|
||||||
|
isStatsBuild,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
|
return createRollupConfig(
|
||||||
|
bundle.config.demo({
|
||||||
|
isProdBuild,
|
||||||
|
latestBuild,
|
||||||
|
isStatsBuild,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
|
return createRollupConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
|
return createRollupConfig(bundle.config.hassio({ isProdBuild, latestBuild }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
|
return createRollupConfig(
|
||||||
|
bundle.config.gallery({ isProdBuild, latestBuild })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
createAppConfig,
|
||||||
|
createDemoConfig,
|
||||||
|
createCastConfig,
|
||||||
|
createHassioConfig,
|
||||||
|
createGalleryConfig,
|
||||||
|
};
|
@ -4,12 +4,12 @@ const TerserPlugin = require("terser-webpack-plugin");
|
|||||||
const ManifestPlugin = require("webpack-manifest-plugin");
|
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||||
const WorkerPlugin = require("worker-plugin");
|
const WorkerPlugin = require("worker-plugin");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
const env = require("./env.js");
|
const bundle = require("./bundle");
|
||||||
const { babelLoaderConfig } = require("./babel.js");
|
|
||||||
|
|
||||||
const createWebpackConfig = ({
|
const createWebpackConfig = ({
|
||||||
entry,
|
entry,
|
||||||
outputRoot,
|
outputPath,
|
||||||
|
publicPath,
|
||||||
defineOverlay,
|
defineOverlay,
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
@ -19,24 +19,30 @@ const createWebpackConfig = ({
|
|||||||
if (!dontHash) {
|
if (!dontHash) {
|
||||||
dontHash = new Set();
|
dontHash = new Set();
|
||||||
}
|
}
|
||||||
|
const ignorePackages = bundle.ignorePackages({ latestBuild });
|
||||||
return {
|
return {
|
||||||
mode: isProdBuild ? "production" : "development",
|
mode: isProdBuild ? "production" : "development",
|
||||||
devtool: isProdBuild
|
devtool: isProdBuild
|
||||||
? "cheap-module-source-map"
|
? "cheap-module-source-map"
|
||||||
: "eval-cheap-module-source-map",
|
: "eval-cheap-module-source-map",
|
||||||
entry,
|
entry,
|
||||||
|
node: false,
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
babelLoaderConfig({ latestBuild }),
|
{
|
||||||
|
test: /\.js$|\.ts$/,
|
||||||
|
exclude: bundle.babelExclude(),
|
||||||
|
use: {
|
||||||
|
loader: "babel-loader",
|
||||||
|
options: bundle.babelOptions({ latestBuild }),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: "raw-loader",
|
use: "raw-loader",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
externals: {
|
|
||||||
esprima: "esprima",
|
|
||||||
},
|
|
||||||
optimization: {
|
optimization: {
|
||||||
minimizer: [
|
minimizer: [
|
||||||
new TerserPlugin({
|
new TerserPlugin({
|
||||||
@ -44,50 +50,50 @@ const createWebpackConfig = ({
|
|||||||
parallel: true,
|
parallel: true,
|
||||||
extractComments: true,
|
extractComments: true,
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
terserOptions: {
|
terserOptions: bundle.terserOptions(latestBuild),
|
||||||
safari10: true,
|
|
||||||
ecma: latestBuild ? undefined : 5,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new WorkerPlugin(),
|
new WorkerPlugin(),
|
||||||
new ManifestPlugin(),
|
new ManifestPlugin({
|
||||||
new webpack.DefinePlugin({
|
// Only include the JS of entrypoints
|
||||||
__DEV__: !isProdBuild,
|
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
||||||
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
}),
|
||||||
__VERSION__: JSON.stringify(env.version()),
|
new webpack.DefinePlugin(
|
||||||
__DEMO__: false,
|
bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })
|
||||||
__BACKWARDS_COMPAT__: false,
|
),
|
||||||
__STATIC_PATH__: "/static/",
|
new webpack.IgnorePlugin({
|
||||||
"process.env.NODE_ENV": JSON.stringify(
|
checkResource(resource, context) {
|
||||||
isProdBuild ? "production" : "development"
|
// Only use ignore to intercept imports that we don't control
|
||||||
),
|
// inside node_module dependencies.
|
||||||
...defineOverlay,
|
if (
|
||||||
|
!context.includes("/node_modules/") ||
|
||||||
|
// calling define.amd will call require("!!webpack amd options")
|
||||||
|
resource.startsWith("!!webpack")
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let fullPath;
|
||||||
|
try {
|
||||||
|
fullPath = resource.startsWith(".")
|
||||||
|
? path.resolve(context, resource)
|
||||||
|
: require.resolve(resource);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error in ignore plugin", resource, context);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignorePackages.some((toIgnorePath) =>
|
||||||
|
fullPath.startsWith(toIgnorePath)
|
||||||
|
);
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
// Ignore moment.js locales
|
|
||||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
|
||||||
// Color.js is bloated, it contains all color definitions for all material color sets.
|
|
||||||
new webpack.NormalModuleReplacementPlugin(
|
new webpack.NormalModuleReplacementPlugin(
|
||||||
/@polymer\/paper-styles\/color\.js$/,
|
new RegExp(bundle.emptyPackages({ latestBuild }).join("|")),
|
||||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||||
),
|
),
|
||||||
// Ignore roboto pointing at CDN. We use local font-roboto-local.
|
],
|
||||||
new webpack.NormalModuleReplacementPlugin(
|
|
||||||
/@polymer\/font-roboto\/roboto\.js$/,
|
|
||||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
|
||||||
),
|
|
||||||
new webpack.NormalModuleReplacementPlugin(
|
|
||||||
/@vaadin\/vaadin-material-styles\/font-roboto\.js$/,
|
|
||||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
|
||||||
),
|
|
||||||
// Ignore mwc icons pointing at CDN.
|
|
||||||
new webpack.NormalModuleReplacementPlugin(
|
|
||||||
/@material\/mwc-icon\/mwc-icon-font\.js$/,
|
|
||||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
|
||||||
),
|
|
||||||
].filter(Boolean),
|
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".ts", ".js", ".json"],
|
extensions: [".ts", ".js", ".json"],
|
||||||
},
|
},
|
||||||
@ -102,11 +108,8 @@ const createWebpackConfig = ({
|
|||||||
isProdBuild && !isStatsBuild
|
isProdBuild && !isStatsBuild
|
||||||
? "chunk.[chunkhash].js"
|
? "chunk.[chunkhash].js"
|
||||||
: "[name].chunk.js",
|
: "[name].chunk.js",
|
||||||
path: path.resolve(
|
path: outputPath,
|
||||||
outputRoot,
|
publicPath,
|
||||||
latestBuild ? "frontend_latest" : "frontend_es5"
|
|
||||||
),
|
|
||||||
publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/",
|
|
||||||
// To silence warning in worker plugin
|
// To silence warning in worker plugin
|
||||||
globalObject: "self",
|
globalObject: "self",
|
||||||
},
|
},
|
||||||
@ -114,94 +117,31 @@ const createWebpackConfig = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
return createWebpackConfig({
|
return createWebpackConfig(
|
||||||
entry: {
|
bundle.config.app({ isProdBuild, latestBuild, isStatsBuild })
|
||||||
service_worker: "./src/entrypoints/service_worker.ts",
|
);
|
||||||
app: "./src/entrypoints/app.ts",
|
|
||||||
authorize: "./src/entrypoints/authorize.ts",
|
|
||||||
onboarding: "./src/entrypoints/onboarding.ts",
|
|
||||||
core: "./src/entrypoints/core.ts",
|
|
||||||
compatibility: "./src/entrypoints/compatibility.ts",
|
|
||||||
"custom-panel": "./src/entrypoints/custom-panel.ts",
|
|
||||||
},
|
|
||||||
outputRoot: paths.root,
|
|
||||||
isProdBuild,
|
|
||||||
latestBuild,
|
|
||||||
isStatsBuild,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
return createWebpackConfig({
|
return createWebpackConfig(
|
||||||
entry: {
|
bundle.config.demo({ isProdBuild, latestBuild, isStatsBuild })
|
||||||
main: path.resolve(paths.demo_dir, "src/entrypoint.ts"),
|
);
|
||||||
compatibility: path.resolve(
|
|
||||||
paths.polymer_dir,
|
|
||||||
"src/entrypoints/compatibility.ts"
|
|
||||||
),
|
|
||||||
},
|
|
||||||
outputRoot: paths.demo_root,
|
|
||||||
defineOverlay: {
|
|
||||||
__VERSION__: JSON.stringify(`DEMO-${env.version()}`),
|
|
||||||
__DEMO__: true,
|
|
||||||
},
|
|
||||||
isProdBuild,
|
|
||||||
latestBuild,
|
|
||||||
isStatsBuild,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
const entry = {
|
return createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
||||||
launcher: path.resolve(paths.cast_dir, "src/launcher/entrypoint.ts"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (latestBuild) {
|
|
||||||
entry.receiver = path.resolve(paths.cast_dir, "src/receiver/entrypoint.ts");
|
|
||||||
}
|
|
||||||
|
|
||||||
return createWebpackConfig({
|
|
||||||
entry,
|
|
||||||
outputRoot: paths.cast_root,
|
|
||||||
isProdBuild,
|
|
||||||
latestBuild,
|
|
||||||
defineOverlay: {
|
|
||||||
__BACKWARDS_COMPAT__: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
if (latestBuild) {
|
return createWebpackConfig(
|
||||||
throw new Error("Hass.io does not support latest build!");
|
bundle.config.hassio({ isProdBuild, latestBuild })
|
||||||
}
|
);
|
||||||
const config = createWebpackConfig({
|
|
||||||
entry: {
|
|
||||||
entrypoint: path.resolve(paths.hassio_dir, "src/entrypoint.ts"),
|
|
||||||
},
|
|
||||||
outputRoot: "",
|
|
||||||
isProdBuild,
|
|
||||||
latestBuild,
|
|
||||||
dontHash: new Set(["entrypoint"]),
|
|
||||||
});
|
|
||||||
|
|
||||||
config.output.path = paths.hassio_root;
|
|
||||||
config.output.publicPath = paths.hassio_publicPath;
|
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
const config = createWebpackConfig({
|
return createWebpackConfig(
|
||||||
entry: {
|
bundle.config.gallery({ isProdBuild, latestBuild })
|
||||||
entrypoint: path.resolve(paths.gallery_dir, "src/entrypoint.js"),
|
);
|
||||||
},
|
|
||||||
outputRoot: paths.gallery_root,
|
|
||||||
isProdBuild,
|
|
||||||
latestBuild,
|
|
||||||
});
|
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
10
cast/rollup.config.js
Normal file
10
cast/rollup.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const rollup = require("../build-scripts/rollup.js");
|
||||||
|
const env = require("../build-scripts/env.js");
|
||||||
|
|
||||||
|
const config = rollup.createCastConfig({
|
||||||
|
isProdBuild: env.isProdBuild(),
|
||||||
|
latestBuild: true,
|
||||||
|
isStatsBuild: env.isStatsBuild(),
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { ...config.inputOptions, output: config.outputOptions };
|
@ -46,7 +46,13 @@
|
|||||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||||
if (!isS101) {
|
if (!isS101) {
|
||||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||||
_ls("<%= es5LauncherJS %>");
|
<% if (useRollup) { %>
|
||||||
|
_ls("/static/js/s.min.js").onload = function() {
|
||||||
|
System.import("<%= es5LauncherJS %>");
|
||||||
|
};
|
||||||
|
<% } else { %>
|
||||||
|
_ls("<%= es5LauncherJS %>");
|
||||||
|
<% } %>
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
@ -37,7 +37,13 @@
|
|||||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||||
if (!isS101) {
|
if (!isS101) {
|
||||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||||
_ls("<%= es5LauncherJS %>");
|
<% if (useRollup) { %>
|
||||||
|
_ls("/static/js/s.min.js").onload = function() {
|
||||||
|
System.import("<%= es5LauncherJS %>");
|
||||||
|
};
|
||||||
|
<% } else { %>
|
||||||
|
_ls("<%= es5LauncherJS %>");
|
||||||
|
<% } %>
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
@ -82,6 +82,7 @@ export class HcMain extends HassElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.lovelaceConfig=${this._lovelaceConfig}
|
.lovelaceConfig=${this._lovelaceConfig}
|
||||||
.viewPath=${this._lovelacePath}
|
.viewPath=${this._lovelacePath}
|
||||||
|
@config-refresh=${this._generateLovelaceConfig}
|
||||||
></hc-lovelace>
|
></hc-lovelace>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -193,12 +194,7 @@ export class HcMain extends HassElement {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Generate a Lovelace config.
|
// Generate a Lovelace config.
|
||||||
this._unsubLovelace = () => undefined;
|
this._unsubLovelace = () => undefined;
|
||||||
const { generateLovelaceConfigFromHass } = await import(
|
await this._generateLovelaceConfig();
|
||||||
"../../../../src/panels/lovelace/common/generate-lovelace-config"
|
|
||||||
);
|
|
||||||
this._handleNewLovelaceConfig(
|
|
||||||
await generateLovelaceConfigFromHass(this.hass!)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!resourcesLoaded) {
|
if (!resourcesLoaded) {
|
||||||
@ -218,6 +214,15 @@ export class HcMain extends HassElement {
|
|||||||
this._sendStatus();
|
this._sendStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _generateLovelaceConfig() {
|
||||||
|
const { generateLovelaceConfigFromHass } = await import(
|
||||||
|
"../../../../src/panels/lovelace/common/generate-lovelace-config"
|
||||||
|
);
|
||||||
|
this._handleNewLovelaceConfig(
|
||||||
|
await generateLovelaceConfigFromHass(this.hass!)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private _handleNewLovelaceConfig(lovelaceConfig: LovelaceConfig) {
|
private _handleNewLovelaceConfig(lovelaceConfig: LovelaceConfig) {
|
||||||
castContext.setApplicationState(lovelaceConfig.title!);
|
castContext.setApplicationState(lovelaceConfig.title!);
|
||||||
this._lovelaceConfig = lovelaceConfig;
|
this._lovelaceConfig = lovelaceConfig;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
import "web-animations-js/web-animations-next-lite.min";
|
import "web-animations-js/web-animations-next-lite.min";
|
||||||
import "../../../src/resources/roboto";
|
import "../../../src/resources/roboto";
|
||||||
|
import "../../../src/resources/ha-style";
|
||||||
import "./layout/hc-lovelace";
|
import "./layout/hc-lovelace";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"background_color": "#FFFFFF",
|
"background_color": "#FFFFFF",
|
||||||
"description": "Open-source home automation platform running on Python 3.",
|
"description": "Home automation platform that puts local control and privacy first.",
|
||||||
"dir": "ltr",
|
"dir": "ltr",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"icons": [
|
"icons": [
|
||||||
@ -31,7 +31,7 @@
|
|||||||
],
|
],
|
||||||
"lang": "en-US",
|
"lang": "en-US",
|
||||||
"name": "Home Assistant Demo",
|
"name": "Home Assistant Demo",
|
||||||
"short_name": "Demo",
|
"short_name": "HA Demo",
|
||||||
"start_url": "/?homescreen=1",
|
"start_url": "/?homescreen=1",
|
||||||
"theme_color": "#03A9F4"
|
"theme_color": "#03A9F4"
|
||||||
}
|
}
|
||||||
|
10
demo/rollup.config.js
Normal file
10
demo/rollup.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const rollup = require("../build-scripts/rollup.js");
|
||||||
|
const env = require("../build-scripts/env.js");
|
||||||
|
|
||||||
|
const config = rollup.createDemoConfig({
|
||||||
|
isProdBuild: env.isProdBuild(),
|
||||||
|
latestBuild: true,
|
||||||
|
isStatsBuild: env.isStatsBuild(),
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { ...config.inputOptions, output: config.outputOptions };
|
@ -1,4 +1,3 @@
|
|||||||
import "@polymer/paper-styles/typography";
|
|
||||||
import "@polymer/polymer/lib/elements/dom-if";
|
import "@polymer/polymer/lib/elements/dom-if";
|
||||||
import "@polymer/polymer/lib/elements/dom-repeat";
|
import "@polymer/polymer/lib/elements/dom-repeat";
|
||||||
import "../../src/resources/ha-style";
|
import "../../src/resources/ha-style";
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import "../../src/resources/compatibility";
|
||||||
import { isNavigationClick } from "../../src/common/dom/is-navigation-click";
|
import { isNavigationClick } from "../../src/common/dom/is-navigation-click";
|
||||||
import { navigate } from "../../src/common/navigate";
|
import { navigate } from "../../src/common/navigate";
|
||||||
import {
|
import {
|
||||||
|
@ -5,18 +5,6 @@
|
|||||||
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />
|
||||||
<link rel="icon" href="/static/icons/favicon.ico" />
|
<link rel="icon" href="/static/icons/favicon.ico" />
|
||||||
<link rel="mask-icon" href="/static/icons/mask-icon.svg" color="#03a9f4" />
|
<link rel="mask-icon" href="/static/icons/mask-icon.svg" color="#03a9f4" />
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/static/fonts/roboto/Roboto-Regular.woff2"
|
|
||||||
as="font"
|
|
||||||
crossorigin
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/static/fonts/roboto/Roboto-Medium.woff2"
|
|
||||||
as="font"
|
|
||||||
crossorigin
|
|
||||||
/>
|
|
||||||
<link
|
<link
|
||||||
rel="apple-touch-icon"
|
rel="apple-touch-icon"
|
||||||
sizes="180x180"
|
sizes="180x180"
|
||||||
@ -96,6 +84,7 @@
|
|||||||
<div id="ha-init-skeleton"></div>
|
<div id="ha-init-skeleton"></div>
|
||||||
<ha-demo></ha-demo>
|
<ha-demo></ha-demo>
|
||||||
<%= renderTemplate('_js_base') %>
|
<%= renderTemplate('_js_base') %>
|
||||||
|
<%= renderTemplate('_preload_roboto') %>
|
||||||
|
|
||||||
<script type="module" src="<%= latestDemoJS %>"></script>
|
<script type="module" src="<%= latestDemoJS %>"></script>
|
||||||
|
|
||||||
@ -104,8 +93,13 @@
|
|||||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||||
if (!isS101) {
|
if (!isS101) {
|
||||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||||
_ls("<%= es5Compatibility %>");
|
<% if (useRollup) { %>
|
||||||
_ls("<%= es5DemoJS %>");
|
_ls("/static/js/s.min.js").onload = function() {
|
||||||
|
System.import("<%= es5DemoJS %>");
|
||||||
|
};
|
||||||
|
<% } else { %>
|
||||||
|
_ls("<%= es5DemoJS %>");
|
||||||
|
<% } %>
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
10
gallery/rollup.config.js
Normal file
10
gallery/rollup.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const rollup = require("../build-scripts/rollup.js");
|
||||||
|
const env = require("../build-scripts/env.js");
|
||||||
|
|
||||||
|
const config = rollup.createGalleryConfig({
|
||||||
|
isProdBuild: env.isProdBuild(),
|
||||||
|
latestBuild: true,
|
||||||
|
isStatsBuild: env.isStatsBuild(),
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { ...config.inputOptions, output: config.outputOptions };
|
@ -1,4 +1,3 @@
|
|||||||
import "@polymer/paper-styles/typography";
|
|
||||||
import "@polymer/polymer/lib/elements/dom-if";
|
import "@polymer/polymer/lib/elements/dom-if";
|
||||||
import "@polymer/polymer/lib/elements/dom-repeat";
|
import "@polymer/polymer/lib/elements/dom-repeat";
|
||||||
import "../../src/resources/ha-style";
|
import "../../src/resources/ha-style";
|
||||||
|
@ -10,6 +10,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 "../../src/components/ha-card";
|
import "../../src/components/ha-card";
|
||||||
import "../../src/managers/notification-manager";
|
import "../../src/managers/notification-manager";
|
||||||
|
import "../../src/styles/polymer-ha-style";
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
const DEMOS = require.context("./demos", true, /^(.*\.(ts$))[^.]*$/im);
|
const DEMOS = require.context("./demos", true, /^(.*\.(ts$))[^.]*$/im);
|
||||||
|
10
hassio/rollup.config.js
Normal file
10
hassio/rollup.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const rollup = require("../build-scripts/rollup.js");
|
||||||
|
const env = require("../build-scripts/env.js");
|
||||||
|
|
||||||
|
const config = rollup.createHassioConfig({
|
||||||
|
isProdBuild: env.isProdBuild(),
|
||||||
|
latestBuild: false,
|
||||||
|
isStatsBuild: env.isStatsBuild(),
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { ...config.inputOptions, output: config.outputOptions };
|
@ -64,6 +64,9 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
max-width: 1024px;
|
max-width: 1024px;
|
||||||
}
|
}
|
||||||
|
ha-markdown {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -630,14 +630,10 @@ class HassioAddonInfo extends LitElement {
|
|||||||
.right {
|
.right {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
ha-markdown img {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
protection-enable mwc-button {
|
protection-enable mwc-button {
|
||||||
--mdc-theme-primary: white;
|
--mdc-theme-primary: white;
|
||||||
}
|
}
|
||||||
.description a,
|
.description a {
|
||||||
ha-markdown a {
|
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
.red {
|
.red {
|
||||||
@ -675,6 +671,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
ha-markdown {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import * as Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
import { HassioAddonInfo } from "../../../src/data/hassio/addon";
|
import { HassioAddonInfo } from "../../../src/data/hassio/addon";
|
||||||
|
|
||||||
export function filterAndSort(addons: HassioAddonInfo[], filter: string) {
|
export function filterAndSort(addons: HassioAddonInfo[], filter: string) {
|
||||||
const options: Fuse.FuseOptions<HassioAddonInfo> = {
|
const options: Fuse.IFuseOptions<HassioAddonInfo> = {
|
||||||
keys: ["name", "description", "slug"],
|
keys: ["name", "description", "slug"],
|
||||||
caseSensitive: false,
|
isCaseSensitive: false,
|
||||||
minMatchCharLength: 2,
|
minMatchCharLength: 2,
|
||||||
threshold: 0.2,
|
threshold: 0.2,
|
||||||
};
|
};
|
||||||
const fuse = new Fuse(addons, options);
|
const fuse = new Fuse(addons, options);
|
||||||
return fuse.search(filter);
|
return fuse.search(filter).map((result) => result.item);
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,9 @@ class HassioMarkdownDialog extends LitElement {
|
|||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
ha-markdown {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -12,7 +12,6 @@ import {
|
|||||||
HassioSupervisorInfo,
|
HassioSupervisorInfo,
|
||||||
} from "../../src/data/hassio/supervisor";
|
} from "../../src/data/hassio/supervisor";
|
||||||
import type { PageNavigation } from "../../src/layouts/hass-tabs-subpage";
|
import type { PageNavigation } from "../../src/layouts/hass-tabs-subpage";
|
||||||
import "../../src/resources/ha-style";
|
|
||||||
import { HomeAssistant, Route } from "../../src/types";
|
import { HomeAssistant, Route } from "../../src/types";
|
||||||
import "./hassio-panel-router";
|
import "./hassio-panel-router";
|
||||||
|
|
||||||
|
18
package.json
18
package.json
@ -86,10 +86,10 @@
|
|||||||
"deep-freeze": "^0.0.1",
|
"deep-freeze": "^0.0.1",
|
||||||
"es6-object-assign": "^1.1.0",
|
"es6-object-assign": "^1.1.0",
|
||||||
"fecha": "^4.2.0",
|
"fecha": "^4.2.0",
|
||||||
"fuse.js": "^3.4.4",
|
"fuse.js": "^6.0.0",
|
||||||
"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": "^5.1.2",
|
"home-assistant-js-websocket": "^5.2.1",
|
||||||
"idb-keyval": "^3.2.0",
|
"idb-keyval": "^3.2.0",
|
||||||
"intl-messageformat": "^8.3.9",
|
"intl-messageformat": "^8.3.9",
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
@ -126,6 +126,10 @@
|
|||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
"@babel/preset-env": "^7.9.5",
|
"@babel/preset-env": "^7.9.5",
|
||||||
"@babel/preset-typescript": "^7.9.0",
|
"@babel/preset-typescript": "^7.9.0",
|
||||||
|
"@rollup/plugin-commonjs": "^11.1.0",
|
||||||
|
"@rollup/plugin-json": "^4.0.3",
|
||||||
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
||||||
|
"@rollup/plugin-replace": "^2.3.2",
|
||||||
"@types/chai": "^4.1.7",
|
"@types/chai": "^4.1.7",
|
||||||
"@types/chromecast-caf-receiver": "^3.0.12",
|
"@types/chromecast-caf-receiver": "^3.0.12",
|
||||||
"@types/codemirror": "^0.0.78",
|
"@types/codemirror": "^0.0.78",
|
||||||
@ -165,22 +169,30 @@
|
|||||||
"lint-staged": "^8.1.5",
|
"lint-staged": "^8.1.5",
|
||||||
"lit-analyzer": "^1.1.10",
|
"lit-analyzer": "^1.1.10",
|
||||||
"lodash.template": "^4.5.0",
|
"lodash.template": "^4.5.0",
|
||||||
|
"magic-string": "^0.25.7",
|
||||||
"map-stream": "^0.0.7",
|
"map-stream": "^0.0.7",
|
||||||
"merge-stream": "^1.0.1",
|
"merge-stream": "^1.0.1",
|
||||||
"mocha": "^6.0.2",
|
"mocha": "^6.0.2",
|
||||||
"object-hash": "^2.0.3",
|
"object-hash": "^2.0.3",
|
||||||
|
"open": "^7.0.4",
|
||||||
"prettier": "^2.0.4",
|
"prettier": "^2.0.4",
|
||||||
"raw-loader": "^2.0.0",
|
"raw-loader": "^2.0.0",
|
||||||
"require-dir": "^1.2.0",
|
"require-dir": "^1.2.0",
|
||||||
|
"rollup": "^2.8.2",
|
||||||
|
"rollup-plugin-babel": "^4.4.0",
|
||||||
|
"rollup-plugin-string": "^3.0.0",
|
||||||
|
"rollup-plugin-terser": "^5.3.0",
|
||||||
|
"rollup-plugin-visualizer": "^4.0.4",
|
||||||
|
"serve": "^11.3.0",
|
||||||
"sinon": "^7.3.1",
|
"sinon": "^7.3.1",
|
||||||
"source-map-url": "^0.4.0",
|
"source-map-url": "^0.4.0",
|
||||||
|
"systemjs": "^6.3.2",
|
||||||
"terser-webpack-plugin": "^1.2.3",
|
"terser-webpack-plugin": "^1.2.3",
|
||||||
"ts-lit-plugin": "^1.1.10",
|
"ts-lit-plugin": "^1.1.10",
|
||||||
"ts-mocha": "^6.0.0",
|
"ts-mocha": "^6.0.0",
|
||||||
"typescript": "^3.8.3",
|
"typescript": "^3.8.3",
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
"vinyl-source-stream": "^2.0.0",
|
"vinyl-source-stream": "^2.0.0",
|
||||||
"web-component-tester": "^6.9.2",
|
|
||||||
"webpack": "^4.40.2",
|
"webpack": "^4.40.2",
|
||||||
"webpack-cli": "^3.3.9",
|
"webpack-cli": "^3.3.9",
|
||||||
"webpack-dev-server": "^3.10.3",
|
"webpack-dev-server": "^3.10.3",
|
||||||
|
10
rollup.config.js
Normal file
10
rollup.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const rollup = require("./build-scripts/rollup.js");
|
||||||
|
const env = require("./build-scripts/env.js");
|
||||||
|
|
||||||
|
const config = rollup.createAppConfig({
|
||||||
|
isProdBuild: env.isProdBuild(),
|
||||||
|
latestBuild: true,
|
||||||
|
isStatsBuild: env.isStatsBuild(),
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = { ...config.inputOptions, output: config.outputOptions };
|
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="20200519.5",
|
version="20200603.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",
|
||||||
|
@ -83,12 +83,24 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
|||||||
${this._renderStep(this._step)}
|
${this._renderStep(this._step)}
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<mwc-button raised @click=${this._handleSubmit}
|
<mwc-button raised @click=${this._handleSubmit}
|
||||||
>${this._step.type === "form" ? "Next" : "Start over"}</mwc-button
|
>${this._step.type === "form"
|
||||||
|
? this.localize("ui.panel.page-authorize.form.next")
|
||||||
|
: this.localize(
|
||||||
|
"ui.panel.page-authorize.form.start_over"
|
||||||
|
)}</mwc-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
case "error":
|
case "error":
|
||||||
return html` <div class="error">Error: ${this._errorMessage}</div> `;
|
return html`
|
||||||
|
<div class="error">
|
||||||
|
${this.localize(
|
||||||
|
"ui.panel.page-authorize.form.error",
|
||||||
|
"error",
|
||||||
|
this._errorMessage
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
case "loading":
|
case "loading":
|
||||||
return html` ${this.localize("ui.panel.page-authorize.form.working")} `;
|
return html` ${this.localize("ui.panel.page-authorize.form.working")} `;
|
||||||
default:
|
default:
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { wrap } from "comlink";
|
import { wrap } from "comlink";
|
||||||
|
|
||||||
type FilterDataType = typeof import("./sort_filter_worker").api["filterData"];
|
import type { api } from "./sort_filter_worker";
|
||||||
|
|
||||||
|
type FilterDataType = api["filterData"];
|
||||||
type FilterDataParamTypes = Parameters<FilterDataType>;
|
type FilterDataParamTypes = Parameters<FilterDataType>;
|
||||||
|
|
||||||
type SortDataType = typeof import("./sort_filter_worker").api["sortData"];
|
type SortDataType = api["sortData"];
|
||||||
type SortDataParamTypes = Parameters<SortDataType>;
|
type SortDataParamTypes = Parameters<SortDataType>;
|
||||||
|
|
||||||
let worker: any | undefined;
|
let worker: any | undefined;
|
||||||
|
@ -67,10 +67,11 @@ const sortData = (
|
|||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export for types
|
const api = {
|
||||||
export const api = {
|
|
||||||
filterData,
|
filterData,
|
||||||
sortData,
|
sortData,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type api = typeof api;
|
||||||
|
|
||||||
expose(api);
|
expose(api);
|
||||||
|
@ -188,7 +188,9 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
|
|||||||
this.hass,
|
this.hass,
|
||||||
deviceEntityLookup[device.id]
|
deviceEntityLookup[device.id]
|
||||||
),
|
),
|
||||||
area: device.area_id ? areaLookup[device.area_id].name : "No area",
|
area: device.area_id
|
||||||
|
? areaLookup[device.area_id].name
|
||||||
|
: this.hass.localize("ui.components.device-picker.no_area"),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (outputDevices.length === 1) {
|
if (outputDevices.length === 1) {
|
||||||
|
71
src/components/ha-markdown-element.ts
Normal file
71
src/components/ha-markdown-element.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { customElement, property, UpdatingElement } from "lit-element";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { renderMarkdown } from "../resources/render-markdown";
|
||||||
|
|
||||||
|
@customElement("ha-markdown-element")
|
||||||
|
class HaMarkdownElement extends UpdatingElement {
|
||||||
|
@property() public content?;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public allowSvg = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public breaks = false;
|
||||||
|
|
||||||
|
protected update(changedProps) {
|
||||||
|
super.update(changedProps);
|
||||||
|
if (this.content !== undefined) {
|
||||||
|
this._render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _render() {
|
||||||
|
this.innerHTML = await renderMarkdown(
|
||||||
|
this.content,
|
||||||
|
{
|
||||||
|
breaks: this.breaks,
|
||||||
|
gfm: true,
|
||||||
|
tables: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
allowSvg: this.allowSvg,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this._resize();
|
||||||
|
|
||||||
|
const walker = document.createTreeWalker(
|
||||||
|
this,
|
||||||
|
1 /* SHOW_ELEMENT */,
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
while (walker.nextNode()) {
|
||||||
|
const node = walker.currentNode;
|
||||||
|
|
||||||
|
// Open external links in a new window
|
||||||
|
if (
|
||||||
|
node instanceof HTMLAnchorElement &&
|
||||||
|
node.host !== document.location.host
|
||||||
|
) {
|
||||||
|
node.target = "_blank";
|
||||||
|
node.rel = "noreferrer";
|
||||||
|
|
||||||
|
// 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
|
||||||
|
} else if (node instanceof HTMLImageElement) {
|
||||||
|
node.addEventListener("load", this._resize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _resize = () => fireEvent(this, "iron-resize");
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-markdown-element": HaMarkdownElement;
|
||||||
|
}
|
||||||
|
}
|
@ -1,65 +1,80 @@
|
|||||||
import { customElement, property, UpdatingElement } from "lit-element";
|
import {
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
css,
|
||||||
import { renderMarkdown } from "../resources/render-markdown";
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
|
import "./ha-markdown-element";
|
||||||
|
|
||||||
@customElement("ha-markdown")
|
@customElement("ha-markdown")
|
||||||
class HaMarkdown extends UpdatingElement {
|
class HaMarkdown extends LitElement {
|
||||||
@property() public content = "";
|
@property() public content?;
|
||||||
|
|
||||||
@property({ type: Boolean }) public allowSvg = false;
|
@property({ type: Boolean }) public allowSvg = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) public breaks = false;
|
@property({ type: Boolean }) public breaks = false;
|
||||||
|
|
||||||
protected update(changedProps) {
|
protected render(): TemplateResult {
|
||||||
super.update(changedProps);
|
if (!this.content) {
|
||||||
this._render();
|
return html``;
|
||||||
}
|
|
||||||
|
|
||||||
private async _render() {
|
|
||||||
this.innerHTML = await renderMarkdown(
|
|
||||||
this.content,
|
|
||||||
{
|
|
||||||
breaks: this.breaks,
|
|
||||||
gfm: true,
|
|
||||||
tables: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
allowSvg: this.allowSvg,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
this._resize();
|
|
||||||
|
|
||||||
const walker = document.createTreeWalker(
|
|
||||||
this,
|
|
||||||
1 /* SHOW_ELEMENT */,
|
|
||||||
null,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
while (walker.nextNode()) {
|
|
||||||
const node = walker.currentNode;
|
|
||||||
|
|
||||||
// Open external links in a new window
|
|
||||||
if (
|
|
||||||
node instanceof HTMLAnchorElement &&
|
|
||||||
node.host !== document.location.host
|
|
||||||
) {
|
|
||||||
node.target = "_blank";
|
|
||||||
node.rel = "noreferrer";
|
|
||||||
|
|
||||||
// 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
|
|
||||||
} else if (node instanceof HTMLImageElement) {
|
|
||||||
node.addEventListener("load", this._resize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return html`<ha-markdown-element
|
||||||
|
.content=${this.content}
|
||||||
|
.allowSvg=${this.allowSvg}
|
||||||
|
.breaks=${this.breaks}
|
||||||
|
></ha-markdown-element>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resize = () => fireEvent(this, "iron-resize");
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
ha-markdown-element {
|
||||||
|
-ms-user-select: text;
|
||||||
|
-webkit-user-select: text;
|
||||||
|
-moz-user-select: text;
|
||||||
|
}
|
||||||
|
ha-markdown-element > *:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
ha-markdown-element > *:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
ha-markdown-element a {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
ha-markdown-element img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
ha-markdown-element code,
|
||||||
|
pre {
|
||||||
|
background-color: var(--markdown-code-background-color, #f6f8fa);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
ha-markdown-element code {
|
||||||
|
font-size: 85%;
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
}
|
||||||
|
ha-markdown-element pre code {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
ha-markdown-element pre {
|
||||||
|
padding: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
ha-markdown-element h2 {
|
||||||
|
font-size: 1.5em !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -65,14 +65,15 @@ export const fetchDeviceTriggerCapabilities = (
|
|||||||
trigger,
|
trigger,
|
||||||
});
|
});
|
||||||
|
|
||||||
const whitelist = [
|
const deviceAutomationIdentifiers = [
|
||||||
"above",
|
"device_id",
|
||||||
"below",
|
"domain",
|
||||||
"brightness_pct",
|
"entity_id",
|
||||||
"code",
|
"type",
|
||||||
"for",
|
"subtype",
|
||||||
"position",
|
"event",
|
||||||
"set_brightness",
|
"condition",
|
||||||
|
"platform",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const deviceAutomationsEqual = (
|
export const deviceAutomationsEqual = (
|
||||||
@ -84,7 +85,7 @@ export const deviceAutomationsEqual = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const property in a) {
|
for (const property in a) {
|
||||||
if (whitelist.includes(property)) {
|
if (!deviceAutomationIdentifiers.includes(property)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!Object.is(a[property], b[property])) {
|
if (!Object.is(a[property], b[property])) {
|
||||||
@ -92,7 +93,7 @@ export const deviceAutomationsEqual = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const property in b) {
|
for (const property in b) {
|
||||||
if (whitelist.includes(property)) {
|
if (!deviceAutomationIdentifiers.includes(property)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!Object.is(a[property], b[property])) {
|
if (!Object.is(a[property], b[property])) {
|
||||||
|
@ -56,7 +56,8 @@ export const fetchRecent = (
|
|||||||
startTime,
|
startTime,
|
||||||
endTime,
|
endTime,
|
||||||
skipInitialState = false,
|
skipInitialState = false,
|
||||||
significantChangesOnly?: boolean
|
significantChangesOnly?: boolean,
|
||||||
|
minimalResponse = true
|
||||||
): Promise<HassEntity[][]> => {
|
): Promise<HassEntity[][]> => {
|
||||||
let url = "history/period";
|
let url = "history/period";
|
||||||
if (startTime) {
|
if (startTime) {
|
||||||
@ -72,6 +73,9 @@ export const fetchRecent = (
|
|||||||
if (significantChangesOnly !== undefined) {
|
if (significantChangesOnly !== undefined) {
|
||||||
url += `&significant_changes_only=${Number(significantChangesOnly)}`;
|
url += `&significant_changes_only=${Number(significantChangesOnly)}`;
|
||||||
}
|
}
|
||||||
|
if (minimalResponse) {
|
||||||
|
url += "&minimal_response";
|
||||||
|
}
|
||||||
|
|
||||||
return hass.callApi("GET", url);
|
return hass.callApi("GET", url);
|
||||||
};
|
};
|
||||||
@ -83,14 +87,17 @@ export const fetchDate = (
|
|||||||
): Promise<HassEntity[][]> => {
|
): Promise<HassEntity[][]> => {
|
||||||
return hass.callApi(
|
return hass.callApi(
|
||||||
"GET",
|
"GET",
|
||||||
`history/period/${startTime.toISOString()}?end_time=${endTime.toISOString()}`
|
`history/period/${startTime.toISOString()}?end_time=${endTime.toISOString()}&minimal_response`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const equalState = (obj1: LineChartState, obj2: LineChartState) =>
|
const equalState = (obj1: LineChartState, obj2: LineChartState) =>
|
||||||
obj1.state === obj2.state &&
|
obj1.state === obj2.state &&
|
||||||
// They either both have an attributes object or not
|
// Only compare attributes if both states have an attributes object.
|
||||||
|
// When `minimal_response` is sent, only the first and last state
|
||||||
|
// will have attributes except for domains in DOMAINS_USE_LAST_UPDATED.
|
||||||
(!obj1.attributes ||
|
(!obj1.attributes ||
|
||||||
|
!obj2.attributes ||
|
||||||
LINE_ATTRIBUTES_TO_KEEP.every(
|
LINE_ATTRIBUTES_TO_KEEP.every(
|
||||||
(attr) => obj1.attributes![attr] === obj2.attributes![attr]
|
(attr) => obj1.attributes![attr] === obj2.attributes![attr]
|
||||||
));
|
));
|
||||||
@ -101,12 +108,20 @@ const processTimelineEntity = (
|
|||||||
states: HassEntity[]
|
states: HassEntity[]
|
||||||
): TimelineEntity => {
|
): TimelineEntity => {
|
||||||
const data: TimelineState[] = [];
|
const data: TimelineState[] = [];
|
||||||
|
const last_element = states.length - 1;
|
||||||
|
|
||||||
for (const state of states) {
|
for (const state of states) {
|
||||||
if (data.length > 0 && state.state === data[data.length - 1].state) {
|
if (data.length > 0 && state.state === data[data.length - 1].state) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the data from the last element as its the newest
|
||||||
|
// and is only needed to localize the data
|
||||||
|
if (!state.entity_id) {
|
||||||
|
state.attributes = states[last_element].attributes;
|
||||||
|
state.entity_id = states[last_element].entity_id;
|
||||||
|
}
|
||||||
|
|
||||||
data.push({
|
data.push({
|
||||||
state_localize: computeStateDisplay(localize, state, language),
|
state_localize: computeStateDisplay(localize, state, language),
|
||||||
state: state.state,
|
state: state.state,
|
||||||
@ -198,7 +213,7 @@ export const computeHistory = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stateWithUnit = stateInfo.find(
|
const stateWithUnit = stateInfo.find(
|
||||||
(state) => "unit_of_measurement" in state.attributes
|
(state) => state.attributes && "unit_of_measurement" in state.attributes
|
||||||
);
|
);
|
||||||
|
|
||||||
let unit: string | undefined;
|
let unit: string | undefined;
|
||||||
|
@ -28,7 +28,6 @@ import {
|
|||||||
subscribeDeviceRegistry,
|
subscribeDeviceRegistry,
|
||||||
} from "../../data/device_registry";
|
} from "../../data/device_registry";
|
||||||
import { PolymerChangedEvent } from "../../polymer-types";
|
import { PolymerChangedEvent } from "../../polymer-types";
|
||||||
import "../../resources/ha-style";
|
|
||||||
import { haStyleDialog } from "../../resources/styles";
|
import { haStyleDialog } from "../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import { DataEntryFlowDialogParams } from "./show-dialog-data-entry-flow";
|
import { DataEntryFlowDialogParams } from "./show-dialog-data-entry-flow";
|
||||||
|
@ -16,7 +16,6 @@ import "../../components/ha-form/ha-form";
|
|||||||
import type { HaFormSchema } from "../../components/ha-form/ha-form";
|
import type { HaFormSchema } from "../../components/ha-form/ha-form";
|
||||||
import "../../components/ha-markdown";
|
import "../../components/ha-markdown";
|
||||||
import type { DataEntryFlowStepForm } from "../../data/data_entry_flow";
|
import type { DataEntryFlowStepForm } from "../../data/data_entry_flow";
|
||||||
import "../../resources/ha-style";
|
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import type { FlowConfig } from "./show-dialog-data-entry-flow";
|
import type { FlowConfig } from "./show-dialog-data-entry-flow";
|
||||||
import { configFlowContentStyles } from "./styles";
|
import { configFlowContentStyles } from "./styles";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import "@polymer/paper-item/paper-icon-item";
|
import "@polymer/paper-item/paper-icon-item";
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
import "@polymer/paper-spinner/paper-spinner-lite";
|
import "@polymer/paper-spinner/paper-spinner-lite";
|
||||||
import * as Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResult,
|
CSSResult,
|
||||||
@ -52,14 +52,14 @@ class StepFlowPickHandler extends LitElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
const options: Fuse.FuseOptions<HandlerObj> = {
|
const options: Fuse.IFuseOptions<HandlerObj> = {
|
||||||
keys: ["name", "slug"],
|
keys: ["name", "slug"],
|
||||||
caseSensitive: false,
|
isCaseSensitive: false,
|
||||||
minMatchCharLength: 2,
|
minMatchCharLength: 2,
|
||||||
threshold: 0.2,
|
threshold: 0.2,
|
||||||
};
|
};
|
||||||
const fuse = new Fuse(handlers, options);
|
const fuse = new Fuse(handlers, options);
|
||||||
return fuse.search(filter);
|
return fuse.search(filter).map((result) => result.item);
|
||||||
}
|
}
|
||||||
return handlers.sort((a, b) =>
|
return handlers.sort((a, b) =>
|
||||||
a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
|
a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
|
||||||
|
@ -5,7 +5,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 { computeStateDomain } from "../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../common/entity/compute_state_domain";
|
||||||
import DialogMixin from "../mixins/dialog-mixin";
|
import DialogMixin from "../mixins/dialog-mixin";
|
||||||
import "../resources/ha-style";
|
import "../styles/polymer-ha-style-dialog";
|
||||||
import "./more-info/more-info-controls";
|
import "./more-info/more-info-controls";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4,7 +4,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 { enableWrite } from "../common/auth/token_storage";
|
import { enableWrite } from "../common/auth/token_storage";
|
||||||
import LocalizeMixin from "../mixins/localize-mixin";
|
import LocalizeMixin from "../mixins/localize-mixin";
|
||||||
import "../resources/ha-style";
|
import "../styles/polymer-ha-style";
|
||||||
|
|
||||||
class HaStoreAuth extends LocalizeMixin(PolymerElement) {
|
class HaStoreAuth extends LocalizeMixin(PolymerElement) {
|
||||||
static get template() {
|
static get template() {
|
||||||
|
@ -17,7 +17,7 @@ import "../../data/ha-state-history-data";
|
|||||||
import { EventsMixin } from "../../mixins/events-mixin";
|
import { EventsMixin } from "../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../mixins/localize-mixin";
|
import LocalizeMixin from "../../mixins/localize-mixin";
|
||||||
import { showEntityEditorDialog } from "../../panels/config/entities/show-dialog-entity-editor";
|
import { showEntityEditorDialog } from "../../panels/config/entities/show-dialog-entity-editor";
|
||||||
import "../../resources/ha-style";
|
import "../../styles/polymer-ha-style-dialog";
|
||||||
import "../../state-summary/state-card-content";
|
import "../../state-summary/state-card-content";
|
||||||
import { showConfirmationDialog } from "../generic/show-dialog-box";
|
import { showConfirmationDialog } from "../generic/show-dialog-box";
|
||||||
import "./controls/more-info-content";
|
import "./controls/more-info-content";
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
// Load polyfill first so HTML imports start resolving
|
|
||||||
/* eslint-disable import/first */
|
|
||||||
import "@polymer/paper-styles/typography";
|
|
||||||
import { setPassiveTouchGestures } from "@polymer/polymer/lib/utils/settings";
|
import { setPassiveTouchGestures } from "@polymer/polymer/lib/utils/settings";
|
||||||
import "../layouts/home-assistant";
|
|
||||||
import "../resources/html-import/polyfill";
|
|
||||||
import "../resources/roboto";
|
import "../resources/roboto";
|
||||||
|
import "../resources/ha-style";
|
||||||
|
import "../layouts/home-assistant";
|
||||||
import "../util/legacy-support";
|
import "../util/legacy-support";
|
||||||
|
|
||||||
setPassiveTouchGestures(true);
|
setPassiveTouchGestures(true);
|
||||||
@ -12,3 +9,5 @@ setPassiveTouchGestures(true);
|
|||||||
document.createElement = Document.prototype.createElement;
|
document.createElement = Document.prototype.createElement;
|
||||||
|
|
||||||
(window as any).frontendVersion = __VERSION__;
|
(window as any).frontendVersion = __VERSION__;
|
||||||
|
|
||||||
|
import("../resources/html-import/polyfill");
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Compat needs to be first import
|
||||||
|
import "../resources/compatibility";
|
||||||
import "@polymer/polymer/lib/elements/dom-if";
|
import "@polymer/polymer/lib/elements/dom-if";
|
||||||
import "@polymer/polymer/lib/elements/dom-repeat";
|
import "@polymer/polymer/lib/elements/dom-repeat";
|
||||||
import "../auth/ha-authorize";
|
import "../auth/ha-authorize";
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Compat needs to be first import
|
||||||
|
import "../resources/compatibility";
|
||||||
import {
|
import {
|
||||||
Auth,
|
Auth,
|
||||||
Connection,
|
Connection,
|
||||||
@ -26,6 +28,7 @@ import { HomeAssistant } from "../types";
|
|||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
hassConnection: Promise<{ auth: Auth; conn: Connection }>;
|
hassConnection: Promise<{ auth: Auth; conn: Connection }>;
|
||||||
|
hassConnectionReady?: (hassConnection: Window["hassConnection"]) => void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +83,11 @@ window.hassConnection = (authProm() as Promise<Auth | ExternalAuth>).then(
|
|||||||
connProm
|
connProm
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// This is set if app was somehow loaded before core.
|
||||||
|
if (window.hassConnectionReady) {
|
||||||
|
window.hassConnectionReady(window.hassConnection);
|
||||||
|
}
|
||||||
|
|
||||||
// Start fetching some of the data that we will need.
|
// Start fetching some of the data that we will need.
|
||||||
window.hassConnection.then(({ conn }) => {
|
window.hassConnection.then(({ conn }) => {
|
||||||
const noop = () => {
|
const noop = () => {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import "../resources/compatibility";
|
||||||
import { PolymerElement } from "@polymer/polymer";
|
import { PolymerElement } from "@polymer/polymer";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { loadJS } from "../common/dom/load_resource";
|
import { loadJS } from "../common/dom/load_resource";
|
||||||
@ -17,12 +18,9 @@ let es5Loaded: Promise<unknown> | undefined;
|
|||||||
|
|
||||||
window.loadES5Adapter = () => {
|
window.loadES5Adapter = () => {
|
||||||
if (!es5Loaded) {
|
if (!es5Loaded) {
|
||||||
es5Loaded = Promise.all([
|
es5Loaded = loadJS(
|
||||||
loadJS(
|
`${__STATIC_PATH__}polyfills/custom-elements-es5-adapter.js`
|
||||||
`${__STATIC_PATH__}polyfills/custom-elements-es5-adapter.js`
|
).catch(); // Swallow errors as it raises errors on old browsers.
|
||||||
).catch(),
|
|
||||||
import(/* webpackChunkName: "compat" */ "./compatibility"),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
return es5Loaded;
|
return es5Loaded;
|
||||||
};
|
};
|
||||||
@ -51,7 +49,6 @@ function initialize(panel: CustomPanelInfo, properties: {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (__BUILD__ === "es5") {
|
if (__BUILD__ === "es5") {
|
||||||
// Load ES5 adapter. Swallow errors as it raises errors on old browsers.
|
|
||||||
start = start.then(() => window.loadES5Adapter());
|
start = start.then(() => window.loadES5Adapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Compat needs to be first import
|
||||||
|
import "../resources/compatibility";
|
||||||
import "../onboarding/ha-onboarding";
|
import "../onboarding/ha-onboarding";
|
||||||
import "../resources/ha-style";
|
import "../resources/ha-style";
|
||||||
import "../resources/roboto";
|
import "../resources/roboto";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { HassConfig } from "home-assistant-js-websocket";
|
import { HassConfig, STATE_RUNNING } from "home-assistant-js-websocket";
|
||||||
|
|
||||||
export const demoConfig: HassConfig = {
|
export const demoConfig: HassConfig = {
|
||||||
location_name: "Home",
|
location_name: "Home",
|
||||||
@ -18,6 +18,7 @@ export const demoConfig: HassConfig = {
|
|||||||
whitelist_external_dirs: [],
|
whitelist_external_dirs: [],
|
||||||
config_source: "storage",
|
config_source: "storage",
|
||||||
safe_mode: false,
|
safe_mode: false,
|
||||||
|
state: STATE_RUNNING,
|
||||||
internal_url: "http://homeassistant.local:8123",
|
internal_url: "http://homeassistant.local:8123",
|
||||||
external_url: null,
|
external_url: null,
|
||||||
};
|
};
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
);
|
);
|
||||||
script.defer = true;
|
script.defer = true;
|
||||||
script.src = src;
|
script.src = src;
|
||||||
|
return script;
|
||||||
}
|
}
|
||||||
window.Polymer = {
|
window.Polymer = {
|
||||||
lazyRegister: true,
|
lazyRegister: true,
|
||||||
|
16
src/html/_preload_roboto.html.template
Normal file
16
src/html/_preload_roboto.html.template
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
if (navigator.userAgent.indexOf("Android") === -1 &&
|
||||||
|
navigator.userAgent.indexOf("CrOS") === -1) {
|
||||||
|
function _pf(src, type) {
|
||||||
|
const el = document.createElement("link");
|
||||||
|
el.rel = "preload";
|
||||||
|
el.as = "font";
|
||||||
|
el.type = "font/woff2";
|
||||||
|
el.href = src;
|
||||||
|
el.crossOrigin = "anonymous";
|
||||||
|
document.head.append(el);
|
||||||
|
}
|
||||||
|
_pf("/static/fonts/roboto/Roboto-Regular.woff2");
|
||||||
|
_pf("/static/fonts/roboto/Roboto-Medium.woff2");
|
||||||
|
}
|
||||||
|
</script>
|
@ -3,18 +3,6 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>Home Assistant</title>
|
<title>Home Assistant</title>
|
||||||
<link rel="preload" href="<%= latestPageJS %>" as="script" crossorigin="use-credentials" />
|
<link rel="preload" href="<%= latestPageJS %>" as="script" crossorigin="use-credentials" />
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/static/fonts/roboto/Roboto-Light.woff2"
|
|
||||||
as="font"
|
|
||||||
crossorigin
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/static/fonts/roboto/Roboto-Regular.woff2"
|
|
||||||
as="font"
|
|
||||||
crossorigin
|
|
||||||
/>
|
|
||||||
<%= renderTemplate('_header') %>
|
<%= renderTemplate('_header') %>
|
||||||
<style>
|
<style>
|
||||||
.content {
|
.content {
|
||||||
@ -46,6 +34,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= renderTemplate('_js_base') %>
|
<%= renderTemplate('_js_base') %>
|
||||||
|
<%= renderTemplate('_preload_roboto') %>
|
||||||
|
|
||||||
<script type="module" crossorigin="use-credentials">
|
<script type="module" crossorigin="use-credentials">
|
||||||
import "<%= latestPageJS %>";
|
import "<%= latestPageJS %>";
|
||||||
@ -59,8 +48,13 @@
|
|||||||
// Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
// Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||||
if (!isS101) {
|
if (!isS101) {
|
||||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||||
_ls("<%= es5Compatibility %>");
|
<% if (useRollup) { %>
|
||||||
_ls("<%= es5PageJS %>");
|
_ls("/static/js/s.min.js").onload = function() {
|
||||||
|
System.import("<%= es5PageJS %>");
|
||||||
|
}
|
||||||
|
<% } else { %>
|
||||||
|
_ls("<%= es5PageJS %>");
|
||||||
|
<% } %>
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,18 +2,7 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="preload" href="<%= latestCoreJS %>" as="script" crossorigin="use-credentials" />
|
<link rel="preload" href="<%= latestCoreJS %>" as="script" crossorigin="use-credentials" />
|
||||||
<link
|
<link rel="preload" href="<%= latestAppJS %>" as="script" crossorigin="use-credentials" />
|
||||||
rel="preload"
|
|
||||||
href="/static/fonts/roboto/Roboto-Regular.woff2"
|
|
||||||
as="font"
|
|
||||||
crossorigin
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/static/fonts/roboto/Roboto-Medium.woff2"
|
|
||||||
as="font"
|
|
||||||
crossorigin
|
|
||||||
/>
|
|
||||||
<%= renderTemplate('_header') %>
|
<%= renderTemplate('_header') %>
|
||||||
<title>Home Assistant</title>
|
<title>Home Assistant</title>
|
||||||
<link
|
<link
|
||||||
@ -61,26 +50,36 @@
|
|||||||
<home-assistant> </home-assistant>
|
<home-assistant> </home-assistant>
|
||||||
|
|
||||||
<%= renderTemplate('_js_base') %>
|
<%= renderTemplate('_js_base') %>
|
||||||
|
<%= renderTemplate('_preload_roboto') %>
|
||||||
|
|
||||||
<script type="module" crossorigin="use-credentials">
|
<script>
|
||||||
import "<%= latestCoreJS %>";
|
import("<%= latestCoreJS %>");
|
||||||
import "<%= latestAppJS %>";
|
import("<%= latestAppJS %>");
|
||||||
window.customPanelJS = "<%= latestCustomPanelJS %>";
|
window.customPanelJS = "<%= latestCustomPanelJS %>";
|
||||||
|
window.latestJS = true;
|
||||||
</script>
|
</script>
|
||||||
{% for extra_module in extra_modules -%}
|
{% for extra_module in extra_modules -%}
|
||||||
<script type="module" crossorigin="use-credentials" src="{{ extra_module }}"></script>
|
<script type="module" crossorigin="use-credentials" src="{{ extra_module }}"></script>
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
|
|
||||||
|
<script>
|
||||||
<script nomodule>
|
|
||||||
(function() {
|
(function() {
|
||||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
if (!window.latestJS) {
|
||||||
if (!isS101) {
|
|
||||||
window.customPanelJS = "<%= es5CustomPanelJS %>";
|
window.customPanelJS = "<%= es5CustomPanelJS %>";
|
||||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||||
_ls("<%= es5Compatibility %>");
|
|
||||||
_ls("<%= es5CoreJS %>");
|
<% if (useRollup) { %>
|
||||||
_ls("<%= es5AppJS %>");
|
_ls("/static/js/s.min.js").onload = function() {
|
||||||
|
// Although core and app can load in any order, we need to
|
||||||
|
// force loading core first because it contains polyfills
|
||||||
|
return System.import("<%= es5CoreJS %>").then(function() {
|
||||||
|
System.import("<%= es5AppJS %>");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
<% } else { %>
|
||||||
|
_ls("<%= es5CoreJS %>");
|
||||||
|
_ls("<%= es5AppJS %>");
|
||||||
|
<% } %>
|
||||||
{% for extra_script in extra_js_es5 -%}
|
{% for extra_script in extra_js_es5 -%}
|
||||||
_ls("{{ extra_script }}");
|
_ls("{{ extra_script }}");
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
|
@ -3,18 +3,6 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>Home Assistant</title>
|
<title>Home Assistant</title>
|
||||||
<link rel="preload" href="<%= latestPageJS %>" as="script" crossorigin="use-credentials" />
|
<link rel="preload" href="<%= latestPageJS %>" as="script" crossorigin="use-credentials" />
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/static/fonts/roboto/Roboto-Light.woff2"
|
|
||||||
as="font"
|
|
||||||
crossorigin
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href="/static/fonts/roboto/Roboto-Regular.woff2"
|
|
||||||
as="font"
|
|
||||||
crossorigin
|
|
||||||
/>
|
|
||||||
<%= renderTemplate('_header') %>
|
<%= renderTemplate('_header') %>
|
||||||
<style>
|
<style>
|
||||||
.content {
|
.content {
|
||||||
@ -48,6 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= renderTemplate('_js_base') %>
|
<%= renderTemplate('_js_base') %>
|
||||||
|
<%= renderTemplate('_preload_roboto') %>
|
||||||
|
|
||||||
<script type="module" crossorigin="use-credentials">
|
<script type="module" crossorigin="use-credentials">
|
||||||
import "<%= latestPageJS %>";
|
import "<%= latestPageJS %>";
|
||||||
@ -61,8 +50,13 @@
|
|||||||
// Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
// Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||||
if (!isS101) {
|
if (!isS101) {
|
||||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||||
_ls("<%= es5Compatibility %>");
|
<% if (useRollup) { %>
|
||||||
_ls("<%= es5PageJS %>");
|
_ls("/static/js/s.min.js").onload = function() {
|
||||||
|
System.import("<%= es5PageJS %>");
|
||||||
|
}
|
||||||
|
<% } else { %>
|
||||||
|
_ls("<%= es5PageJS %>");
|
||||||
|
<% } %>
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,7 +3,6 @@ import { html, property, PropertyValues } from "lit-element";
|
|||||||
import { navigate } from "../common/navigate";
|
import { navigate } from "../common/navigate";
|
||||||
import { getStorageDefaultPanelUrlPath } from "../data/panel";
|
import { getStorageDefaultPanelUrlPath } from "../data/panel";
|
||||||
import "../resources/custom-card-support";
|
import "../resources/custom-card-support";
|
||||||
import "../resources/ha-style";
|
|
||||||
import { HassElement } from "../state/hass-element";
|
import { HassElement } from "../state/hass-element";
|
||||||
import { HomeAssistant, Route } from "../types";
|
import { HomeAssistant, Route } from "../types";
|
||||||
import {
|
import {
|
||||||
@ -94,7 +93,18 @@ export class HomeAssistantAppEl extends HassElement {
|
|||||||
|
|
||||||
protected async _initialize() {
|
protected async _initialize() {
|
||||||
try {
|
try {
|
||||||
const { auth, conn } = await window.hassConnection;
|
let result;
|
||||||
|
|
||||||
|
if (window.hassConnection) {
|
||||||
|
result = await window.hassConnection;
|
||||||
|
} else {
|
||||||
|
// In the edge case that
|
||||||
|
result = await new Promise((resolve) => {
|
||||||
|
window.hassConnectionReady = resolve;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { auth, conn } = result;
|
||||||
this._haVersion = conn.haVersion;
|
this._haVersion = conn.haVersion;
|
||||||
this.initializeHass(auth, conn);
|
this.initializeHass(auth, conn);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -8,6 +8,11 @@ import {
|
|||||||
RouteOptions,
|
RouteOptions,
|
||||||
RouterOptions,
|
RouterOptions,
|
||||||
} from "./hass-router-page";
|
} from "./hass-router-page";
|
||||||
|
import {
|
||||||
|
STATE_STARTING,
|
||||||
|
STATE_NOT_RUNNING,
|
||||||
|
STATE_RUNNING,
|
||||||
|
} from "home-assistant-js-websocket";
|
||||||
|
|
||||||
const CACHE_URL_PATHS = ["lovelace", "developer-tools"];
|
const CACHE_URL_PATHS = ["lovelace", "developer-tools"];
|
||||||
const COMPONENTS = {
|
const COMPONENTS = {
|
||||||
@ -84,6 +89,8 @@ class PartialPanelResolver extends HassRouterPage {
|
|||||||
|
|
||||||
@property() public narrow?: boolean;
|
@property() public narrow?: boolean;
|
||||||
|
|
||||||
|
private _waitForStart = false;
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
super.updated(changedProps);
|
super.updated(changedProps);
|
||||||
|
|
||||||
@ -93,6 +100,15 @@ class PartialPanelResolver extends HassRouterPage {
|
|||||||
|
|
||||||
const oldHass = changedProps.get("hass") as this["hass"];
|
const oldHass = changedProps.get("hass") as this["hass"];
|
||||||
|
|
||||||
|
if (
|
||||||
|
this._waitForStart &&
|
||||||
|
(this.hass.config.state === STATE_STARTING ||
|
||||||
|
this.hass.config.state === STATE_RUNNING)
|
||||||
|
) {
|
||||||
|
this._waitForStart = false;
|
||||||
|
this.rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.hass.panels && (!oldHass || oldHass.panels !== this.hass.panels)) {
|
if (this.hass.panels && (!oldHass || oldHass.panels !== this.hass.panels)) {
|
||||||
this._updateRoutes(oldHass?.panels);
|
this._updateRoutes(oldHass?.panels);
|
||||||
}
|
}
|
||||||
@ -128,6 +144,21 @@ class PartialPanelResolver extends HassRouterPage {
|
|||||||
private async _updateRoutes(oldPanels?: HomeAssistant["panels"]) {
|
private async _updateRoutes(oldPanels?: HomeAssistant["panels"]) {
|
||||||
this.routerOptions = getRoutes(this.hass.panels);
|
this.routerOptions = getRoutes(this.hass.panels);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this._waitForStart &&
|
||||||
|
this._currentPage &&
|
||||||
|
!this.hass.panels[this._currentPage]
|
||||||
|
) {
|
||||||
|
if (this.hass.config.state !== STATE_NOT_RUNNING) {
|
||||||
|
this._waitForStart = true;
|
||||||
|
if (this.lastChild) {
|
||||||
|
this.removeChild(this.lastChild);
|
||||||
|
}
|
||||||
|
this.appendChild(this.createLoadingScreen());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!oldPanels ||
|
!oldPanels ||
|
||||||
!deepEqual(
|
!deepEqual(
|
||||||
|
@ -24,7 +24,11 @@ export const SubscribeMixin = <T extends Constructor<UpdatingElement>>(
|
|||||||
if (this.__unsubs) {
|
if (this.__unsubs) {
|
||||||
while (this.__unsubs.length) {
|
while (this.__unsubs.length) {
|
||||||
const unsub = this.__unsubs.pop()!;
|
const unsub = this.__unsubs.pop()!;
|
||||||
Promise.resolve(unsub).then((unsubFunc) => unsubFunc());
|
if (unsub instanceof Promise) {
|
||||||
|
unsub.then((unsubFunc) => unsubFunc());
|
||||||
|
} else {
|
||||||
|
unsub();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.__unsubs = undefined;
|
this.__unsubs = undefined;
|
||||||
}
|
}
|
||||||
|
@ -56,13 +56,24 @@ class DialogAreaDetail extends LitElement {
|
|||||||
<paper-dialog-scrollable>
|
<paper-dialog-scrollable>
|
||||||
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
|
${this._error ? html` <div class="error">${this._error}</div> ` : ""}
|
||||||
<div class="form">
|
<div class="form">
|
||||||
${entry ? html` <div>Area ID: ${entry.area_id}</div> ` : ""}
|
${entry
|
||||||
|
? html`
|
||||||
|
<div>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.areas.editor.area_id"
|
||||||
|
)}:
|
||||||
|
${entry.area_id}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
|
||||||
<paper-input
|
<paper-input
|
||||||
.value=${this._name}
|
.value=${this._name}
|
||||||
@value-changed=${this._nameChanged}
|
@value-changed=${this._nameChanged}
|
||||||
label="Name"
|
.label=${this.hass.localize("ui.panel.config.areas.editor.name")}
|
||||||
error-message="Name is required"
|
.errorMessage=${this.hass.localize(
|
||||||
|
"ui.panel.config.areas.editor.name_required"
|
||||||
|
)}
|
||||||
.invalid=${nameInvalid}
|
.invalid=${nameInvalid}
|
||||||
></paper-input>
|
></paper-input>
|
||||||
</div>
|
</div>
|
||||||
@ -110,7 +121,9 @@ class DialogAreaDetail extends LitElement {
|
|||||||
}
|
}
|
||||||
this._params = undefined;
|
this._params = undefined;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = err.message || "Unknown error";
|
this._error =
|
||||||
|
err.message ||
|
||||||
|
this.hass.localize("ui.panel.config.areas.editor.unknown_error");
|
||||||
} finally {
|
} finally {
|
||||||
this._submitting = false;
|
this._submitting = false;
|
||||||
}
|
}
|
||||||
|
@ -51,14 +51,18 @@ export class HaDeviceAction extends LitElement {
|
|||||||
.value=${deviceId}
|
.value=${deviceId}
|
||||||
@value-changed=${this._devicePicked}
|
@value-changed=${this._devicePicked}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
label="Device"
|
label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.actions.type.device_id.label"
|
||||||
|
)}
|
||||||
></ha-device-picker>
|
></ha-device-picker>
|
||||||
<ha-device-action-picker
|
<ha-device-action-picker
|
||||||
.value=${this.action}
|
.value=${this.action}
|
||||||
.deviceId=${deviceId}
|
.deviceId=${deviceId}
|
||||||
@value-changed=${this._deviceActionPicked}
|
@value-changed=${this._deviceActionPicked}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
label="Action"
|
label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.actions.type.device_id.action"
|
||||||
|
)}
|
||||||
></ha-device-action-picker>
|
></ha-device-action-picker>
|
||||||
${extraFieldsData
|
${extraFieldsData
|
||||||
? html`
|
? html`
|
||||||
@ -125,7 +129,7 @@ export class HaDeviceAction extends LitElement {
|
|||||||
// Returns a callback for ha-form to calculate labels per schema object
|
// Returns a callback for ha-form to calculate labels per schema object
|
||||||
return (schema) =>
|
return (schema) =>
|
||||||
localize(
|
localize(
|
||||||
`ui.panel.config.automation.editor.actions.type.device.extra_fields.${schema.name}`
|
`ui.panel.config.automation.editor.actions.type.device_id.extra_fields.${schema.name}`
|
||||||
) || schema.name;
|
) || schema.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,14 +45,18 @@ export class HaDeviceCondition extends LitElement {
|
|||||||
.value=${deviceId}
|
.value=${deviceId}
|
||||||
@value-changed=${this._devicePicked}
|
@value-changed=${this._devicePicked}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
label="Device"
|
label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.conditions.type.device.label"
|
||||||
|
)}
|
||||||
></ha-device-picker>
|
></ha-device-picker>
|
||||||
<ha-device-condition-picker
|
<ha-device-condition-picker
|
||||||
.value=${this.condition}
|
.value=${this.condition}
|
||||||
.deviceId=${deviceId}
|
.deviceId=${deviceId}
|
||||||
@value-changed=${this._deviceConditionPicked}
|
@value-changed=${this._deviceConditionPicked}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
label="Condition"
|
label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.conditions.type.device.condition"
|
||||||
|
)}
|
||||||
></ha-device-condition-picker>
|
></ha-device-condition-picker>
|
||||||
${extraFieldsData
|
${extraFieldsData
|
||||||
? html`
|
? html`
|
||||||
|
@ -45,14 +45,18 @@ export class HaDeviceTrigger extends LitElement {
|
|||||||
.value=${deviceId}
|
.value=${deviceId}
|
||||||
@value-changed=${this._devicePicked}
|
@value-changed=${this._devicePicked}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
label="Device"
|
label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.triggers.type.device.label"
|
||||||
|
)}
|
||||||
></ha-device-picker>
|
></ha-device-picker>
|
||||||
<ha-device-trigger-picker
|
<ha-device-trigger-picker
|
||||||
.value=${this.trigger}
|
.value=${this.trigger}
|
||||||
.deviceId=${deviceId}
|
.deviceId=${deviceId}
|
||||||
@value-changed=${this._deviceTriggerPicked}
|
@value-changed=${this._deviceTriggerPicked}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
label="Trigger"
|
label=${this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.triggers.type.device.trigger"
|
||||||
|
)}
|
||||||
></ha-device-trigger-picker>
|
></ha-device-trigger-picker>
|
||||||
${extraFieldsData
|
${extraFieldsData
|
||||||
? html`
|
? html`
|
||||||
|
@ -10,7 +10,7 @@ import { fetchCloudSubscriptionInfo } from "../../../../data/cloud";
|
|||||||
import "../../../../layouts/hass-subpage";
|
import "../../../../layouts/hass-subpage";
|
||||||
import { EventsMixin } from "../../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
||||||
import "../../../../resources/ha-style";
|
import "../../../../styles/polymer-ha-style";
|
||||||
import "../../ha-config-section";
|
import "../../ha-config-section";
|
||||||
import "./cloud-alexa-pref";
|
import "./cloud-alexa-pref";
|
||||||
import "./cloud-google-pref";
|
import "./cloud-google-pref";
|
||||||
|
@ -7,7 +7,7 @@ import "../../../../components/ha-card";
|
|||||||
import "../../../../layouts/hass-subpage";
|
import "../../../../layouts/hass-subpage";
|
||||||
import { EventsMixin } from "../../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
||||||
import "../../../../resources/ha-style";
|
import "../../../../styles/polymer-ha-style";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @appliesMixin EventsMixin
|
* @appliesMixin EventsMixin
|
||||||
|
@ -14,7 +14,7 @@ import "../../../../layouts/hass-subpage";
|
|||||||
import { EventsMixin } from "../../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
||||||
import NavigateMixin from "../../../../mixins/navigate-mixin";
|
import NavigateMixin from "../../../../mixins/navigate-mixin";
|
||||||
import "../../../../resources/ha-style";
|
import "../../../../styles/polymer-ha-style";
|
||||||
import "../../ha-config-section";
|
import "../../ha-config-section";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7,7 +7,7 @@ import "../../../../components/ha-card";
|
|||||||
import "../../../../layouts/hass-subpage";
|
import "../../../../layouts/hass-subpage";
|
||||||
import { EventsMixin } from "../../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../../mixins/localize-mixin";
|
||||||
import "../../../../resources/ha-style";
|
import "../../../../styles/polymer-ha-style";
|
||||||
import "../../ha-config-section";
|
import "../../ha-config-section";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6,7 +6,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 "../../../layouts/hass-tabs-subpage";
|
import "../../../layouts/hass-tabs-subpage";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import "../../../resources/ha-style";
|
import "../../../styles/polymer-ha-style";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "./ha-config-section-core";
|
import "./ha-config-section-core";
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
|||||||
import "../../../components/buttons/ha-call-service-button";
|
import "../../../components/buttons/ha-call-service-button";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import "../../../resources/ha-style";
|
import "../../../styles/polymer-ha-style";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import "./ha-config-core-form";
|
import "./ha-config-core-form";
|
||||||
import "./ha-config-name-form";
|
import "./ha-config-name-form";
|
||||||
|
@ -6,7 +6,7 @@ import { computeStateName } from "../../../common/entity/compute_state_name";
|
|||||||
import { sortStatesByName } from "../../../common/entity/states_sort_by_name";
|
import { sortStatesByName } from "../../../common/entity/states_sort_by_name";
|
||||||
import "../../../layouts/hass-tabs-subpage";
|
import "../../../layouts/hass-tabs-subpage";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import "../../../resources/ha-style";
|
import "../../../styles/polymer-ha-style";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import "../ha-entity-config";
|
import "../ha-entity-config";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
@ -37,7 +37,7 @@ class HaConfigCustomize extends LocalizeMixin(PolymerElement) {
|
|||||||
</span>
|
</span>
|
||||||
<ha-entity-config
|
<ha-entity-config
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
label="Entity"
|
label="[[localize('ui.panel.config.customize.picker.entity')]]"
|
||||||
entities="[[entities]]"
|
entities="[[entities]]"
|
||||||
config="[[entityConfig]]"
|
config="[[entityConfig]]"
|
||||||
>
|
>
|
||||||
|
@ -8,6 +8,8 @@ import { computeStateDomain } from "../../../common/entity/compute_state_domain"
|
|||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import hassAttributeUtil from "../../../util/hass-attributes-util";
|
import hassAttributeUtil from "../../../util/hass-attributes-util";
|
||||||
import "./ha-form-customize-attributes";
|
import "./ha-form-customize-attributes";
|
||||||
|
import "../ha-form-style";
|
||||||
|
import "../../../styles/polymer-ha-style";
|
||||||
|
|
||||||
class HaFormCustomize extends LocalizeMixin(PolymerElement) {
|
class HaFormCustomize extends LocalizeMixin(PolymerElement) {
|
||||||
static get template() {
|
static get template() {
|
||||||
|
@ -154,7 +154,9 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
),
|
),
|
||||||
model: device.model || "<unknown>",
|
model: device.model || "<unknown>",
|
||||||
manufacturer: device.manufacturer || "<unknown>",
|
manufacturer: device.manufacturer || "<unknown>",
|
||||||
area: device.area_id ? areaLookup[device.area_id].name : "No area",
|
area: device.area_id
|
||||||
|
? areaLookup[device.area_id].name
|
||||||
|
: this.hass.localize("ui.panel.config.devices.data_table.no_area"),
|
||||||
integration: device.config_entries.length
|
integration: device.config_entries.length
|
||||||
? device.config_entries
|
? device.config_entries
|
||||||
.filter((entId) => entId in entryLookup)
|
.filter((entId) => entId in entryLookup)
|
||||||
|
@ -8,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 { computeStateName } from "../../common/entity/compute_state_name";
|
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||||
import "../../components/ha-card";
|
import "../../components/ha-card";
|
||||||
|
import "../../styles/polymer-ha-style";
|
||||||
|
|
||||||
class HaEntityConfig extends PolymerElement {
|
class HaEntityConfig extends PolymerElement {
|
||||||
static get template() {
|
static get template() {
|
||||||
|
@ -108,7 +108,7 @@ export class DialogHelperDetail extends LitElement {
|
|||||||
@click="${this._goBack}"
|
@click="${this._goBack}"
|
||||||
.disabled=${this._submitting}
|
.disabled=${this._submitting}
|
||||||
>
|
>
|
||||||
Back
|
${this.hass!.localize("ui.common.back")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import * as Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
import { caseInsensitiveCompare } from "../../../common/string/compare";
|
import { caseInsensitiveCompare } from "../../../common/string/compare";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
import { nextRender } from "../../../common/util/render-status";
|
import { nextRender } from "../../../common/util/render-status";
|
||||||
@ -149,14 +149,14 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
if (!filter) {
|
if (!filter) {
|
||||||
return [...configEntries];
|
return [...configEntries];
|
||||||
}
|
}
|
||||||
const options: Fuse.FuseOptions<ConfigEntryExtended> = {
|
const options: Fuse.IFuseOptions<ConfigEntryExtended> = {
|
||||||
keys: ["domain", "localized_domain_name", "title"],
|
keys: ["domain", "localized_domain_name", "title"],
|
||||||
caseSensitive: false,
|
isCaseSensitive: false,
|
||||||
minMatchCharLength: 2,
|
minMatchCharLength: 2,
|
||||||
threshold: 0.2,
|
threshold: 0.2,
|
||||||
};
|
};
|
||||||
const fuse = new Fuse(configEntries, options);
|
const fuse = new Fuse(configEntries, options);
|
||||||
return fuse.search(filter);
|
return fuse.search(filter).map((result) => result.item);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -193,14 +193,14 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
if (!filter) {
|
if (!filter) {
|
||||||
return configEntriesInProgress;
|
return configEntriesInProgress;
|
||||||
}
|
}
|
||||||
const options: Fuse.FuseOptions<DataEntryFlowProgressExtended> = {
|
const options: Fuse.IFuseOptions<DataEntryFlowProgressExtended> = {
|
||||||
keys: ["handler", "localized_title"],
|
keys: ["handler", "localized_title"],
|
||||||
caseSensitive: false,
|
isCaseSensitive: false,
|
||||||
minMatchCharLength: 2,
|
minMatchCharLength: 2,
|
||||||
threshold: 0.2,
|
threshold: 0.2,
|
||||||
};
|
};
|
||||||
const fuse = new Fuse(configEntriesInProgress, options);
|
const fuse = new Fuse(configEntriesInProgress, options);
|
||||||
return fuse.search(filter);
|
return fuse.search(filter).map((result) => result.item);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
columns.url_path = {
|
columns.url_path = {
|
||||||
title: "",
|
title: "",
|
||||||
filterable: true,
|
filterable: true,
|
||||||
width: "75px",
|
width: "100px",
|
||||||
template: (urlPath) =>
|
template: (urlPath) =>
|
||||||
narrow
|
narrow
|
||||||
? html`
|
? html`
|
||||||
|
@ -7,7 +7,7 @@ import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
|||||||
import "../../../components/buttons/ha-call-service-button";
|
import "../../../components/buttons/ha-call-service-button";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import "../../../resources/ha-style";
|
import "../../../styles/polymer-ha-style";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5,7 +5,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 "../../../layouts/hass-tabs-subpage";
|
import "../../../layouts/hass-tabs-subpage";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import "../../../resources/ha-style";
|
import "../../../styles/polymer-ha-style";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
import "./ha-config-section-server-control";
|
import "./ha-config-section-server-control";
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ export class DialogAddUser extends LitElement {
|
|||||||
required
|
required
|
||||||
auto-validate
|
auto-validate
|
||||||
autocapitalize="on"
|
autocapitalize="on"
|
||||||
error-message="Required"
|
.errorMessage=${this.hass.localize("ui.common.error_required")}
|
||||||
@value-changed=${this._nameChanged}
|
@value-changed=${this._nameChanged}
|
||||||
@blur=${this._maybePopulateUsername}
|
@blur=${this._maybePopulateUsername}
|
||||||
></paper-input>
|
></paper-input>
|
||||||
@ -99,7 +99,7 @@ export class DialogAddUser extends LitElement {
|
|||||||
auto-validate
|
auto-validate
|
||||||
autocapitalize="none"
|
autocapitalize="none"
|
||||||
@value-changed=${this._usernameChanged}
|
@value-changed=${this._usernameChanged}
|
||||||
error-message="Required"
|
.errorMessage=${this.hass.localize("ui.common.error_required")}
|
||||||
></paper-input>
|
></paper-input>
|
||||||
<paper-input
|
<paper-input
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
@ -110,7 +110,7 @@ export class DialogAddUser extends LitElement {
|
|||||||
required
|
required
|
||||||
auto-validate
|
auto-validate
|
||||||
@value-changed=${this._passwordChanged}
|
@value-changed=${this._passwordChanged}
|
||||||
error-message="Required"
|
.errorMessage=${this.hass.localize("ui.common.error_required")}
|
||||||
></paper-input>
|
></paper-input>
|
||||||
<ha-switch .checked=${this._isAdmin} @change=${this._adminChanged}>
|
<ha-switch .checked=${this._isAdmin} @change=${this._adminChanged}>
|
||||||
${this.hass.localize("ui.panel.config.users.editor.admin")}
|
${this.hass.localize("ui.panel.config.users.editor.admin")}
|
||||||
@ -118,10 +118,9 @@ export class DialogAddUser extends LitElement {
|
|||||||
${!this._isAdmin
|
${!this._isAdmin
|
||||||
? html`
|
? html`
|
||||||
<br />
|
<br />
|
||||||
The users group is a work in progress. The user will be unable
|
${this.hass.localize(
|
||||||
to administer the instance via the UI. We're still auditing all
|
"ui.panel.config.users.users_privileges_note"
|
||||||
management API endpoints to ensure that they correctly limit
|
)}
|
||||||
access to administrators.
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
|
@ -109,10 +109,9 @@ class DialogUserDetail extends LitElement {
|
|||||||
${!this._isAdmin
|
${!this._isAdmin
|
||||||
? html`
|
? html`
|
||||||
<br />
|
<br />
|
||||||
The users group is a work in progress. The user will be unable
|
${this.hass.localize(
|
||||||
to administer the instance via the UI. We're still auditing
|
"ui.panel.config.users.users_privileges_note"
|
||||||
all management API endpoints to ensure that they correctly
|
)}
|
||||||
limit access to administrators.
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@ import "../../../components/ha-service-description";
|
|||||||
import "../../../layouts/ha-app-layout";
|
import "../../../layouts/ha-app-layout";
|
||||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import "../../../resources/ha-style";
|
import "../../../styles/polymer-ha-style";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import "../ha-form-style";
|
import "../ha-form-style";
|
||||||
import "./zwave-groups";
|
import "./zwave-groups";
|
||||||
@ -106,7 +106,9 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
<!-- Node card -->
|
<!-- Node card -->
|
||||||
<ha-config-section is-wide="[[isWide]]">
|
<ha-config-section is-wide="[[isWide]]">
|
||||||
<div class="sectionHeader" slot="header">
|
<div class="sectionHeader" slot="header">
|
||||||
<span>Z-Wave Node Management</span>
|
<span
|
||||||
|
>[[localize('ui.panel.config.zwave.node_management.header')]]</span
|
||||||
|
>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
class="toggle-help-icon"
|
class="toggle-help-icon"
|
||||||
on-click="toggleHelp"
|
on-click="toggleHelp"
|
||||||
@ -114,13 +116,16 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
</div>
|
</div>
|
||||||
<span slot="introduction">
|
<span slot="introduction">
|
||||||
Run Z-Wave commands that affect a single node. Pick a node to see a
|
[[localize('ui.panel.config.zwave.node_management.introduction')]]
|
||||||
list of available commands.
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="device-picker">
|
<div class="device-picker">
|
||||||
<paper-dropdown-menu dynamic-align="" label="Nodes" class="flex">
|
<paper-dropdown-menu
|
||||||
|
dynamic-align=""
|
||||||
|
label="[[localize('ui.panel.config.zwave.node_management.nodes')]]"
|
||||||
|
class="flex"
|
||||||
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
selected="{{selectedNode}}"
|
selected="{{selectedNode}}"
|
||||||
@ -134,7 +139,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
<template is="dom-if" if="[[!computeIsNodeSelected(selectedNode)]]">
|
<template is="dom-if" if="[[!computeIsNodeSelected(selectedNode)]]">
|
||||||
<template is="dom-if" if="[[showHelp]]">
|
<template is="dom-if" if="[[showHelp]]">
|
||||||
<div style="color: grey; padding: 12px">
|
<div style="color: grey; padding: 12px">
|
||||||
Select node to view per-node options
|
[[localize('ui.panel.config.zwave.node_management.introduction')]]
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@ -147,7 +152,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
service="refresh_node"
|
service="refresh_node"
|
||||||
service-data="[[computeNodeServiceData(selectedNode)]]"
|
service-data="[[computeNodeServiceData(selectedNode)]]"
|
||||||
>
|
>
|
||||||
Refresh Node
|
[[localize('ui.panel.config.zwave.services.refresh_node')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
<ha-service-description
|
<ha-service-description
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
@ -164,7 +169,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
service="remove_failed_node"
|
service="remove_failed_node"
|
||||||
service-data="[[computeNodeServiceData(selectedNode)]]"
|
service-data="[[computeNodeServiceData(selectedNode)]]"
|
||||||
>
|
>
|
||||||
Remove Failed Node
|
[[localize('ui.panel.config.zwave.services.remove_failed_node')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
<ha-service-description
|
<ha-service-description
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
@ -180,7 +185,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
service="replace_failed_node"
|
service="replace_failed_node"
|
||||||
service-data="[[computeNodeServiceData(selectedNode)]]"
|
service-data="[[computeNodeServiceData(selectedNode)]]"
|
||||||
>
|
>
|
||||||
Replace Failed Node
|
[[localize('ui.panel.config.zwave.services.replace_failed_node')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
<ha-service-description
|
<ha-service-description
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
@ -197,7 +202,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
service="print_node"
|
service="print_node"
|
||||||
service-data="[[computeNodeServiceData(selectedNode)]]"
|
service-data="[[computeNodeServiceData(selectedNode)]]"
|
||||||
>
|
>
|
||||||
Print Node
|
[[localize('ui.panel.config.zwave.services.print_node')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
<ha-service-description
|
<ha-service-description
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
@ -213,7 +218,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
service="heal_node"
|
service="heal_node"
|
||||||
service-data="[[computeHealNodeServiceData(selectedNode)]]"
|
service-data="[[computeHealNodeServiceData(selectedNode)]]"
|
||||||
>
|
>
|
||||||
Heal Node
|
[[localize('ui.panel.config.zwave.services.heal_node')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
<ha-service-description
|
<ha-service-description
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
@ -229,7 +234,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
service="test_node"
|
service="test_node"
|
||||||
service-data="[[computeNodeServiceData(selectedNode)]]"
|
service-data="[[computeNodeServiceData(selectedNode)]]"
|
||||||
>
|
>
|
||||||
Test Node
|
[[localize('ui.panel.config.zwave.services.test_node')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
<ha-service-description
|
<ha-service-description
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
@ -239,13 +244,13 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
>
|
>
|
||||||
</ha-service-description>
|
</ha-service-description>
|
||||||
<mwc-button on-click="_nodeMoreInfo"
|
<mwc-button on-click="_nodeMoreInfo"
|
||||||
>Node Information</mwc-button
|
>[[localize('ui.panel.config.zwave.services.node_info')]]</mwc-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="device-picker">
|
<div class="device-picker">
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
label="Entities of this node"
|
label="[[localize('ui.panel.config.zwave.node_management.entities')]]"
|
||||||
dynamic-align=""
|
dynamic-align=""
|
||||||
class="flex"
|
class="flex"
|
||||||
>
|
>
|
||||||
@ -270,7 +275,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
service="refresh_entity"
|
service="refresh_entity"
|
||||||
service-data="[[computeRefreshEntityServiceData(selectedEntity)]]"
|
service-data="[[computeRefreshEntityServiceData(selectedEntity)]]"
|
||||||
>
|
>
|
||||||
Refresh Entity
|
[[localize('ui.panel.config.zwave.services.refresh_entity')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
<ha-service-description
|
<ha-service-description
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
@ -280,7 +285,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
>
|
>
|
||||||
</ha-service-description>
|
</ha-service-description>
|
||||||
<mwc-button on-click="_entityMoreInfo"
|
<mwc-button on-click="_entityMoreInfo"
|
||||||
>Entity Information</mwc-button
|
>[[localize('ui.panel.config.zwave.node_management.entity_info')]]</mwc-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -288,11 +293,11 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
checked="{{entityIgnored}}"
|
checked="{{entityIgnored}}"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
>
|
>
|
||||||
Exclude this entity from Home Assistant
|
[[localize('ui.panel.config.zwave.node_management.exclude_entity')]]
|
||||||
</paper-checkbox>
|
</paper-checkbox>
|
||||||
<paper-input
|
<paper-input
|
||||||
disabled="{{entityIgnored}}"
|
disabled="{{entityIgnored}}"
|
||||||
label="Polling intensity"
|
label="[[localize('ui.panel.config.zwave.node_management.pooling_intensity')]]"
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
value="{{entityPollingIntensity}}"
|
value="{{entityPollingIntensity}}"
|
||||||
@ -306,7 +311,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
service="set_poll_intensity"
|
service="set_poll_intensity"
|
||||||
service-data="[[computePollIntensityServiceData(entityPollingIntensity)]]"
|
service-data="[[computePollIntensityServiceData(entityPollingIntensity)]]"
|
||||||
>
|
>
|
||||||
Save
|
[[localize('ui.common.save')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -7,6 +7,7 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import "../../../components/buttons/ha-call-service-button";
|
import "../../../components/buttons/ha-call-service-button";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../styles/polymer-ha-style";
|
||||||
|
|
||||||
class ZwaveGroups extends PolymerElement {
|
class ZwaveGroups extends PolymerElement {
|
||||||
static get template() {
|
static get template() {
|
||||||
@ -35,10 +36,17 @@ class ZwaveGroups extends PolymerElement {
|
|||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<ha-card class="content" header="Node group associations">
|
<ha-card
|
||||||
|
class="content"
|
||||||
|
header="[[localize('ui.panel.config.zwave.node_management.node_group_associations')]]"
|
||||||
|
>
|
||||||
<!-- TODO make api for getting groups and members -->
|
<!-- TODO make api for getting groups and members -->
|
||||||
<div class="device-picker">
|
<div class="device-picker">
|
||||||
<paper-dropdown-menu label="Group" dynamic-align="" class="flex">
|
<paper-dropdown-menu
|
||||||
|
label="[[localize('ui.panel.config.zwave.node_management.group')]]"
|
||||||
|
dynamic-align=""
|
||||||
|
class="flex"
|
||||||
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
selected="{{_selectedGroup}}"
|
selected="{{_selectedGroup}}"
|
||||||
@ -52,7 +60,7 @@ class ZwaveGroups extends PolymerElement {
|
|||||||
<template is="dom-if" if="[[_computeIsGroupSelected(_selectedGroup)]]">
|
<template is="dom-if" if="[[_computeIsGroupSelected(_selectedGroup)]]">
|
||||||
<div class="device-picker">
|
<div class="device-picker">
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
label="Node to control"
|
label="[[localize('ui.panel.config.zwave.node_management.node_to_control')]]"
|
||||||
dynamic-align=""
|
dynamic-align=""
|
||||||
class="flex"
|
class="flex"
|
||||||
>
|
>
|
||||||
@ -68,13 +76,18 @@ class ZwaveGroups extends PolymerElement {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="help-text">
|
<div class="help-text">
|
||||||
<span>Other Nodes in this group:</span>
|
<span
|
||||||
|
>[[localize('ui.panel.config.zwave.node_management.nodes_in_group')]]</span
|
||||||
|
>
|
||||||
<template is="dom-repeat" items="[[_otherGroupNodes]]" as="state">
|
<template is="dom-repeat" items="[[_otherGroupNodes]]" as="state">
|
||||||
<div>[[state]]</div>
|
<div>[[state]]</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="help-text">
|
<div class="help-text">
|
||||||
<span>Max Associations:</span> <span>[[_maxAssociations]]</span>
|
<span
|
||||||
|
>[[localize('ui.panel.config.zwave.node_management.max_associations')]]</span
|
||||||
|
>
|
||||||
|
<span>[[_maxAssociations]]</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -90,7 +103,7 @@ class ZwaveGroups extends PolymerElement {
|
|||||||
service="change_association"
|
service="change_association"
|
||||||
service-data="[[_addAssocServiceData]]"
|
service-data="[[_addAssocServiceData]]"
|
||||||
>
|
>
|
||||||
Add To Group
|
[[localize('ui.panel.config.zwave.node_management.add_to_group')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
</template>
|
</template>
|
||||||
<template
|
<template
|
||||||
@ -103,7 +116,7 @@ class ZwaveGroups extends PolymerElement {
|
|||||||
service="change_association"
|
service="change_association"
|
||||||
service-data="[[_removeAssocServiceData]]"
|
service-data="[[_removeAssocServiceData]]"
|
||||||
>
|
>
|
||||||
Remove From Group
|
[[localize('ui.panel.config.zwave.node_management.remove_from_group')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
</template>
|
</template>
|
||||||
<template is="dom-if" if="[[_isBroadcastNodeInGroup]]">
|
<template is="dom-if" if="[[_isBroadcastNodeInGroup]]">
|
||||||
@ -113,7 +126,7 @@ class ZwaveGroups extends PolymerElement {
|
|||||||
service="change_association"
|
service="change_association"
|
||||||
service-data="[[_removeBroadcastNodeServiceData]]"
|
service-data="[[_removeBroadcastNodeServiceData]]"
|
||||||
>
|
>
|
||||||
Remove Broadcast
|
[[localize('ui.panel.config.zwave.node_management.remove_broadcast')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,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/dialog/ha-paper-dialog";
|
import "../../../components/dialog/ha-paper-dialog";
|
||||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||||
import "../../../resources/ha-style";
|
import "../../../styles/polymer-ha-style-dialog";
|
||||||
|
|
||||||
class ZwaveLogDialog extends EventsMixin(PolymerElement) {
|
class ZwaveLogDialog extends EventsMixin(PolymerElement) {
|
||||||
static get template() {
|
static get template() {
|
||||||
|
@ -9,6 +9,7 @@ import "../../../components/ha-card";
|
|||||||
import { EventsMixin } from "../../../mixins/events-mixin";
|
import { EventsMixin } from "../../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../../mixins/localize-mixin";
|
import LocalizeMixin from "../../../mixins/localize-mixin";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
|
import "../../../styles/polymer-ha-style";
|
||||||
|
|
||||||
let registeredDialog = false;
|
let registeredDialog = false;
|
||||||
|
|
||||||
@ -41,12 +42,12 @@ class OzwLog extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
|||||||
</span>
|
</span>
|
||||||
<ha-card class="content">
|
<ha-card class="content">
|
||||||
<div class="device-picker">
|
<div class="device-picker">
|
||||||
<paper-input label="Number of last log lines." type="number" min="0" max="1000" step="10" value="{{numLogLines}}">
|
<paper-input label="[[localize('ui.panel.config.zwave.ozw_log.last_log_lines')]]" type="number" min="0" max="1000" step="10" value="{{numLogLines}}">
|
||||||
</paper-input>
|
</paper-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button raised="true" on-click="_openLogWindow">Load</mwc-button>
|
<mwc-button raised="true" on-click="_openLogWindow">[[localize('ui.panel.config.zwave.ozw_log.load')]]</mwc-button>
|
||||||
<mwc-button raised="true" on-click="_tailLog" disabled="{{_completeLog}}">Tail</mwc-button>
|
<mwc-button raised="true" on-click="_tailLog" disabled="{{_completeLog}}">[[localize('ui.panel.config.zwave.ozw_log.tail')]]</mwc-button>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
`;
|
`;
|
||||||
|
@ -7,6 +7,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/buttons/ha-call-api-button";
|
import "../../../components/buttons/ha-call-api-button";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../styles/polymer-ha-style";
|
||||||
|
|
||||||
class ZwaveNodeProtection extends PolymerElement {
|
class ZwaveNodeProtection extends PolymerElement {
|
||||||
static get template() {
|
static get template() {
|
||||||
@ -32,9 +33,9 @@ class ZwaveNodeProtection extends PolymerElement {
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-card header="Node protection">
|
<ha-card header="[[localize('ui.panel.config.zwave.node_management.node_protection')]]">
|
||||||
<div class="device-picker">
|
<div class="device-picker">
|
||||||
<paper-dropdown-menu label="Protection" dynamic-align class="flex" placeholder="{{_loadedProtectionValue}}">
|
<paper-dropdown-menu label="[[localize('ui.panel.config.zwave.node_management.protection')]]" dynamic-align class="flex" placeholder="{{_loadedProtectionValue}}">
|
||||||
<paper-listbox slot="dropdown-content" selected="{{_selectedProtectionParameter}}">
|
<paper-listbox slot="dropdown-content" selected="{{_selectedProtectionParameter}}">
|
||||||
<template is="dom-repeat" items="[[_protectionOptions]]" as="state">
|
<template is="dom-repeat" items="[[_protectionOptions]]" as="state">
|
||||||
<paper-item>[[state]]</paper-item>
|
<paper-item>[[state]]</paper-item>
|
||||||
@ -47,7 +48,7 @@ class ZwaveNodeProtection extends PolymerElement {
|
|||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
path="[[_nodePath]]"
|
path="[[_nodePath]]"
|
||||||
data="[[_protectionData]]">
|
data="[[_protectionData]]">
|
||||||
Set Protection
|
[[localize('ui.panel.config.zwave.node_management.set_protection')]]
|
||||||
</ha-call-service-button>
|
</ha-call-service-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
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