Compare commits
2 Commits
add-import
...
stye-unava
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
355440c0fa | ||
|
|
e7d89d0f9a |
80
.eslintrc-hound.json
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"extends": ["airbnb-base", "prettier"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "2020",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
"modules": true
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"pragma": "h",
|
||||
"version": "15.0"
|
||||
},
|
||||
"import/resolver": {
|
||||
"webpack": {
|
||||
"config": "webpack.config.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"__DEV__": false,
|
||||
"__DEMO__": false,
|
||||
"__BUILD__": false,
|
||||
"__VERSION__": false,
|
||||
"__STATIC_PATH__": false,
|
||||
"Polymer": true,
|
||||
"webkitSpeechRecognition": false,
|
||||
"ResizeObserver": false
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"mocha": true
|
||||
},
|
||||
"rules": {
|
||||
"class-methods-use-this": 0,
|
||||
"new-cap": 0,
|
||||
"prefer-template": 0,
|
||||
"object-shorthand": 0,
|
||||
"func-names": 0,
|
||||
"prefer-arrow-callback": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-var": 0,
|
||||
"strict": 0,
|
||||
"prefer-spread": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-bitwise": 0,
|
||||
"comma-dangle": 0,
|
||||
"vars-on-top": 0,
|
||||
"no-continue": 0,
|
||||
"no-param-reassign": 0,
|
||||
"no-multi-assign": 0,
|
||||
"radix": 0,
|
||||
"no-alert": 0,
|
||||
"no-return-await": 0,
|
||||
"prefer-destructuring": 0,
|
||||
"no-restricted-globals": [2, "event"],
|
||||
"prefer-promise-reject-errors": 0,
|
||||
"import/prefer-default-export": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/extensions": [2, "ignorePackages"],
|
||||
"object-curly-newline": 0,
|
||||
"default-case": 0,
|
||||
"react/jsx-no-bind": [2, { "ignoreRefs": true }],
|
||||
"react/jsx-no-duplicate-props": 2,
|
||||
"react/self-closing-comp": 2,
|
||||
"react/prefer-es6-class": 2,
|
||||
"react/no-string-refs": 2,
|
||||
"react/require-render-return": 2,
|
||||
"react/no-find-dom-node": 2,
|
||||
"react/no-is-mounted": 2,
|
||||
"react/jsx-no-comment-textnodes": 2,
|
||||
"react/jsx-no-undef": 2,
|
||||
"react/jsx-uses-react": 2,
|
||||
"react/jsx-uses-vars": 2,
|
||||
"no-restricted-syntax": [0, "ForOfStatement"],
|
||||
"prettier/prettier": "error"
|
||||
},
|
||||
"plugins": ["react", "prettier"]
|
||||
}
|
||||
@@ -1,88 +1,12 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"airbnb-typescript/base",
|
||||
"plugin:wc/recommended",
|
||||
"plugin:lit/recommended",
|
||||
"prettier",
|
||||
"prettier/@typescript-eslint"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"ecmaFeatures": {
|
||||
"modules": true
|
||||
},
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"webpack": {
|
||||
"config": "./webpack.config.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"__DEV__": false,
|
||||
"__DEMO__": false,
|
||||
"__BUILD__": false,
|
||||
"__VERSION__": false,
|
||||
"__STATIC_PATH__": false,
|
||||
"Polymer": true,
|
||||
"webkitSpeechRecognition": false,
|
||||
"ResizeObserver": false
|
||||
},
|
||||
"extends": "./.eslintrc-hound.json",
|
||||
"plugins": ["react"],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
"browser": true
|
||||
},
|
||||
"rules": {
|
||||
"class-methods-use-this": 0,
|
||||
"new-cap": 0,
|
||||
"prefer-template": 0,
|
||||
"object-shorthand": 0,
|
||||
"func-names": 0,
|
||||
"prefer-arrow-callback": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-var": 0,
|
||||
"strict": 0,
|
||||
"prefer-spread": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-bitwise": 0,
|
||||
"comma-dangle": 0,
|
||||
"vars-on-top": 0,
|
||||
"no-continue": 0,
|
||||
"no-param-reassign": 0,
|
||||
"no-multi-assign": 0,
|
||||
"radix": 0,
|
||||
"no-alert": 0,
|
||||
"no-return-await": 0,
|
||||
"no-nested-ternary": 0,
|
||||
"prefer-destructuring": 0,
|
||||
"no-restricted-globals": [2, "event"],
|
||||
"prefer-promise-reject-errors": 0,
|
||||
"import/order": 0,
|
||||
"import/prefer-default-export": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-cycle": 0,
|
||||
"import/extensions": [
|
||||
2,
|
||||
"ignorePackages",
|
||||
{ "ts": "ignorePackages", "js": "ignorePackages" }
|
||||
],
|
||||
"no-restricted-syntax": ["error", "LabeledStatement", "WithStatement"],
|
||||
"object-curly-newline": 0,
|
||||
"default-case": 0,
|
||||
"wc/no-self-class": 0,
|
||||
"@typescript-eslint/camelcase": 0,
|
||||
"@typescript-eslint/ban-ts-ignore": 0,
|
||||
"@typescript-eslint/no-use-before-define": 0,
|
||||
"@typescript-eslint/no-non-null-assertion": 0,
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/no-unused-vars": 0,
|
||||
"@typescript-eslint/explicit-function-return-type": 0
|
||||
},
|
||||
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
|
||||
"processor": "disable/disable"
|
||||
"import/no-unresolved": 2,
|
||||
"linebreak-style": 0,
|
||||
"implicit-arrow-linebreak": 0
|
||||
}
|
||||
}
|
||||
|
||||
12
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
@@ -62,18 +62,6 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
|
||||
- Browser and browser version:
|
||||
- Operating system:
|
||||
|
||||
## State of relevant entities
|
||||
|
||||
<!--
|
||||
If your issue is about how an entity is shown in the UI, please add the state
|
||||
and attributes for all situations with a screenshot of the UI.
|
||||
You can find this information at `/developer-tools/state`
|
||||
-->
|
||||
|
||||
```yaml
|
||||
|
||||
```
|
||||
|
||||
## Problem-relevant configuration
|
||||
|
||||
<!--
|
||||
|
||||
9
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
@@ -3,24 +3,23 @@ name: Request a feature for the UI, Frontend or Lovelace
|
||||
about: Request an new feature for the Home Assistant frontend.
|
||||
labels: feature request
|
||||
---
|
||||
|
||||
<!--
|
||||
DO NOT DELETE ANY TEXT from this template!
|
||||
Otherwise, your request may be closed without comment.
|
||||
-->
|
||||
|
||||
## The request
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Describe to our maintainers, the feature you would like to be added.
|
||||
Please be clear and concise and, if possible, provide a screenshot or mockup.
|
||||
-->
|
||||
|
||||
## The alternatives
|
||||
|
||||
## The alternatives
|
||||
<!--
|
||||
Are you currently using, or have you considered alternatives?
|
||||
If so, could you please describe those?
|
||||
-->
|
||||
|
||||
|
||||
## Additional information
|
||||
|
||||
|
||||
18
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -2,9 +2,7 @@
|
||||
You are amazing! Thanks for contributing to our project!
|
||||
Please, DO NOT DELETE ANY TEXT from this template! (unless instructed).
|
||||
-->
|
||||
|
||||
## Breaking change
|
||||
|
||||
<!--
|
||||
If your PR contains a breaking change for existing users, it is important
|
||||
to tell them what breaks, how to make it work again and why we did this.
|
||||
@@ -13,20 +11,20 @@
|
||||
Note: Remove this section if this PR is NOT a breaking change.
|
||||
-->
|
||||
|
||||
## Proposed change
|
||||
|
||||
<!--
|
||||
## Proposed change
|
||||
<!--
|
||||
Describe the big picture of your changes here to communicate to the
|
||||
maintainers why we should accept this pull request. If it fixes a bug
|
||||
or resolves a feature request, be sure to link to that issue in the
|
||||
additional information section.
|
||||
-->
|
||||
|
||||
## Type of change
|
||||
|
||||
## Type of change
|
||||
<!--
|
||||
What type of change does your PR introduce to the Home Assistant frontend?
|
||||
NOTE: Please, check only 1! box!
|
||||
NOTE: Please, check only 1! box!
|
||||
If your PR requires multiple boxes to be checked, you'll most likely need to
|
||||
split it into multiple PRs. This makes things easier and faster to code review.
|
||||
-->
|
||||
@@ -38,7 +36,6 @@
|
||||
- [ ] Code quality improvements to existing code or addition of tests
|
||||
|
||||
## Example configuration
|
||||
|
||||
<!--
|
||||
Supplying a configuration snippet, makes it easier for a maintainer to test
|
||||
your PR.
|
||||
@@ -49,18 +46,16 @@
|
||||
```
|
||||
|
||||
## Additional information
|
||||
|
||||
<!--
|
||||
Details are important, and help maintainers processing your PR.
|
||||
Please be sure to fill out additional details, if applicable.
|
||||
-->
|
||||
|
||||
- This PR fixes or closes issue: fixes #
|
||||
- This PR is related to issue:
|
||||
- Link to documentation pull request:
|
||||
- This PR is related to issue:
|
||||
- Link to documentation pull request:
|
||||
|
||||
## Checklist
|
||||
|
||||
<!--
|
||||
Put an `x` in the boxes that apply. You can also fill these out after
|
||||
creating the PR. If you're unsure about any of them, don't hesitate to ask.
|
||||
@@ -79,5 +74,4 @@ If user exposed functionality or configuration variables are added/changed:
|
||||
<!--
|
||||
Thank you for contributing <3
|
||||
-->
|
||||
|
||||
[docs-repository]: https://github.com/home-assistant/home-assistant.io
|
||||
|
||||
2
.github/lock.yml
vendored
@@ -24,4 +24,4 @@ only: pulls
|
||||
|
||||
# Optionally, specify configuration settings just for `issues` or `pulls`
|
||||
issues:
|
||||
daysUntilLock: 30
|
||||
daysUntilLock: 30
|
||||
|
||||
10
.github/workflows/ci.yaml
vendored
@@ -35,11 +35,13 @@ jobs:
|
||||
env:
|
||||
CI: true
|
||||
- name: Build icons
|
||||
run: ./node_modules/.bin/gulp gen-icons-json
|
||||
run: ./node_modules/.bin/gulp gen-icons-hassio gen-icons-mdi gen-icons-app
|
||||
- name: Build translations
|
||||
run: ./node_modules/.bin/gulp build-translations
|
||||
- name: Run eslint
|
||||
run: ./node_modules/.bin/eslint '{**/src,src}/**/*.{js,ts,html}' --ignore-path .gitignore
|
||||
run: ./node_modules/.bin/eslint src hassio/src gallery/src
|
||||
- name: Run tslint
|
||||
run: ./node_modules/.bin/tslint 'src/**/*.ts' 'hassio/src/**/*.ts' 'gallery/src/**/*.ts' 'cast/src/**/*.ts' 'test-mocha/**/*.ts'
|
||||
- name: Run tsc
|
||||
run: ./node_modules/.bin/tsc
|
||||
test:
|
||||
@@ -94,7 +96,7 @@ jobs:
|
||||
- name: Build Application
|
||||
run: ./node_modules/.bin/gulp build-app
|
||||
env:
|
||||
IS_TEST: "true"
|
||||
TRAVIS: "true"
|
||||
supervisor:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, test]
|
||||
@@ -122,4 +124,4 @@ jobs:
|
||||
- name: Build Application
|
||||
run: ./node_modules/.bin/gulp build-hassio
|
||||
env:
|
||||
IS_TEST: "true"
|
||||
TRAVIS: "true"
|
||||
|
||||
4
.gitignore
vendored
@@ -5,6 +5,7 @@ npm-debug.log
|
||||
.DS_Store
|
||||
hass_frontend/*
|
||||
.reify-cache
|
||||
demo/hademo-icons.html
|
||||
|
||||
# Python stuff
|
||||
*.py[cod]
|
||||
@@ -30,6 +31,3 @@ src/cast/dev_const.ts
|
||||
# Secrets
|
||||
.lokalise_token
|
||||
yarn-error.log
|
||||
|
||||
#asdf
|
||||
.tool-versions
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
build
|
||||
build-translations/*
|
||||
translations/*
|
||||
node_modules/*
|
||||
hass_frontend/*
|
||||
pip-selfcheck.json
|
||||
|
||||
# vscode
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
1
.vscode/extensions.json
vendored
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||
"esbenp.prettier-vscode",
|
||||
"bierner.lit-html",
|
||||
"runem.lit-plugin"
|
||||
|
||||
@@ -8,7 +8,7 @@ schedules:
|
||||
branches:
|
||||
include:
|
||||
- dev
|
||||
always: true
|
||||
always: false
|
||||
variables:
|
||||
- group: netlify
|
||||
|
||||
@@ -24,7 +24,4 @@ jobs:
|
||||
|
||||
# Demo
|
||||
curl -X POST -d {} https://api.netlify.com/build_hooks/${NETLIFY_DEMO}
|
||||
|
||||
# Gallery
|
||||
curl -X POST -d {} https://api.netlify.com/build_hooks/${NETLIFY_GALLERY}
|
||||
displayName: 'Trigger netlify build preview'
|
||||
|
||||
@@ -8,7 +8,7 @@ trigger:
|
||||
pr: none
|
||||
variables:
|
||||
- name: versionWheels
|
||||
value: '1.10.1-3.7-alpine3.11'
|
||||
value: '1.3-3.7-alpine3.10'
|
||||
- name: versionNode
|
||||
value: '12.1'
|
||||
- group: twine
|
||||
@@ -47,13 +47,18 @@ stages:
|
||||
|
||||
script/release
|
||||
displayName: "Build and release package"
|
||||
- stage: "Wheels"
|
||||
jobs:
|
||||
- template: templates/azp-job-wheels.yaml@azure
|
||||
parameters:
|
||||
builderVersion: '$(versionWheels)'
|
||||
wheelsRequirement: 'requirement.txt'
|
||||
builderApk: 'build-base'
|
||||
wheelsLocal: true
|
||||
preBuild:
|
||||
- task: NodeTool@0
|
||||
displayName: "Use Node $(versionNode)"
|
||||
inputs:
|
||||
versionSpec: "$(versionNode)"
|
||||
- script: |
|
||||
sleep 240
|
||||
echo "home-assistant-frontend==$(Build.SourceBranchName)" > requirement.txt
|
||||
set -e
|
||||
|
||||
yarn install
|
||||
script/build_frontend
|
||||
|
||||
@@ -1,40 +1,50 @@
|
||||
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.options = options;
|
||||
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 }),
|
||||
options: {
|
||||
presets: [
|
||||
!latestBuild && [
|
||||
require("@babel/preset-env").default,
|
||||
{ modules: false },
|
||||
],
|
||||
[
|
||||
require("@babel/preset-typescript").default,
|
||||
{
|
||||
jsxPragma: "h",
|
||||
},
|
||||
],
|
||||
].filter(Boolean),
|
||||
plugins: [
|
||||
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
||||
[
|
||||
"@babel/plugin-proposal-object-rest-spread",
|
||||
{ loose: true, useBuiltIns: true },
|
||||
],
|
||||
// Only support the syntax, Webpack will handle it.
|
||||
"@babel/syntax-dynamic-import",
|
||||
[
|
||||
"@babel/transform-react-jsx",
|
||||
{
|
||||
pragma: "h",
|
||||
},
|
||||
],
|
||||
"@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 },
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,27 +1,6 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const paths = require("./paths.js");
|
||||
|
||||
module.exports = {
|
||||
isProdBuild() {
|
||||
return process.env.NODE_ENV === "production";
|
||||
},
|
||||
isStatsBuild() {
|
||||
return process.env.STATS === "1";
|
||||
},
|
||||
isTest() {
|
||||
return process.env.IS_TEST === "true";
|
||||
},
|
||||
isNetlify() {
|
||||
return process.env.NETLIFY === "true";
|
||||
},
|
||||
version() {
|
||||
const version = fs
|
||||
.readFileSync(path.resolve(paths.polymer_dir, "setup.py"), "utf8")
|
||||
.match(/\d{8}\.\d+/);
|
||||
if (!version) {
|
||||
throw Error("Version not found");
|
||||
}
|
||||
return version[0];
|
||||
},
|
||||
isProdBuild: process.env.NODE_ENV === "production",
|
||||
isStatsBuild: process.env.STATS === "1",
|
||||
isTravis: process.env.TRAVIS === "true",
|
||||
isNetlify: process.env.NETLIFY === "true",
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ const envVars = require("../env");
|
||||
|
||||
require("./clean.js");
|
||||
require("./translations.js");
|
||||
require("./gen-icons-json.js");
|
||||
require("./gen-icons.js");
|
||||
require("./gather-static.js");
|
||||
require("./compress.js");
|
||||
require("./webpack.js");
|
||||
@@ -21,7 +21,7 @@ gulp.task(
|
||||
"clean",
|
||||
gulp.parallel(
|
||||
"gen-service-worker-dev",
|
||||
"gen-icons-json",
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi"),
|
||||
"gen-pages-dev",
|
||||
"gen-index-app-dev",
|
||||
"build-translations"
|
||||
@@ -38,11 +38,11 @@ gulp.task(
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean",
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi", "build-translations"),
|
||||
"copy-static",
|
||||
"webpack-prod-app",
|
||||
...// Don't compress running tests
|
||||
(envVars.isTest() ? [] : ["compress-app"]),
|
||||
(envVars.isTravis ? [] : ["compress-app"]),
|
||||
gulp.parallel(
|
||||
"gen-pages-prod",
|
||||
"gen-index-app-prod",
|
||||
|
||||
@@ -2,6 +2,7 @@ const gulp = require("gulp");
|
||||
|
||||
require("./clean.js");
|
||||
require("./translations.js");
|
||||
require("./gen-icons.js");
|
||||
require("./gather-static.js");
|
||||
require("./webpack.js");
|
||||
require("./service-worker.js");
|
||||
@@ -14,8 +15,12 @@ gulp.task(
|
||||
process.env.NODE_ENV = "development";
|
||||
},
|
||||
"clean-cast",
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
gulp.parallel(
|
||||
"gen-icons-app",
|
||||
"gen-icons-mdi",
|
||||
"gen-index-cast-dev",
|
||||
"build-translations"
|
||||
),
|
||||
"copy-static-cast",
|
||||
"webpack-dev-server-cast"
|
||||
)
|
||||
@@ -28,8 +33,7 @@ gulp.task(
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean-cast",
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi", "build-translations"),
|
||||
"copy-static-cast",
|
||||
"webpack-prod-cast",
|
||||
"gen-index-cast-prod"
|
||||
|
||||
@@ -3,7 +3,7 @@ const gulp = require("gulp");
|
||||
|
||||
require("./clean.js");
|
||||
require("./translations.js");
|
||||
require("./gen-icons-json.js");
|
||||
require("./gen-icons.js");
|
||||
require("./gather-static.js");
|
||||
require("./webpack.js");
|
||||
require("./service-worker.js");
|
||||
@@ -16,8 +16,13 @@ gulp.task(
|
||||
process.env.NODE_ENV = "development";
|
||||
},
|
||||
"clean-demo",
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel("gen-icons-json", "gen-index-demo-dev", "build-translations"),
|
||||
gulp.parallel(
|
||||
"gen-icons-app",
|
||||
"gen-icons-mdi",
|
||||
"gen-icons-demo",
|
||||
"gen-index-demo-dev",
|
||||
"build-translations"
|
||||
),
|
||||
"copy-static-demo",
|
||||
"webpack-dev-server-demo"
|
||||
)
|
||||
@@ -30,9 +35,12 @@ gulp.task(
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean-demo",
|
||||
// Cast needs to be backwards compatible and older HA has no translations
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
gulp.parallel(
|
||||
"gen-icons-app",
|
||||
"gen-icons-mdi",
|
||||
"gen-icons-demo",
|
||||
"build-translations"
|
||||
),
|
||||
"copy-static-demo",
|
||||
"webpack-prod-demo",
|
||||
"gen-index-demo-prod"
|
||||
|
||||
@@ -2,7 +2,7 @@ const del = require("del");
|
||||
const gulp = require("gulp");
|
||||
const mapStream = require("map-stream");
|
||||
|
||||
const inDir = "translations/frontend";
|
||||
const inDir = "translations";
|
||||
const downloadDir = inDir + "/downloads";
|
||||
|
||||
const tasks = [];
|
||||
@@ -12,7 +12,7 @@ function hasHtml(data) {
|
||||
}
|
||||
|
||||
function recursiveCheckHasHtml(file, data, errors, recKey) {
|
||||
Object.keys(data).forEach(function (key) {
|
||||
Object.keys(data).forEach(function(key) {
|
||||
if (typeof data[key] === "object") {
|
||||
const nextRecKey = recKey ? `${recKey}.${key}` : key;
|
||||
recursiveCheckHasHtml(file, data[key], errors, nextRecKey);
|
||||
@@ -25,7 +25,7 @@ function recursiveCheckHasHtml(file, data, errors, recKey) {
|
||||
function checkHtml() {
|
||||
const errors = [];
|
||||
|
||||
return mapStream(function (file, cb) {
|
||||
return mapStream(function(file, cb) {
|
||||
const content = file.contents;
|
||||
let error;
|
||||
if (content) {
|
||||
@@ -42,19 +42,19 @@ function checkHtml() {
|
||||
}
|
||||
|
||||
let taskName = "clean-downloaded-translations";
|
||||
gulp.task(taskName, function () {
|
||||
gulp.task(taskName, function() {
|
||||
return del([`${downloadDir}/**`]);
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = "check-translations-html";
|
||||
gulp.task(taskName, function () {
|
||||
gulp.task(taskName, function() {
|
||||
return gulp.src(`${downloadDir}/*.json`).pipe(checkHtml());
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = "move-downloaded-translations";
|
||||
gulp.task(taskName, function () {
|
||||
gulp.task(taskName, function() {
|
||||
return gulp.src(`${downloadDir}/*.json`).pipe(gulp.dest(inDir));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
@@ -47,9 +47,11 @@ gulp.task("gen-pages-dev", (done) => {
|
||||
for (const page of PAGES) {
|
||||
const content = renderTemplate(page, {
|
||||
latestPageJS: `/frontend_latest/${page}.js`,
|
||||
latestHassIconsJS: "/frontend_latest/hass-icons.js",
|
||||
|
||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
||||
es5PageJS: `/frontend_es5/${page}.js`,
|
||||
es5HassIconsJS: "/frontend_es5/hass-icons.js",
|
||||
});
|
||||
|
||||
fs.outputFileSync(path.resolve(config.root, `${page}.html`), content);
|
||||
@@ -64,9 +66,11 @@ gulp.task("gen-pages-prod", (done) => {
|
||||
for (const page of PAGES) {
|
||||
const content = renderTemplate(page, {
|
||||
latestPageJS: latestManifest[`${page}.js`],
|
||||
latestHassIconsJS: latestManifest["hass-icons.js"],
|
||||
|
||||
es5Compatibility: es5Manifest["compatibility.js"],
|
||||
es5PageJS: es5Manifest[`${page}.js`],
|
||||
es5HassIconsJS: es5Manifest["hass-icons.js"],
|
||||
});
|
||||
|
||||
fs.outputFileSync(
|
||||
@@ -84,11 +88,13 @@ gulp.task("gen-index-app-dev", (done) => {
|
||||
latestAppJS: "/frontend_latest/app.js",
|
||||
latestCoreJS: "/frontend_latest/core.js",
|
||||
latestCustomPanelJS: "/frontend_latest/custom-panel.js",
|
||||
latestHassIconsJS: "/frontend_latest/hass-icons.js",
|
||||
|
||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
||||
es5AppJS: "/frontend_es5/app.js",
|
||||
es5CoreJS: "/frontend_es5/core.js",
|
||||
es5CustomPanelJS: "/frontend_es5/custom-panel.js",
|
||||
es5HassIconsJS: "/frontend_es5/hass-icons.js",
|
||||
}).replace(/#THEMEC/g, "{{ theme_color }}");
|
||||
|
||||
fs.outputFileSync(path.resolve(config.root, "index.html"), content);
|
||||
@@ -102,11 +108,13 @@ gulp.task("gen-index-app-prod", (done) => {
|
||||
latestAppJS: latestManifest["app.js"],
|
||||
latestCoreJS: latestManifest["core.js"],
|
||||
latestCustomPanelJS: latestManifest["custom-panel.js"],
|
||||
latestHassIconsJS: latestManifest["hass-icons.js"],
|
||||
|
||||
es5Compatibility: es5Manifest["compatibility.js"],
|
||||
es5AppJS: es5Manifest["app.js"],
|
||||
es5CoreJS: es5Manifest["core.js"],
|
||||
es5CustomPanelJS: es5Manifest["custom-panel.js"],
|
||||
es5HassIconsJS: es5Manifest["hass-icons.js"],
|
||||
});
|
||||
const minified = minifyHtml(content).replace(/#THEMEC/g, "{{ theme_color }}");
|
||||
|
||||
@@ -214,7 +222,7 @@ gulp.task("gen-index-gallery-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderGalleryTemplate("index", {
|
||||
latestGalleryJS: "./frontend_latest/entrypoint.js",
|
||||
latestGalleryJS: "./entrypoint.js",
|
||||
});
|
||||
|
||||
fs.outputFileSync(path.resolve(config.gallery_root, "index.html"), content);
|
||||
|
||||
@@ -3,7 +3,7 @@ const gulp = require("gulp");
|
||||
|
||||
require("./clean.js");
|
||||
require("./translations.js");
|
||||
require("./gen-icons-json.js");
|
||||
require("./gen-icons.js");
|
||||
require("./gather-static.js");
|
||||
require("./webpack.js");
|
||||
require("./service-worker.js");
|
||||
@@ -16,8 +16,7 @@ gulp.task(
|
||||
process.env.NODE_ENV = "development";
|
||||
},
|
||||
"clean-gallery",
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi", "build-translations"),
|
||||
"copy-static-gallery",
|
||||
"gen-index-gallery-dev",
|
||||
"webpack-dev-server-gallery"
|
||||
@@ -31,8 +30,7 @@ gulp.task(
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean-gallery",
|
||||
"translations-enable-merge-backend",
|
||||
gulp.parallel("gen-icons-json", "build-translations"),
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi", "build-translations"),
|
||||
"copy-static-gallery",
|
||||
"webpack-prod-gallery",
|
||||
"gen-index-gallery-prod"
|
||||
|
||||
@@ -26,13 +26,6 @@ function copyTranslations(staticDir) {
|
||||
);
|
||||
}
|
||||
|
||||
function copyMdiIcons(staticDir) {
|
||||
const staticPath = genStaticPath(staticDir);
|
||||
|
||||
// MDI icons output
|
||||
fs.copySync(polyPath("build/mdi"), staticPath("mdi"));
|
||||
}
|
||||
|
||||
function copyPolyfills(staticDir) {
|
||||
const staticPath = genStaticPath(staticDir);
|
||||
|
||||
@@ -80,15 +73,19 @@ gulp.task("copy-translations", (done) => {
|
||||
|
||||
gulp.task("copy-static", (done) => {
|
||||
const staticDir = paths.static;
|
||||
const staticPath = genStaticPath(paths.static);
|
||||
// Basic static files
|
||||
fs.copySync(polyPath("public"), paths.root);
|
||||
|
||||
copyPolyfills(staticDir);
|
||||
copyFonts(staticDir);
|
||||
copyTranslations(staticDir);
|
||||
copyMdiIcons(staticDir);
|
||||
|
||||
// Panel assets
|
||||
copyFileDir(
|
||||
npmPath("react-big-calendar/lib/css/react-big-calendar.css"),
|
||||
staticPath("panels/calendar/")
|
||||
);
|
||||
copyMapPanel(staticDir);
|
||||
done();
|
||||
});
|
||||
@@ -106,7 +103,6 @@ gulp.task("copy-static-demo", (done) => {
|
||||
copyMapPanel(paths.demo_static);
|
||||
copyFonts(paths.demo_static);
|
||||
copyTranslations(paths.demo_static);
|
||||
copyMdiIcons(paths.demo_static);
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -119,7 +115,6 @@ gulp.task("copy-static-cast", (done) => {
|
||||
copyMapPanel(paths.cast_static);
|
||||
copyFonts(paths.cast_static);
|
||||
copyTranslations(paths.cast_static);
|
||||
copyMdiIcons(paths.cast_static);
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -132,6 +127,5 @@ gulp.task("copy-static-gallery", (done) => {
|
||||
copyMapPanel(paths.gallery_static);
|
||||
copyFonts(paths.gallery_static);
|
||||
copyTranslations(paths.gallery_static);
|
||||
copyMdiIcons(paths.gallery_static);
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
const gulp = require("gulp");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const hash = require("object-hash");
|
||||
|
||||
const ICON_PACKAGE_PATH = path.resolve(
|
||||
__dirname,
|
||||
"../../node_modules/@mdi/svg/"
|
||||
);
|
||||
const META_PATH = path.resolve(ICON_PACKAGE_PATH, "meta.json");
|
||||
const PACKAGE_PATH = path.resolve(ICON_PACKAGE_PATH, "package.json");
|
||||
const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, "svg");
|
||||
const OUTPUT_DIR = path.resolve(__dirname, "../../build/mdi");
|
||||
|
||||
const encoding = "utf8";
|
||||
|
||||
const getMeta = () => {
|
||||
const file = fs.readFileSync(META_PATH, { encoding });
|
||||
const meta = JSON.parse(file);
|
||||
return meta.map((icon) => {
|
||||
const svg = fs.readFileSync(`${ICON_PATH}/${icon.name}.svg`, {
|
||||
encoding,
|
||||
});
|
||||
return { path: svg.match(/ d="([^"]+)"/)[1], name: icon.name };
|
||||
});
|
||||
};
|
||||
|
||||
const splitBySize = (meta) => {
|
||||
const chunks = [];
|
||||
const CHUNK_SIZE = 50000;
|
||||
|
||||
let curSize = 0;
|
||||
let startKey;
|
||||
let icons = [];
|
||||
|
||||
Object.values(meta).forEach((icon) => {
|
||||
if (startKey === undefined) {
|
||||
startKey = icon.name;
|
||||
}
|
||||
curSize += icon.path.length;
|
||||
icons.push(icon);
|
||||
if (curSize > CHUNK_SIZE) {
|
||||
chunks.push({
|
||||
startKey,
|
||||
endKey: icon.name,
|
||||
icons,
|
||||
});
|
||||
curSize = 0;
|
||||
startKey = undefined;
|
||||
icons = [];
|
||||
}
|
||||
});
|
||||
|
||||
chunks.push({
|
||||
startKey,
|
||||
icons,
|
||||
});
|
||||
|
||||
return chunks;
|
||||
};
|
||||
|
||||
const findDifferentiator = (curString, prevString) => {
|
||||
for (let i = 0; i < curString.length; i++) {
|
||||
if (curString[i] !== prevString[i]) {
|
||||
return curString.substring(0, i + 1);
|
||||
}
|
||||
}
|
||||
throw new Error("Cannot find differentiator", curString, prevString);
|
||||
};
|
||||
|
||||
gulp.task("gen-icons-json", (done) => {
|
||||
const meta = getMeta();
|
||||
const split = splitBySize(meta);
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
const parts = [];
|
||||
|
||||
let lastEnd;
|
||||
split.forEach((chunk) => {
|
||||
let startKey;
|
||||
if (lastEnd === undefined) {
|
||||
chunk.startKey = undefined;
|
||||
startKey = undefined;
|
||||
} else {
|
||||
startKey = findDifferentiator(chunk.startKey, lastEnd);
|
||||
}
|
||||
lastEnd = chunk.endKey;
|
||||
|
||||
const output = {};
|
||||
chunk.icons.forEach((icon) => {
|
||||
output[icon.name] = icon.path;
|
||||
});
|
||||
const filename = hash(output);
|
||||
parts.push({ start: startKey, file: filename });
|
||||
fs.writeFileSync(
|
||||
path.resolve(OUTPUT_DIR, `${filename}.json`),
|
||||
JSON.stringify(output)
|
||||
);
|
||||
});
|
||||
|
||||
const file = fs.readFileSync(PACKAGE_PATH, { encoding });
|
||||
const package = JSON.parse(file);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.resolve(OUTPUT_DIR, "iconMetadata.json"),
|
||||
JSON.stringify({ version: package.version, parts })
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
127
build-scripts/gulp/gen-icons.js
Normal file
@@ -0,0 +1,127 @@
|
||||
const gulp = require("gulp");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const paths = require("../paths");
|
||||
const { mapFiles } = require("../util");
|
||||
|
||||
const ICON_PACKAGE_PATH = path.resolve(
|
||||
__dirname,
|
||||
"../../node_modules/@mdi/svg/"
|
||||
);
|
||||
const META_PATH = path.resolve(ICON_PACKAGE_PATH, "meta.json");
|
||||
const ICON_PATH = path.resolve(ICON_PACKAGE_PATH, "svg");
|
||||
const OUTPUT_DIR = path.resolve(__dirname, "../../build");
|
||||
const MDI_OUTPUT_PATH = path.resolve(OUTPUT_DIR, "mdi.html");
|
||||
const HASS_OUTPUT_PATH = path.resolve(OUTPUT_DIR, "hass-icons.html");
|
||||
|
||||
const BUILT_IN_PANEL_ICONS = [
|
||||
"calendar", // Calendar
|
||||
"settings", // Config
|
||||
"home-assistant", // Hass.io
|
||||
"poll-box", // History panel
|
||||
"format-list-bulleted-type", // Logbook
|
||||
"mailbox", // Mailbox
|
||||
"tooltip-account", // Map
|
||||
"cart", // Shopping List
|
||||
"hammer", // developer-tools
|
||||
];
|
||||
|
||||
// Given an icon name, load the SVG file
|
||||
function loadIcon(name) {
|
||||
const iconPath = path.resolve(ICON_PATH, `${name}.svg`);
|
||||
try {
|
||||
return fs.readFileSync(iconPath, "utf-8");
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Given an SVG file, convert it to an iron-iconset-svg definition
|
||||
function transformXMLtoPolymer(name, xml) {
|
||||
const start = xml.indexOf("><path") + 1;
|
||||
const end = xml.length - start - 6;
|
||||
const pth = xml.substr(start, end);
|
||||
return `<g id="${name}">${pth}</g>`;
|
||||
}
|
||||
|
||||
// Given an iconset name and icon names, generate a polymer iconset
|
||||
function generateIconset(iconsetName, iconNames) {
|
||||
const iconDefs = Array.from(iconNames)
|
||||
.map((name) => {
|
||||
const iconDef = loadIcon(name);
|
||||
if (!iconDef) {
|
||||
throw new Error(`Unknown icon referenced: ${name}`);
|
||||
}
|
||||
return transformXMLtoPolymer(name, iconDef);
|
||||
})
|
||||
.join("");
|
||||
return `<ha-iconset-svg name="${iconsetName}" size="24"><svg><defs>${iconDefs}</defs></svg></ha-iconset-svg>`;
|
||||
}
|
||||
|
||||
// Find all icons used by the project.
|
||||
function findIcons(searchPath, iconsetName) {
|
||||
const iconRegex = new RegExp(`${iconsetName}:[\\w-]+`, "g");
|
||||
const icons = new Set();
|
||||
function processFile(filename) {
|
||||
const content = fs.readFileSync(filename);
|
||||
let match;
|
||||
// eslint-disable-next-line
|
||||
while ((match = iconRegex.exec(content))) {
|
||||
// strip off "hass:" and add to set
|
||||
icons.add(match[0].substr(iconsetName.length + 1));
|
||||
}
|
||||
}
|
||||
mapFiles(searchPath, ".js", processFile);
|
||||
mapFiles(searchPath, ".ts", processFile);
|
||||
return icons;
|
||||
}
|
||||
|
||||
gulp.task("gen-icons-mdi", (done) => {
|
||||
const meta = JSON.parse(
|
||||
fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), "UTF-8")
|
||||
);
|
||||
const iconNames = meta.map((iconInfo) => iconInfo.name);
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset("mdi", iconNames));
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-icons-app", (done) => {
|
||||
const iconNames = findIcons("./src", "hass");
|
||||
BUILT_IN_PANEL_ICONS.forEach((name) => iconNames.add(name));
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset("hass", iconNames));
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-icons-demo", (done) => {
|
||||
const iconNames = findIcons(path.resolve(paths.demo_dir, "./src"), "hademo");
|
||||
fs.writeFileSync(
|
||||
path.resolve(paths.demo_dir, "hademo-icons.html"),
|
||||
generateIconset("hademo", iconNames)
|
||||
);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-icons-hassio", (done) => {
|
||||
const iconNames = findIcons(
|
||||
path.resolve(paths.hassio_dir, "./src"),
|
||||
"hassio"
|
||||
);
|
||||
// Find hassio icons inside HA main repo.
|
||||
for (const item of findIcons(
|
||||
path.resolve(paths.polymer_dir, "./src"),
|
||||
"hassio"
|
||||
)) {
|
||||
iconNames.add(item);
|
||||
}
|
||||
fs.writeFileSync(
|
||||
path.resolve(paths.hassio_dir, "hassio-icons.html"),
|
||||
generateIconset("hassio", iconNames)
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -3,7 +3,7 @@ const gulp = require("gulp");
|
||||
const envVars = require("../env");
|
||||
|
||||
require("./clean.js");
|
||||
require("./gen-icons-json.js");
|
||||
require("./gen-icons.js");
|
||||
require("./webpack.js");
|
||||
require("./compress.js");
|
||||
|
||||
@@ -14,7 +14,7 @@ gulp.task(
|
||||
process.env.NODE_ENV = "development";
|
||||
},
|
||||
"clean-hassio",
|
||||
"gen-icons-json",
|
||||
gulp.parallel("gen-icons-hassio", "gen-icons-mdi"),
|
||||
"webpack-watch-hassio"
|
||||
)
|
||||
);
|
||||
@@ -26,9 +26,9 @@ gulp.task(
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean-hassio",
|
||||
"gen-icons-json",
|
||||
gulp.parallel("gen-icons-hassio", "gen-icons-mdi"),
|
||||
"webpack-prod-hassio",
|
||||
...// Don't compress running tests
|
||||
(envVars.isTest() ? [] : ["compress-hassio"])
|
||||
(envVars.isTravis ? [] : ["compress-hassio"])
|
||||
)
|
||||
);
|
||||
|
||||
@@ -14,20 +14,13 @@ const { mapFiles } = require("../util");
|
||||
const env = require("../env");
|
||||
const paths = require("../paths");
|
||||
|
||||
const inFrontendDir = "translations/frontend";
|
||||
const inBackendDir = "translations/backend";
|
||||
const inDir = "translations";
|
||||
const workDir = "build-translations";
|
||||
const fullDir = workDir + "/full";
|
||||
const coreDir = workDir + "/core";
|
||||
const outDir = workDir + "/output";
|
||||
let mergeBackend = false;
|
||||
|
||||
gulp.task("translations-enable-merge-backend", (done) => {
|
||||
mergeBackend = true;
|
||||
done();
|
||||
});
|
||||
|
||||
String.prototype.rsplit = function (sep, maxsplit) {
|
||||
String.prototype.rsplit = function(sep, maxsplit) {
|
||||
var split = this.split(sep);
|
||||
return maxsplit
|
||||
? [split.slice(0, -maxsplit).join(sep)].concat(split.slice(-maxsplit))
|
||||
@@ -52,7 +45,7 @@ const TRANSLATION_FRAGMENTS = [
|
||||
|
||||
function recursiveFlatten(prefix, data) {
|
||||
let output = {};
|
||||
Object.keys(data).forEach(function (key) {
|
||||
Object.keys(data).forEach(function(key) {
|
||||
if (typeof data[key] === "object") {
|
||||
output = {
|
||||
...output,
|
||||
@@ -114,12 +107,7 @@ function lokaliseTransform(data, original, file) {
|
||||
output[key] = lokaliseTransform(value, original, file);
|
||||
} else {
|
||||
output[key] = value.replace(re_key_reference, (match, key) => {
|
||||
const replace = key.split("::").reduce((tr, k) => {
|
||||
if (!tr) {
|
||||
throw Error(`Invalid key placeholder ${key} in ${file.path}`);
|
||||
}
|
||||
return tr[k];
|
||||
}, original);
|
||||
const replace = key.split("::").reduce((tr, k) => tr[k], original);
|
||||
if (typeof replace !== "string") {
|
||||
throw Error(`Invalid key placeholder ${key} in ${file.path}`);
|
||||
}
|
||||
@@ -130,7 +118,7 @@ function lokaliseTransform(data, original, file) {
|
||||
return output;
|
||||
}
|
||||
|
||||
gulp.task("clean-translations", function () {
|
||||
gulp.task("clean-translations", function() {
|
||||
return del([workDir]);
|
||||
});
|
||||
|
||||
@@ -141,7 +129,7 @@ gulp.task("ensure-translations-build-dir", (done) => {
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("create-test-metadata", function (cb) {
|
||||
gulp.task("create-test-metadata", function(cb) {
|
||||
fs.writeFile(
|
||||
workDir + "/testMetadata.json",
|
||||
JSON.stringify({
|
||||
@@ -159,7 +147,7 @@ gulp.task(
|
||||
return gulp
|
||||
.src(path.join(paths.translations_src, "en.json"))
|
||||
.pipe(
|
||||
transform(function (data, file) {
|
||||
transform(function(data, file) {
|
||||
return recursiveEmpty(data);
|
||||
})
|
||||
)
|
||||
@@ -177,40 +165,28 @@ gulp.task(
|
||||
* project is buildable immediately after merging new translation keys, since
|
||||
* the Lokalise update to translations/en.json will not happen immediately.
|
||||
*/
|
||||
gulp.task("build-master-translation", function () {
|
||||
const src = [path.join(paths.translations_src, "en.json")];
|
||||
|
||||
if (mergeBackend) {
|
||||
src.push(path.join(inBackendDir, "en.json"));
|
||||
}
|
||||
|
||||
gulp.task("build-master-translation", function() {
|
||||
return gulp
|
||||
.src(src)
|
||||
.src(path.join(paths.translations_src, "en.json"))
|
||||
.pipe(
|
||||
transform(function (data, file) {
|
||||
transform(function(data, file) {
|
||||
return lokaliseTransform(data, data, file);
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
merge({
|
||||
fileName: "translationMaster.json",
|
||||
})
|
||||
)
|
||||
.pipe(rename("translationMaster.json"))
|
||||
.pipe(gulp.dest(workDir));
|
||||
});
|
||||
|
||||
gulp.task("build-merged-translations", function () {
|
||||
gulp.task("build-merged-translations", function() {
|
||||
return gulp
|
||||
.src([inFrontendDir + "/*.json", workDir + "/test.json"], {
|
||||
allowEmpty: true,
|
||||
})
|
||||
.src([inDir + "/*.json", workDir + "/test.json"], { allowEmpty: true })
|
||||
.pipe(
|
||||
transform(function (data, file) {
|
||||
transform(function(data, file) {
|
||||
return lokaliseTransform(data, data, file);
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
foreach(function (stream, file) {
|
||||
foreach(function(stream, file) {
|
||||
// For each language generate a merged json file. It begins with the master
|
||||
// translation as a failsafe for untranslated strings, and merges all parent
|
||||
// tags into one file for each specific subtag
|
||||
@@ -226,10 +202,7 @@ gulp.task("build-merged-translations", function () {
|
||||
if (lang === "test") {
|
||||
src.push(workDir + "/test.json");
|
||||
} else if (lang !== "en") {
|
||||
src.push(inFrontendDir + "/" + lang + ".json");
|
||||
if (mergeBackend) {
|
||||
src.push(inBackendDir + "/" + lang + ".json");
|
||||
}
|
||||
src.push(inDir + "/" + lang + ".json");
|
||||
}
|
||||
}
|
||||
return gulp
|
||||
@@ -250,7 +223,7 @@ var taskName;
|
||||
const splitTasks = [];
|
||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||
taskName = "build-translation-fragment-" + fragment;
|
||||
gulp.task(taskName, function () {
|
||||
gulp.task(taskName, function() {
|
||||
// Return only the translations for this fragment.
|
||||
return gulp
|
||||
.src(fullDir + "/*.json")
|
||||
@@ -269,12 +242,12 @@ TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||
});
|
||||
|
||||
taskName = "build-translation-core";
|
||||
gulp.task(taskName, function () {
|
||||
gulp.task(taskName, function() {
|
||||
// Remove the fragment translations from the core translation.
|
||||
return gulp
|
||||
.src(fullDir + "/*.json")
|
||||
.pipe(
|
||||
transform((data, file) => {
|
||||
transform((data) => {
|
||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||
delete data.ui.panel[fragment];
|
||||
});
|
||||
@@ -286,7 +259,7 @@ gulp.task(taskName, function () {
|
||||
|
||||
splitTasks.push(taskName);
|
||||
|
||||
gulp.task("build-flattened-translations", function () {
|
||||
gulp.task("build-flattened-translations", function() {
|
||||
// Flatten the split versions of our translations, and move them into outDir
|
||||
return gulp
|
||||
.src(
|
||||
@@ -296,7 +269,7 @@ gulp.task("build-flattened-translations", function () {
|
||||
{ base: workDir }
|
||||
)
|
||||
.pipe(
|
||||
transform(function (data) {
|
||||
transform(function(data) {
|
||||
// Polymer.AppLocalizeBehavior requires flattened json
|
||||
return flatten(data);
|
||||
})
|
||||
@@ -319,11 +292,10 @@ gulp.task(
|
||||
function fingerprintTranslationFiles() {
|
||||
// Fingerprint full file of each language
|
||||
const files = fs.readdirSync(fullDir);
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
fingerprints[files[i].split(".")[0]] = {
|
||||
// In dev we create fake hashes
|
||||
hash: env.isProdBuild()
|
||||
hash: env.isProdBuild
|
||||
? crypto
|
||||
.createHash("md5")
|
||||
.update(fs.readFileSync(path.join(fullDir, files[i]), "utf-8"))
|
||||
@@ -360,7 +332,7 @@ gulp.task(
|
||||
gulp.series(
|
||||
"clean-translations",
|
||||
"ensure-translations-build-dir",
|
||||
env.isProdBuild() ? (done) => done() : "create-test-translation",
|
||||
env.isProdBuild ? (done) => done() : "create-test-translation",
|
||||
"build-master-translation",
|
||||
"build-merged-translations",
|
||||
gulp.parallel(...splitTasks),
|
||||
@@ -378,7 +350,7 @@ gulp.task(
|
||||
)
|
||||
.pipe(merge({}))
|
||||
.pipe(
|
||||
transform(function (data) {
|
||||
transform(function(data) {
|
||||
const newData = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
// Filter out translations without native name.
|
||||
|
||||
@@ -28,7 +28,7 @@ const runDevServer = ({
|
||||
open: true,
|
||||
watchContentBase: true,
|
||||
contentBase,
|
||||
}).listen(port, listenHost, function (err) {
|
||||
}).listen(port, listenHost, function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
@@ -150,8 +150,9 @@ gulp.task(
|
||||
|
||||
gulp.task("webpack-dev-server-gallery", () => {
|
||||
runDevServer({
|
||||
// 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(
|
||||
createGalleryConfig({ latestBuild: true, isProdBuild: false })
|
||||
),
|
||||
contentBase: paths.gallery_root,
|
||||
port: 8100,
|
||||
});
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
const webpack = require("webpack");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const WorkboxPlugin = require("workbox-webpack-plugin");
|
||||
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||
const paths = require("./paths.js");
|
||||
const env = require("./env.js");
|
||||
const { babelLoaderConfig } = require("./babel.js");
|
||||
|
||||
let version = fs
|
||||
.readFileSync(path.resolve(paths.polymer_dir, "setup.py"), "utf8")
|
||||
.match(/\d{8}\.\d+/);
|
||||
if (!version) {
|
||||
throw Error("Version not found");
|
||||
}
|
||||
version = version[0];
|
||||
|
||||
const createWebpackConfig = ({
|
||||
entry,
|
||||
outputRoot,
|
||||
@@ -30,11 +38,17 @@ const createWebpackConfig = ({
|
||||
test: /\.css$/,
|
||||
use: "raw-loader",
|
||||
},
|
||||
{
|
||||
test: /\.(html)$/,
|
||||
use: {
|
||||
loader: "html-loader",
|
||||
options: {
|
||||
exportAsEs6Default: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
externals: {
|
||||
esprima: "esprima",
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
@@ -54,9 +68,8 @@ const createWebpackConfig = ({
|
||||
new webpack.DefinePlugin({
|
||||
__DEV__: !isProdBuild,
|
||||
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
||||
__VERSION__: JSON.stringify(env.version()),
|
||||
__VERSION__: JSON.stringify(version),
|
||||
__DEMO__: false,
|
||||
__BACKWARDS_COMPAT__: false,
|
||||
__STATIC_PATH__: "/static/",
|
||||
"process.env.NODE_ENV": JSON.stringify(
|
||||
isProdBuild ? "production" : "development"
|
||||
@@ -83,6 +96,14 @@ const createWebpackConfig = ({
|
||||
].filter(Boolean),
|
||||
resolve: {
|
||||
extensions: [".ts", ".js", ".json"],
|
||||
alias: {
|
||||
react: "preact-compat",
|
||||
"react-dom": "preact-compat",
|
||||
// Not necessary unless you consume a module using `createClass`
|
||||
"create-react-class": "preact-compat/lib/create-react-class",
|
||||
// Not necessary unless you consume a module requiring `react-dom-factories`
|
||||
"react-dom-factories": "preact-compat/lib/react-dom-factories",
|
||||
},
|
||||
},
|
||||
output: {
|
||||
filename: ({ chunk }) => {
|
||||
@@ -115,6 +136,7 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
core: "./src/entrypoints/core.ts",
|
||||
compatibility: "./src/entrypoints/compatibility.ts",
|
||||
"custom-panel": "./src/entrypoints/custom-panel.ts",
|
||||
"hass-icons": "./src/entrypoints/hass-icons.ts",
|
||||
},
|
||||
outputRoot: paths.root,
|
||||
isProdBuild,
|
||||
@@ -133,7 +155,7 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
`/static/translations/${englishFilename}`
|
||||
] = `build-translations/output/${englishFilename}`;
|
||||
|
||||
translationMetadata.fragments.forEach((fragment) => {
|
||||
Object.keys(translationMetadata.fragments).forEach((fragment) => {
|
||||
workBoxTranslationsTemplatedURLs[
|
||||
`/static/translations/${fragment}/${englishFilename}`
|
||||
] = `build-translations/output/${fragment}/${englishFilename}`;
|
||||
@@ -176,7 +198,7 @@ const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
},
|
||||
outputRoot: paths.demo_root,
|
||||
defineOverlay: {
|
||||
__VERSION__: JSON.stringify(`DEMO-${env.version()}`),
|
||||
__VERSION__: JSON.stringify(`DEMO-${version}`),
|
||||
__DEMO__: true,
|
||||
},
|
||||
isProdBuild,
|
||||
@@ -199,9 +221,6 @@ const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
||||
outputRoot: paths.cast_root,
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
defineOverlay: {
|
||||
__BACKWARDS_COMPAT__: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -226,6 +245,9 @@ const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
||||
};
|
||||
|
||||
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
||||
if (!latestBuild) {
|
||||
throw new Error("Gallery only supports latest build!");
|
||||
}
|
||||
const config = createWebpackConfig({
|
||||
entry: {
|
||||
entrypoint: path.resolve(paths.gallery_dir, "src/entrypoint.js"),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import "../../../src/resources/ha-style";
|
||||
import "../../../src/resources/roboto";
|
||||
import "../../../src/components/ha-iconset-svg";
|
||||
import "../../../src/resources/hass-icons";
|
||||
import "./layout/hc-connect";
|
||||
|
||||
@@ -1,53 +1,51 @@
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { Auth, Connection } from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
html,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import { CastManager } from "../../../../src/cast/cast_manager";
|
||||
import {
|
||||
castSendShowLovelaceView,
|
||||
ensureConnectedCastSession,
|
||||
} from "../../../../src/cast/receiver_messages";
|
||||
import {
|
||||
askWrite,
|
||||
enableWrite,
|
||||
saveTokens,
|
||||
} from "../../../../src/common/auth/token_storage";
|
||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||
import { toggleAttribute } from "../../../../src/common/dom/toggle_attribute";
|
||||
import { Connection, Auth } from "home-assistant-js-websocket";
|
||||
import "@polymer/iron-icon";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "../../../../src/components/ha-icon";
|
||||
import {
|
||||
getLegacyLovelaceCollection,
|
||||
getLovelaceCollection,
|
||||
LovelaceConfig,
|
||||
} from "../../../../src/data/lovelace";
|
||||
enableWrite,
|
||||
askWrite,
|
||||
saveTokens,
|
||||
} from "../../../../src/common/auth/token_storage";
|
||||
import {
|
||||
ensureConnectedCastSession,
|
||||
castSendShowLovelaceView,
|
||||
} from "../../../../src/cast/receiver_messages";
|
||||
import "../../../../src/layouts/loading-screen";
|
||||
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
||||
import { CastManager } from "../../../../src/cast/cast_manager";
|
||||
import {
|
||||
LovelaceConfig,
|
||||
getLovelaceCollection,
|
||||
getLegacyLovelaceCollection,
|
||||
} from "../../../../src/data/lovelace";
|
||||
import "./hc-layout";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
||||
import { toggleAttribute } from "../../../../src/common/dom/toggle_attribute";
|
||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||
|
||||
@customElement("hc-cast")
|
||||
class HcCast extends LitElement {
|
||||
@property() public auth!: Auth;
|
||||
|
||||
@property() public connection!: Connection;
|
||||
|
||||
@property() public castManager!: CastManager;
|
||||
|
||||
@property() private askWrite = false;
|
||||
|
||||
@property() private lovelaceConfig?: LovelaceConfig | null;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (this.lovelaceConfig === undefined) {
|
||||
return html` <loading-screen></loading-screen>> `;
|
||||
return html`
|
||||
<loading-screen></loading-screen>>
|
||||
`;
|
||||
}
|
||||
|
||||
const error =
|
||||
@@ -77,12 +75,14 @@ class HcCast extends LitElement {
|
||||
`
|
||||
: ""}
|
||||
${error
|
||||
? html` <div class="card-content">${error}</div> `
|
||||
? html`
|
||||
<div class="card-content">${error}</div>
|
||||
`
|
||||
: !this.castManager.status
|
||||
? html`
|
||||
<p class="center-item">
|
||||
<mwc-button raised @click=${this._handleLaunch}>
|
||||
<ha-icon icon="hass:cast"></ha-icon>
|
||||
<iron-icon icon="hass:cast"></iron-icon>
|
||||
Start Casting
|
||||
</mwc-button>
|
||||
</p>
|
||||
@@ -120,7 +120,7 @@ class HcCast extends LitElement {
|
||||
${this.castManager.status
|
||||
? html`
|
||||
<mwc-button @click=${this._handleLaunch}>
|
||||
<ha-icon icon="hass:cast-connected"></ha-icon>
|
||||
<iron-icon icon="hass:cast-connected"></iron-icon>
|
||||
Manage
|
||||
</mwc-button>
|
||||
`
|
||||
@@ -242,7 +242,7 @@ class HcCast extends LitElement {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
mwc-button ha-icon {
|
||||
mwc-button iron-icon {
|
||||
margin-right: 8px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import {
|
||||
Auth,
|
||||
Connection,
|
||||
createConnection,
|
||||
ERR_CANNOT_CONNECT,
|
||||
ERR_HASS_HOST_REQUIRED,
|
||||
ERR_INVALID_AUTH,
|
||||
ERR_INVALID_HTTPS_TO_HTTP,
|
||||
getAuth,
|
||||
getAuthOptions,
|
||||
} from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
customElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
html,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import { CastManager, getCastManager } from "../../../../src/cast/cast_manager";
|
||||
import { castSendShowDemo } from "../../../../src/cast/receiver_messages";
|
||||
import {
|
||||
getAuth,
|
||||
createConnection,
|
||||
Auth,
|
||||
getAuthOptions,
|
||||
ERR_HASS_HOST_REQUIRED,
|
||||
ERR_INVALID_HTTPS_TO_HTTP,
|
||||
Connection,
|
||||
ERR_CANNOT_CONNECT,
|
||||
ERR_INVALID_AUTH,
|
||||
} from "home-assistant-js-websocket";
|
||||
import "@polymer/iron-icon";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import {
|
||||
loadTokens,
|
||||
saveTokens,
|
||||
} from "../../../../src/common/auth/token_storage";
|
||||
import "../../../../src/components/ha-icon";
|
||||
import "../../../../src/layouts/loading-screen";
|
||||
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
||||
import { CastManager, getCastManager } from "../../../../src/cast/cast_manager";
|
||||
import "./hc-layout";
|
||||
import { castSendShowDemo } from "../../../../src/cast/receiver_messages";
|
||||
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
||||
|
||||
const seeFAQ = (qid) => html`
|
||||
See <a href="./faq.html${qid ? `#${qid}` : ""}">the FAQ</a> for more
|
||||
@@ -61,19 +61,13 @@ const INTRO = html`
|
||||
@customElement("hc-connect")
|
||||
export class HcConnect extends LitElement {
|
||||
@property() private loading = false;
|
||||
|
||||
// If we had stored credentials but we cannot connect,
|
||||
// show a screen asking retry or logout.
|
||||
@property() private cannotConnect = false;
|
||||
|
||||
@property() private error?: string | TemplateResult;
|
||||
|
||||
@property() private auth?: Auth;
|
||||
|
||||
@property() private connection?: Connection;
|
||||
|
||||
@property() private castManager?: CastManager | null;
|
||||
|
||||
private openDemo = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
@@ -98,7 +92,9 @@ export class HcConnect extends LitElement {
|
||||
}
|
||||
|
||||
if (this.castManager === undefined || this.loading) {
|
||||
return html` <loading-screen></loading-screen> `;
|
||||
return html`
|
||||
<loading-screen></loading-screen>
|
||||
`;
|
||||
}
|
||||
|
||||
if (this.castManager === null) {
|
||||
@@ -131,16 +127,20 @@ export class HcConnect extends LitElement {
|
||||
@keydown=${this._handleInputKeyDown}
|
||||
></paper-input>
|
||||
</p>
|
||||
${this.error ? html` <p class="error">${this.error}</p> ` : ""}
|
||||
${this.error
|
||||
? html`
|
||||
<p class="error">${this.error}</p>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._handleDemo}>
|
||||
Show Demo
|
||||
<ha-icon
|
||||
<iron-icon
|
||||
.icon=${this.castManager.castState === "CONNECTED"
|
||||
? "hass:cast-connected"
|
||||
: "hass:cast"}
|
||||
></ha-icon>
|
||||
></iron-icon>
|
||||
</mwc-button>
|
||||
<div class="spacer"></div>
|
||||
<mwc-button @click=${this._handleConnect}>Authorize</mwc-button>
|
||||
@@ -211,8 +211,7 @@ export class HcConnect extends LitElement {
|
||||
if (value === "") {
|
||||
this.error = "Please enter a Home Assistant URL.";
|
||||
return;
|
||||
}
|
||||
if (value.indexOf("://") === -1) {
|
||||
} else if (value.indexOf("://") === -1) {
|
||||
this.error =
|
||||
"Please enter your full URL, including the protocol part (https://).";
|
||||
return;
|
||||
@@ -316,7 +315,7 @@ export class HcConnect extends LitElement {
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
mwc-button ha-icon {
|
||||
mwc-button iron-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
import {
|
||||
customElement,
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
html,
|
||||
CSSResult,
|
||||
css,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import {
|
||||
Auth,
|
||||
Connection,
|
||||
getUser,
|
||||
HassUser,
|
||||
getUser,
|
||||
} from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "../../../../src/components/ha-card";
|
||||
|
||||
@customElement("hc-layout")
|
||||
class HcLayout extends LitElement {
|
||||
@property() public subtitle?: string | undefined;
|
||||
|
||||
@property() public auth?: Auth;
|
||||
|
||||
@property() public connection?: Connection;
|
||||
|
||||
@property() public user?: HassUser;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
@@ -40,7 +37,11 @@ class HcLayout extends LitElement {
|
||||
this.auth.data.hassUrl.indexOf("//") + 2
|
||||
)}</a
|
||||
>
|
||||
${this.user ? html` – ${this.user.name} ` : ""}
|
||||
${this.user
|
||||
? html`
|
||||
– ${this.user.name}
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
/* eslint-disable no-undef */
|
||||
export const castContext = cast.framework.CastReceiverContext.getInstance();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { convertEntities, Entity } from "../../../../src/fake_data/entity";
|
||||
import { Entity, convertEntities } from "../../../../src/fake_data/entity";
|
||||
|
||||
export const castDemoEntities: () => Entity[] = () =>
|
||||
convertEntities({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
LovelaceCardConfig,
|
||||
LovelaceConfig,
|
||||
LovelaceCardConfig,
|
||||
} from "../../../../src/data/lovelace";
|
||||
import { castContext } from "../cast_context";
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/* eslint-disable no-undef */
|
||||
import { CAST_NS } from "../../../src/cast/const";
|
||||
import { HassMessage } from "../../../src/cast/receiver_messages";
|
||||
import "../../../src/resources/custom-card-support";
|
||||
import { castContext } from "./cast_context";
|
||||
import { HcMain } from "./layout/hc-main";
|
||||
import { ReceivedMessage } from "./types";
|
||||
import { HassMessage } from "../../../src/cast/receiver_messages";
|
||||
import { HcMain } from "./layout/hc-main";
|
||||
import { CAST_NS } from "../../../src/cast/const";
|
||||
|
||||
const controller = new HcMain();
|
||||
document.body.append(controller);
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import { customElement, html, property, TemplateResult } from "lit-element";
|
||||
import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import { HassElement } from "../../../../src/state/hass-element";
|
||||
import "./hc-lovelace";
|
||||
import { customElement, TemplateResult, html, property } from "lit-element";
|
||||
import {
|
||||
MockHomeAssistant,
|
||||
provideHass,
|
||||
} from "../../../../src/fake_data/provide_hass";
|
||||
import { HassElement } from "../../../../src/state/hass-element";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import { castDemoEntities } from "../demo/cast-demo-entities";
|
||||
import { castDemoLovelace } from "../demo/cast-demo-lovelace";
|
||||
import "./hc-lovelace";
|
||||
import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||
|
||||
@customElement("hc-demo")
|
||||
class HcDemo extends HassElement {
|
||||
@property() public lovelacePath!: string;
|
||||
|
||||
@property() private _lovelaceConfig?: LovelaceConfig;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
@@ -29,7 +28,6 @@ class HcDemo extends HassElement {
|
||||
></hc-lovelace>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
this._initialize();
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
html,
|
||||
customElement,
|
||||
CSSResult,
|
||||
css,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
|
||||
@customElement("hc-launch-screen")
|
||||
class HcLaunchScreen extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() public error?: string;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
@@ -23,7 +22,11 @@ class HcLaunchScreen extends LitElement {
|
||||
/>
|
||||
<div class="status">
|
||||
${this.hass ? "Connected" : "Not Connected"}
|
||||
${this.error ? html` <p>Error: ${this.error}</p> ` : ""}
|
||||
${this.error
|
||||
? html`
|
||||
<p>Error: ${this.error}</p>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
customElement,
|
||||
html,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
html,
|
||||
customElement,
|
||||
CSSResult,
|
||||
css,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
||||
import "../../../../src/panels/lovelace/views/hui-panel-view";
|
||||
import "../../../../src/panels/lovelace/views/hui-view";
|
||||
import "../../../../src/panels/lovelace/views/hui-panel-view";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
||||
import "./hc-launch-screen";
|
||||
|
||||
@customElement("hc-lovelace")
|
||||
@@ -46,7 +46,6 @@ class HcLovelace extends LitElement {
|
||||
? html`
|
||||
<hui-panel-view
|
||||
.hass=${this.hass}
|
||||
.lovelace=${lovelace}
|
||||
.config=${this.lovelaceConfig.views[index]}
|
||||
></hui-panel-view>
|
||||
`
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
import {
|
||||
createConnection,
|
||||
getAuth,
|
||||
createConnection,
|
||||
UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { customElement, html, property, TemplateResult } from "lit-element";
|
||||
import { CAST_NS } from "../../../../src/cast/const";
|
||||
import {
|
||||
ConnectMessage,
|
||||
GetStatusMessage,
|
||||
HassMessage,
|
||||
ShowDemoMessage,
|
||||
ShowLovelaceViewMessage,
|
||||
} from "../../../../src/cast/receiver_messages";
|
||||
import { ReceiverStatusMessage } from "../../../../src/cast/sender_messages";
|
||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||
import { isNavigationClick } from "../../../../src/common/dom/is-navigation-click";
|
||||
import {
|
||||
fetchResources,
|
||||
getLegacyLovelaceCollection,
|
||||
getLovelaceCollection,
|
||||
LegacyLovelaceConfig,
|
||||
LovelaceConfig,
|
||||
} from "../../../../src/data/lovelace";
|
||||
import { loadLovelaceResources } from "../../../../src/panels/lovelace/common/load-resources";
|
||||
import { customElement, TemplateResult, html, property } from "lit-element";
|
||||
import { HassElement } from "../../../../src/state/hass-element";
|
||||
import { castContext } from "../cast_context";
|
||||
import {
|
||||
HassMessage,
|
||||
ConnectMessage,
|
||||
ShowLovelaceViewMessage,
|
||||
GetStatusMessage,
|
||||
ShowDemoMessage,
|
||||
} from "../../../../src/cast/receiver_messages";
|
||||
import {
|
||||
LovelaceConfig,
|
||||
getLovelaceCollection,
|
||||
fetchResources,
|
||||
LegacyLovelaceConfig,
|
||||
getLegacyLovelaceCollection,
|
||||
} from "../../../../src/data/lovelace";
|
||||
import "./hc-launch-screen";
|
||||
import { castContext } from "../cast_context";
|
||||
import { CAST_NS } from "../../../../src/cast/const";
|
||||
import { ReceiverStatusMessage } from "../../../../src/cast/sender_messages";
|
||||
import { loadLovelaceResources } from "../../../../src/panels/lovelace/common/load-resources";
|
||||
import { isNavigationClick } from "../../../../src/common/dom/is-navigation-click";
|
||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||
|
||||
let resourcesLoaded = false;
|
||||
|
||||
@@ -40,7 +40,6 @@ export class HcMain extends HassElement {
|
||||
@property() private _error?: string;
|
||||
|
||||
private _unsubLovelace?: UnsubscribeFunc;
|
||||
|
||||
private _urlPath?: string | null;
|
||||
|
||||
public processIncomingMessage(msg: HassMessage) {
|
||||
@@ -53,14 +52,16 @@ export class HcMain extends HassElement {
|
||||
} else if (msg.type === "show_demo") {
|
||||
this._handleShowDemo(msg);
|
||||
} else {
|
||||
// eslint-disable-next-line no-console
|
||||
// tslint:disable-next-line: no-console
|
||||
console.warn("unknown msg type", msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (this._showDemo) {
|
||||
return html` <hc-demo .lovelacePath=${this._lovelacePath}></hc-demo> `;
|
||||
return html`
|
||||
<hc-demo .lovelacePath=${this._lovelacePath}></hc-demo>
|
||||
`;
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -90,17 +91,15 @@ export class HcMain extends HassElement {
|
||||
super.firstUpdated(changedProps);
|
||||
import("../second-load");
|
||||
window.addEventListener("location-changed", () => {
|
||||
const panelPath = `/${this._urlPath || "lovelace"}/`;
|
||||
if (location.pathname.startsWith(panelPath)) {
|
||||
this._lovelacePath = location.pathname.substr(panelPath.length);
|
||||
if (location.pathname.startsWith("/lovelace/")) {
|
||||
this._lovelacePath = location.pathname.substr(10);
|
||||
this._sendStatus();
|
||||
}
|
||||
});
|
||||
document.body.addEventListener("click", (ev) => {
|
||||
const panelPath = `/${this._urlPath || "lovelace"}/`;
|
||||
const href = isNavigationClick(ev);
|
||||
if (href && href.startsWith(panelPath)) {
|
||||
this._lovelacePath = href.substr(panelPath.length);
|
||||
if (href && href.startsWith("/lovelace/")) {
|
||||
this._lovelacePath = href.substr(10);
|
||||
this._sendStatus();
|
||||
}
|
||||
});
|
||||
@@ -172,9 +171,6 @@ export class HcMain extends HassElement {
|
||||
this._error = "Cannot show Lovelace because we're not connected.";
|
||||
return;
|
||||
}
|
||||
if (msg.urlPath === "lovelace") {
|
||||
msg.urlPath = null;
|
||||
}
|
||||
if (!this._unsubLovelace || this._urlPath !== msg.urlPath) {
|
||||
this._urlPath = msg.urlPath;
|
||||
if (this._unsubLovelace) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import "web-animations-js/web-animations-next-lite.min";
|
||||
import "../../../src/resources/hass-icons";
|
||||
import "../../../src/resources/roboto";
|
||||
import "../../../src/components/ha-iconset-svg";
|
||||
import "./layout/hc-lovelace";
|
||||
|
||||
@@ -6,6 +6,6 @@ const { isProdBuild } = require("../build-scripts/env.js");
|
||||
const latestBuild = true;
|
||||
|
||||
module.exports = createCastConfig({
|
||||
isProdBuild: isProdBuild(),
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
});
|
||||
|
||||
BIN
demo/public/api/camera_proxy_stream/camera.backyard
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
demo/public/api/camera_proxy_stream/camera.driveway
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
demo/public/api/camera_proxy_stream/camera.patio
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
demo/public/api/camera_proxy_stream/camera.porch
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
demo/public/api/media_player_proxy/media_player.family_room_2
Normal file
|
After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 803 B After Width: | Height: | Size: 805 B |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 781 B |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 115 KiB |
|
Before Width: | Height: | Size: 185 KiB |
@@ -291,7 +291,16 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
state: "13:21",
|
||||
attributes: {
|
||||
attribution: "Data provided by Ring.com",
|
||||
device_id: "e04f434dca02",
|
||||
firmware: "Up to Date",
|
||||
kind: "lpd_v2",
|
||||
timezone: "America/New_York",
|
||||
type: "doorbots",
|
||||
wifi_name: "RingOfSecurity-hUrGKNlhR",
|
||||
created_at: "2019-01-22T13:21:03-05:00",
|
||||
answered: false,
|
||||
recording_status: "ready",
|
||||
category: "motion",
|
||||
friendly_name: "Front Door Last Motion",
|
||||
icon: "hademo:history",
|
||||
},
|
||||
@@ -304,7 +313,8 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
"cbd8dfac9efb441f19168e271cb8629b0372d0c1f721353394b23ed0202013b0",
|
||||
motion_detection: true,
|
||||
friendly_name: "Patio",
|
||||
entity_picture: "/assets/arsaboo/images/camera.patio.jpg",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.patio?token=cbd8dfac9efb441f19168e271cb8629b0372d0c1f721353394b23ed0202013b0",
|
||||
supported_features: 0,
|
||||
},
|
||||
},
|
||||
@@ -316,7 +326,8 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
"479b332e0a7cad4c58e0fb98a1ecb7942e3b225190adb93a1341edfa7daf45b0",
|
||||
motion_detection: true,
|
||||
friendly_name: "Porch",
|
||||
entity_picture: "/assets/arsaboo/images/camera.porch.jpg",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.porch?token=479b332e0a7cad4c58e0fb98a1ecb7942e3b225190adb93a1341edfa7daf45b0",
|
||||
supported_features: 0,
|
||||
},
|
||||
},
|
||||
@@ -328,7 +339,8 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
"9381b2e4edd1bb21e868e2193f5d132a5fae153ce4f458451d979a02712b4642",
|
||||
motion_detection: true,
|
||||
friendly_name: "Backyard",
|
||||
entity_picture: "/assets/arsaboo/images/camera.backyard.jpg",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.backyard?token=9381b2e4edd1bb21e868e2193f5d132a5fae153ce4f458451d979a02712b4642",
|
||||
supported_features: 0,
|
||||
},
|
||||
},
|
||||
@@ -340,7 +352,8 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
"ac38bf88c2c5896eed66ae15739a3e726677f92d79e0d57f83f726ac28bda746",
|
||||
motion_detection: true,
|
||||
friendly_name: "Driveway",
|
||||
entity_picture: "/assets/arsaboo/images/camera.driveway.jpg",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.driveway?token=ac38bf88c2c5896eed66ae15739a3e726677f92d79e0d57f83f726ac28bda746",
|
||||
supported_features: 0,
|
||||
},
|
||||
},
|
||||
@@ -464,7 +477,8 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.names.family_room"
|
||||
),
|
||||
entity_picture: "/assets/arsaboo/images/media_player_family_room.jpg",
|
||||
entity_picture:
|
||||
"/api/media_player_proxy/media_player.family_room_2?token=be41a86e2a360761d67c36a010b09654b730deec092016ee92aafef79b1978ff&cache=e03d22fb103202e7",
|
||||
supported_features: 64063,
|
||||
},
|
||||
},
|
||||
@@ -473,7 +487,16 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
state: "06:44",
|
||||
attributes: {
|
||||
attribution: "Data provided by Ring.com",
|
||||
device_id: "e04f434dca02",
|
||||
firmware: "Up to Date",
|
||||
kind: "lpd_v2",
|
||||
timezone: "America/New_York",
|
||||
type: "doorbots",
|
||||
wifi_name: "RingOfSecurity-hUrGKNlhR",
|
||||
created_at: "2019-01-22T06:44:31-05:00",
|
||||
answered: false,
|
||||
recording_status: "ready",
|
||||
category: "ding",
|
||||
friendly_name: "Front Door Last Ding",
|
||||
icon: "hademo:history",
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DemoConfig } from "../types";
|
||||
import { demoEntitiesArsaboo } from "./entities";
|
||||
import { demoLovelaceArsaboo } from "./lovelace";
|
||||
import { demoEntitiesArsaboo } from "./entities";
|
||||
import { demoThemeArsaboo } from "./theme";
|
||||
|
||||
export const demoArsaboo: DemoConfig = {
|
||||
|
||||