mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-18 05:39:26 +00:00
Compare commits
3 Commits
data_disk_
...
fix-number
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a63e788ced | ||
![]() |
c377c01c65 | ||
![]() |
aaf65e0599 |
@@ -4,7 +4,7 @@
|
|||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
"context": ".."
|
"context": ".."
|
||||||
},
|
},
|
||||||
"appPort": "8124:8123",
|
"appPort": 8123,
|
||||||
"context": "..",
|
"context": "..",
|
||||||
"postCreateCommand": "script/bootstrap",
|
"postCreateCommand": "script/bootstrap",
|
||||||
"extensions": [
|
"extensions": [
|
||||||
|
119
.eslintrc.json
119
.eslintrc.json
@@ -4,7 +4,8 @@
|
|||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
"plugin:wc/recommended",
|
"plugin:wc/recommended",
|
||||||
"plugin:lit/recommended",
|
"plugin:lit/recommended",
|
||||||
"prettier"
|
"prettier",
|
||||||
|
"prettier/@typescript-eslint"
|
||||||
],
|
],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
@@ -28,89 +29,63 @@
|
|||||||
"__BUILD__": false,
|
"__BUILD__": false,
|
||||||
"__VERSION__": false,
|
"__VERSION__": false,
|
||||||
"__STATIC_PATH__": false,
|
"__STATIC_PATH__": false,
|
||||||
"Polymer": true
|
"Polymer": true,
|
||||||
|
"webkitSpeechRecognition": false,
|
||||||
|
"ResizeObserver": false
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es6": true
|
"es6": true
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"class-methods-use-this": "off",
|
"class-methods-use-this": 0,
|
||||||
"new-cap": "off",
|
"new-cap": 0,
|
||||||
"prefer-template": "off",
|
"prefer-template": 0,
|
||||||
"object-shorthand": "off",
|
"object-shorthand": 0,
|
||||||
"func-names": "off",
|
"func-names": 0,
|
||||||
"no-underscore-dangle": "off",
|
"prefer-arrow-callback": 0,
|
||||||
"strict": "off",
|
"no-underscore-dangle": 0,
|
||||||
"no-plusplus": "off",
|
"strict": 0,
|
||||||
"no-bitwise": "error",
|
"prefer-spread": 0,
|
||||||
"comma-dangle": "off",
|
"no-plusplus": 0,
|
||||||
"vars-on-top": "off",
|
"no-bitwise": 2,
|
||||||
"no-continue": "off",
|
"comma-dangle": 0,
|
||||||
"no-param-reassign": "off",
|
"vars-on-top": 0,
|
||||||
"no-multi-assign": "off",
|
"no-continue": 0,
|
||||||
"no-console": "error",
|
"no-param-reassign": 0,
|
||||||
"radix": "off",
|
"no-multi-assign": 0,
|
||||||
"no-alert": "off",
|
"no-console": 2,
|
||||||
"no-nested-ternary": "off",
|
"radix": 0,
|
||||||
"prefer-destructuring": "off",
|
"no-alert": 0,
|
||||||
|
"no-return-await": 0,
|
||||||
|
"no-nested-ternary": 0,
|
||||||
|
"prefer-destructuring": 0,
|
||||||
"no-restricted-globals": [2, "event"],
|
"no-restricted-globals": [2, "event"],
|
||||||
"prefer-promise-reject-errors": "off",
|
"prefer-promise-reject-errors": 0,
|
||||||
"import/prefer-default-export": "off",
|
"import/order": 0,
|
||||||
"import/no-default-export": "off",
|
"import/prefer-default-export": 0,
|
||||||
"import/no-unresolved": "off",
|
"import/no-unresolved": 0,
|
||||||
"import/no-cycle": "off",
|
"import/no-cycle": 0,
|
||||||
"import/extensions": [
|
"import/extensions": [
|
||||||
"error",
|
2,
|
||||||
"ignorePackages",
|
"ignorePackages",
|
||||||
{ "ts": "never", "js": "never" }
|
{ "ts": "never", "js": "never" }
|
||||||
],
|
],
|
||||||
"no-restricted-syntax": ["error", "LabeledStatement", "WithStatement"],
|
"no-restricted-syntax": ["error", "LabeledStatement", "WithStatement"],
|
||||||
"object-curly-newline": "off",
|
"object-curly-newline": 0,
|
||||||
"default-case": "off",
|
"default-case": 0,
|
||||||
"wc/no-self-class": "off",
|
"wc/no-self-class": 0,
|
||||||
"no-shadow": "off",
|
"no-shadow": 0,
|
||||||
"@typescript-eslint/camelcase": "off",
|
"@typescript-eslint/camelcase": 0,
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
"@typescript-eslint/ban-ts-comment": 0,
|
||||||
"@typescript-eslint/no-use-before-define": "off",
|
"@typescript-eslint/no-use-before-define": 0,
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
"@typescript-eslint/no-non-null-assertion": 0,
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
"@typescript-eslint/no-explicit-any": 0,
|
||||||
"@typescript-eslint/explicit-function-return-type": "off",
|
"@typescript-eslint/no-unused-vars": 0,
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
"@typescript-eslint/explicit-function-return-type": 0,
|
||||||
"@typescript-eslint/no-shadow": ["error"],
|
"@typescript-eslint/explicit-module-boundary-types": 0,
|
||||||
"@typescript-eslint/naming-convention": [
|
"@typescript-eslint/no-shadow": ["error"]
|
||||||
"off",
|
|
||||||
{
|
|
||||||
"selector": "default",
|
|
||||||
"format": ["camelCase", "snake_case"],
|
|
||||||
"leadingUnderscore": "allow",
|
|
||||||
"trailingUnderscore": "allow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": ["variable"],
|
|
||||||
"format": ["camelCase", "snake_case", "UPPER_CASE"],
|
|
||||||
"leadingUnderscore": "allow",
|
|
||||||
"trailingUnderscore": "allow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "typeLike",
|
|
||||||
"format": ["PascalCase"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
|
||||||
"unused-imports/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"vars": "all",
|
|
||||||
"varsIgnorePattern": "^_",
|
|
||||||
"args": "after-used",
|
|
||||||
"argsIgnorePattern": "^_",
|
|
||||||
"ignoreRestSiblings": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"unused-imports/no-unused-imports": "error",
|
|
||||||
"lit/attribute-value-entities": "off"
|
|
||||||
},
|
},
|
||||||
"plugins": ["disable", "unused-imports"],
|
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
|
||||||
"processor": "disable/disable"
|
"processor": "disable/disable"
|
||||||
}
|
}
|
||||||
|
121
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
121
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,121 +0,0 @@
|
|||||||
name: Report a bug with the UI, Frontend or Lovelace
|
|
||||||
description: Report an issue related to the Home Assistant frontend.
|
|
||||||
labels: bug
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Make sure you are running the [latest version of Home Assistant][releases] before reporting an issue.
|
|
||||||
|
|
||||||
If you have a feature or enhancement request for the frontend, please [start an discussion][fr] instead of creating an issue.
|
|
||||||
|
|
||||||
**Please not not report issues for custom Lovelace cards.**
|
|
||||||
|
|
||||||
[fr]: https://github.com/home-assistant/frontend/discussions
|
|
||||||
[releases]: https://github.com/home-assistant/home-assistant/releases
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Checklist
|
|
||||||
description: Please verify that you've followed these steps
|
|
||||||
options:
|
|
||||||
- label: I have updated to the latest available Home Assistant version.
|
|
||||||
required: true
|
|
||||||
- label: I have cleared the cache of my browser.
|
|
||||||
required: true
|
|
||||||
- label: I have tried a different browser to see if it is related to my browser.
|
|
||||||
required: true
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
## The problem
|
|
||||||
- type: textarea
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
attributes:
|
|
||||||
label: Describe the issue you are experiencing
|
|
||||||
description: Provide a clear and concise description of what the bug is.
|
|
||||||
- type: textarea
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
attributes:
|
|
||||||
label: Describe the behavior you expected
|
|
||||||
description: Describe what you expected to happen or it should look/behave.
|
|
||||||
- type: textarea
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
attributes:
|
|
||||||
label: Steps to reproduce the issue
|
|
||||||
description: |
|
|
||||||
Please tell us exactly how to reproduce your issue.
|
|
||||||
Provide clear and concise step by step instructions and add code snippets if needed.
|
|
||||||
value: |
|
|
||||||
1.
|
|
||||||
2.
|
|
||||||
3.
|
|
||||||
...
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
## Environment
|
|
||||||
- type: input
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
attributes:
|
|
||||||
label: What version of Home Assistant Core has the issue?
|
|
||||||
placeholder: core-
|
|
||||||
description: >
|
|
||||||
Can be found in the Configuration panel -> Info.
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: What was the last working version of Home Assistant Core?
|
|
||||||
placeholder: core-
|
|
||||||
description: >
|
|
||||||
If known, otherwise leave blank.
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: In which browser are you experiencing the issue with?
|
|
||||||
placeholder: Google Chrome 88.0.4324.150
|
|
||||||
description: >
|
|
||||||
Provide the full name and don't forget to add the version!
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: Which operating system are you using to run this browser?
|
|
||||||
placeholder: macOS Big Sur (1.11)
|
|
||||||
description: >
|
|
||||||
Don't forget to add the version!
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
# Details
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: State of relevant entities
|
|
||||||
description: >
|
|
||||||
If your issue is about how an entity is shown in the UI, please add the
|
|
||||||
state and attributes for all situations. You can find this information
|
|
||||||
at Developer Tools -> States.
|
|
||||||
render: txt
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Problem-relevant frontend configuration
|
|
||||||
description: >
|
|
||||||
An example configuration that caused the problem for you, e.g., the YAML
|
|
||||||
configuration of the used cards. Fill this out even if it seems
|
|
||||||
unimportant to you. Please be sure to remove personal information like
|
|
||||||
passwords, private URLs and other credentials.
|
|
||||||
render: yaml
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Javascript errors shown in your browser console/inspector
|
|
||||||
description: >
|
|
||||||
If you come across any Javascript or other error logs, e.g., in your
|
|
||||||
browser console/inspector please provide them.
|
|
||||||
render: txt
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional information
|
|
||||||
description: >
|
|
||||||
If you have any additional information for us, use the field below.
|
|
||||||
Please note, you can attach screenshots or screen recordings here, by
|
|
||||||
dragging and dropping files in the field below.
|
|
82
.github/workflows/ci.yaml
vendored
82
.github/workflows/ci.yaml
vendored
@@ -10,21 +10,26 @@ on:
|
|||||||
- dev
|
- dev
|
||||||
- master
|
- master
|
||||||
|
|
||||||
env:
|
|
||||||
NODE_VERSION: 14
|
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Setting up Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: 12.x
|
||||||
cache: yarn
|
- name: Get yarn cache path
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
- name: Fetching Yarn cache
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install
|
run: yarn install
|
||||||
env:
|
env:
|
||||||
@@ -32,40 +37,54 @@ jobs:
|
|||||||
- name: Build resources
|
- name: Build resources
|
||||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations gather-gallery-demos
|
run: ./node_modules/.bin/gulp gen-icons-json build-translations gather-gallery-demos
|
||||||
- name: Run eslint
|
- name: Run eslint
|
||||||
run: yarn run lint:eslint
|
run: ./node_modules/.bin/eslint '{**/src,src}/**/*.{js,ts,html}' --ignore-path .gitignore
|
||||||
- name: Run tsc
|
- name: Run tsc
|
||||||
run: yarn run lint:types
|
run: ./node_modules/.bin/tsc
|
||||||
- name: Run prettier
|
|
||||||
run: yarn run lint:prettier
|
|
||||||
- name: Check for duplicate dependencies
|
|
||||||
run: yarn dedupe --check
|
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Setting up Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: 12.x
|
||||||
cache: yarn
|
- name: Get yarn cache path
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
- name: Fetching Yarn cache
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install
|
run: yarn install
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
- name: Run Mocha
|
- name: Run Mocha
|
||||||
run: yarn run mocha
|
run: npm run mocha
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Setting up Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: 12.x
|
||||||
cache: yarn
|
- name: Get yarn cache path
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
- name: Fetching Yarn cache
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install
|
run: yarn install
|
||||||
env:
|
env:
|
||||||
@@ -80,11 +99,20 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Setting up Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: 12.x
|
||||||
cache: yarn
|
- name: Get yarn cache path
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
- name: Fetching Yarn cache
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install
|
run: yarn install
|
||||||
env:
|
env:
|
||||||
|
22
.github/workflows/demo.yaml
vendored
22
.github/workflows/demo.yaml
vendored
@@ -4,22 +4,26 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
|
|
||||||
env:
|
|
||||||
NODE_VERSION: 14
|
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Setting up Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: 12.x
|
||||||
cache: yarn
|
- name: Get yarn cache path
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
- name: Fetching Yarn cache
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install
|
run: yarn install
|
||||||
env:
|
env:
|
||||||
|
18
.github/workflows/release.yaml
vendored
18
.github/workflows/release.yaml
vendored
@@ -6,9 +6,9 @@ on:
|
|||||||
- published
|
- published
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: 3.8
|
WHEELS_TAG: 3.7-alpine3.11
|
||||||
NODE_VERSION: 14
|
PYTHON_VERSION: 3.7
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_VERSION: 12.1
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
@@ -30,15 +30,7 @@ jobs:
|
|||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: yarn install
|
|
||||||
|
|
||||||
- name: Download Translations
|
|
||||||
run: ./script/translations_download
|
|
||||||
env:
|
|
||||||
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
|
|
||||||
- name: Build and release package
|
- name: Build and release package
|
||||||
run: |
|
run: |
|
||||||
python3 -m pip install twine
|
python3 -m pip install twine
|
||||||
@@ -72,8 +64,6 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
arch: ["aarch64", "armhf", "armv7", "amd64", "i386"]
|
arch: ["aarch64", "armhf", "armv7", "amd64", "i386"]
|
||||||
tag:
|
|
||||||
- "3.9-alpine3.14"
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download requirements.txt
|
- name: Download requirements.txt
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
@@ -83,7 +73,7 @@ jobs:
|
|||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: home-assistant/wheels@master
|
uses: home-assistant/wheels@master
|
||||||
with:
|
with:
|
||||||
tag: ${{ matrix.tag }}
|
tag: ${{ env.WHEELS_TAG }}
|
||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
wheels-host: ${{ secrets.WHEELS_HOST }}
|
wheels-host: ${{ secrets.WHEELS_HOST }}
|
||||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||||
|
44
.github/workflows/translations.yaml
vendored
44
.github/workflows/translations.yaml
vendored
@@ -1,14 +1,16 @@
|
|||||||
name: Translations
|
name: Translations
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "30 0 * * *"
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
paths:
|
paths:
|
||||||
- src/translations/en.json
|
- translations/en.json
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 12
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
upload:
|
upload:
|
||||||
@@ -18,8 +20,46 @@ jobs:
|
|||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
|
||||||
- name: Upload Translations
|
- name: Upload Translations
|
||||||
run: |
|
run: |
|
||||||
export LOKALISE_TOKEN="${{ secrets.LOKALISE_TOKEN }}"
|
export LOKALISE_TOKEN="${{ secrets.LOKALISE_TOKEN }}"
|
||||||
|
|
||||||
./script/translations_upload_base
|
./script/translations_upload_base
|
||||||
|
|
||||||
|
download:
|
||||||
|
name: Download
|
||||||
|
needs: upload
|
||||||
|
if: github.event_name == 'schedule'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
|
||||||
|
- name: Download Translations
|
||||||
|
run: |
|
||||||
|
export LOKALISE_TOKEN="${{ secrets.LOKALISE_TOKEN }}"
|
||||||
|
|
||||||
|
npm install
|
||||||
|
./script/translations_download
|
||||||
|
|
||||||
|
- name: Initialize git
|
||||||
|
uses: home-assistant/actions/helpers/git-init@master
|
||||||
|
with:
|
||||||
|
name: GitHub Action
|
||||||
|
email: github-action@users.noreply.github.com
|
||||||
|
|
||||||
|
- name: Update translation
|
||||||
|
run: |
|
||||||
|
git add translations
|
||||||
|
git commit -am "Translation update"
|
||||||
|
git push
|
||||||
|
27
.gitignore
vendored
27
.gitignore
vendored
@@ -1,23 +1,10 @@
|
|||||||
.DS_Store
|
|
||||||
.reify-cache
|
|
||||||
|
|
||||||
# build
|
|
||||||
build
|
build
|
||||||
build-translations/*
|
build-translations/*
|
||||||
hass_frontend/*
|
|
||||||
dist
|
|
||||||
|
|
||||||
# yarn
|
|
||||||
.yarn/*
|
|
||||||
!.yarn/patches
|
|
||||||
!.yarn/releases
|
|
||||||
!.yarn/plugins
|
|
||||||
!.yarn/sdks
|
|
||||||
!.yarn/versions
|
|
||||||
.pnp.*
|
|
||||||
node_modules/*
|
node_modules/*
|
||||||
yarn-error.log
|
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
.DS_Store
|
||||||
|
hass_frontend/*
|
||||||
|
.reify-cache
|
||||||
|
|
||||||
# Python stuff
|
# Python stuff
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
@@ -27,8 +14,11 @@ npm-debug.log
|
|||||||
# venv stuff
|
# venv stuff
|
||||||
pyvenv.cfg
|
pyvenv.cfg
|
||||||
pip-selfcheck.json
|
pip-selfcheck.json
|
||||||
venv/*
|
venv
|
||||||
.venv
|
.venv
|
||||||
|
lib
|
||||||
|
bin
|
||||||
|
dist
|
||||||
|
|
||||||
# vscode
|
# vscode
|
||||||
.vscode/*
|
.vscode/*
|
||||||
@@ -41,8 +31,9 @@ src/cast/dev_const.ts
|
|||||||
|
|
||||||
# Secrets
|
# Secrets
|
||||||
.lokalise_token
|
.lokalise_token
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
# asdf
|
#asdf
|
||||||
.tool-versions
|
.tool-versions
|
||||||
|
|
||||||
# Home Assistant config
|
# Home Assistant config
|
||||||
|
@@ -1,4 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
require: "test-mocha/testconf.js",
|
|
||||||
timeout: 10000,
|
|
||||||
};
|
|
File diff suppressed because one or more lines are too long
@@ -1,29 +0,0 @@
|
|||||||
diff --git a/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js b/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js
|
|
||||||
index d92179f7fd5315203f870a6963e871dc8ddf6c0c..362e284121b97e0fba0925225777aebc32e26b8d 100644
|
|
||||||
--- a/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js
|
|
||||||
+++ b/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js
|
|
||||||
@@ -1,14 +1,15 @@
|
|
||||||
-let _ET, ET;
|
|
||||||
+let _ET;
|
|
||||||
+let ET;
|
|
||||||
export default async function EventTarget() {
|
|
||||||
- return ET || init();
|
|
||||||
+ return ET || init();
|
|
||||||
}
|
|
||||||
async function init() {
|
|
||||||
- _ET = window.EventTarget;
|
|
||||||
- try {
|
|
||||||
- new _ET();
|
|
||||||
- }
|
|
||||||
- catch (_a) {
|
|
||||||
- _ET = (await import('event-target-shim')).EventTarget;
|
|
||||||
- }
|
|
||||||
- return (ET = _ET);
|
|
||||||
+ _ET = window.EventTarget;
|
|
||||||
+ try {
|
|
||||||
+ new _ET();
|
|
||||||
+ } catch (_a) {
|
|
||||||
+ _ET = (await import("event-target-shim")).default.EventTarget;
|
|
||||||
+ }
|
|
||||||
+ return (ET = _ET);
|
|
||||||
}
|
|
@@ -1,34 +0,0 @@
|
|||||||
diff --git a/lib/legacy/class.js b/lib/legacy/class.js
|
|
||||||
index aee2511be1cd9bf900ee552bc98190c1631c57c0..f2f499d68bf52034cac9c28307c99e8ce6b8417d 100644
|
|
||||||
--- a/lib/legacy/class.js
|
|
||||||
+++ b/lib/legacy/class.js
|
|
||||||
@@ -304,17 +304,23 @@ function GenerateClassFromInfo(info, Base, behaviors) {
|
|
||||||
// only proceed if the generated class' prototype has not been registered.
|
|
||||||
const generatedProto = PolymerGenerated.prototype;
|
|
||||||
if (!generatedProto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', generatedProto))) {
|
|
||||||
- generatedProto.__hasRegisterFinished = true;
|
|
||||||
+ // make sure legacy lifecycle is called on the *element*'s prototype
|
|
||||||
+ // and not the generated class prototype; if the element has been
|
|
||||||
+ // extended, these are *not* the same.
|
|
||||||
+ const proto = Object.getPrototypeOf(this);
|
|
||||||
+ // Only set flag when generated prototype itself is registered,
|
|
||||||
+ // as this element may be extended from, and needs to run `registered`
|
|
||||||
+ // on all behaviors on the subclass as well.
|
|
||||||
+ if (proto === generatedProto) {
|
|
||||||
+ generatedProto.__hasRegisterFinished = true;
|
|
||||||
+ }
|
|
||||||
// ensure superclass is registered first.
|
|
||||||
super._registered();
|
|
||||||
// copy properties onto the generated class lazily if we're optimizing,
|
|
||||||
- if (legacyOptimizations) {
|
|
||||||
+ if (legacyOptimizations && !Object.hasOwnProperty(generatedProto, '__hasCopiedProperties')) {
|
|
||||||
+ generatedProto.__hasCopiedProperties = true;
|
|
||||||
copyPropertiesToProto(generatedProto);
|
|
||||||
}
|
|
||||||
- // make sure legacy lifecycle is called on the *element*'s prototype
|
|
||||||
- // and not the generated class prototype; if the element has been
|
|
||||||
- // extended, these are *not* the same.
|
|
||||||
- const proto = Object.getPrototypeOf(this);
|
|
||||||
let list = lifecycle.beforeRegister;
|
|
||||||
if (list) {
|
|
||||||
for (let i=0; i < list.length; i++) {
|
|
File diff suppressed because one or more lines are too long
8
.yarn/plugins/@yarnpkg/plugin-typescript.cjs
vendored
8
.yarn/plugins/@yarnpkg/plugin-typescript.cjs
vendored
File diff suppressed because one or more lines are too long
55
.yarn/releases/yarn-2.4.2.cjs
vendored
55
.yarn/releases/yarn-2.4.2.cjs
vendored
File diff suppressed because one or more lines are too long
@@ -1,9 +0,0 @@
|
|||||||
nodeLinker: node-modules
|
|
||||||
|
|
||||||
plugins:
|
|
||||||
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
|
|
||||||
spec: "@yarnpkg/plugin-typescript"
|
|
||||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
|
||||||
spec: "@yarnpkg/plugin-interactive-tools"
|
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-2.4.2.cjs
|
|
@@ -1,170 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
|
||||||
|
|
||||||
// Currently only supports CommonJS modules, as require is synchronous. `import` would need babel running asynchronous.
|
|
||||||
module.exports = function inlineConstants(babel, options, cwd) {
|
|
||||||
const t = babel.types;
|
|
||||||
|
|
||||||
if (!Array.isArray(options.modules)) {
|
|
||||||
throw new TypeError(
|
|
||||||
"babel-plugin-inline-constants: expected a `modules` array to be passed"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.resolveExtensions && !Array.isArray(options.resolveExtensions)) {
|
|
||||||
throw new TypeError(
|
|
||||||
"babel-plugin-inline-constants: expected `resolveExtensions` to be an array"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ignoreModuleNotFound = options.ignoreModuleNotFound;
|
|
||||||
const resolveExtensions = options.resolveExtensions;
|
|
||||||
|
|
||||||
const hasRelativeModules = options.modules.some(
|
|
||||||
(module) => module.startsWith(".") || module.startsWith("/")
|
|
||||||
);
|
|
||||||
|
|
||||||
const modules = Object.fromEntries(
|
|
||||||
options.modules.map((module) => {
|
|
||||||
const absolute = module.startsWith(".")
|
|
||||||
? require.resolve(module, { paths: [cwd] })
|
|
||||||
: module;
|
|
||||||
// eslint-disable-next-line import/no-dynamic-require
|
|
||||||
return [absolute, require(absolute)];
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const toLiteral = (value) => {
|
|
||||||
if (typeof value === "string") {
|
|
||||||
return t.stringLiteral(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === "number") {
|
|
||||||
return t.numericLiteral(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === "boolean") {
|
|
||||||
return t.booleanLiteral(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value === null) {
|
|
||||||
return t.nullLiteral();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(
|
|
||||||
"babel-plugin-inline-constants: cannot handle non-literal `" + value + "`"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const resolveAbsolute = (value, state, resolveExtensionIndex) => {
|
|
||||||
if (!state.filename) {
|
|
||||||
throw new TypeError(
|
|
||||||
"babel-plugin-inline-constants: expected a `filename` to be set for files"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolveExtensions && resolveExtensionIndex !== undefined) {
|
|
||||||
value += resolveExtensions[resolveExtensionIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return require.resolve(value, { paths: [path.dirname(state.filename)] });
|
|
||||||
} catch (error) {
|
|
||||||
if (
|
|
||||||
error.code === "MODULE_NOT_FOUND" &&
|
|
||||||
resolveExtensions &&
|
|
||||||
(resolveExtensionIndex === undefined ||
|
|
||||||
resolveExtensionIndex < resolveExtensions.length - 1)
|
|
||||||
) {
|
|
||||||
const resolveExtensionIdx = (resolveExtensionIndex || -1) + 1;
|
|
||||||
return resolveAbsolute(value, state, resolveExtensionIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.code === "MODULE_NOT_FOUND" && ignoreModuleNotFound) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const importDeclaration = (p, state) => {
|
|
||||||
if (p.node.type !== "ImportDeclaration") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const absolute =
|
|
||||||
hasRelativeModules && p.node.source.value.startsWith(".")
|
|
||||||
? resolveAbsolute(p.node.source.value, state)
|
|
||||||
: p.node.source.value;
|
|
||||||
|
|
||||||
if (!absolute || !(absolute in modules)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const module = modules[absolute];
|
|
||||||
|
|
||||||
for (const specifier of p.node.specifiers) {
|
|
||||||
if (
|
|
||||||
specifier.type === "ImportDefaultSpecifier" &&
|
|
||||||
specifier.local &&
|
|
||||||
specifier.local.type === "Identifier"
|
|
||||||
) {
|
|
||||||
if (!("default" in module)) {
|
|
||||||
throw new Error(
|
|
||||||
"babel-plugin-inline-constants: cannot access default export from `" +
|
|
||||||
p.node.source.value +
|
|
||||||
"`"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const variableValue = toLiteral(module.default);
|
|
||||||
const variable = t.variableDeclarator(
|
|
||||||
t.identifier(specifier.local.name),
|
|
||||||
variableValue
|
|
||||||
);
|
|
||||||
|
|
||||||
p.insertBefore({
|
|
||||||
type: "VariableDeclaration",
|
|
||||||
kind: "const",
|
|
||||||
declarations: [variable],
|
|
||||||
});
|
|
||||||
} else if (
|
|
||||||
specifier.type === "ImportSpecifier" &&
|
|
||||||
specifier.imported &&
|
|
||||||
specifier.imported.type === "Identifier" &&
|
|
||||||
specifier.local &&
|
|
||||||
specifier.local.type === "Identifier"
|
|
||||||
) {
|
|
||||||
if (!(specifier.imported.name in module)) {
|
|
||||||
throw new Error(
|
|
||||||
"babel-plugin-inline-constants: cannot access `" +
|
|
||||||
specifier.imported.name +
|
|
||||||
"` from `" +
|
|
||||||
p.node.source.value +
|
|
||||||
"`"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const variableValue = toLiteral(module[specifier.imported.name]);
|
|
||||||
const variable = t.variableDeclarator(
|
|
||||||
t.identifier(specifier.local.name),
|
|
||||||
variableValue
|
|
||||||
);
|
|
||||||
|
|
||||||
p.insertBefore({
|
|
||||||
type: "VariableDeclaration",
|
|
||||||
kind: "const",
|
|
||||||
declarations: [variable],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new Error("Cannot handle specifier `" + specifier.type + "`");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.remove();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
visitor: {
|
|
||||||
ImportDeclaration: importDeclaration,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@@ -1,10 +1,11 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const env = require("./env.js");
|
const env = require("./env.js");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
|
|
||||||
// Files from NPM Packages that should not be imported
|
// Files from NPM Packages that should not be imported
|
||||||
module.exports.ignorePackages = ({ latestBuild }) => [
|
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
|
// Part of yaml.js and only used for !!js functions that we don't use
|
||||||
require.resolve("esprima"),
|
require.resolve("esprima"),
|
||||||
];
|
];
|
||||||
@@ -18,8 +19,7 @@ module.exports.emptyPackages = ({ latestBuild }) =>
|
|||||||
require.resolve("@polymer/paper-styles/default-theme.js"),
|
require.resolve("@polymer/paper-styles/default-theme.js"),
|
||||||
// Loads stuff from a CDN
|
// Loads stuff from a CDN
|
||||||
require.resolve("@polymer/font-roboto/roboto.js"),
|
require.resolve("@polymer/font-roboto/roboto.js"),
|
||||||
require.resolve("@vaadin/vaadin-material-styles/typography.js"),
|
require.resolve("@vaadin/vaadin-material-styles/font-roboto.js"),
|
||||||
require.resolve("@vaadin/vaadin-material-styles/font-icons.js"),
|
|
||||||
// Compatibility not needed for latest builds
|
// Compatibility not needed for latest builds
|
||||||
latestBuild &&
|
latestBuild &&
|
||||||
// wrapped in require.resolve so it blows up if file no longer exists
|
// wrapped in require.resolve so it blows up if file no longer exists
|
||||||
@@ -51,29 +51,17 @@ module.exports.terserOptions = (latestBuild) => ({
|
|||||||
|
|
||||||
module.exports.babelOptions = ({ latestBuild }) => ({
|
module.exports.babelOptions = ({ latestBuild }) => ({
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
compact: false,
|
|
||||||
presets: [
|
presets: [
|
||||||
!latestBuild && [
|
!latestBuild && [
|
||||||
"@babel/preset-env",
|
require("@babel/preset-env").default,
|
||||||
{
|
{
|
||||||
useBuiltIns: "entry",
|
useBuiltIns: "entry",
|
||||||
corejs: "3.15",
|
corejs: "3.6",
|
||||||
bugfixes: true,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"@babel/preset-typescript",
|
require("@babel/preset-typescript").default,
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
plugins: [
|
plugins: [
|
||||||
[
|
|
||||||
path.resolve(
|
|
||||||
paths.polymer_dir,
|
|
||||||
"build-scripts/babel-plugins/inline-constants-plugin.js"
|
|
||||||
),
|
|
||||||
{
|
|
||||||
modules: ["@mdi/js"],
|
|
||||||
ignoreModuleNotFound: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
||||||
!latestBuild && [
|
!latestBuild && [
|
||||||
"@babel/plugin-proposal-object-rest-spread",
|
"@babel/plugin-proposal-object-rest-spread",
|
||||||
@@ -84,18 +72,23 @@ module.exports.babelOptions = ({ latestBuild }) => ({
|
|||||||
"@babel/plugin-syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
"@babel/plugin-proposal-optional-chaining",
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
|
[
|
||||||
["@babel/plugin-proposal-private-methods", { loose: true }],
|
require("@babel/plugin-proposal-decorators").default,
|
||||||
["@babel/plugin-proposal-private-property-in-object", { loose: true }],
|
{ decoratorsBeforeExport: true },
|
||||||
["@babel/plugin-proposal-class-properties", { loose: true }],
|
],
|
||||||
|
[
|
||||||
|
require("@babel/plugin-proposal-class-properties").default,
|
||||||
|
{ loose: true },
|
||||||
|
],
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
exclude: [
|
|
||||||
// \\ for Windows, / for Mac OS and Linux
|
|
||||||
/node_modules[\\/]core-js/,
|
|
||||||
/node_modules[\\/]webpack[\\/]buildin/,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Are already ES5, cause warnings when babelified.
|
||||||
|
module.exports.babelExclude = () => [
|
||||||
|
require.resolve("@mdi/js/mdi.js"),
|
||||||
|
require.resolve("hls.js"),
|
||||||
|
];
|
||||||
|
|
||||||
const outputPath = (outputRoot, latestBuild) =>
|
const outputPath = (outputRoot, latestBuild) =>
|
||||||
path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5");
|
path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5");
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
|
@@ -47,8 +47,8 @@ gulp.task(
|
|||||||
gulp.parallel("gen-icons-json", "build-translations"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-app",
|
"copy-static-app",
|
||||||
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
|
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
|
||||||
// Don't compress running tests
|
...// Don't compress running tests
|
||||||
...(env.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",
|
||||||
|
@@ -5,32 +5,32 @@ require("./translations");
|
|||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean",
|
"clean",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||||
del([paths.app_output_root, paths.build_dir])
|
return del([paths.app_output_root, paths.build_dir]);
|
||||||
)
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-demo",
|
"clean-demo",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||||
del([paths.demo_output_root, paths.build_dir])
|
return del([paths.demo_output_root, paths.build_dir]);
|
||||||
)
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-cast",
|
"clean-cast",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||||
del([paths.cast_output_root, paths.build_dir])
|
return del([paths.cast_output_root, paths.build_dir]);
|
||||||
)
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("clean-hassio", () =>
|
gulp.task("clean-hassio", function cleanOutputAndBuildDir() {
|
||||||
del([paths.hassio_output_root, paths.build_dir])
|
return del([paths.hassio_output_root, paths.build_dir]);
|
||||||
);
|
});
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-gallery",
|
"clean-gallery",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||||
del([paths.gallery_output_root, paths.build_dir])
|
return del([paths.gallery_output_root, paths.build_dir]);
|
||||||
)
|
})
|
||||||
);
|
);
|
||||||
|
@@ -302,23 +302,15 @@ gulp.task("gen-index-hassio-prod", async () => {
|
|||||||
|
|
||||||
function writeHassioEntrypoint(latestEntrypoint, es5Entrypoint) {
|
function writeHassioEntrypoint(latestEntrypoint, es5Entrypoint) {
|
||||||
fs.mkdirSync(paths.hassio_output_root, { recursive: true });
|
fs.mkdirSync(paths.hassio_output_root, { recursive: true });
|
||||||
// Safari 12 and below does not have a compliant ES2015 implementation of template literals, so we ship ES5
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.resolve(paths.hassio_output_root, "entrypoint.js"),
|
path.resolve(paths.hassio_output_root, "entrypoint.js"),
|
||||||
`
|
`
|
||||||
function loadES5() {
|
try {
|
||||||
|
new Function("import('${latestEntrypoint}')")();
|
||||||
|
} catch (err) {
|
||||||
var el = document.createElement('script');
|
var el = document.createElement('script');
|
||||||
el.src = '${es5Entrypoint}';
|
el.src = '${es5Entrypoint}';
|
||||||
document.body.appendChild(el);
|
document.body.appendChild(el);
|
||||||
}
|
|
||||||
if (/.*Version\\/(?:11|12)(?:\\.\\d+)*.*Safari\\//.test(navigator.userAgent)) {
|
|
||||||
loadES5();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
new Function("import('${latestEntrypoint}')")();
|
|
||||||
} catch (err) {
|
|
||||||
loadES5();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
{ encoding: "utf-8" }
|
{ encoding: "utf-8" }
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const cpx = require("cpx");
|
||||||
const fs = require("fs-extra");
|
const fs = require("fs-extra");
|
||||||
const paths = require("../paths");
|
const paths = require("../paths");
|
||||||
|
|
||||||
@@ -12,10 +13,8 @@ const polyPath = (...parts) => path.resolve(paths.polymer_dir, ...parts);
|
|||||||
const copyFileDir = (fromFile, toDir) =>
|
const copyFileDir = (fromFile, toDir) =>
|
||||||
fs.copySync(fromFile, path.join(toDir, path.basename(fromFile)));
|
fs.copySync(fromFile, path.join(toDir, path.basename(fromFile)));
|
||||||
|
|
||||||
const genStaticPath =
|
const genStaticPath = (staticDir) => (...parts) =>
|
||||||
(staticDir) =>
|
path.resolve(staticDir, ...parts);
|
||||||
(...parts) =>
|
|
||||||
path.resolve(staticDir, ...parts);
|
|
||||||
|
|
||||||
function copyTranslations(staticDir) {
|
function copyTranslations(staticDir) {
|
||||||
const staticPath = genStaticPath(staticDir);
|
const staticPath = genStaticPath(staticDir);
|
||||||
@@ -63,12 +62,9 @@ function copyLoaderJS(staticDir) {
|
|||||||
function copyFonts(staticDir) {
|
function copyFonts(staticDir) {
|
||||||
const staticPath = genStaticPath(staticDir);
|
const staticPath = genStaticPath(staticDir);
|
||||||
// Local fonts
|
// Local fonts
|
||||||
fs.copySync(
|
cpx.copySync(
|
||||||
npmPath("roboto-fontface/fonts/roboto/"),
|
npmPath("roboto-fontface/fonts/roboto/*.woff2"),
|
||||||
staticPath("fonts/roboto/"),
|
staticPath("fonts/roboto")
|
||||||
{
|
|
||||||
filter: (src) => !src.includes(".") || src.endsWith(".woff2"),
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,11 +85,6 @@ gulp.task("copy-translations-app", async () => {
|
|||||||
copyTranslations(staticDir);
|
copyTranslations(staticDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("copy-translations-supervisor", async () => {
|
|
||||||
const staticDir = paths.hassio_output_static;
|
|
||||||
copyTranslations(staticDir);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("copy-static-app", async () => {
|
gulp.task("copy-static-app", async () => {
|
||||||
const staticDir = paths.app_output_static;
|
const staticDir = paths.app_output_static;
|
||||||
// Basic static files
|
// Basic static files
|
||||||
|
@@ -10,8 +10,6 @@ require("./gen-icons-json.js");
|
|||||||
require("./webpack.js");
|
require("./webpack.js");
|
||||||
require("./compress.js");
|
require("./compress.js");
|
||||||
require("./rollup.js");
|
require("./rollup.js");
|
||||||
require("./gather-static.js");
|
|
||||||
require("./translations.js");
|
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-hassio",
|
"develop-hassio",
|
||||||
@@ -22,8 +20,6 @@ gulp.task(
|
|||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"gen-index-hassio-dev",
|
"gen-index-hassio-dev",
|
||||||
"build-supervisor-translations",
|
|
||||||
"copy-translations-supervisor",
|
|
||||||
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -36,8 +32,6 @@ gulp.task(
|
|||||||
},
|
},
|
||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"build-supervisor-translations",
|
|
||||||
"copy-translations-supervisor",
|
|
||||||
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
|
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
|
||||||
"gen-index-hassio-prod",
|
"gen-index-hassio-prod",
|
||||||
...// Don't compress running tests
|
...// Don't compress running tests
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
|
|
||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
const del = require("del");
|
const del = require("del");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
@@ -28,6 +26,13 @@ gulp.task("translations-enable-merge-backend", (done) => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
String.prototype.rsplit = function (sep, maxsplit) {
|
||||||
|
var split = this.split(sep);
|
||||||
|
return maxsplit
|
||||||
|
? [split.slice(0, -maxsplit).join(sep)].concat(split.slice(-maxsplit))
|
||||||
|
: split;
|
||||||
|
};
|
||||||
|
|
||||||
// Panel translations which should be split from the core translations.
|
// Panel translations which should be split from the core translations.
|
||||||
const TRANSLATION_FRAGMENTS = Object.keys(
|
const TRANSLATION_FRAGMENTS = Object.keys(
|
||||||
require("../../src/translations/en.json").ui.panel
|
require("../../src/translations/en.json").ui.panel
|
||||||
@@ -35,7 +40,7 @@ const TRANSLATION_FRAGMENTS = Object.keys(
|
|||||||
|
|
||||||
function recursiveFlatten(prefix, data) {
|
function recursiveFlatten(prefix, data) {
|
||||||
let output = {};
|
let output = {};
|
||||||
Object.keys(data).forEach((key) => {
|
Object.keys(data).forEach(function (key) {
|
||||||
if (typeof data[key] === "object") {
|
if (typeof data[key] === "object") {
|
||||||
output = {
|
output = {
|
||||||
...output,
|
...output,
|
||||||
@@ -96,19 +101,15 @@ function lokaliseTransform(data, original, file) {
|
|||||||
if (value instanceof Object) {
|
if (value instanceof Object) {
|
||||||
output[key] = lokaliseTransform(value, original, file);
|
output[key] = lokaliseTransform(value, original, file);
|
||||||
} else {
|
} else {
|
||||||
output[key] = value.replace(re_key_reference, (_match, lokalise_key) => {
|
output[key] = value.replace(re_key_reference, (match, key) => {
|
||||||
const replace = lokalise_key.split("::").reduce((tr, k) => {
|
const replace = key.split("::").reduce((tr, k) => {
|
||||||
if (!tr) {
|
if (!tr) {
|
||||||
throw Error(
|
throw Error(`Invalid key placeholder ${key} in ${file.path}`);
|
||||||
`Invalid key placeholder ${lokalise_key} in ${file.path}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return tr[k];
|
return tr[k];
|
||||||
}, original);
|
}, original);
|
||||||
if (typeof replace !== "string") {
|
if (typeof replace !== "string") {
|
||||||
throw Error(
|
throw Error(`Invalid key placeholder ${key} in ${file.path}`);
|
||||||
`Invalid key placeholder ${lokalise_key} in ${file.path}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return replace;
|
return replace;
|
||||||
});
|
});
|
||||||
@@ -117,7 +118,9 @@ function lokaliseTransform(data, original, file) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task("clean-translations", () => del([workDir]));
|
gulp.task("clean-translations", function () {
|
||||||
|
return del([workDir]);
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task("ensure-translations-build-dir", (done) => {
|
gulp.task("ensure-translations-build-dir", (done) => {
|
||||||
if (!fs.existsSync(workDir)) {
|
if (!fs.existsSync(workDir)) {
|
||||||
@@ -126,7 +129,7 @@ gulp.task("ensure-translations-build-dir", (done) => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("create-test-metadata", (cb) => {
|
gulp.task("create-test-metadata", function (cb) {
|
||||||
fs.writeFile(
|
fs.writeFile(
|
||||||
workDir + "/testMetadata.json",
|
workDir + "/testMetadata.json",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -140,13 +143,17 @@ gulp.task("create-test-metadata", (cb) => {
|
|||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"create-test-translation",
|
"create-test-translation",
|
||||||
gulp.series("create-test-metadata", () =>
|
gulp.series("create-test-metadata", function createTestTranslation() {
|
||||||
gulp
|
return gulp
|
||||||
.src(path.join(paths.translations_src, "en.json"))
|
.src(path.join(paths.translations_src, "en.json"))
|
||||||
.pipe(transform((data, _file) => recursiveEmpty(data)))
|
.pipe(
|
||||||
|
transform(function (data, file) {
|
||||||
|
return recursiveEmpty(data);
|
||||||
|
})
|
||||||
|
)
|
||||||
.pipe(rename("test.json"))
|
.pipe(rename("test.json"))
|
||||||
.pipe(gulp.dest(workDir))
|
.pipe(gulp.dest(workDir));
|
||||||
)
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,7 +165,7 @@ gulp.task(
|
|||||||
* project is buildable immediately after merging new translation keys, since
|
* project is buildable immediately after merging new translation keys, since
|
||||||
* the Lokalise update to translations/en.json will not happen immediately.
|
* the Lokalise update to translations/en.json will not happen immediately.
|
||||||
*/
|
*/
|
||||||
gulp.task("build-master-translation", () => {
|
gulp.task("build-master-translation", function () {
|
||||||
const src = [path.join(paths.translations_src, "en.json")];
|
const src = [path.join(paths.translations_src, "en.json")];
|
||||||
|
|
||||||
if (mergeBackend) {
|
if (mergeBackend) {
|
||||||
@@ -167,7 +174,11 @@ gulp.task("build-master-translation", () => {
|
|||||||
|
|
||||||
return gulp
|
return gulp
|
||||||
.src(src)
|
.src(src)
|
||||||
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
.pipe(
|
||||||
|
transform(function (data, file) {
|
||||||
|
return lokaliseTransform(data, data, file);
|
||||||
|
})
|
||||||
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
merge({
|
merge({
|
||||||
fileName: "translationMaster.json",
|
fileName: "translationMaster.json",
|
||||||
@@ -176,14 +187,18 @@ gulp.task("build-master-translation", () => {
|
|||||||
.pipe(gulp.dest(workDir));
|
.pipe(gulp.dest(workDir));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("build-merged-translations", () =>
|
gulp.task("build-merged-translations", function () {
|
||||||
gulp
|
return gulp
|
||||||
.src([inFrontendDir + "/*.json", workDir + "/test.json"], {
|
.src([inFrontendDir + "/*.json", workDir + "/test.json"], {
|
||||||
allowEmpty: true,
|
allowEmpty: true,
|
||||||
})
|
})
|
||||||
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
|
||||||
.pipe(
|
.pipe(
|
||||||
foreach((stream, file) => {
|
transform(function (data, file) {
|
||||||
|
return lokaliseTransform(data, data, file);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
foreach(function (stream, file) {
|
||||||
// For each language generate a merged json file. It begins with the master
|
// For each language generate a merged json file. It begins with the master
|
||||||
// translation as a failsafe for untranslated strings, and merges all parent
|
// translation as a failsafe for untranslated strings, and merges all parent
|
||||||
// tags into one file for each specific subtag
|
// tags into one file for each specific subtag
|
||||||
@@ -215,17 +230,17 @@ gulp.task("build-merged-translations", () =>
|
|||||||
)
|
)
|
||||||
.pipe(gulp.dest(fullDir));
|
.pipe(gulp.dest(fullDir));
|
||||||
})
|
})
|
||||||
)
|
);
|
||||||
);
|
});
|
||||||
|
|
||||||
let taskName;
|
var taskName;
|
||||||
|
|
||||||
const splitTasks = [];
|
const splitTasks = [];
|
||||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||||
taskName = "build-translation-fragment-" + fragment;
|
taskName = "build-translation-fragment-" + fragment;
|
||||||
gulp.task(taskName, () =>
|
gulp.task(taskName, function () {
|
||||||
// Return only the translations for this fragment.
|
// Return only the translations for this fragment.
|
||||||
gulp
|
return gulp
|
||||||
.src(fullDir + "/*.json")
|
.src(fullDir + "/*.json")
|
||||||
.pipe(
|
.pipe(
|
||||||
transform((data) => ({
|
transform((data) => ({
|
||||||
@@ -236,33 +251,32 @@ TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(workDir + "/" + fragment))
|
.pipe(gulp.dest(workDir + "/" + fragment));
|
||||||
);
|
});
|
||||||
splitTasks.push(taskName);
|
splitTasks.push(taskName);
|
||||||
});
|
});
|
||||||
|
|
||||||
taskName = "build-translation-core";
|
taskName = "build-translation-core";
|
||||||
gulp.task(taskName, () =>
|
gulp.task(taskName, function () {
|
||||||
// Remove the fragment translations from the core translation.
|
// Remove the fragment translations from the core translation.
|
||||||
gulp
|
return gulp
|
||||||
.src(fullDir + "/*.json")
|
.src(fullDir + "/*.json")
|
||||||
.pipe(
|
.pipe(
|
||||||
transform((data, _file) => {
|
transform((data, file) => {
|
||||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||||
delete data.ui.panel[fragment];
|
delete data.ui.panel[fragment];
|
||||||
});
|
});
|
||||||
delete data.supervisor;
|
|
||||||
return data;
|
return data;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(coreDir))
|
.pipe(gulp.dest(coreDir));
|
||||||
);
|
});
|
||||||
|
|
||||||
splitTasks.push(taskName);
|
splitTasks.push(taskName);
|
||||||
|
|
||||||
gulp.task("build-flattened-translations", () =>
|
gulp.task("build-flattened-translations", function () {
|
||||||
// Flatten the split versions of our translations, and move them into outDir
|
// Flatten the split versions of our translations, and move them into outDir
|
||||||
gulp
|
return gulp
|
||||||
.src(
|
.src(
|
||||||
TRANSLATION_FRAGMENTS.map(
|
TRANSLATION_FRAGMENTS.map(
|
||||||
(fragment) => workDir + "/" + fragment + "/*.json"
|
(fragment) => workDir + "/" + fragment + "/*.json"
|
||||||
@@ -270,45 +284,41 @@ gulp.task("build-flattened-translations", () =>
|
|||||||
{ base: workDir }
|
{ base: workDir }
|
||||||
)
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
transform((data) =>
|
transform(function (data) {
|
||||||
// Polymer.AppLocalizeBehavior requires flattened json
|
// Polymer.AppLocalizeBehavior requires flattened json
|
||||||
flatten(data)
|
return flatten(data);
|
||||||
)
|
})
|
||||||
)
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
rename((filePath) => {
|
rename((filePath) => {
|
||||||
if (filePath.dirname === "core") {
|
if (filePath.dirname === "core") {
|
||||||
filePath.dirname = "";
|
filePath.dirname = "";
|
||||||
}
|
}
|
||||||
// In dev we create the file with the fake hash in the filename
|
|
||||||
if (!env.isProdBuild()) {
|
|
||||||
filePath.basename += "-dev";
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(outDir))
|
.pipe(gulp.dest(outDir));
|
||||||
);
|
});
|
||||||
|
|
||||||
const fingerprints = {};
|
const fingerprints = {};
|
||||||
|
|
||||||
gulp.task("build-translation-fingerprints", () => {
|
gulp.task(
|
||||||
// Fingerprint full file of each language
|
"build-translation-fingerprints",
|
||||||
const files = fs.readdirSync(fullDir);
|
function fingerprintTranslationFiles() {
|
||||||
|
// Fingerprint full file of each language
|
||||||
|
const files = fs.readdirSync(fullDir);
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
fingerprints[files[i].split(".")[0]] = {
|
fingerprints[files[i].split(".")[0]] = {
|
||||||
// In dev we create fake hashes
|
// In dev we create fake hashes
|
||||||
hash: env.isProdBuild()
|
hash: env.isProdBuild()
|
||||||
? crypto
|
? crypto
|
||||||
.createHash("md5")
|
.createHash("md5")
|
||||||
.update(fs.readFileSync(path.join(fullDir, files[i]), "utf-8"))
|
.update(fs.readFileSync(path.join(fullDir, files[i]), "utf-8"))
|
||||||
.digest("hex")
|
.digest("hex")
|
||||||
: "dev",
|
: "dev",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// In dev we create the file with the fake hash in the filename
|
|
||||||
if (env.isProdBuild()) {
|
|
||||||
mapFiles(outDir, ".json", (filename) => {
|
mapFiles(outDir, ".json", (filename) => {
|
||||||
const parsed = path.parse(filename);
|
const parsed = path.parse(filename);
|
||||||
|
|
||||||
@@ -324,80 +334,12 @@ gulp.task("build-translation-fingerprints", () => {
|
|||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const stream = source("translationFingerprints.json");
|
||||||
|
stream.write(JSON.stringify(fingerprints));
|
||||||
|
process.nextTick(() => stream.end());
|
||||||
|
return stream.pipe(vinylBuffer()).pipe(gulp.dest(workDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
const stream = source("translationFingerprints.json");
|
|
||||||
stream.write(JSON.stringify(fingerprints));
|
|
||||||
process.nextTick(() => stream.end());
|
|
||||||
return stream.pipe(vinylBuffer()).pipe(gulp.dest(workDir));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("build-translation-fragment-supervisor", () =>
|
|
||||||
gulp
|
|
||||||
.src(fullDir + "/*.json")
|
|
||||||
.pipe(transform((data) => data.supervisor))
|
|
||||||
.pipe(gulp.dest(workDir + "/supervisor"))
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task("build-translation-flatten-supervisor", () =>
|
|
||||||
gulp
|
|
||||||
.src(workDir + "/supervisor/*.json")
|
|
||||||
.pipe(
|
|
||||||
transform((data) =>
|
|
||||||
// Polymer.AppLocalizeBehavior requires flattened json
|
|
||||||
flatten(data)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.pipe(gulp.dest(outDir))
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task("build-translation-write-metadata", () =>
|
|
||||||
gulp
|
|
||||||
.src(
|
|
||||||
[
|
|
||||||
path.join(paths.translations_src, "translationMetadata.json"),
|
|
||||||
workDir + "/testMetadata.json",
|
|
||||||
workDir + "/translationFingerprints.json",
|
|
||||||
],
|
|
||||||
{ allowEmpty: true }
|
|
||||||
)
|
|
||||||
.pipe(merge({}))
|
|
||||||
.pipe(
|
|
||||||
transform((data) => {
|
|
||||||
const newData = {};
|
|
||||||
Object.entries(data).forEach(([key, value]) => {
|
|
||||||
// Filter out translations without native name.
|
|
||||||
if (value.nativeName) {
|
|
||||||
newData[key] = value;
|
|
||||||
} else {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.warn(
|
|
||||||
`Skipping language ${key}. Native name was not translated.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return newData;
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(
|
|
||||||
transform((data) => ({
|
|
||||||
fragments: TRANSLATION_FRAGMENTS,
|
|
||||||
translations: data,
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
.pipe(rename("translationMetadata.json"))
|
|
||||||
.pipe(gulp.dest(workDir))
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task(
|
|
||||||
"create-translations",
|
|
||||||
gulp.series(
|
|
||||||
env.isProdBuild() ? (done) => done() : "create-test-translation",
|
|
||||||
"build-master-translation",
|
|
||||||
"build-merged-translations",
|
|
||||||
gulp.parallel(...splitTasks),
|
|
||||||
"build-flattened-translations"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
@@ -405,22 +347,48 @@ gulp.task(
|
|||||||
gulp.series(
|
gulp.series(
|
||||||
"clean-translations",
|
"clean-translations",
|
||||||
"ensure-translations-build-dir",
|
"ensure-translations-build-dir",
|
||||||
"create-translations",
|
env.isProdBuild() ? (done) => done() : "create-test-translation",
|
||||||
"build-translation-fingerprints",
|
|
||||||
"build-translation-write-metadata"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task(
|
|
||||||
"build-supervisor-translations",
|
|
||||||
gulp.series(
|
|
||||||
"clean-translations",
|
|
||||||
"ensure-translations-build-dir",
|
|
||||||
"build-master-translation",
|
"build-master-translation",
|
||||||
"build-merged-translations",
|
"build-merged-translations",
|
||||||
"build-translation-fragment-supervisor",
|
gulp.parallel(...splitTasks),
|
||||||
"build-translation-flatten-supervisor",
|
"build-flattened-translations",
|
||||||
"build-translation-fingerprints",
|
"build-translation-fingerprints",
|
||||||
"build-translation-write-metadata"
|
function writeMetadata() {
|
||||||
|
return gulp
|
||||||
|
.src(
|
||||||
|
[
|
||||||
|
path.join(paths.translations_src, "translationMetadata.json"),
|
||||||
|
workDir + "/testMetadata.json",
|
||||||
|
workDir + "/translationFingerprints.json",
|
||||||
|
],
|
||||||
|
{ allowEmpty: true }
|
||||||
|
)
|
||||||
|
.pipe(merge({}))
|
||||||
|
.pipe(
|
||||||
|
transform(function (data) {
|
||||||
|
const newData = {};
|
||||||
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
|
// Filter out translations without native name.
|
||||||
|
if (data[key].nativeName) {
|
||||||
|
newData[key] = data[key];
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
`Skipping language ${key}. Native name was not translated.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (data[key]) newData[key] = value;
|
||||||
|
});
|
||||||
|
return newData;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
transform((data) => ({
|
||||||
|
fragments: TRANSLATION_FRAGMENTS,
|
||||||
|
translations: data,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
.pipe(rename("translationMetadata.json"))
|
||||||
|
.pipe(gulp.dest(workDir));
|
||||||
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
// Tasks to run webpack.
|
// Tasks to run webpack.
|
||||||
const fs = require("fs");
|
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
const WebpackDevServer = require("webpack-dev-server");
|
const WebpackDevServer = require("webpack-dev-server");
|
||||||
@@ -20,13 +18,6 @@ const bothBuilds = (createConfigFunc, params) => [
|
|||||||
createConfigFunc({ ...params, latestBuild: false }),
|
createConfigFunc({ ...params, latestBuild: false }),
|
||||||
];
|
];
|
||||||
|
|
||||||
const isWsl =
|
|
||||||
fs.existsSync("/proc/version") &&
|
|
||||||
fs
|
|
||||||
.readFileSync("/proc/version", "utf-8")
|
|
||||||
.toLocaleLowerCase()
|
|
||||||
.includes("microsoft");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {{
|
* @param {{
|
||||||
* compiler: import("webpack").Compiler,
|
* compiler: import("webpack").Compiler,
|
||||||
@@ -45,7 +36,7 @@ const runDevServer = ({
|
|||||||
open: true,
|
open: true,
|
||||||
watchContentBase: true,
|
watchContentBase: true,
|
||||||
contentBase,
|
contentBase,
|
||||||
}).listen(port, listenHost, (err) => {
|
}).listen(port, listenHost, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@@ -66,7 +57,6 @@ const doneHandler = (done) => (err, stats) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stats.hasErrors() || stats.hasWarnings()) {
|
if (stats.hasErrors() || stats.hasWarnings()) {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(stats.toString("minimal"));
|
console.log(stats.toString("minimal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,14 +78,13 @@ const prodBuild = (conf) =>
|
|||||||
|
|
||||||
gulp.task("webpack-watch-app", () => {
|
gulp.task("webpack-watch-app", () => {
|
||||||
// This command will run forever because we don't close compiler
|
// This command will run forever because we don't close compiler
|
||||||
webpack(
|
webpack(createAppConfig({ isProdBuild: false, latestBuild: true })).watch(
|
||||||
process.env.ES5
|
{ ignored: /build-translations/ },
|
||||||
? bothBuilds(createAppConfig, { isProdBuild: false })
|
doneHandler()
|
||||||
: createAppConfig({ isProdBuild: false, latestBuild: true })
|
);
|
||||||
).watch({ poll: isWsl }, doneHandler());
|
|
||||||
gulp.watch(
|
gulp.watch(
|
||||||
path.join(paths.translations_src, "en.json"),
|
path.join(paths.translations_src, "en.json"),
|
||||||
gulp.series("create-translations", "copy-translations-app")
|
gulp.series("build-translations", "copy-translations-app")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -148,12 +137,7 @@ gulp.task("webpack-watch-hassio", () => {
|
|||||||
isProdBuild: false,
|
isProdBuild: false,
|
||||||
latestBuild: true,
|
latestBuild: true,
|
||||||
})
|
})
|
||||||
).watch({ ignored: /build-translations/, poll: isWsl }, doneHandler());
|
).watch({}, doneHandler());
|
||||||
|
|
||||||
gulp.watch(
|
|
||||||
path.join(paths.translations_src, "en.json"),
|
|
||||||
gulp.series("build-supervisor-translations", "copy-translations-supervisor")
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-hassio", () =>
|
gulp.task("webpack-prod-hassio", () =>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -35,7 +34,6 @@ module.exports = {
|
|||||||
|
|
||||||
hassio_dir: path.resolve(__dirname, "../hassio"),
|
hassio_dir: path.resolve(__dirname, "../hassio"),
|
||||||
hassio_output_root: path.resolve(__dirname, "../hassio/build"),
|
hassio_output_root: path.resolve(__dirname, "../hassio/build"),
|
||||||
hassio_output_static: path.resolve(__dirname, "../hassio/build/static"),
|
|
||||||
hassio_output_latest: path.resolve(
|
hassio_output_latest: path.resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../hassio/build/frontend_latest"
|
"../hassio/build/frontend_latest"
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
const commonjs = require("@rollup/plugin-commonjs");
|
const commonjs = require("@rollup/plugin-commonjs");
|
||||||
@@ -33,77 +32,88 @@ const createRollupConfig = ({
|
|||||||
publicPath,
|
publicPath,
|
||||||
dontHash,
|
dontHash,
|
||||||
isWDS,
|
isWDS,
|
||||||
}) => ({
|
}) => {
|
||||||
/**
|
return {
|
||||||
* @type { import("rollup").InputOptions }
|
/**
|
||||||
*/
|
* @type { import("rollup").InputOptions }
|
||||||
inputOptions: {
|
*/
|
||||||
input: entry,
|
inputOptions: {
|
||||||
// Some entry points contain no JavaScript. This setting silences a warning about that.
|
input: entry,
|
||||||
// https://rollupjs.org/guide/en/#preserveentrysignatures
|
// Some entry points contain no JavaScript. This setting silences a warning about that.
|
||||||
preserveEntrySignatures: false,
|
// https://rollupjs.org/guide/en/#preserveentrysignatures
|
||||||
plugins: [
|
preserveEntrySignatures: false,
|
||||||
ignore({
|
plugins: [
|
||||||
files: bundle.emptyPackages({ latestBuild }),
|
ignore({
|
||||||
}),
|
files: bundle.emptyPackages({ latestBuild }),
|
||||||
resolve({
|
|
||||||
extensions,
|
|
||||||
preferBuiltins: false,
|
|
||||||
browser: true,
|
|
||||||
rootDir: paths.polymer_dir,
|
|
||||||
}),
|
|
||||||
commonjs(),
|
|
||||||
json(),
|
|
||||||
babel({
|
|
||||||
...bundle.babelOptions({ latestBuild }),
|
|
||||||
extensions,
|
|
||||||
babelHelpers: isWDS ? "inline" : "bundled",
|
|
||||||
}),
|
|
||||||
string({
|
|
||||||
// Import certain extensions as strings
|
|
||||||
include: [path.join(paths.polymer_dir, "node_modules/**/*.css")],
|
|
||||||
}),
|
|
||||||
replace(bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })),
|
|
||||||
!isWDS &&
|
|
||||||
manifest({
|
|
||||||
publicPath,
|
|
||||||
}),
|
}),
|
||||||
!isWDS && worker(),
|
resolve({
|
||||||
!isWDS && dontHashPlugin({ dontHash }),
|
extensions,
|
||||||
!isWDS && isProdBuild && terser(bundle.terserOptions(latestBuild)),
|
preferBuiltins: false,
|
||||||
!isWDS &&
|
browser: true,
|
||||||
isStatsBuild &&
|
rootDir: paths.polymer_dir,
|
||||||
visualizer({
|
|
||||||
// https://github.com/btd/rollup-plugin-visualizer#options
|
|
||||||
open: true,
|
|
||||||
sourcemap: true,
|
|
||||||
}),
|
}),
|
||||||
].filter(Boolean),
|
commonjs({
|
||||||
},
|
namedExports: {
|
||||||
/**
|
"js-yaml": ["safeDump", "safeLoad"],
|
||||||
* @type { import("rollup").OutputOptions }
|
},
|
||||||
*/
|
}),
|
||||||
outputOptions: {
|
json(),
|
||||||
// https://rollupjs.org/guide/en/#outputdir
|
babel({
|
||||||
dir: outputPath,
|
...bundle.babelOptions({ latestBuild }),
|
||||||
// https://rollupjs.org/guide/en/#outputformat
|
extensions,
|
||||||
format: latestBuild ? "es" : "systemjs",
|
exclude: bundle.babelExclude(),
|
||||||
// https://rollupjs.org/guide/en/#outputexternallivebindings
|
babelHelpers: isWDS ? "inline" : "bundled",
|
||||||
externalLiveBindings: false,
|
}),
|
||||||
// https://rollupjs.org/guide/en/#outputentryfilenames
|
string({
|
||||||
// https://rollupjs.org/guide/en/#outputchunkfilenames
|
// Import certain extensions as strings
|
||||||
// https://rollupjs.org/guide/en/#outputassetfilenames
|
include: [path.join(paths.polymer_dir, "node_modules/**/*.css")],
|
||||||
entryFileNames:
|
}),
|
||||||
isProdBuild && !isStatsBuild ? "[name]-[hash].js" : "[name].js",
|
replace(
|
||||||
chunkFileNames: isProdBuild && !isStatsBuild ? "c.[hash].js" : "[name].js",
|
bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })
|
||||||
assetFileNames: isProdBuild && !isStatsBuild ? "a.[hash].js" : "[name].js",
|
),
|
||||||
// https://rollupjs.org/guide/en/#outputsourcemap
|
!isWDS &&
|
||||||
sourcemap: isProdBuild ? true : "inline",
|
manifest({
|
||||||
},
|
publicPath,
|
||||||
});
|
}),
|
||||||
|
!isWDS && worker(),
|
||||||
|
!isWDS && dontHashPlugin({ dontHash }),
|
||||||
|
!isWDS && isProdBuild && terser(bundle.terserOptions(latestBuild)),
|
||||||
|
!isWDS &&
|
||||||
|
isStatsBuild &&
|
||||||
|
visualizer({
|
||||||
|
// https://github.com/btd/rollup-plugin-visualizer#options
|
||||||
|
open: true,
|
||||||
|
sourcemap: true,
|
||||||
|
}),
|
||||||
|
].filter(Boolean),
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @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, isWDS }) =>
|
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) => {
|
||||||
createRollupConfig(
|
return createRollupConfig(
|
||||||
bundle.config.app({
|
bundle.config.app({
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
@@ -111,24 +121,31 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) =>
|
|||||||
isWDS,
|
isWDS,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
|
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
createRollupConfig(
|
return createRollupConfig(
|
||||||
bundle.config.demo({
|
bundle.config.demo({
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
isStatsBuild,
|
isStatsBuild,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createCastConfig = ({ isProdBuild, latestBuild }) =>
|
const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createRollupConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
return createRollupConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
||||||
|
};
|
||||||
|
|
||||||
const createHassioConfig = ({ isProdBuild, latestBuild }) =>
|
const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createRollupConfig(bundle.config.hassio({ isProdBuild, latestBuild }));
|
return createRollupConfig(bundle.config.hassio({ isProdBuild, latestBuild }));
|
||||||
|
};
|
||||||
|
|
||||||
const createGalleryConfig = ({ isProdBuild, latestBuild }) =>
|
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createRollupConfig(bundle.config.gallery({ isProdBuild, latestBuild }));
|
return createRollupConfig(
|
||||||
|
bundle.config.gallery({ isProdBuild, latestBuild })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createAppConfig,
|
createAppConfig,
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
|
@@ -1,10 +1,9 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const TerserPlugin = require("terser-webpack-plugin");
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
|
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
const bundle = require("./bundle.js");
|
const bundle = require("./bundle");
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
|
|
||||||
class LogStartCompilePlugin {
|
class LogStartCompilePlugin {
|
||||||
@@ -47,18 +46,15 @@ const createWebpackConfig = ({
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.m?js$|\.ts$/,
|
test: /\.m?js$|\.ts$/,
|
||||||
|
exclude: bundle.babelExclude(),
|
||||||
use: {
|
use: {
|
||||||
loader: "babel-loader",
|
loader: "babel-loader",
|
||||||
options: {
|
options: bundle.babelOptions({ latestBuild }),
|
||||||
...bundle.babelOptions({ latestBuild }),
|
|
||||||
cacheDirectory: !isProdBuild,
|
|
||||||
cacheCompression: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
type: "asset/source",
|
use: "raw-loader",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -70,11 +66,9 @@ const createWebpackConfig = ({
|
|||||||
terserOptions: bundle.terserOptions(latestBuild),
|
terserOptions: bundle.terserOptions(latestBuild),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
moduleIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
|
||||||
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new WebpackManifestPlugin({
|
new ManifestPlugin({
|
||||||
// Only include the JS of entrypoints
|
// Only include the JS of entrypoints
|
||||||
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
||||||
}),
|
}),
|
||||||
@@ -100,7 +94,6 @@ const createWebpackConfig = ({
|
|||||||
? path.resolve(context, resource)
|
? path.resolve(context, resource)
|
||||||
: require.resolve(resource);
|
: require.resolve(resource);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(
|
console.error(
|
||||||
"Error in Home Assistant ignore plugin",
|
"Error in Home Assistant ignore plugin",
|
||||||
resource,
|
resource,
|
||||||
@@ -118,25 +111,31 @@ const createWebpackConfig = ({
|
|||||||
new RegExp(bundle.emptyPackages({ latestBuild }).join("|")),
|
new RegExp(bundle.emptyPackages({ latestBuild }).join("|")),
|
||||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||||
),
|
),
|
||||||
|
// We need to change the import of the polyfill for EventTarget, so we replace the polyfill file with our customized one
|
||||||
|
new webpack.NormalModuleReplacementPlugin(
|
||||||
|
new RegExp(
|
||||||
|
require.resolve(
|
||||||
|
"lit-virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js")
|
||||||
|
),
|
||||||
!isProdBuild && new LogStartCompilePlugin(),
|
!isProdBuild && new LogStartCompilePlugin(),
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".ts", ".js", ".json"],
|
extensions: [".ts", ".js", ".json"],
|
||||||
alias: {
|
|
||||||
"lit/decorators$": "lit/decorators.js",
|
|
||||||
"lit/directive$": "lit/directive.js",
|
|
||||||
"lit/polyfill-support$": "lit/polyfill-support.js",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: ({ chunk }) => {
|
filename: ({ chunk }) => {
|
||||||
if (!isProdBuild || isStatsBuild || dontHash.has(chunk.name)) {
|
if (!isProdBuild || dontHash.has(chunk.name)) {
|
||||||
return `${chunk.name}.js`;
|
return `${chunk.name}.js`;
|
||||||
}
|
}
|
||||||
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
||||||
},
|
},
|
||||||
chunkFilename:
|
chunkFilename:
|
||||||
isProdBuild && !isStatsBuild ? "[chunkhash:8].js" : "[id].chunk.js",
|
isProdBuild && !isStatsBuild
|
||||||
|
? "chunk.[chunkhash].js"
|
||||||
|
: "[name].chunk.js",
|
||||||
path: outputPath,
|
path: outputPath,
|
||||||
publicPath,
|
publicPath,
|
||||||
// To silence warning in worker plugin
|
// To silence warning in worker plugin
|
||||||
@@ -145,24 +144,33 @@ const createWebpackConfig = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
|
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
createWebpackConfig(
|
return createWebpackConfig(
|
||||||
bundle.config.app({ isProdBuild, latestBuild, isStatsBuild })
|
bundle.config.app({ isProdBuild, latestBuild, isStatsBuild })
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
|
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
createWebpackConfig(
|
return createWebpackConfig(
|
||||||
bundle.config.demo({ isProdBuild, latestBuild, isStatsBuild })
|
bundle.config.demo({ isProdBuild, latestBuild, isStatsBuild })
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createCastConfig = ({ isProdBuild, latestBuild }) =>
|
const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
return createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
||||||
|
};
|
||||||
|
|
||||||
const createHassioConfig = ({ isProdBuild, latestBuild }) =>
|
const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createWebpackConfig(bundle.config.hassio({ isProdBuild, latestBuild }));
|
return createWebpackConfig(
|
||||||
|
bundle.config.hassio({ isProdBuild, latestBuild })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createGalleryConfig = ({ isProdBuild, latestBuild }) =>
|
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createWebpackConfig(bundle.config.gallery({ isProdBuild, latestBuild }));
|
return createWebpackConfig(
|
||||||
|
bundle.config.gallery({ isProdBuild, latestBuild })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createAppConfig,
|
createAppConfig,
|
||||||
|
@@ -139,7 +139,7 @@
|
|||||||
Your authentication credentials or Home Assistant url are never sent
|
Your authentication credentials or Home Assistant url are never sent
|
||||||
to the Cloud. You can validate this behavior in
|
to the Cloud. You can validate this behavior in
|
||||||
<a
|
<a
|
||||||
href="https://github.com/home-assistant/frontend/tree/dev/cast"
|
href="https://github.com/home-assistant/home-assistant-polymer/tree/dev/cast"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>the source code</a
|
>the source code</a
|
||||||
>.
|
>.
|
||||||
|
@@ -1,9 +1,16 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
|
||||||
import "@polymer/paper-item/paper-icon-item";
|
import "@polymer/paper-item/paper-icon-item";
|
||||||
import "@polymer/paper-listbox/paper-listbox";
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
import { Auth, Connection } from "home-assistant-js-websocket";
|
import { Auth, Connection } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
internalProperty,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { CastManager } from "../../../../src/cast/cast_manager";
|
import { CastManager } from "../../../../src/cast/cast_manager";
|
||||||
import {
|
import {
|
||||||
castSendShowLovelaceView,
|
castSendShowLovelaceView,
|
||||||
@@ -25,6 +32,7 @@ import {
|
|||||||
import "../../../../src/layouts/hass-loading-screen";
|
import "../../../../src/layouts/hass-loading-screen";
|
||||||
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
||||||
import "./hc-layout";
|
import "./hc-layout";
|
||||||
|
import "@material/mwc-button/mwc-button";
|
||||||
|
|
||||||
@customElement("hc-cast")
|
@customElement("hc-cast")
|
||||||
class HcCast extends LitElement {
|
class HcCast extends LitElement {
|
||||||
@@ -34,19 +42,21 @@ class HcCast extends LitElement {
|
|||||||
|
|
||||||
@property() public castManager!: CastManager;
|
@property() public castManager!: CastManager;
|
||||||
|
|
||||||
@state() private askWrite = false;
|
@internalProperty() private askWrite = false;
|
||||||
|
|
||||||
@state() private lovelaceConfig?: LovelaceConfig | null;
|
@internalProperty() private lovelaceConfig?: LovelaceConfig | null;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (this.lovelaceConfig === undefined) {
|
if (this.lovelaceConfig === undefined) {
|
||||||
return html`<hass-loading-screen no-toolbar></hass-loading-screen>`;
|
return html` <hass-loading-screen no-toolbar></hass-loading-screen>> `;
|
||||||
}
|
}
|
||||||
|
|
||||||
const error =
|
const error =
|
||||||
this.castManager.castState === "NO_DEVICES_AVAILABLE"
|
this.castManager.castState === "NO_DEVICES_AVAILABLE"
|
||||||
? html`
|
? html`
|
||||||
<p>There were no suitable Chromecast devices to cast to found.</p>
|
<p>
|
||||||
|
There were no suitable Chromecast devices to cast to found.
|
||||||
|
</p>
|
||||||
`
|
`
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
@@ -196,7 +206,7 @@ class HcCast extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
.center-item {
|
.center-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@@ -11,8 +11,15 @@ import {
|
|||||||
getAuth,
|
getAuth,
|
||||||
getAuthOptions,
|
getAuthOptions,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
internalProperty,
|
||||||
|
} from "lit-element";
|
||||||
import { CastManager, getCastManager } from "../../../../src/cast/cast_manager";
|
import { CastManager, getCastManager } from "../../../../src/cast/cast_manager";
|
||||||
import { castSendShowDemo } from "../../../../src/cast/receiver_messages";
|
import { castSendShowDemo } from "../../../../src/cast/receiver_messages";
|
||||||
import {
|
import {
|
||||||
@@ -53,19 +60,19 @@ const INTRO = html`
|
|||||||
|
|
||||||
@customElement("hc-connect")
|
@customElement("hc-connect")
|
||||||
export class HcConnect extends LitElement {
|
export class HcConnect extends LitElement {
|
||||||
@state() private loading = false;
|
@internalProperty() private loading = false;
|
||||||
|
|
||||||
// If we had stored credentials but we cannot connect,
|
// If we had stored credentials but we cannot connect,
|
||||||
// show a screen asking retry or logout.
|
// show a screen asking retry or logout.
|
||||||
@state() private cannotConnect = false;
|
@internalProperty() private cannotConnect = false;
|
||||||
|
|
||||||
@state() private error?: string | TemplateResult;
|
@internalProperty() private error?: string | TemplateResult;
|
||||||
|
|
||||||
@state() private auth?: Auth;
|
@internalProperty() private auth?: Auth;
|
||||||
|
|
||||||
@state() private connection?: Connection;
|
@internalProperty() private connection?: Connection;
|
||||||
|
|
||||||
@state() private castManager?: CastManager | null;
|
@internalProperty() private castManager?: CastManager | null;
|
||||||
|
|
||||||
private openDemo = false;
|
private openDemo = false;
|
||||||
|
|
||||||
@@ -79,7 +86,9 @@ export class HcConnect extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<mwc-button> Retry </mwc-button>
|
<mwc-button>
|
||||||
|
Retry
|
||||||
|
</mwc-button>
|
||||||
</a>
|
</a>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<mwc-button @click=${this._handleLogout}>Log out</mwc-button>
|
<mwc-button @click=${this._handleLogout}>Log out</mwc-button>
|
||||||
@@ -290,7 +299,7 @@ export class HcConnect extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
.card-content a {
|
.card-content a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
@@ -4,8 +4,15 @@ import {
|
|||||||
getUser,
|
getUser,
|
||||||
HassUser,
|
HassUser,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
|
|
||||||
@customElement("hc-layout")
|
@customElement("hc-layout")
|
||||||
@@ -62,7 +69,7 @@ class HcLayout extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -91,12 +98,8 @@ class HcLayout extends LitElement {
|
|||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
padding: 24px 16px 16px;
|
padding: 24px 16px 16px;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero {
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
}
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
|
@@ -5,8 +5,8 @@ import {
|
|||||||
import { castContext } from "../cast_context";
|
import { castContext } from "../cast_context";
|
||||||
|
|
||||||
export const castDemoLovelace: () => LovelaceConfig = () => {
|
export const castDemoLovelace: () => LovelaceConfig = () => {
|
||||||
const touchSupported =
|
const touchSupported = castContext.getDeviceCapabilities()
|
||||||
castContext.getDeviceCapabilities().touch_input_supported;
|
.touch_input_supported;
|
||||||
return {
|
return {
|
||||||
views: [
|
views: [
|
||||||
{
|
{
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
import { html, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { mockHistory } from "../../../../demo/src/stubs/history";
|
import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||||
import {
|
import {
|
||||||
@@ -16,7 +21,7 @@ import "./hc-lovelace";
|
|||||||
class HcDemo extends HassElement {
|
class HcDemo extends HassElement {
|
||||||
@property({ attribute: false }) public lovelacePath!: string;
|
@property({ attribute: false }) public lovelacePath!: string;
|
||||||
|
|
||||||
@state() private _lovelaceConfig?: LovelaceConfig;
|
@internalProperty() private _lovelaceConfig?: LovelaceConfig;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._lovelaceConfig) {
|
if (!this._lovelaceConfig) {
|
||||||
@@ -33,10 +38,10 @@ class HcDemo extends HassElement {
|
|||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
protected firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this._initializeHass();
|
this._initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initializeHass() {
|
private async _initialize() {
|
||||||
const initial: Partial<MockHomeAssistant> = {
|
const initial: Partial<MockHomeAssistant> = {
|
||||||
// Override updateHass so that the correct hass lifecycle methods are called
|
// Override updateHass so that the correct hass lifecycle methods are called
|
||||||
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
|
||||||
@customElement("hc-launch-screen")
|
@customElement("hc-launch-screen")
|
||||||
@@ -22,7 +29,7 @@ class HcLaunchScreen extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||||
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
||||||
import "../../../../src/panels/lovelace/views/hui-view";
|
import "../../../../src/panels/lovelace/views/hui-view";
|
||||||
@@ -28,12 +35,11 @@ class HcLovelace extends LitElement {
|
|||||||
}
|
}
|
||||||
const lovelace: Lovelace = {
|
const lovelace: Lovelace = {
|
||||||
config: this.lovelaceConfig,
|
config: this.lovelaceConfig,
|
||||||
rawConfig: this.lovelaceConfig,
|
|
||||||
editMode: false,
|
editMode: false,
|
||||||
urlPath: this.urlPath!,
|
urlPath: this.urlPath!,
|
||||||
enableFullEditMode: () => undefined,
|
enableFullEditMode: () => undefined,
|
||||||
mode: "storage",
|
mode: "storage",
|
||||||
locale: this.hass.locale,
|
language: "en",
|
||||||
saveConfig: async () => undefined,
|
saveConfig: async () => undefined,
|
||||||
deleteConfig: async () => undefined,
|
deleteConfig: async () => undefined,
|
||||||
setEditMode: () => undefined,
|
setEditMode: () => undefined,
|
||||||
@@ -84,11 +90,10 @@ class HcLovelace extends LitElement {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
height: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@@ -3,8 +3,12 @@ import {
|
|||||||
getAuth,
|
getAuth,
|
||||||
UnsubscribeFunc,
|
UnsubscribeFunc,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { html, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, state } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { CAST_NS } from "../../../../src/cast/const";
|
import { CAST_NS } from "../../../../src/cast/const";
|
||||||
import {
|
import {
|
||||||
ConnectMessage,
|
ConnectMessage,
|
||||||
@@ -32,13 +36,13 @@ let resourcesLoaded = false;
|
|||||||
|
|
||||||
@customElement("hc-main")
|
@customElement("hc-main")
|
||||||
export class HcMain extends HassElement {
|
export class HcMain extends HassElement {
|
||||||
@state() private _showDemo = false;
|
@internalProperty() private _showDemo = false;
|
||||||
|
|
||||||
@state() private _lovelaceConfig?: LovelaceConfig;
|
@internalProperty() private _lovelaceConfig?: LovelaceConfig;
|
||||||
|
|
||||||
@state() private _lovelacePath: string | number | null = null;
|
@internalProperty() private _lovelacePath: string | number | null = null;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
private _unsubLovelace?: UnsubscribeFunc;
|
private _unsubLovelace?: UnsubscribeFunc;
|
||||||
|
|
||||||
@@ -217,17 +221,11 @@ export class HcMain extends HassElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _generateLovelaceConfig() {
|
private async _generateLovelaceConfig() {
|
||||||
const { generateLovelaceDashboardStrategy } = await import(
|
const { generateLovelaceConfigFromHass } = await import(
|
||||||
"../../../../src/panels/lovelace/strategies/get-strategy"
|
"../../../../src/panels/lovelace/common/generate-lovelace-config"
|
||||||
);
|
);
|
||||||
this._handleNewLovelaceConfig(
|
this._handleNewLovelaceConfig(
|
||||||
await generateLovelaceDashboardStrategy(
|
await generateLovelaceConfigFromHass(this.hass!)
|
||||||
{
|
|
||||||
hass: this.hass!,
|
|
||||||
narrow: false,
|
|
||||||
},
|
|
||||||
"original-states"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -246,15 +246,11 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
|
|
||||||
"light.living_room_lights": {
|
"light.living_room_lights": {
|
||||||
entity_id: "light.living_room_lights",
|
entity_id: "light.living_room_lights",
|
||||||
state: "on",
|
state: "off",
|
||||||
attributes: {
|
attributes: {
|
||||||
min_mireds: 111,
|
min_mireds: 111,
|
||||||
max_mireds: 400,
|
max_mireds: 400,
|
||||||
brightness: 175,
|
|
||||||
color_temp: 300,
|
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
friendly_name: "Living Room Lights",
|
friendly_name: "Living Room Lights",
|
||||||
color_mode: "color_temp",
|
|
||||||
supported_features: 55,
|
supported_features: 55,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -267,27 +263,13 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
},
|
},
|
||||||
"light.kitchen_lights": {
|
"light.kitchen_lights": {
|
||||||
entity_id: "light.kitchen_lights",
|
entity_id: "light.kitchen_lights",
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
min_mireds: 111,
|
|
||||||
max_mireds: 400,
|
|
||||||
brightness: 200,
|
|
||||||
rgb_color: [255, 175, 96],
|
|
||||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
|
||||||
color_mode: "rgb",
|
|
||||||
friendly_name: "Kitchen Lights",
|
|
||||||
supported_features: 55,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"light.lifx5": {
|
|
||||||
entity_id: "light.lifx5",
|
|
||||||
state: "off",
|
state: "off",
|
||||||
attributes: {
|
attributes: {
|
||||||
supported_color_modes: ["brightness"],
|
friendly_name: "Kitchen Lights",
|
||||||
friendly_name: "Garage Lights",
|
|
||||||
supported_features: 1,
|
supported_features: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"sensor.plexspy": {
|
"sensor.plexspy": {
|
||||||
entity_id: "sensor.plexspy",
|
entity_id: "sensor.plexspy",
|
||||||
state: "0",
|
state: "0",
|
||||||
@@ -500,6 +482,16 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
icon: "hademo:history",
|
icon: "hademo:history",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"light.lifx5": {
|
||||||
|
entity_id: "light.lifx5",
|
||||||
|
state: "on",
|
||||||
|
attributes: {
|
||||||
|
min_mireds: 111,
|
||||||
|
max_mireds: 400,
|
||||||
|
friendly_name: "Garage Lights",
|
||||||
|
supported_features: 55,
|
||||||
|
},
|
||||||
|
},
|
||||||
"sensor.alok_to_home": {
|
"sensor.alok_to_home": {
|
||||||
entity_id: "sensor.alok_to_home",
|
entity_id: "sensor.alok_to_home",
|
||||||
state: "41",
|
state: "41",
|
||||||
|
@@ -29,11 +29,6 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: "Energy distribution today",
|
|
||||||
type: "energy-distribution",
|
|
||||||
link_dashboard: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
type: "thermostat",
|
type: "thermostat",
|
||||||
entity: "climate.upstairs",
|
entity: "climate.upstairs",
|
||||||
@@ -118,7 +113,8 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({
|
|||||||
on: "/assets/arsaboo/icons/light_bulb_on.png",
|
on: "/assets/arsaboo/icons/light_bulb_on.png",
|
||||||
},
|
},
|
||||||
state_filter: {
|
state_filter: {
|
||||||
on: "brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)",
|
on:
|
||||||
|
"brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)",
|
||||||
off: "brightness(80%) saturate(0.8)",
|
off: "brightness(80%) saturate(0.8)",
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
@@ -200,7 +196,8 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({
|
|||||||
on: "/assets/arsaboo/icons/light_bulb_on.png",
|
on: "/assets/arsaboo/icons/light_bulb_on.png",
|
||||||
},
|
},
|
||||||
state_filter: {
|
state_filter: {
|
||||||
on: "brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)",
|
on:
|
||||||
|
"brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)",
|
||||||
off: "brightness(80%) saturate(0.8)",
|
off: "brightness(80%) saturate(0.8)",
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
@@ -280,7 +277,8 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({
|
|||||||
on: "/assets/arsaboo/icons/light_bulb_on.png",
|
on: "/assets/arsaboo/icons/light_bulb_on.png",
|
||||||
},
|
},
|
||||||
state_filter: {
|
state_filter: {
|
||||||
on: "brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)",
|
on:
|
||||||
|
"brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)",
|
||||||
off: "brightness(80%) saturate(0.8)",
|
off: "brightness(80%) saturate(0.8)",
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
@@ -317,7 +315,8 @@ export const demoLovelaceArsaboo: DemoConfig["lovelace"] = (localize) => ({
|
|||||||
on: "/assets/arsaboo/icons/light_bulb_on.png",
|
on: "/assets/arsaboo/icons/light_bulb_on.png",
|
||||||
},
|
},
|
||||||
state_filter: {
|
state_filter: {
|
||||||
on: "brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)",
|
on:
|
||||||
|
"brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold)",
|
||||||
off: "brightness(80%) saturate(0.8)",
|
off: "brightness(80%) saturate(0.8)",
|
||||||
},
|
},
|
||||||
style: {
|
style: {
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
import { Lovelace } from "../../../src/panels/lovelace/types";
|
import { Lovelace } from "../../../src/panels/lovelace/types";
|
||||||
import { energyEntities } from "../stubs/entities";
|
|
||||||
import { DemoConfig } from "./types";
|
import { DemoConfig } from "./types";
|
||||||
|
|
||||||
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
||||||
@@ -13,8 +12,9 @@ export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
|||||||
// eslint-disable-next-line import/no-mutable-exports
|
// eslint-disable-next-line import/no-mutable-exports
|
||||||
export let selectedDemoConfigIndex = 0;
|
export let selectedDemoConfigIndex = 0;
|
||||||
// eslint-disable-next-line import/no-mutable-exports
|
// eslint-disable-next-line import/no-mutable-exports
|
||||||
export let selectedDemoConfig: Promise<DemoConfig> =
|
export let selectedDemoConfig: Promise<DemoConfig> = demoConfigs[
|
||||||
demoConfigs[selectedDemoConfigIndex]();
|
selectedDemoConfigIndex
|
||||||
|
]();
|
||||||
|
|
||||||
export const setDemoConfig = async (
|
export const setDemoConfig = async (
|
||||||
hass: MockHomeAssistant,
|
hass: MockHomeAssistant,
|
||||||
@@ -28,7 +28,6 @@ export const setDemoConfig = async (
|
|||||||
selectedDemoConfig = confProm;
|
selectedDemoConfig = confProm;
|
||||||
|
|
||||||
hass.addEntities(config.entities(hass.localize), true);
|
hass.addEntities(config.entities(hass.localize), true);
|
||||||
hass.addEntities(energyEntities());
|
|
||||||
lovelace.saveConfig(config.lovelace(hass.localize));
|
lovelace.saveConfig(config.lovelace(hass.localize));
|
||||||
hass.mockTheme(config.theme());
|
hass.mockTheme(config.theme());
|
||||||
};
|
};
|
||||||
|
@@ -980,7 +980,8 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
icon: "mdi:account-off",
|
icon: "mdi:account-off",
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
templates: {
|
templates: {
|
||||||
icon: "if (state === 'on') return 'mdi:account'; else if (state === 'off') return 'mdi:account-off';\n",
|
icon:
|
||||||
|
"if (state === 'on') return 'mdi:account'; else if (state === 'off') return 'mdi:account-off';\n",
|
||||||
icon_color:
|
icon_color:
|
||||||
"if (state === 'on') return 'rgb(56, 150, 56)'; else if (state === 'off') return 'rgb(249, 251, 255)';\n",
|
"if (state === 'on') return 'rgb(56, 150, 56)'; else if (state === 'off') return 'rgb(249, 251, 255)';\n",
|
||||||
},
|
},
|
||||||
@@ -1004,7 +1005,8 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
icon: "mdi:account-multiple-minus",
|
icon: "mdi:account-multiple-minus",
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
templates: {
|
templates: {
|
||||||
icon: "if (state === 'on') return 'mdi:account-group'; else if (state === 'off') return 'mdi:account-multiple-minus';\n",
|
icon:
|
||||||
|
"if (state === 'on') return 'mdi:account-group'; else if (state === 'off') return 'mdi:account-multiple-minus';\n",
|
||||||
icon_color:
|
icon_color:
|
||||||
"if (state === 'on') return 'rgb(56, 150, 56)'; else if (state === 'off') return 'rgb(249, 251, 255)';\n",
|
"if (state === 'on') return 'rgb(56, 150, 56)'; else if (state === 'off') return 'rgb(249, 251, 255)';\n",
|
||||||
},
|
},
|
||||||
@@ -1112,9 +1114,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
min_mireds: 153,
|
min_mireds: 153,
|
||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
brightness: 63,
|
brightness: 63,
|
||||||
color_temp: 200,
|
|
||||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
|
||||||
color_mode: "color_temp",
|
|
||||||
friendly_name: "Upstairs lights",
|
friendly_name: "Upstairs lights",
|
||||||
supported_features: 63,
|
supported_features: 63,
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
@@ -1126,7 +1125,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
friendly_name: "Walk in closet lights",
|
friendly_name: "Walk in closet lights",
|
||||||
supported_features: 41,
|
supported_features: 41,
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:wall-sconce",
|
icon: "mdi:wall-sconce",
|
||||||
},
|
},
|
||||||
@@ -1138,8 +1136,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
brightness: 254,
|
brightness: 254,
|
||||||
friendly_name: "Outdoor lights",
|
friendly_name: "Outdoor lights",
|
||||||
supported_features: 41,
|
supported_features: 41,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
color_mode: "brightness",
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:wall-sconce",
|
icon: "mdi:wall-sconce",
|
||||||
},
|
},
|
||||||
@@ -1152,8 +1148,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
brightness: 128,
|
brightness: 128,
|
||||||
color_temp: 366,
|
color_temp: 366,
|
||||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
|
||||||
color_mode: "color_temp",
|
|
||||||
effect_list: ["colorloop"],
|
effect_list: ["colorloop"],
|
||||||
friendly_name: "Downstairs lights",
|
friendly_name: "Downstairs lights",
|
||||||
supported_features: 63,
|
supported_features: 63,
|
||||||
@@ -1313,7 +1307,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
min_mireds: 153,
|
min_mireds: 153,
|
||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
friendly_name: "Bedside Lamp",
|
friendly_name: "Bedside Lamp",
|
||||||
supported_features: 63,
|
supported_features: 63,
|
||||||
@@ -1327,7 +1320,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
min_mireds: 153,
|
min_mireds: 153,
|
||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
friendly_name: "Floorlamp Reading Light",
|
friendly_name: "Floorlamp Reading Light",
|
||||||
supported_features: 43,
|
supported_features: 43,
|
||||||
@@ -1343,8 +1335,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
brightness: 128,
|
brightness: 128,
|
||||||
color_temp: 366,
|
color_temp: 366,
|
||||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
|
||||||
color_mode: "color_temp",
|
|
||||||
effect_list: ["colorloop"],
|
effect_list: ["colorloop"],
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
friendly_name: "Hallway window light",
|
friendly_name: "Hallway window light",
|
||||||
@@ -1359,7 +1349,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
brightness: 77,
|
brightness: 77,
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
friendly_name: "Isa Ceiling Light",
|
friendly_name: "Isa Ceiling Light",
|
||||||
supported_features: 41,
|
supported_features: 41,
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
@@ -1374,8 +1363,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
brightness: 150,
|
brightness: 150,
|
||||||
color_temp: 366,
|
color_temp: 366,
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
color_mode: "color_temp",
|
|
||||||
effect_list: ["colorloop"],
|
effect_list: ["colorloop"],
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
friendly_name: "Floorlamp",
|
friendly_name: "Floorlamp",
|
||||||
@@ -1390,7 +1377,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
friendly_name: "Bedroom Ceiling Light",
|
friendly_name: "Bedroom Ceiling Light",
|
||||||
supported_features: 41,
|
supported_features: 41,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:ceiling-light",
|
icon: "mdi:ceiling-light",
|
||||||
},
|
},
|
||||||
@@ -1401,7 +1387,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
friendly_name: "Nightlight",
|
friendly_name: "Nightlight",
|
||||||
supported_features: 17,
|
supported_features: 17,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:lamp",
|
icon: "mdi:lamp",
|
||||||
},
|
},
|
||||||
@@ -1768,7 +1753,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 2.2,
|
power_consumption: 2.2,
|
||||||
friendly_name: "Upstairs Hallway Light",
|
friendly_name: "Upstairs Hallway Light",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:ceiling-light",
|
icon: "mdi:ceiling-light",
|
||||||
},
|
},
|
||||||
@@ -1784,7 +1768,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 0,
|
power_consumption: 0,
|
||||||
friendly_name: "Dining Room Light",
|
friendly_name: "Dining Room Light",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:ceiling-light",
|
icon: "mdi:ceiling-light",
|
||||||
},
|
},
|
||||||
@@ -1800,7 +1783,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 0,
|
power_consumption: 0,
|
||||||
friendly_name: "Living room Spotlights",
|
friendly_name: "Living room Spotlights",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:track-light",
|
icon: "mdi:track-light",
|
||||||
},
|
},
|
||||||
@@ -1817,7 +1799,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 2.5,
|
power_consumption: 2.5,
|
||||||
friendly_name: "Passage Lights",
|
friendly_name: "Passage Lights",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:track-light",
|
icon: "mdi:track-light",
|
||||||
},
|
},
|
||||||
@@ -1862,7 +1843,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 37.4,
|
power_consumption: 37.4,
|
||||||
friendly_name: "Kitchen Lights",
|
friendly_name: "Kitchen Lights",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:track-light",
|
icon: "mdi:track-light",
|
||||||
},
|
},
|
||||||
|
@@ -440,43 +440,57 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
type: "horizontal-stack",
|
type: "horizontal-stack",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "grid",
|
|
||||||
columns: 2,
|
|
||||||
cards: [
|
cards: [
|
||||||
{
|
{
|
||||||
graph: "line",
|
cards: [
|
||||||
type: "sensor",
|
{
|
||||||
entity: "sensor.temperature_bedroom",
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
entity: "sensor.temperature_bedroom",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
name: "S's room",
|
||||||
|
entity: "sensor.temperature_stefan",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "horizontal-stack",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
graph: "line",
|
cards: [
|
||||||
type: "sensor",
|
{
|
||||||
name: "S's room",
|
graph: "line",
|
||||||
entity: "sensor.temperature_stefan",
|
type: "sensor",
|
||||||
|
entity: "sensor.temperature_passage",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
name: "Bathroom",
|
||||||
|
entity: "sensor.temperature_downstairs_bathroom",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "horizontal-stack",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
graph: "line",
|
cards: [
|
||||||
type: "sensor",
|
{
|
||||||
entity: "sensor.temperature_passage",
|
graph: "line",
|
||||||
},
|
type: "sensor",
|
||||||
{
|
entity: "sensor.temperature_storage",
|
||||||
graph: "line",
|
},
|
||||||
type: "sensor",
|
{
|
||||||
name: "Bathroom",
|
graph: "line",
|
||||||
entity: "sensor.temperature_downstairs_bathroom",
|
type: "sensor",
|
||||||
},
|
name: "Refrigerator",
|
||||||
{
|
entity: "sensor.refrigerator",
|
||||||
graph: "line",
|
},
|
||||||
type: "sensor",
|
],
|
||||||
entity: "sensor.temperature_storage",
|
type: "horizontal-stack",
|
||||||
},
|
|
||||||
{
|
|
||||||
graph: "line",
|
|
||||||
type: "sensor",
|
|
||||||
name: "Refrigerator",
|
|
||||||
entity: "sensor.refrigerator",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
type: "vertical-stack",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
entities: [
|
entities: [
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { LitElement } from "lit";
|
import { LitElement } from "lit-element";
|
||||||
import "./card-tools";
|
import "./card-tools";
|
||||||
|
|
||||||
class CardModder extends LitElement {
|
class CardModder extends LitElement {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { html, LitElement } from "lit";
|
import { html, LitElement } from "lit-element";
|
||||||
|
|
||||||
if (!window.cardTools) {
|
if (!window.cardTools) {
|
||||||
const version = 0.2;
|
const version = 0.2;
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { CastManager } from "../../../src/cast/cast_manager";
|
import { CastManager } from "../../../src/cast/cast_manager";
|
||||||
import { castSendShowDemo } from "../../../src/cast/receiver_messages";
|
import { castSendShowDemo } from "../../../src/cast/receiver_messages";
|
||||||
import "../../../src/components/ha-icon";
|
import "../../../src/components/ha-icon";
|
||||||
@@ -13,7 +20,7 @@ import { HomeAssistant } from "../../../src/types";
|
|||||||
class CastDemoRow extends LitElement implements LovelaceRow {
|
class CastDemoRow extends LitElement implements LovelaceRow {
|
||||||
public hass!: HomeAssistant;
|
public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() private _castManager?: CastManager | null;
|
@internalProperty() private _castManager?: CastManager | null;
|
||||||
|
|
||||||
public setConfig(_config: CastConfig): void {
|
public setConfig(_config: CastConfig): void {
|
||||||
// No config possible.
|
// No config possible.
|
||||||
@@ -66,7 +73,7 @@ class CastDemoRow extends LitElement implements LovelaceRow {
|
|||||||
this.style.display = this._castManager ? "" : "none";
|
this.style.display = this._castManager ? "" : "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@@ -1,7 +1,14 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { property, state } from "lit/decorators";
|
css,
|
||||||
import { until } from "lit/directives/until";
|
CSSResult,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/ha-circular-progress";
|
import "../../../src/components/ha-circular-progress";
|
||||||
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
||||||
@@ -19,7 +26,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
@property({ attribute: false }) public hass!: MockHomeAssistant;
|
@property({ attribute: false }) public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
@state() private _switching = false;
|
@internalProperty() private _switching?: boolean;
|
||||||
|
|
||||||
private _hidden = localStorage.hide_demo_card;
|
private _hidden = localStorage.hide_demo_card;
|
||||||
|
|
||||||
@@ -27,7 +34,12 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
return this._hidden ? 0 : 2;
|
return this._hidden ? 0 : 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setConfig(_config: LovelaceCardConfig) {}
|
public setConfig(
|
||||||
|
// @ts-ignore
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
config: LovelaceCardConfig
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
) {}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (this._hidden) {
|
if (this._hidden) {
|
||||||
@@ -101,7 +113,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
css`
|
css`
|
||||||
a {
|
a {
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import "@polymer/polymer/lib/elements/dom-if";
|
||||||
|
import "@polymer/polymer/lib/elements/dom-repeat";
|
||||||
import "../../src/resources/ha-style";
|
import "../../src/resources/ha-style";
|
||||||
import "../../src/resources/roboto";
|
import "../../src/resources/roboto";
|
||||||
import "../../src/resources/safari-14-attachshadow-patch";
|
import "../../src/resources/safari-14-attachshadow-patch";
|
||||||
|
@@ -20,14 +20,11 @@ import { mockShoppingList } from "./stubs/shopping_list";
|
|||||||
import { mockSystemLog } from "./stubs/system_log";
|
import { mockSystemLog } from "./stubs/system_log";
|
||||||
import { mockTemplate } from "./stubs/template";
|
import { mockTemplate } from "./stubs/template";
|
||||||
import { mockTranslations } from "./stubs/translations";
|
import { mockTranslations } from "./stubs/translations";
|
||||||
import { mockEnergy } from "./stubs/energy";
|
|
||||||
import { mockConfig } from "./stubs/config";
|
|
||||||
import { energyEntities } from "./stubs/entities";
|
|
||||||
|
|
||||||
class HaDemo extends HomeAssistantAppEl {
|
class HaDemo extends HomeAssistantAppEl {
|
||||||
protected async _initializeHass() {
|
protected async _initialize() {
|
||||||
const initial: Partial<MockHomeAssistant> = {
|
const initial: Partial<MockHomeAssistant> = {
|
||||||
panelUrl: (this as any)._panelUrl,
|
panelUrl: (this as any).panelUrl,
|
||||||
// Override updateHass so that the correct hass lifecycle methods are called
|
// Override updateHass so that the correct hass lifecycle methods are called
|
||||||
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
||||||
this._updateHass(hassUpdate),
|
this._updateHass(hassUpdate),
|
||||||
@@ -50,12 +47,8 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
mockEvents(hass);
|
mockEvents(hass);
|
||||||
mockMediaPlayer(hass);
|
mockMediaPlayer(hass);
|
||||||
mockFrontend(hass);
|
mockFrontend(hass);
|
||||||
mockEnergy(hass);
|
|
||||||
mockConfig(hass);
|
|
||||||
mockPersistentNotification(hass);
|
mockPersistentNotification(hass);
|
||||||
|
|
||||||
hass.addEntities(energyEntities());
|
|
||||||
|
|
||||||
// Once config is loaded AND localize, set entities and apply theme.
|
// Once config is loaded AND localize, set entities and apply theme.
|
||||||
Promise.all([selectedDemoConfig, localizePromise]).then(
|
Promise.all([selectedDemoConfig, localizePromise]).then(
|
||||||
([conf, localize]) => {
|
([conf, localize]) => {
|
||||||
@@ -77,7 +70,7 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
navigate(href);
|
navigate(this, href);
|
||||||
},
|
},
|
||||||
{ capture: true }
|
{ capture: true }
|
||||||
);
|
);
|
||||||
|
@@ -1,41 +0,0 @@
|
|||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
export const mockConfig = (hass: MockHomeAssistant) => {
|
|
||||||
hass.mockAPI("config/config_entries/entry", () => [
|
|
||||||
{
|
|
||||||
entry_id: "co2signal",
|
|
||||||
domain: "co2signal",
|
|
||||||
title: "CO2 Signal",
|
|
||||||
source: "user",
|
|
||||||
state: "loaded",
|
|
||||||
supports_options: false,
|
|
||||||
supports_unload: true,
|
|
||||||
pref_disable_new_entities: false,
|
|
||||||
pref_disable_polling: false,
|
|
||||||
disabled_by: null,
|
|
||||||
reason: null,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
hass.mockWS("config/entity_registry/list", () => [
|
|
||||||
{
|
|
||||||
config_entry_id: "co2signal",
|
|
||||||
device_id: "co2signal",
|
|
||||||
area_id: null,
|
|
||||||
disabled_by: null,
|
|
||||||
entity_id: "sensor.co2_intensity",
|
|
||||||
name: null,
|
|
||||||
icon: null,
|
|
||||||
platform: "co2signal",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config_entry_id: "co2signal",
|
|
||||||
device_id: "co2signal",
|
|
||||||
area_id: null,
|
|
||||||
disabled_by: null,
|
|
||||||
entity_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
name: null,
|
|
||||||
icon: null,
|
|
||||||
platform: "co2signal",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
@@ -1,134 +0,0 @@
|
|||||||
import { format, startOfToday, startOfTomorrow } from "date-fns";
|
|
||||||
import { EnergySolarForecasts } from "../../../src/data/energy";
|
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
export const mockEnergy = (hass: MockHomeAssistant) => {
|
|
||||||
hass.mockWS("energy/get_prefs", () => ({
|
|
||||||
energy_sources: [
|
|
||||||
{
|
|
||||||
type: "grid",
|
|
||||||
flow_from: [
|
|
||||||
{
|
|
||||||
stat_energy_from: "sensor.energy_consumption_tarif_1",
|
|
||||||
stat_cost: "sensor.energy_consumption_tarif_1_cost",
|
|
||||||
entity_energy_from: "sensor.energy_consumption_tarif_1",
|
|
||||||
entity_energy_price: null,
|
|
||||||
number_energy_price: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stat_energy_from: "sensor.energy_consumption_tarif_2",
|
|
||||||
stat_cost: "sensor.energy_consumption_tarif_2_cost",
|
|
||||||
entity_energy_from: "sensor.energy_consumption_tarif_2",
|
|
||||||
entity_energy_price: null,
|
|
||||||
number_energy_price: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
flow_to: [
|
|
||||||
{
|
|
||||||
stat_energy_to: "sensor.energy_production_tarif_1",
|
|
||||||
stat_compensation: "sensor.energy_production_tarif_1_compensation",
|
|
||||||
entity_energy_to: "sensor.energy_production_tarif_1",
|
|
||||||
entity_energy_price: null,
|
|
||||||
number_energy_price: null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stat_energy_to: "sensor.energy_production_tarif_2",
|
|
||||||
stat_compensation: "sensor.energy_production_tarif_2_compensation",
|
|
||||||
entity_energy_to: "sensor.energy_production_tarif_2",
|
|
||||||
entity_energy_price: null,
|
|
||||||
number_energy_price: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
cost_adjustment_day: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "solar",
|
|
||||||
stat_energy_from: "sensor.solar_production",
|
|
||||||
config_entry_solar_forecast: ["solar_forecast"],
|
|
||||||
},
|
|
||||||
/* {
|
|
||||||
type: "battery",
|
|
||||||
stat_energy_from: "sensor.battery_output",
|
|
||||||
stat_energy_to: "sensor.battery_input",
|
|
||||||
}, */
|
|
||||||
{
|
|
||||||
type: "gas",
|
|
||||||
stat_energy_from: "sensor.energy_gas",
|
|
||||||
stat_cost: "sensor.energy_gas_cost",
|
|
||||||
entity_energy_from: "sensor.energy_gas",
|
|
||||||
entity_energy_price: null,
|
|
||||||
number_energy_price: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
device_consumption: [
|
|
||||||
{
|
|
||||||
stat_consumption: "sensor.energy_car",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stat_consumption: "sensor.energy_ac",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stat_consumption: "sensor.energy_washing_machine",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stat_consumption: "sensor.energy_dryer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stat_consumption: "sensor.energy_heat_pump",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
stat_consumption: "sensor.energy_boiler",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}));
|
|
||||||
hass.mockWS("energy/info", () => ({ cost_sensors: [] }));
|
|
||||||
const todayString = format(startOfToday(), "yyyy-MM-dd");
|
|
||||||
const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd");
|
|
||||||
hass.mockWS(
|
|
||||||
"energy/solar_forecast",
|
|
||||||
(): EnergySolarForecasts => ({
|
|
||||||
solar_forecast: {
|
|
||||||
wh_hours: {
|
|
||||||
[`${todayString}T06:00:00`]: 0,
|
|
||||||
[`${todayString}T06:23:00`]: 6,
|
|
||||||
[`${todayString}T06:45:00`]: 39,
|
|
||||||
[`${todayString}T07:00:00`]: 28,
|
|
||||||
[`${todayString}T08:00:00`]: 208,
|
|
||||||
[`${todayString}T09:00:00`]: 352,
|
|
||||||
[`${todayString}T10:00:00`]: 544,
|
|
||||||
[`${todayString}T11:00:00`]: 748,
|
|
||||||
[`${todayString}T12:00:00`]: 1259,
|
|
||||||
[`${todayString}T13:00:00`]: 1361,
|
|
||||||
[`${todayString}T14:00:00`]: 1373,
|
|
||||||
[`${todayString}T15:00:00`]: 1370,
|
|
||||||
[`${todayString}T16:00:00`]: 1186,
|
|
||||||
[`${todayString}T17:00:00`]: 937,
|
|
||||||
[`${todayString}T18:00:00`]: 652,
|
|
||||||
[`${todayString}T19:00:00`]: 370,
|
|
||||||
[`${todayString}T20:00:00`]: 155,
|
|
||||||
[`${todayString}T21:48:00`]: 24,
|
|
||||||
[`${todayString}T22:36:00`]: 0,
|
|
||||||
[`${tomorrowString}T06:01:00`]: 0,
|
|
||||||
[`${tomorrowString}T06:23:00`]: 9,
|
|
||||||
[`${tomorrowString}T06:45:00`]: 47,
|
|
||||||
[`${tomorrowString}T07:00:00`]: 48,
|
|
||||||
[`${tomorrowString}T08:00:00`]: 473,
|
|
||||||
[`${tomorrowString}T09:00:00`]: 827,
|
|
||||||
[`${tomorrowString}T10:00:00`]: 1153,
|
|
||||||
[`${tomorrowString}T11:00:00`]: 1413,
|
|
||||||
[`${tomorrowString}T12:00:00`]: 1590,
|
|
||||||
[`${tomorrowString}T13:00:00`]: 1652,
|
|
||||||
[`${tomorrowString}T14:00:00`]: 1612,
|
|
||||||
[`${tomorrowString}T15:00:00`]: 1438,
|
|
||||||
[`${tomorrowString}T16:00:00`]: 1149,
|
|
||||||
[`${tomorrowString}T17:00:00`]: 830,
|
|
||||||
[`${tomorrowString}T18:00:00`]: 542,
|
|
||||||
[`${tomorrowString}T19:00:00`]: 311,
|
|
||||||
[`${tomorrowString}T20:00:00`]: 140,
|
|
||||||
[`${tomorrowString}T21:47:00`]: 22,
|
|
||||||
[`${tomorrowString}T22:34:00`]: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
@@ -1,178 +0,0 @@
|
|||||||
import { convertEntities } from "../../../src/fake_data/entity";
|
|
||||||
|
|
||||||
export const energyEntities = () =>
|
|
||||||
convertEntities({
|
|
||||||
"sensor.grid_fossil_fuel_percentage": {
|
|
||||||
entity_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
state: "88.6",
|
|
||||||
attributes: {
|
|
||||||
unit_of_measurement: "%",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.solar_production": {
|
|
||||||
entity_id: "sensor.solar_production",
|
|
||||||
state: "88.6",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Solar",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.battery_input": {
|
|
||||||
entity_id: "sensor.battery_input",
|
|
||||||
state: "4",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Battery Input",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.battery_output": {
|
|
||||||
entity_id: "sensor.battery_output",
|
|
||||||
state: "3",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Battery Output",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_consumption_tarif_1": {
|
|
||||||
entity_id: "sensor.energy_consumption_tarif_1 ",
|
|
||||||
state: "88.6",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Grid consumption low tariff",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_consumption_tarif_2": {
|
|
||||||
entity_id: "sensor.energy_consumption_tarif_2",
|
|
||||||
state: "88.6",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Grid consumption high tariff",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_production_tarif_1": {
|
|
||||||
entity_id: "sensor.energy_production_tarif_1",
|
|
||||||
state: "88.6",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Returned to grid low tariff",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_production_tarif_2": {
|
|
||||||
entity_id: "sensor.energy_production_tarif_2",
|
|
||||||
state: "88.6",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Returned to grid high tariff",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_consumption_tarif_1_cost": {
|
|
||||||
entity_id: "sensor.energy_consumption_tarif_1_cost",
|
|
||||||
state: "2",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
unit_of_measurement: "EUR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_consumption_tarif_2_cost": {
|
|
||||||
entity_id: "sensor.energy_consumption_tarif_2_cost",
|
|
||||||
state: "2",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
unit_of_measurement: "EUR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_production_tarif_1_compensation": {
|
|
||||||
entity_id: "sensor.energy_production_tarif_1_compensation",
|
|
||||||
state: "2",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
unit_of_measurement: "EUR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_production_tarif_2_compensation": {
|
|
||||||
entity_id: "sensor.energy_production_tarif_2_compensation",
|
|
||||||
state: "2",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
unit_of_measurement: "EUR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_gas_cost": {
|
|
||||||
entity_id: "sensor.energy_gas_cost",
|
|
||||||
state: "2",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
unit_of_measurement: "EUR",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_gas": {
|
|
||||||
entity_id: "sensor.energy_gas",
|
|
||||||
state: "4",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Gas",
|
|
||||||
unit_of_measurement: "m³",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_car": {
|
|
||||||
entity_id: "sensor.energy_car",
|
|
||||||
state: "4",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Electric car",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_ac": {
|
|
||||||
entity_id: "sensor.energy_ac",
|
|
||||||
state: "3",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Air conditioning",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_washing_machine": {
|
|
||||||
entity_id: "sensor.energy_washing_machine",
|
|
||||||
state: "6",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Washing machine",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_dryer": {
|
|
||||||
entity_id: "sensor.energy_dryer",
|
|
||||||
state: "5.5",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Dryer",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_heat_pump": {
|
|
||||||
entity_id: "sensor.energy_heat_pump",
|
|
||||||
state: "6",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Heat pump",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"sensor.energy_boiler": {
|
|
||||||
entity_id: "sensor.energy_boiler",
|
|
||||||
state: "7",
|
|
||||||
attributes: {
|
|
||||||
last_reset: "1970-01-01T00:00:00:00+00",
|
|
||||||
friendly_name: "Boiler",
|
|
||||||
unit_of_measurement: "kWh",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
@@ -1,6 +1,4 @@
|
|||||||
import { addHours, differenceInHours, endOfDay } from "date-fns";
|
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { StatisticValue } from "../../../src/data/history";
|
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
interface HistoryQueryParams {
|
interface HistoryQueryParams {
|
||||||
@@ -66,219 +64,17 @@ const generateHistory = (state, deltas) => {
|
|||||||
|
|
||||||
const incrementalUnits = ["clients", "queries", "ads"];
|
const incrementalUnits = ["clients", "queries", "ads"];
|
||||||
|
|
||||||
const generateMeanStatistics = (
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
initValue: number,
|
|
||||||
maxDiff: number
|
|
||||||
) => {
|
|
||||||
const statistics: StatisticValue[] = [];
|
|
||||||
let currentDate = new Date(start);
|
|
||||||
currentDate.setMinutes(0, 0, 0);
|
|
||||||
let lastVal = initValue;
|
|
||||||
const now = new Date();
|
|
||||||
while (end > currentDate && currentDate < now) {
|
|
||||||
const delta = Math.random() * maxDiff;
|
|
||||||
const mean = lastVal + delta;
|
|
||||||
statistics.push({
|
|
||||||
statistic_id: id,
|
|
||||||
start: currentDate.toISOString(),
|
|
||||||
mean,
|
|
||||||
min: mean - Math.random() * maxDiff,
|
|
||||||
max: mean + Math.random() * maxDiff,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: mean,
|
|
||||||
sum: null,
|
|
||||||
});
|
|
||||||
lastVal = mean;
|
|
||||||
currentDate = addHours(currentDate, 1);
|
|
||||||
}
|
|
||||||
return statistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateSumStatistics = (
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
initValue: number,
|
|
||||||
maxDiff: number
|
|
||||||
) => {
|
|
||||||
const statistics: StatisticValue[] = [];
|
|
||||||
let currentDate = new Date(start);
|
|
||||||
currentDate.setMinutes(0, 0, 0);
|
|
||||||
let sum = initValue;
|
|
||||||
const now = new Date();
|
|
||||||
while (end > currentDate && currentDate < now) {
|
|
||||||
const add = Math.random() * maxDiff;
|
|
||||||
sum += add;
|
|
||||||
statistics.push({
|
|
||||||
statistic_id: id,
|
|
||||||
start: currentDate.toISOString(),
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: initValue + sum,
|
|
||||||
sum,
|
|
||||||
});
|
|
||||||
currentDate = addHours(currentDate, 1);
|
|
||||||
}
|
|
||||||
return statistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateCurvedStatistics = (
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
initValue: number,
|
|
||||||
maxDiff: number,
|
|
||||||
metered: boolean
|
|
||||||
) => {
|
|
||||||
const statistics: StatisticValue[] = [];
|
|
||||||
let currentDate = new Date(start);
|
|
||||||
currentDate.setMinutes(0, 0, 0);
|
|
||||||
let sum = initValue;
|
|
||||||
const hours = differenceInHours(end, start) - 1;
|
|
||||||
let i = 0;
|
|
||||||
let half = false;
|
|
||||||
const now = new Date();
|
|
||||||
while (end > currentDate && currentDate < now) {
|
|
||||||
const add = Math.random() * maxDiff;
|
|
||||||
sum += i * add;
|
|
||||||
statistics.push({
|
|
||||||
statistic_id: id,
|
|
||||||
start: currentDate.toISOString(),
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: initValue + sum,
|
|
||||||
sum: metered ? sum : null,
|
|
||||||
});
|
|
||||||
currentDate = addHours(currentDate, 1);
|
|
||||||
if (!half && i > hours / 2) {
|
|
||||||
half = true;
|
|
||||||
}
|
|
||||||
i += half ? -1 : 1;
|
|
||||||
}
|
|
||||||
return statistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
const statisticsFunctions: Record<
|
|
||||||
string,
|
|
||||||
(id: string, start: Date, end: Date) => StatisticValue[]
|
|
||||||
> = {
|
|
||||||
"sensor.energy_consumption_tarif_1": (id: string, start: Date, end: Date) => {
|
|
||||||
const morningEnd = new Date(start.getTime() + 10 * 60 * 60 * 1000);
|
|
||||||
const morningLow = generateSumStatistics(id, start, morningEnd, 0, 0.7);
|
|
||||||
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
|
||||||
const morningFinalVal = morningLow.length
|
|
||||||
? morningLow[morningLow.length - 1].sum!
|
|
||||||
: 0;
|
|
||||||
const empty = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
morningEnd,
|
|
||||||
eveningStart,
|
|
||||||
morningFinalVal,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const eveningLow = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
eveningStart,
|
|
||||||
end,
|
|
||||||
morningFinalVal,
|
|
||||||
0.7
|
|
||||||
);
|
|
||||||
return [...morningLow, ...empty, ...eveningLow];
|
|
||||||
},
|
|
||||||
"sensor.energy_consumption_tarif_2": (id: string, start: Date, end: Date) => {
|
|
||||||
const morningEnd = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
|
||||||
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
|
||||||
const highTarif = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
morningEnd,
|
|
||||||
eveningStart,
|
|
||||||
0,
|
|
||||||
0.3
|
|
||||||
);
|
|
||||||
const highTarifFinalVal = highTarif.length
|
|
||||||
? highTarif[highTarif.length - 1].sum!
|
|
||||||
: 0;
|
|
||||||
const morning = generateSumStatistics(id, start, morningEnd, 0, 0);
|
|
||||||
const evening = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
eveningStart,
|
|
||||||
end,
|
|
||||||
highTarifFinalVal,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
return [...morning, ...highTarif, ...evening];
|
|
||||||
},
|
|
||||||
"sensor.energy_production_tarif_1": (id, start, end) =>
|
|
||||||
generateSumStatistics(id, start, end, 0, 0),
|
|
||||||
"sensor.energy_production_tarif_1_compensation": (id, start, end) =>
|
|
||||||
generateSumStatistics(id, start, end, 0, 0),
|
|
||||||
"sensor.energy_production_tarif_2": (id, start, end) => {
|
|
||||||
const productionStart = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
|
||||||
const productionEnd = new Date(start.getTime() + 21 * 60 * 60 * 1000);
|
|
||||||
const dayEnd = new Date(endOfDay(productionEnd));
|
|
||||||
const production = generateCurvedStatistics(
|
|
||||||
id,
|
|
||||||
productionStart,
|
|
||||||
productionEnd,
|
|
||||||
0,
|
|
||||||
0.15,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
const productionFinalVal = production.length
|
|
||||||
? production[production.length - 1].sum!
|
|
||||||
: 0;
|
|
||||||
const morning = generateSumStatistics(id, start, productionStart, 0, 0);
|
|
||||||
const evening = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
productionEnd,
|
|
||||||
dayEnd,
|
|
||||||
productionFinalVal,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const rest = generateSumStatistics(id, dayEnd, end, productionFinalVal, 1);
|
|
||||||
return [...morning, ...production, ...evening, ...rest];
|
|
||||||
},
|
|
||||||
"sensor.solar_production": (id, start, end) => {
|
|
||||||
const productionStart = new Date(start.getTime() + 7 * 60 * 60 * 1000);
|
|
||||||
const productionEnd = new Date(start.getTime() + 23 * 60 * 60 * 1000);
|
|
||||||
const dayEnd = new Date(endOfDay(productionEnd));
|
|
||||||
const production = generateCurvedStatistics(
|
|
||||||
id,
|
|
||||||
productionStart,
|
|
||||||
productionEnd,
|
|
||||||
0,
|
|
||||||
0.3,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
const productionFinalVal = production.length
|
|
||||||
? production[production.length - 1].sum!
|
|
||||||
: 0;
|
|
||||||
const morning = generateSumStatistics(id, start, productionStart, 0, 0);
|
|
||||||
const evening = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
productionEnd,
|
|
||||||
dayEnd,
|
|
||||||
productionFinalVal,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const rest = generateSumStatistics(id, dayEnd, end, productionFinalVal, 2);
|
|
||||||
return [...morning, ...production, ...evening, ...rest];
|
|
||||||
},
|
|
||||||
"sensor.grid_fossil_fuel_percentage": (id, start, end) =>
|
|
||||||
generateMeanStatistics(id, start, end, 35, 1.3),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
||||||
mockHass.mockAPI(
|
mockHass.mockAPI(
|
||||||
new RegExp("history/period/.+"),
|
new RegExp("history/period/.+"),
|
||||||
(hass, _method, path, _parameters) => {
|
(
|
||||||
|
hass,
|
||||||
|
// @ts-ignore
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
// @ts-ignore
|
||||||
|
parameters
|
||||||
|
) => {
|
||||||
const params = parseQuery<HistoryQueryParams>(path.split("?")[1]);
|
const params = parseQuery<HistoryQueryParams>(path.split("?")[1]);
|
||||||
const entities = params.filter_entity_id.split(",");
|
const entities = params.filter_entity_id.split(",");
|
||||||
|
|
||||||
@@ -299,7 +95,7 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
|
|||||||
const numberState = Number(state.state);
|
const numberState = Number(state.state);
|
||||||
|
|
||||||
if (isNaN(numberState)) {
|
if (isNaN(numberState)) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line
|
||||||
console.log(
|
console.log(
|
||||||
"Ignoring state with unparsable state but with a unit",
|
"Ignoring state with unparsable state but with a unit",
|
||||||
entityId,
|
entityId,
|
||||||
@@ -344,40 +140,4 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
mockHass.mockWS("history/list_statistic_ids", () => []);
|
|
||||||
mockHass.mockWS(
|
|
||||||
"history/statistics_during_period",
|
|
||||||
({ statistic_ids, start_time, end_time }, hass) => {
|
|
||||||
const start = new Date(start_time);
|
|
||||||
const end = end_time ? new Date(end_time) : new Date();
|
|
||||||
|
|
||||||
const statistics: Record<string, StatisticValue[]> = {};
|
|
||||||
|
|
||||||
statistic_ids.forEach((id: string) => {
|
|
||||||
if (id in statisticsFunctions) {
|
|
||||||
statistics[id] = statisticsFunctions[id](id, start, end);
|
|
||||||
} else {
|
|
||||||
const entityState = hass.states[id];
|
|
||||||
const state = entityState ? Number(entityState.state) : 1;
|
|
||||||
statistics[id] =
|
|
||||||
entityState && "last_reset" in entityState.attributes
|
|
||||||
? generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
state,
|
|
||||||
state * (state > 80 ? 0.01 : 0.05)
|
|
||||||
)
|
|
||||||
: generateMeanStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
state,
|
|
||||||
state * (state > 80 ? 0.05 : 0.1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return statistics;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
@@ -10,9 +10,10 @@ export const mockLovelace = (
|
|||||||
localizePromise: Promise<LocalizeFunc>
|
localizePromise: Promise<LocalizeFunc>
|
||||||
) => {
|
) => {
|
||||||
hass.mockWS("lovelace/config", () =>
|
hass.mockWS("lovelace/config", () =>
|
||||||
Promise.all([selectedDemoConfig, localizePromise]).then(
|
Promise.all([
|
||||||
([config, localize]) => config.lovelace(localize)
|
selectedDemoConfig,
|
||||||
)
|
localizePromise,
|
||||||
|
]).then(([config, localize]) => config.lovelace(localize))
|
||||||
);
|
);
|
||||||
|
|
||||||
hass.mockWS("lovelace/config/save", () => Promise.resolve());
|
hass.mockWS("lovelace/config/save", () => Promise.resolve());
|
||||||
|
@@ -6,7 +6,7 @@ export const mockTemplate = (hass: MockHomeAssistant) => {
|
|||||||
body: { message: "Template dev tool does not work in the demo." },
|
body: { message: "Template dev tool does not work in the demo." },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
hass.mockWS("render_template", (msg, _hass, onChange) => {
|
hass.mockWS("render_template", (msg, onChange) => {
|
||||||
onChange!({
|
onChange!({
|
||||||
result: msg.template,
|
result: msg.template,
|
||||||
listeners: { all: false, domains: [], entities: [], time: false },
|
listeners: { all: false, domains: [], entities: [], time: false },
|
||||||
|
@@ -3,6 +3,8 @@ import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|||||||
export const mockTranslations = (hass: MockHomeAssistant) => {
|
export const mockTranslations = (hass: MockHomeAssistant) => {
|
||||||
hass.mockWS(
|
hass.mockWS(
|
||||||
"frontend/get_translations",
|
"frontend/get_translations",
|
||||||
(/* msg: {language: string, category: string} */) => ({ resources: {} })
|
(/* msg: {language: string, category: string} */) => {
|
||||||
|
return { resources: {} };
|
||||||
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
/* eslint-plugin-disable lit */
|
/* eslint-plugin-disable lit */
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import { load } from "js-yaml";
|
import { safeLoad } from "js-yaml";
|
||||||
import { createCardElement } from "../../../src/panels/lovelace/create-element/create-card-element";
|
import { createCardElement } from "../../../src/panels/lovelace/create-element/create-card-element";
|
||||||
|
|
||||||
class DemoCard extends PolymerElement {
|
class DemoCard extends PolymerElement {
|
||||||
@@ -15,10 +15,6 @@ class DemoCard extends PolymerElement {
|
|||||||
margin: 0 0 20px;
|
margin: 0 0 20px;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
h2 small {
|
|
||||||
font-size: 0.5em;
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
#card {
|
#card {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
@@ -38,12 +34,7 @@ class DemoCard extends PolymerElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<h2>
|
<h2>[[config.heading]]</h2>
|
||||||
[[config.heading]]
|
|
||||||
<template is="dom-if" if="[[_size]]">
|
|
||||||
<small>(size [[_size]])</small>
|
|
||||||
</template>
|
|
||||||
</h2>
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<div id="card"></div>
|
<div id="card"></div>
|
||||||
<template is="dom-if" if="[[showConfig]]">
|
<template is="dom-if" if="[[showConfig]]">
|
||||||
@@ -64,9 +55,6 @@ class DemoCard extends PolymerElement {
|
|||||||
observer: "_configChanged",
|
observer: "_configChanged",
|
||||||
},
|
},
|
||||||
showConfig: Boolean,
|
showConfig: Boolean,
|
||||||
_size: {
|
|
||||||
type: Number,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,19 +68,8 @@ class DemoCard extends PolymerElement {
|
|||||||
card.removeChild(card.lastChild);
|
card.removeChild(card.lastChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
const el = this._createCardElement(load(config.config)[0]);
|
const el = this._createCardElement(safeLoad(config.config)[0]);
|
||||||
card.appendChild(el);
|
card.appendChild(el);
|
||||||
this._getSize(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _getSize(el) {
|
|
||||||
await customElements.whenDefined(el.localName);
|
|
||||||
|
|
||||||
if (!("getCardSize" in el)) {
|
|
||||||
this._size = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._size = await el.getCardSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_createCardElement(cardConfig) {
|
_createCardElement(cardConfig) {
|
||||||
|
@@ -1,349 +0,0 @@
|
|||||||
import { DemoTrace } from "./types";
|
|
||||||
|
|
||||||
export const basicTrace: DemoTrace = {
|
|
||||||
trace: {
|
|
||||||
last_step: "action/2",
|
|
||||||
run_id: "0",
|
|
||||||
state: "stopped",
|
|
||||||
timestamp: {
|
|
||||||
start: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
finish: "2021-03-25T04:36:51.266132+00:00",
|
|
||||||
},
|
|
||||||
trigger: "state of input_boolean.toggle_1",
|
|
||||||
domain: "automation",
|
|
||||||
item_id: "1615419646544",
|
|
||||||
trace: {
|
|
||||||
"trigger/0": [
|
|
||||||
{
|
|
||||||
path: "trigger/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"condition/0": [
|
|
||||||
{
|
|
||||||
path: "condition/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.228243+00:00",
|
|
||||||
changed_variables: {
|
|
||||||
trigger: {
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
from_state: {
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
editable: true,
|
|
||||||
friendly_name: "Toggle 1",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-24T19:03:59.141440+00:00",
|
|
||||||
last_updated: "2021-03-24T19:03:59.141440+00:00",
|
|
||||||
context: {
|
|
||||||
id: "5d0918eb379214d07554bdab6a08bcff",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
to_state: {
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
state: "off",
|
|
||||||
attributes: {
|
|
||||||
editable: true,
|
|
||||||
friendly_name: "Toggle 1",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-25T04:36:51.220696+00:00",
|
|
||||||
last_updated: "2021-03-25T04:36:51.220696+00:00",
|
|
||||||
context: {
|
|
||||||
id: "664d6d261450a9ecea6738e97269a149",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: "d1b4e89da01445fa8bc98e39fac477ca",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
for: null,
|
|
||||||
attribute: null,
|
|
||||||
description: "state of input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/0": [
|
|
||||||
{
|
|
||||||
path: "action/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.243018+00:00",
|
|
||||||
changed_variables: {
|
|
||||||
trigger: {
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
from_state: {
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
editable: true,
|
|
||||||
friendly_name: "Toggle 1",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-24T19:03:59.141440+00:00",
|
|
||||||
last_updated: "2021-03-24T19:03:59.141440+00:00",
|
|
||||||
context: {
|
|
||||||
id: "5d0918eb379214d07554bdab6a08bcff",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
to_state: {
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
state: "off",
|
|
||||||
attributes: {
|
|
||||||
editable: true,
|
|
||||||
friendly_name: "Toggle 1",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-25T04:36:51.220696+00:00",
|
|
||||||
last_updated: "2021-03-25T04:36:51.220696+00:00",
|
|
||||||
context: {
|
|
||||||
id: "664d6d261450a9ecea6738e97269a149",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: "d1b4e89da01445fa8bc98e39fac477ca",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
for: null,
|
|
||||||
attribute: null,
|
|
||||||
description: "state of input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "6cfcae368e7b3686fad6c59e83ae76c9",
|
|
||||||
parent_id: "664d6d261450a9ecea6738e97269a149",
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
params: {
|
|
||||||
domain: "input_boolean",
|
|
||||||
service: "toggle",
|
|
||||||
service_data: {},
|
|
||||||
target: {
|
|
||||||
entity_id: ["input_boolean.toggle_4"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
running_script: false,
|
|
||||||
limit: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1": [
|
|
||||||
{
|
|
||||||
path: "action/1",
|
|
||||||
timestamp: "2021-03-25T04:36:51.252406+00:00",
|
|
||||||
result: {
|
|
||||||
choice: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1/choose/0": [
|
|
||||||
{
|
|
||||||
path: "action/1/choose/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.254569+00:00",
|
|
||||||
result: {
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1/choose/0/conditions/0": [
|
|
||||||
{
|
|
||||||
path: "action/1/choose/0/conditions/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.254697+00:00",
|
|
||||||
result: {
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1/choose/0/sequence/0": [
|
|
||||||
{
|
|
||||||
path: "action/1/choose/0/sequence/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.257360+00:00",
|
|
||||||
result: {
|
|
||||||
params: {
|
|
||||||
domain: "input_boolean",
|
|
||||||
service: "toggle",
|
|
||||||
service_data: {},
|
|
||||||
target: {
|
|
||||||
entity_id: ["input_boolean.toggle_2"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
running_script: false,
|
|
||||||
limit: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1/choose/0/sequence/1": [
|
|
||||||
{
|
|
||||||
path: "action/1/choose/0/sequence/1",
|
|
||||||
timestamp: "2021-03-25T04:36:51.260658+00:00",
|
|
||||||
result: {
|
|
||||||
params: {
|
|
||||||
domain: "input_boolean",
|
|
||||||
service: "toggle",
|
|
||||||
service_data: {},
|
|
||||||
target: {
|
|
||||||
entity_id: ["input_boolean.toggle_3"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
running_script: false,
|
|
||||||
limit: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/2": [
|
|
||||||
{
|
|
||||||
path: "action/2",
|
|
||||||
timestamp: "2021-03-25T04:36:51.264159+00:00",
|
|
||||||
result: {
|
|
||||||
params: {
|
|
||||||
domain: "input_boolean",
|
|
||||||
service: "toggle",
|
|
||||||
service_data: {},
|
|
||||||
target: {
|
|
||||||
entity_id: ["input_boolean.toggle_4"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
running_script: false,
|
|
||||||
limit: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
config: {
|
|
||||||
id: "1615419646544",
|
|
||||||
alias: "Ensure Party mode",
|
|
||||||
description: "",
|
|
||||||
trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
condition: [
|
|
||||||
{
|
|
||||||
condition: "template",
|
|
||||||
alias: "Test if Paulus is home",
|
|
||||||
value_template: "{{ true }}",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
action: [
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
choose: [
|
|
||||||
{
|
|
||||||
alias: "If toggle 3 is on",
|
|
||||||
conditions: [
|
|
||||||
{
|
|
||||||
condition: "template",
|
|
||||||
value_template:
|
|
||||||
"{{ is_state('input_boolean.toggle_3', 'on') }}",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
sequence: [
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
alias: "Toggle 2 while 3 is on",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
alias: "Toggle 3",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
default: [
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
alias: "Toggle 2",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
mode: "single",
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "6cfcae368e7b3686fad6c59e83ae76c9",
|
|
||||||
parent_id: "664d6d261450a9ecea6738e97269a149",
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
script_execution: "finished",
|
|
||||||
},
|
|
||||||
logbookEntries: [
|
|
||||||
{
|
|
||||||
name: "Ensure Party mode",
|
|
||||||
message: "has been triggered by state of input_boolean.toggle_1",
|
|
||||||
source: "state of input_boolean.toggle_1",
|
|
||||||
entity_id: "automation.toggle_toggles",
|
|
||||||
context_id: "6cfcae368e7b3686fad6c59e83ae76c9",
|
|
||||||
when: "2021-03-25T04:36:51.240832+00:00",
|
|
||||||
domain: "automation",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-25T04:36:51.249828+00:00",
|
|
||||||
name: "Toggle 4",
|
|
||||||
state: "on",
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
context_entity_id: "automation.toggle_toggles",
|
|
||||||
context_entity_id_name: "Ensure Party mode",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Ensure Party mode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-25T04:36:51.258947+00:00",
|
|
||||||
name: "Toggle 2",
|
|
||||||
state: "on",
|
|
||||||
entity_id: "input_boolean.toggle_2",
|
|
||||||
context_entity_id: "automation.toggle_toggles",
|
|
||||||
context_entity_id_name: "Ensure Party mode",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Ensure Party mode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-25T04:36:51.261806+00:00",
|
|
||||||
name: "Toggle 3",
|
|
||||||
state: "off",
|
|
||||||
entity_id: "input_boolean.toggle_3",
|
|
||||||
context_entity_id: "automation.toggle_toggles",
|
|
||||||
context_entity_id_name: "Ensure Party mode",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Ensure Party mode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-25T04:36:51.265246+00:00",
|
|
||||||
name: "Toggle 4",
|
|
||||||
state: "off",
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
context_entity_id: "automation.toggle_toggles",
|
|
||||||
context_entity_id_name: "Ensure Party mode",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Ensure Party mode",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
@@ -1,44 +0,0 @@
|
|||||||
import { LogbookEntry } from "../../../../src/data/logbook";
|
|
||||||
import { AutomationTraceExtended } from "../../../../src/data/trace";
|
|
||||||
import { DemoTrace } from "./types";
|
|
||||||
|
|
||||||
export const mockDemoTrace = (
|
|
||||||
tracePartial: Partial<AutomationTraceExtended>,
|
|
||||||
logbookEntries?: LogbookEntry[]
|
|
||||||
): DemoTrace => ({
|
|
||||||
trace: {
|
|
||||||
last_step: "",
|
|
||||||
run_id: "0",
|
|
||||||
state: "stopped",
|
|
||||||
timestamp: {
|
|
||||||
start: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
finish: "2021-03-25T04:36:51.266132+00:00",
|
|
||||||
},
|
|
||||||
trigger: "mocked trigger",
|
|
||||||
domain: "automation",
|
|
||||||
item_id: "1615419646544",
|
|
||||||
trace: {
|
|
||||||
"trigger/0": [
|
|
||||||
{
|
|
||||||
path: "trigger/0",
|
|
||||||
changed_variables: {
|
|
||||||
trigger: {
|
|
||||||
description: "mocked trigger",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
trigger: [],
|
|
||||||
action: [],
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "abcd",
|
|
||||||
},
|
|
||||||
script_execution: "finished",
|
|
||||||
...tracePartial,
|
|
||||||
},
|
|
||||||
logbookEntries: logbookEntries || [],
|
|
||||||
});
|
|
@@ -1,214 +0,0 @@
|
|||||||
import { DemoTrace } from "./types";
|
|
||||||
|
|
||||||
export const motionLightTrace: DemoTrace = {
|
|
||||||
trace: {
|
|
||||||
last_step: "action/3",
|
|
||||||
run_id: "1",
|
|
||||||
state: "stopped",
|
|
||||||
timestamp: {
|
|
||||||
start: "2021-03-14T06:07:01.768006+00:00",
|
|
||||||
finish: "2021-03-14T06:07:53.287525+00:00",
|
|
||||||
},
|
|
||||||
trigger: "state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
domain: "automation",
|
|
||||||
item_id: "1614732497392",
|
|
||||||
trace: {
|
|
||||||
"trigger/0": [
|
|
||||||
{
|
|
||||||
path: "trigger/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/0": [
|
|
||||||
{
|
|
||||||
path: "action/0",
|
|
||||||
timestamp: "2021-03-14T06:07:01.771038+00:00",
|
|
||||||
changed_variables: {
|
|
||||||
trigger: {
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
from_state: {
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
state: "off",
|
|
||||||
attributes: {
|
|
||||||
friendly_name: "Paulus’s MacBook Pro Camera In Use",
|
|
||||||
icon: "mdi:camera-off",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-14T06:06:29.235325+00:00",
|
|
||||||
last_updated: "2021-03-14T06:06:29.235325+00:00",
|
|
||||||
context: {
|
|
||||||
id: "ad4864c5ce957c38a07b50378eeb245d",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
to_state: {
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
friendly_name: "Paulus’s MacBook Pro Camera In Use",
|
|
||||||
icon: "mdi:camera",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-14T06:07:01.762009+00:00",
|
|
||||||
last_updated: "2021-03-14T06:07:01.762009+00:00",
|
|
||||||
context: {
|
|
||||||
id: "e22ddfd5f11dc4aad9a52fc10dab613b",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
for: null,
|
|
||||||
attribute: null,
|
|
||||||
description:
|
|
||||||
"state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "43b6ee9293a551c5cc14e8eb60af54ba",
|
|
||||||
parent_id: "e22ddfd5f11dc4aad9a52fc10dab613b",
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1": [
|
|
||||||
{ path: "action/1", timestamp: "2021-03-14T06:07:01.875316+00:00" },
|
|
||||||
],
|
|
||||||
"action/2": [
|
|
||||||
{
|
|
||||||
path: "action/2",
|
|
||||||
timestamp: "2021-03-14T06:07:53.195013+00:00",
|
|
||||||
changed_variables: {
|
|
||||||
wait: {
|
|
||||||
remaining: null,
|
|
||||||
trigger: {
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
from_state: {
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
friendly_name: "Paulus’s MacBook Pro Camera In Use",
|
|
||||||
icon: "mdi:camera",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-14T06:07:01.762009+00:00",
|
|
||||||
last_updated: "2021-03-14T06:07:01.762009+00:00",
|
|
||||||
context: {
|
|
||||||
id: "e22ddfd5f11dc4aad9a52fc10dab613b",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
to_state: {
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
state: "off",
|
|
||||||
attributes: {
|
|
||||||
friendly_name: "Paulus’s MacBook Pro Camera In Use",
|
|
||||||
icon: "mdi:camera-off",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-14T06:07:53.186755+00:00",
|
|
||||||
last_updated: "2021-03-14T06:07:53.186755+00:00",
|
|
||||||
context: {
|
|
||||||
id: "b2308cc91d509ea8e0c623331ab178d6",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
for: null,
|
|
||||||
attribute: null,
|
|
||||||
description:
|
|
||||||
"state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/3": [
|
|
||||||
{
|
|
||||||
path: "action/3",
|
|
||||||
timestamp: "2021-03-14T06:07:53.196014+00:00",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
mode: "restart",
|
|
||||||
max_exceeded: "silent",
|
|
||||||
trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
from: "off",
|
|
||||||
to: "on",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
action: [
|
|
||||||
{
|
|
||||||
service: "light.turn_on",
|
|
||||||
target: {
|
|
||||||
entity_id: "light.elgato_key_light_air",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wait_for_trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
from: "on",
|
|
||||||
to: "off",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
delay: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "light.turn_off",
|
|
||||||
target: {
|
|
||||||
entity_id: "light.elgato_key_light_air",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
id: "1614732497392",
|
|
||||||
alias: "Auto Elgato",
|
|
||||||
description: "",
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "43b6ee9293a551c5cc14e8eb60af54ba",
|
|
||||||
parent_id: "e22ddfd5f11dc4aad9a52fc10dab613b",
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
script_execution: "finished",
|
|
||||||
},
|
|
||||||
logbookEntries: [
|
|
||||||
{
|
|
||||||
name: "Auto Elgato",
|
|
||||||
message:
|
|
||||||
"has been triggered by state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
source: "state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
entity_id: "automation.auto_elgato",
|
|
||||||
when: "2021-03-14T06:07:01.768492+00:00",
|
|
||||||
domain: "automation",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-14T06:07:01.872187+00:00",
|
|
||||||
name: "Elgato Key Light Air",
|
|
||||||
state: "on",
|
|
||||||
entity_id: "light.elgato_key_light_air",
|
|
||||||
context_entity_id: "automation.auto_elgato",
|
|
||||||
context_entity_id_name: "Auto Elgato",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Auto Elgato",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-14T06:07:53.284505+00:00",
|
|
||||||
name: "Elgato Key Light Air",
|
|
||||||
state: "off",
|
|
||||||
entity_id: "light.elgato_key_light_air",
|
|
||||||
context_entity_id: "automation.auto_elgato",
|
|
||||||
context_entity_id_name: "Auto Elgato",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Auto Elgato",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
@@ -1,7 +0,0 @@
|
|||||||
import { AutomationTraceExtended } from "../../../../src/data/trace";
|
|
||||||
import { LogbookEntry } from "../../../../src/data/logbook";
|
|
||||||
|
|
||||||
export interface DemoTrace {
|
|
||||||
trace: AutomationTraceExtended;
|
|
||||||
logbookEntries: LogbookEntry[];
|
|
||||||
}
|
|
@@ -1,96 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeAction } from "../../../src/data/script_i18n";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
|
|
||||||
const actions = [
|
|
||||||
{ wait_template: "{{ true }}", alias: "Something with an alias" },
|
|
||||||
{ delay: "0:05" },
|
|
||||||
{ wait_template: "{{ true }}" },
|
|
||||||
{
|
|
||||||
condition: "template",
|
|
||||||
value_template: "{{ true }}",
|
|
||||||
},
|
|
||||||
{ event: "happy_event" },
|
|
||||||
{
|
|
||||||
device_id: "abcdefgh",
|
|
||||||
domain: "plex",
|
|
||||||
entity_id: "media_player.kitchen",
|
|
||||||
},
|
|
||||||
{ scene: "scene.kitchen_morning" },
|
|
||||||
{
|
|
||||||
wait_for_trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
variables: {
|
|
||||||
hello: "world",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-action")
|
|
||||||
export class DemoAutomationDescribeAction extends LitElement {
|
|
||||||
@property({ attribute: false }) hass!: HomeAssistant;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<ha-card header="Actions">
|
|
||||||
${actions.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="action">
|
|
||||||
<span>${describeAction(this.hass, conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.action {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-action": DemoAutomationDescribeAction;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,60 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeCondition } from "../../../src/data/automation_i18n";
|
|
||||||
|
|
||||||
const conditions = [
|
|
||||||
{ condition: "and" },
|
|
||||||
{ condition: "not" },
|
|
||||||
{ condition: "or" },
|
|
||||||
{ condition: "state" },
|
|
||||||
{ condition: "numeric_state" },
|
|
||||||
{ condition: "sun", after: "sunset" },
|
|
||||||
{ condition: "sun", after: "sunrise" },
|
|
||||||
{ condition: "zone" },
|
|
||||||
{ condition: "time" },
|
|
||||||
{ condition: "template" },
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-condition")
|
|
||||||
export class DemoAutomationDescribeCondition extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="Conditions">
|
|
||||||
${conditions.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="condition">
|
|
||||||
<span>${describeCondition(conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.condition {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-condition": DemoAutomationDescribeCondition;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,63 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeTrigger } from "../../../src/data/automation_i18n";
|
|
||||||
|
|
||||||
const triggers = [
|
|
||||||
{ platform: "state" },
|
|
||||||
{ platform: "mqtt" },
|
|
||||||
{ platform: "geo_location" },
|
|
||||||
{ platform: "homeassistant" },
|
|
||||||
{ platform: "numeric_state" },
|
|
||||||
{ platform: "sun" },
|
|
||||||
{ platform: "time_pattern" },
|
|
||||||
{ platform: "webhook" },
|
|
||||||
{ platform: "zone" },
|
|
||||||
{ platform: "tag" },
|
|
||||||
{ platform: "time" },
|
|
||||||
{ platform: "template" },
|
|
||||||
{ platform: "event" },
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-trigger")
|
|
||||||
export class DemoAutomationDescribeTrigger extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="Triggers">
|
|
||||||
${triggers.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="trigger">
|
|
||||||
<span>${describeTrigger(conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.trigger {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-trigger": DemoAutomationDescribeTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,81 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import "../../../src/components/trace/hat-script-graph";
|
|
||||||
import "../../../src/components/trace/hat-trace-timeline";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
import { mockDemoTrace } from "../data/traces/mock-demo-trace";
|
|
||||||
import { DemoTrace } from "../data/traces/types";
|
|
||||||
|
|
||||||
const traces: DemoTrace[] = [
|
|
||||||
mockDemoTrace({ state: "running" }),
|
|
||||||
mockDemoTrace({ state: "debugged" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "failed_conditions" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "failed_single" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "failed_max_runs" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "finished" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "aborted" }),
|
|
||||||
mockDemoTrace({
|
|
||||||
state: "stopped",
|
|
||||||
script_execution: "error",
|
|
||||||
error: 'Variable "beer" cannot be None',
|
|
||||||
}),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "cancelled" }),
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-trace-timeline")
|
|
||||||
export class DemoAutomationTraceTimeline extends LitElement {
|
|
||||||
@property({ attribute: false }) hass?: HomeAssistant;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
${traces.map(
|
|
||||||
(trace) => html`
|
|
||||||
<ha-card .header=${trace.trace.config.alias}>
|
|
||||||
<div class="card-content">
|
|
||||||
<hat-trace-timeline
|
|
||||||
.hass=${this.hass}
|
|
||||||
.trace=${trace.trace}
|
|
||||||
.logbookEntries=${trace.logbookEntries}
|
|
||||||
></hat-trace-timeline>
|
|
||||||
<button @click=${() => console.log(trace)}>Log trace</button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px;
|
|
||||||
}
|
|
||||||
.card-content {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-trace-timeline": DemoAutomationTraceTimeline;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,91 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import "../../../src/components/trace/hat-script-graph";
|
|
||||||
import "../../../src/components/trace/hat-trace-timeline";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
import { DemoTrace } from "../data/traces/types";
|
|
||||||
import { basicTrace } from "../data/traces/basic_trace";
|
|
||||||
import { motionLightTrace } from "../data/traces/motion-light-trace";
|
|
||||||
|
|
||||||
const traces: DemoTrace[] = [basicTrace, motionLightTrace];
|
|
||||||
|
|
||||||
@customElement("demo-automation-trace")
|
|
||||||
export class DemoAutomationTrace extends LitElement {
|
|
||||||
@property({ attribute: false }) hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _selected = {};
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
${traces.map(
|
|
||||||
(trace, idx) => html`
|
|
||||||
<ha-card .header=${trace.trace.config.alias}>
|
|
||||||
<div class="card-content">
|
|
||||||
<hat-script-graph
|
|
||||||
.trace=${trace.trace}
|
|
||||||
.selected=${this._selected[idx]}
|
|
||||||
@graph-node-selected=${(ev) => {
|
|
||||||
this._selected = { ...this._selected, [idx]: ev.detail.path };
|
|
||||||
}}
|
|
||||||
></hat-script-graph>
|
|
||||||
<hat-trace-timeline
|
|
||||||
allowPick
|
|
||||||
.hass=${this.hass}
|
|
||||||
.trace=${trace.trace}
|
|
||||||
.logbookEntries=${trace.logbookEntries}
|
|
||||||
.selectedPath=${this._selected[idx]}
|
|
||||||
@value-changed=${(ev) => {
|
|
||||||
this._selected = {
|
|
||||||
...this._selected,
|
|
||||||
[idx]: ev.detail.value,
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
></hat-trace-timeline>
|
|
||||||
<button @click=${() => console.log(trace)}>Log trace</button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px;
|
|
||||||
}
|
|
||||||
.card-content {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.card-content > * {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
.card-content > *:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-trace": DemoAutomationTrace;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,150 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-alert";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
|
|
||||||
const alerts: {
|
|
||||||
title?: string;
|
|
||||||
description: string | TemplateResult;
|
|
||||||
type: "info" | "warning" | "error" | "success";
|
|
||||||
dismissable?: boolean;
|
|
||||||
action?: string;
|
|
||||||
rtl?: boolean;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
title: "Test info alert",
|
|
||||||
description: "This is a test info alert with a title and description",
|
|
||||||
type: "info",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Test warning alert",
|
|
||||||
description: "This is a test warning alert with a title and description",
|
|
||||||
type: "warning",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Test error alert",
|
|
||||||
description: "This is a test error alert with a title and description",
|
|
||||||
type: "error",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Test warning with long string",
|
|
||||||
description:
|
|
||||||
"sensor.lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum",
|
|
||||||
type: "warning",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Test success alert",
|
|
||||||
description: "This is a test success alert with a title and description",
|
|
||||||
type: "success",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "This is a test info alert with description only",
|
|
||||||
type: "info",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description:
|
|
||||||
"This is a test warning alert with a rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really long description only",
|
|
||||||
type: "warning",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Error with description and list",
|
|
||||||
description: html`<p>
|
|
||||||
This is a test error alert with a title, description and a list
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>List item #1</li>
|
|
||||||
<li>List item #2</li>
|
|
||||||
<li>List item #3</li>
|
|
||||||
</ul>`,
|
|
||||||
type: "error",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Test dismissable alert",
|
|
||||||
description: "This is a test success alert that can be dismissable",
|
|
||||||
type: "success",
|
|
||||||
dismissable: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Dismissable information",
|
|
||||||
type: "info",
|
|
||||||
dismissable: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Error with action",
|
|
||||||
description: "This is a test error alert with action",
|
|
||||||
type: "error",
|
|
||||||
action: "restart",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Unsaved data",
|
|
||||||
description: "You have unsaved data",
|
|
||||||
type: "warning",
|
|
||||||
action: "save",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Dismissable information (RTL)",
|
|
||||||
type: "info",
|
|
||||||
dismissable: true,
|
|
||||||
rtl: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Error with action",
|
|
||||||
description: "This is a test error alert with action (RTL)",
|
|
||||||
type: "error",
|
|
||||||
action: "restart",
|
|
||||||
rtl: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Test success alert (RTL)",
|
|
||||||
description: "This is a test success alert with a title and description",
|
|
||||||
type: "success",
|
|
||||||
rtl: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-ha-alert")
|
|
||||||
export class DemoHaAlert extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="ha-alert demo">
|
|
||||||
${alerts.map(
|
|
||||||
(alert) => html`
|
|
||||||
<ha-alert
|
|
||||||
.title=${alert.title || ""}
|
|
||||||
.alertType=${alert.type}
|
|
||||||
.dismissable=${alert.dismissable || false}
|
|
||||||
.actionText=${alert.action || ""}
|
|
||||||
.rtl=${alert.rtl || false}
|
|
||||||
>
|
|
||||||
${alert.description}
|
|
||||||
</ha-alert>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.condition {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-alert": DemoHaAlert;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -87,8 +93,4 @@ class DemoAlarmPanelEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-alarm-panel-card", DemoAlarmPanelEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-alarm-panel-card": DemoAlarmPanelEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -69,8 +75,4 @@ class DemoConditional extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-conditional-card", DemoConditional);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-conditional-card": DemoConditional;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -233,8 +239,4 @@ class DemoEntities extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-entities-card", DemoEntities);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-entities-card": DemoEntities;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -85,8 +91,4 @@ class DemoButtonEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-entity-button-card", DemoButtonEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-entity-button-card": DemoButtonEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -126,8 +132,4 @@ class DemoEntityFilter extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-entity-filter-card", DemoEntityFilter);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-entity-filter-card": DemoEntityFilter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -123,8 +129,4 @@ class DemoGaugeEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-gauge-card", DemoGaugeEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-gauge-card": DemoGaugeEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -180,7 +186,7 @@ const CONFIGS = [
|
|||||||
name:
|
name:
|
||||||
- light.kitchen_lights
|
- light.kitchen_lights
|
||||||
- entity: lock.kitchen_door
|
- entity: lock.kitchen_door
|
||||||
name:
|
name:
|
||||||
- light.ceiling_lights
|
- light.ceiling_lights
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
@@ -188,7 +194,7 @@ const CONFIGS = [
|
|||||||
heading: "Custom tap action",
|
heading: "Custom tap action",
|
||||||
config: `
|
config: `
|
||||||
- type: glance
|
- type: glance
|
||||||
columns: 4
|
columns: 4
|
||||||
entities:
|
entities:
|
||||||
- entity: lock.kitchen_door
|
- entity: lock.kitchen_door
|
||||||
name: Custom
|
name: Custom
|
||||||
@@ -226,8 +232,4 @@ class DemoGlanceEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-glance-card", DemoGlanceEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-glance-card": DemoGlanceEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { customElement, html, LitElement, TemplateResult } from "lit-element";
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
@@ -43,8 +42,4 @@ class DemoIframe extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-iframe-card", DemoIframe);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-iframe-card": DemoIframe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -79,8 +85,4 @@ class DemoLightEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-light-card", DemoLightEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-light-card": DemoLightEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -177,8 +183,4 @@ class DemoMap extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-map-card", DemoMap);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-map-card": DemoMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { mockTemplate } from "../../../demo/src/stubs/template";
|
import { mockTemplate } from "../../../demo/src/stubs/template";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -270,8 +276,4 @@ class DemoMarkdown extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-markdown-card", DemoMarkdown);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-markdown-card": DemoMarkdown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
import { createMediaPlayerEntities } from "../data/media_players";
|
import { createMediaPlayerEntities } from "../data/media_players";
|
||||||
@@ -174,8 +180,4 @@ class DemoHuiMediaControlCard extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-media-control-card", DemoHuiMediaControlCard);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-media-control-card": DemoHuiMediaControlCard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
import { createMediaPlayerEntities } from "../data/media_players";
|
import { createMediaPlayerEntities } from "../data/media_players";
|
||||||
@@ -71,8 +77,4 @@ class DemoHuiMediaPlayerRow extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-media-player-row", DemoHuiMediaPlayerRow);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-media-player-row": DemoHuiMediaPlayerRow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -141,8 +147,4 @@ class DemoPictureElements extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-picture-elements-card", DemoPictureElements);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-picture-elements-card": DemoPictureElements;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -96,8 +102,4 @@ class DemoPictureEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-picture-entity-card", DemoPictureEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-picture-entity-card": DemoPictureEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -137,8 +143,4 @@ class DemoPictureGlance extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-picture-glance-card", DemoPictureGlance);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-picture-glance-card": DemoPictureGlance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
import { createPlantEntities } from "../data/plants";
|
import { createPlantEntities } from "../data/plants";
|
||||||
@@ -46,8 +52,4 @@ export class DemoPlantEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-plant-card", DemoPlantEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-plant-card": DemoPlantEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
@@ -42,8 +48,4 @@ class DemoShoppingListEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-shopping-list-card", DemoShoppingListEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-shopping-list-card": DemoShoppingListEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { mockHistory } from "../../../demo/src/stubs/history";
|
import { mockHistory } from "../../../demo/src/stubs/history";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
@@ -43,110 +49,6 @@ const ENTITIES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
{
|
|
||||||
heading: "Default Grid",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_paulus
|
|
||||||
- type: sensor
|
|
||||||
entity: sensor.illumination
|
|
||||||
graph: line
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_anne_therese
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Non-square Grid with 2 columns",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 2
|
|
||||||
square: false
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_paulus
|
|
||||||
- type: sensor
|
|
||||||
entity: sensor.illumination
|
|
||||||
graph: line
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Default Grid with title",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
title: Kitchen
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_paulus
|
|
||||||
- type: sensor
|
|
||||||
entity: sensor.illumination
|
|
||||||
graph: line
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_anne_therese
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Columns 4",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 4
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_paulus
|
|
||||||
- type: sensor
|
|
||||||
entity: sensor.illumination
|
|
||||||
graph: line
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Columns 2",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 2
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Columns 1",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 1
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Size for single card",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
heading: "Vertical Stack",
|
heading: "Vertical Stack",
|
||||||
config: `
|
config: `
|
||||||
@@ -197,9 +99,45 @@ const CONFIGS = [
|
|||||||
entity: light.bed_light
|
entity: light.bed_light
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
heading: "Default Grid",
|
||||||
|
config: `
|
||||||
|
- type: grid
|
||||||
|
cards:
|
||||||
|
- type: entity
|
||||||
|
entity: light.kitchen_lights
|
||||||
|
- type: entity
|
||||||
|
entity: light.bed_light
|
||||||
|
- type: entity
|
||||||
|
entity: device_tracker.demo_paulus
|
||||||
|
- type: sensor
|
||||||
|
entity: sensor.illumination
|
||||||
|
graph: line
|
||||||
|
- type: entity
|
||||||
|
entity: device_tracker.demo_anne_therese
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Non-square Grid with 2 columns",
|
||||||
|
config: `
|
||||||
|
- type: grid
|
||||||
|
columns: 2
|
||||||
|
square: false
|
||||||
|
cards:
|
||||||
|
- type: entity
|
||||||
|
entity: light.kitchen_lights
|
||||||
|
- type: entity
|
||||||
|
entity: light.bed_light
|
||||||
|
- type: entity
|
||||||
|
entity: device_tracker.demo_paulus
|
||||||
|
- type: sensor
|
||||||
|
entity: sensor.illumination
|
||||||
|
graph: line
|
||||||
|
`,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-grid-and-stack-card")
|
@customElement("demo-hui-stack-card")
|
||||||
class DemoStack extends LitElement {
|
class DemoStack extends LitElement {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
@query("#demos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
@@ -217,8 +155,4 @@ class DemoStack extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-stack-card", DemoStack);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-grid-and-stack-card": DemoStack;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -90,8 +96,4 @@ class DemoThermostatEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-thermostat-card", DemoThermostatEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-thermostat-card": DemoThermostatEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,354 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import "../../../src/components/ha-formfield";
|
|
||||||
import "../../../src/components/ha-switch";
|
|
||||||
|
|
||||||
import { classMap } from "lit/directives/class-map";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import { IntegrationManifest } from "../../../src/data/integration";
|
|
||||||
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
import "../../../src/panels/config/integrations/ha-integration-card";
|
|
||||||
import "../../../src/panels/config/integrations/ha-ignored-config-entry-card";
|
|
||||||
import "../../../src/panels/config/integrations/ha-config-flow-card";
|
|
||||||
import type {
|
|
||||||
ConfigEntryExtended,
|
|
||||||
DataEntryFlowProgressExtended,
|
|
||||||
} from "../../../src/panels/config/integrations/ha-config-integrations";
|
|
||||||
import { DeviceRegistryEntry } from "../../../src/data/device_registry";
|
|
||||||
import { EntityRegistryEntry } from "../../../src/data/entity_registry";
|
|
||||||
|
|
||||||
const createConfigEntry = (
|
|
||||||
title: string,
|
|
||||||
override: Partial<ConfigEntryExtended> = {}
|
|
||||||
): ConfigEntryExtended => ({
|
|
||||||
entry_id: title,
|
|
||||||
domain: "esphome",
|
|
||||||
localized_domain_name: "ESPHome",
|
|
||||||
title,
|
|
||||||
source: "zeroconf",
|
|
||||||
state: "loaded",
|
|
||||||
supports_options: false,
|
|
||||||
supports_unload: true,
|
|
||||||
disabled_by: null,
|
|
||||||
pref_disable_new_entities: false,
|
|
||||||
pref_disable_polling: false,
|
|
||||||
reason: null,
|
|
||||||
...override,
|
|
||||||
});
|
|
||||||
|
|
||||||
const createManifest = (
|
|
||||||
isCustom: boolean,
|
|
||||||
isCloud: boolean,
|
|
||||||
name = "ESPHome"
|
|
||||||
): IntegrationManifest => ({
|
|
||||||
name,
|
|
||||||
domain: "esphome",
|
|
||||||
is_built_in: !isCustom,
|
|
||||||
config_flow: false,
|
|
||||||
documentation: "https://www.home-assistant.io/integrations/esphome/",
|
|
||||||
iot_class: isCloud ? "cloud_polling" : "local_polling",
|
|
||||||
});
|
|
||||||
|
|
||||||
const loadedEntry = createConfigEntry("Loaded");
|
|
||||||
const nameAsDomainEntry = createConfigEntry("ESPHome");
|
|
||||||
const longNameEntry = createConfigEntry(
|
|
||||||
"Entry with a super long name that is going to the next line"
|
|
||||||
);
|
|
||||||
const longNonBreakingNameEntry = createConfigEntry(
|
|
||||||
"EntryWithASuperLongNameThatDoesNotBreak"
|
|
||||||
);
|
|
||||||
const configPanelEntry = createConfigEntry("Config Panel", {
|
|
||||||
domain: "mqtt",
|
|
||||||
localized_domain_name: "MQTT",
|
|
||||||
});
|
|
||||||
const optionsFlowEntry = createConfigEntry("Options Flow", {
|
|
||||||
supports_options: true,
|
|
||||||
});
|
|
||||||
const disabledPollingEntry = createConfigEntry("Disabled Polling", {
|
|
||||||
pref_disable_polling: true,
|
|
||||||
});
|
|
||||||
const setupErrorEntry = createConfigEntry("Setup Error", {
|
|
||||||
state: "setup_error",
|
|
||||||
});
|
|
||||||
const migrationErrorEntry = createConfigEntry("Migration Error", {
|
|
||||||
state: "migration_error",
|
|
||||||
});
|
|
||||||
const setupRetryEntry = createConfigEntry("Setup Retry", {
|
|
||||||
state: "setup_retry",
|
|
||||||
});
|
|
||||||
const setupRetryReasonEntry = createConfigEntry("Setup Retry", {
|
|
||||||
state: "setup_retry",
|
|
||||||
reason: "connection_error",
|
|
||||||
});
|
|
||||||
const setupRetryReasonMissingKeyEntry = createConfigEntry("Setup Retry", {
|
|
||||||
state: "setup_retry",
|
|
||||||
reason:
|
|
||||||
"HTTPSConnectionpool: Max retries exceeded with NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x9eedfc10>: Failed to establish a new connection: [Errno 113] Host is unreachable')",
|
|
||||||
});
|
|
||||||
const failedUnloadEntry = createConfigEntry("Failed Unload", {
|
|
||||||
state: "failed_unload",
|
|
||||||
});
|
|
||||||
const notLoadedEntry = createConfigEntry("Not Loaded", { state: "not_loaded" });
|
|
||||||
const disabledEntry = createConfigEntry("Disabled", {
|
|
||||||
state: "not_loaded",
|
|
||||||
disabled_by: "user",
|
|
||||||
});
|
|
||||||
const disabledFailedUnloadEntry = createConfigEntry(
|
|
||||||
"Disabled - Failed Unload",
|
|
||||||
{
|
|
||||||
state: "failed_unload",
|
|
||||||
disabled_by: "user",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const configFlows: DataEntryFlowProgressExtended[] = [
|
|
||||||
{
|
|
||||||
flow_id: "adbb401329d8439ebb78ef29837826a8",
|
|
||||||
handler: "roku",
|
|
||||||
context: {
|
|
||||||
source: "ssdp",
|
|
||||||
unique_id: "YF008D862864",
|
|
||||||
title_placeholders: {
|
|
||||||
name: "Living room Roku",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
step_id: "discovery_confirm",
|
|
||||||
localized_title: "Living room Roku",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
flow_id: "adbb401329d8439ebb78ef29837826a8",
|
|
||||||
handler: "hue",
|
|
||||||
context: {
|
|
||||||
source: "reauth",
|
|
||||||
unique_id: "YF008D862864",
|
|
||||||
title_placeholders: {
|
|
||||||
name: "Living room Roku",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
step_id: "discovery_confirm",
|
|
||||||
localized_title: "Philips Hue",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const configEntries: Array<{
|
|
||||||
items: ConfigEntryExtended[];
|
|
||||||
is_custom?: boolean;
|
|
||||||
disabled?: boolean;
|
|
||||||
highlight?: string;
|
|
||||||
}> = [
|
|
||||||
{ items: [loadedEntry] },
|
|
||||||
{ items: [configPanelEntry] },
|
|
||||||
{ items: [optionsFlowEntry] },
|
|
||||||
{ items: [disabledPollingEntry] },
|
|
||||||
{ items: [nameAsDomainEntry] },
|
|
||||||
{ items: [longNameEntry] },
|
|
||||||
{ items: [longNonBreakingNameEntry] },
|
|
||||||
{ items: [setupErrorEntry] },
|
|
||||||
{ items: [migrationErrorEntry] },
|
|
||||||
{ items: [setupRetryEntry] },
|
|
||||||
{ items: [setupRetryReasonEntry] },
|
|
||||||
{ items: [setupRetryReasonMissingKeyEntry] },
|
|
||||||
{ items: [failedUnloadEntry] },
|
|
||||||
{ items: [notLoadedEntry] },
|
|
||||||
{
|
|
||||||
items: [
|
|
||||||
loadedEntry,
|
|
||||||
setupErrorEntry,
|
|
||||||
migrationErrorEntry,
|
|
||||||
longNameEntry,
|
|
||||||
longNonBreakingNameEntry,
|
|
||||||
setupRetryEntry,
|
|
||||||
failedUnloadEntry,
|
|
||||||
notLoadedEntry,
|
|
||||||
disabledEntry,
|
|
||||||
nameAsDomainEntry,
|
|
||||||
configPanelEntry,
|
|
||||||
optionsFlowEntry,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ disabled: true, items: [disabledEntry] },
|
|
||||||
{ disabled: true, items: [disabledFailedUnloadEntry] },
|
|
||||||
{
|
|
||||||
disabled: true,
|
|
||||||
items: [disabledEntry, disabledFailedUnloadEntry],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
items: [loadedEntry, configPanelEntry],
|
|
||||||
highlight: "Loaded",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const createEntityRegistryEntries = (
|
|
||||||
item: ConfigEntryExtended
|
|
||||||
): EntityRegistryEntry[] => [
|
|
||||||
{
|
|
||||||
config_entry_id: item.entry_id,
|
|
||||||
device_id: "mock-device-id",
|
|
||||||
area_id: null,
|
|
||||||
disabled_by: null,
|
|
||||||
entity_id: "binary_sensor.updater",
|
|
||||||
name: null,
|
|
||||||
icon: null,
|
|
||||||
platform: "updater",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const createDeviceRegistryEntries = (
|
|
||||||
item: ConfigEntryExtended
|
|
||||||
): DeviceRegistryEntry[] => [
|
|
||||||
{
|
|
||||||
entry_type: null,
|
|
||||||
config_entries: [item.entry_id],
|
|
||||||
connections: [],
|
|
||||||
manufacturer: "ESPHome",
|
|
||||||
model: "Mock Device",
|
|
||||||
name: "Tag Reader",
|
|
||||||
sw_version: null,
|
|
||||||
id: "mock-device-id",
|
|
||||||
identifiers: [],
|
|
||||||
via_device_id: null,
|
|
||||||
area_id: null,
|
|
||||||
name_by_user: null,
|
|
||||||
disabled_by: null,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-integration-card")
|
|
||||||
export class DemoIntegrationCard extends LitElement {
|
|
||||||
@property({ attribute: false }) hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@state() isCustomIntegration = false;
|
|
||||||
|
|
||||||
@state() isCloud = false;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<div class="container">
|
|
||||||
<div class="filters">
|
|
||||||
<ha-formfield label="Custom Integration">
|
|
||||||
<ha-switch @change=${this._toggleCustomIntegration}></ha-switch>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield label="Relies on cloud">
|
|
||||||
<ha-switch @change=${this._toggleCloud}></ha-switch>
|
|
||||||
</ha-formfield>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ha-ignored-config-entry-card
|
|
||||||
.hass=${this.hass}
|
|
||||||
.entry=${createConfigEntry("Ignored Entry")}
|
|
||||||
.manifest=${createManifest(this.isCustomIntegration, this.isCloud)}
|
|
||||||
></ha-ignored-config-entry-card>
|
|
||||||
|
|
||||||
${configFlows.map(
|
|
||||||
(flow) => html`
|
|
||||||
<ha-config-flow-card
|
|
||||||
.hass=${this.hass}
|
|
||||||
.flow=${flow}
|
|
||||||
.manifest=${createManifest(
|
|
||||||
this.isCustomIntegration,
|
|
||||||
this.isCloud,
|
|
||||||
flow.handler === "roku" ? "Roku" : "Philips Hue"
|
|
||||||
)}
|
|
||||||
></ha-config-flow-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
${configEntries.map(
|
|
||||||
(info) => html`
|
|
||||||
<ha-integration-card
|
|
||||||
class=${classMap({
|
|
||||||
highlight: info.highlight !== undefined,
|
|
||||||
})}
|
|
||||||
.hass=${this.hass}
|
|
||||||
domain="esphome"
|
|
||||||
.items=${info.items}
|
|
||||||
.manifest=${createManifest(
|
|
||||||
this.isCustomIntegration,
|
|
||||||
this.isCloud
|
|
||||||
)}
|
|
||||||
.entityRegistryEntries=${createEntityRegistryEntries(
|
|
||||||
info.items[0]
|
|
||||||
)}
|
|
||||||
.deviceRegistryEntries=${createDeviceRegistryEntries(
|
|
||||||
info.items[0]
|
|
||||||
)}
|
|
||||||
?disabled=${info.disabled}
|
|
||||||
.selectedConfigEntryId=${info.highlight}
|
|
||||||
></ha-integration-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<!-- One that is standalone to see how it increases height if height
|
|
||||||
not defined by other cards. -->
|
|
||||||
<ha-integration-card
|
|
||||||
.hass=${this.hass}
|
|
||||||
domain="esphome"
|
|
||||||
.items=${[
|
|
||||||
loadedEntry,
|
|
||||||
setupErrorEntry,
|
|
||||||
migrationErrorEntry,
|
|
||||||
setupRetryEntry,
|
|
||||||
failedUnloadEntry,
|
|
||||||
]}
|
|
||||||
.manifest=${createManifest(this.isCustomIntegration, this.isCloud)}
|
|
||||||
.entityRegistryEntries=${createEntityRegistryEntries(loadedEntry)}
|
|
||||||
.deviceRegistryEntries=${createDeviceRegistryEntries(loadedEntry)}
|
|
||||||
></ha-integration-card>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("config", "en");
|
|
||||||
// Normally this string is loaded from backend
|
|
||||||
hass.addTranslations(
|
|
||||||
{
|
|
||||||
"component.esphome.config.error.connection_error":
|
|
||||||
"Can't connect to ESP. Please make sure your YAML file contains an 'api:' line.",
|
|
||||||
},
|
|
||||||
"en"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toggleCustomIntegration() {
|
|
||||||
this.isCustomIntegration = !this.isCustomIntegration;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toggleCloud() {
|
|
||||||
this.isCloud = !this.isCloud;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
||||||
grid-gap: 16px 16px;
|
|
||||||
padding: 8px 16px 16px;
|
|
||||||
margin-bottom: 64px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container > * {
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-formfield {
|
|
||||||
margin: 8px 0;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-integration-card": DemoIntegrationCard;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +1,21 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
LightColorModes,
|
SUPPORT_BRIGHTNESS,
|
||||||
|
SUPPORT_COLOR,
|
||||||
|
SUPPORT_COLOR_TEMP,
|
||||||
SUPPORT_EFFECT,
|
SUPPORT_EFFECT,
|
||||||
SUPPORT_FLASH,
|
SUPPORT_FLASH,
|
||||||
SUPPORT_TRANSITION,
|
SUPPORT_TRANSITION,
|
||||||
|
SUPPORT_WHITE_VALUE,
|
||||||
} from "../../../src/data/light";
|
} from "../../../src/data/light";
|
||||||
import "../../../src/dialogs/more-info/more-info-content";
|
import "../../../src/dialogs/more-info/more-info-content";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
@@ -22,8 +32,7 @@ const ENTITIES = [
|
|||||||
getEntity("light", "kitchen_light", "on", {
|
getEntity("light", "kitchen_light", "on", {
|
||||||
friendly_name: "Brightness Light",
|
friendly_name: "Brightness Light",
|
||||||
brightness: 200,
|
brightness: 200,
|
||||||
supported_color_modes: [LightColorModes.BRIGHTNESS],
|
supported_features: SUPPORT_BRIGHTNESS,
|
||||||
color_mode: LightColorModes.BRIGHTNESS,
|
|
||||||
}),
|
}),
|
||||||
getEntity("light", "color_temperature_light", "on", {
|
getEntity("light", "color_temperature_light", "on", {
|
||||||
friendly_name: "White Color Temperature Light",
|
friendly_name: "White Color Temperature Light",
|
||||||
@@ -31,96 +40,20 @@ const ENTITIES = [
|
|||||||
color_temp: 75,
|
color_temp: 75,
|
||||||
min_mireds: 30,
|
min_mireds: 30,
|
||||||
max_mireds: 150,
|
max_mireds: 150,
|
||||||
supported_color_modes: [
|
supported_features: SUPPORT_BRIGHTNESS + SUPPORT_COLOR_TEMP,
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.COLOR_TEMP,
|
|
||||||
}),
|
}),
|
||||||
getEntity("light", "color_hs_light", "on", {
|
getEntity("light", "color_effectslight", "on", {
|
||||||
friendly_name: "Color HS Light",
|
|
||||||
brightness: 255,
|
|
||||||
hs_color: [30, 100],
|
|
||||||
rgb_color: [30, 100, 255],
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.HS,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.HS,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_rgb_ct_light", "on", {
|
|
||||||
friendly_name: "Color RGB + CT Light",
|
|
||||||
brightness: 255,
|
|
||||||
color_temp: 75,
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.RGB,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.COLOR_TEMP,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_RGB_light", "on", {
|
|
||||||
friendly_name: "Color Effets Light",
|
friendly_name: "Color Effets Light",
|
||||||
brightness: 255,
|
brightness: 255,
|
||||||
rgb_color: [30, 100, 255],
|
hs_color: [30, 100],
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
white_value: 36,
|
||||||
supported_color_modes: [LightColorModes.BRIGHTNESS, LightColorModes.RGB],
|
supported_features:
|
||||||
color_mode: LightColorModes.RGB,
|
SUPPORT_BRIGHTNESS +
|
||||||
effect_list: ["random", "colorloop"],
|
SUPPORT_EFFECT +
|
||||||
}),
|
SUPPORT_FLASH +
|
||||||
getEntity("light", "color_rgbw_light", "on", {
|
SUPPORT_COLOR +
|
||||||
friendly_name: "Color RGBW Light",
|
SUPPORT_TRANSITION +
|
||||||
brightness: 255,
|
SUPPORT_WHITE_VALUE,
|
||||||
rgbw_color: [30, 100, 255, 125],
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.RGBW,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.RGBW,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_rgbww_light", "on", {
|
|
||||||
friendly_name: "Color RGBWW Light",
|
|
||||||
brightness: 255,
|
|
||||||
rgbww_color: [30, 100, 255, 125, 10],
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.RGBWW,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.RGBWW,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_xy_light", "on", {
|
|
||||||
friendly_name: "Color XY Light",
|
|
||||||
brightness: 255,
|
|
||||||
xy_color: [30, 100],
|
|
||||||
rgb_color: [30, 100, 255],
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.XY,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.XY,
|
|
||||||
effect_list: ["random", "colorloop"],
|
effect_list: ["random", "colorloop"],
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@@ -148,8 +81,4 @@ class DemoMoreInfoLight extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-more-info-light", DemoMoreInfoLight);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-more-info-light": DemoMoreInfoLight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { customElement, html, LitElement, TemplateResult } from "lit-element";
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
||||||
import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive";
|
import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive";
|
||||||
|
@@ -111,9 +111,29 @@ class HaGallery extends PolymerElement {
|
|||||||
</template>
|
</template>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
|
||||||
<ha-card header="Other Demos">
|
<ha-card header="More Info Demos">
|
||||||
<div class="card-content intro"></div>
|
<div class="card-content intro">
|
||||||
<template is="dom-repeat" items="[[_restDemos]]">
|
<p>
|
||||||
|
More info screens show up when an entity is clicked.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<template is="dom-repeat" items="[[_moreInfoDemos]]">
|
||||||
|
<a href="#[[item]]">
|
||||||
|
<paper-item>
|
||||||
|
<paper-item-body>{{ item }}</paper-item-body>
|
||||||
|
<ha-icon icon="hass:chevron-right"></ha-icon>
|
||||||
|
</paper-item>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</ha-card>
|
||||||
|
|
||||||
|
<ha-card header="Util Demos">
|
||||||
|
<div class="card-content intro">
|
||||||
|
<p>
|
||||||
|
Test pages for our utility functions.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<template is="dom-repeat" items="[[_utilDemos]]">
|
||||||
<a href="#[[item]]">
|
<a href="#[[item]]">
|
||||||
<paper-item>
|
<paper-item>
|
||||||
<paper-item-body>{{ item }}</paper-item-body>
|
<paper-item-body>{{ item }}</paper-item-body>
|
||||||
@@ -158,9 +178,13 @@ class HaGallery extends PolymerElement {
|
|||||||
type: Array,
|
type: Array,
|
||||||
computed: "_computeLovelace(_demos)",
|
computed: "_computeLovelace(_demos)",
|
||||||
},
|
},
|
||||||
_restDemos: {
|
_moreInfoDemos: {
|
||||||
type: Array,
|
type: Array,
|
||||||
computed: "_computeRest(_demos)",
|
computed: "_computeMoreInfos(_demos)",
|
||||||
|
},
|
||||||
|
_utilDemos: {
|
||||||
|
type: Array,
|
||||||
|
computed: "_computeUtil(_demos)",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -172,14 +196,6 @@ class HaGallery extends PolymerElement {
|
|||||||
this.$.notifications.showDialog({ message: ev.detail.message })
|
this.$.notifications.showDialog({ message: ev.detail.message })
|
||||||
);
|
);
|
||||||
|
|
||||||
this.addEventListener("alert-dismissed-clicked", () =>
|
|
||||||
this.$.notifications.showDialog({ message: "Alert dismissed clicked" })
|
|
||||||
);
|
|
||||||
|
|
||||||
this.addEventListener("alert-action-clicked", () =>
|
|
||||||
this.$.notifications.showDialog({ message: "Alert action clicked" })
|
|
||||||
);
|
|
||||||
|
|
||||||
this.addEventListener("hass-more-info", (ev) => {
|
this.addEventListener("hass-more-info", (ev) => {
|
||||||
if (ev.detail.entityId) {
|
if (ev.detail.entityId) {
|
||||||
this.$.notifications.showDialog({
|
this.$.notifications.showDialog({
|
||||||
@@ -221,8 +237,12 @@ class HaGallery extends PolymerElement {
|
|||||||
return demos.filter((demo) => demo.includes("hui"));
|
return demos.filter((demo) => demo.includes("hui"));
|
||||||
}
|
}
|
||||||
|
|
||||||
_computeRest(demos) {
|
_computeMoreInfos(demos) {
|
||||||
return demos.filter((demo) => !demo.includes("hui"));
|
return demos.filter((demo) => demo.includes("more-info"));
|
||||||
|
}
|
||||||
|
|
||||||
|
_computeUtil(demos) {
|
||||||
|
return demos.filter((demo) => demo.includes("util"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js";
|
import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { property } from "lit/decorators";
|
css,
|
||||||
|
CSSResultArray,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import { navigate } from "../../../src/common/navigate";
|
import { navigate } from "../../../src/common/navigate";
|
||||||
@@ -9,7 +15,6 @@ import {
|
|||||||
HassioAddonInfo,
|
HassioAddonInfo,
|
||||||
HassioAddonRepository,
|
HassioAddonRepository,
|
||||||
} from "../../../src/data/hassio/addon";
|
} from "../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
import "../components/hassio-card-content";
|
import "../components/hassio-card-content";
|
||||||
import { filterAndSort } from "../components/hassio-filter-addons";
|
import { filterAndSort } from "../components/hassio-filter-addons";
|
||||||
@@ -18,8 +23,6 @@ import { hassioStyle } from "../resources/hassio-style";
|
|||||||
class HassioAddonRepositoryEl extends LitElement {
|
class HassioAddonRepositoryEl extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public repo!: HassioAddonRepository;
|
@property({ attribute: false }) public repo!: HassioAddonRepository;
|
||||||
|
|
||||||
@property({ attribute: false }) public addons!: HassioAddonInfo[];
|
@property({ attribute: false }) public addons!: HassioAddonInfo[];
|
||||||
@@ -41,7 +44,9 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
const repo = this.repo;
|
const repo = this.repo;
|
||||||
let _addons = this.addons;
|
let _addons = this.addons;
|
||||||
if (!this.hass.userData?.showAdvanced) {
|
if (!this.hass.userData?.showAdvanced) {
|
||||||
_addons = _addons.filter((addon) => !addon.advanced);
|
_addons = _addons.filter((addon) => {
|
||||||
|
return !addon.advanced;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const addons = this._getAddons(_addons, this.filter);
|
const addons = this._getAddons(_addons, this.filter);
|
||||||
|
|
||||||
@@ -49,18 +54,16 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p class="description">
|
<p class="description">
|
||||||
${this.supervisor.localize(
|
No results found in "${repo.name}."
|
||||||
"store.no_results_found",
|
|
||||||
"repository",
|
|
||||||
repo.name
|
|
||||||
)}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1>${repo.name}</h1>
|
<h1>
|
||||||
|
${repo.name}
|
||||||
|
</h1>
|
||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
${addons.map(
|
${addons.map(
|
||||||
(addon) => html`
|
(addon) => html`
|
||||||
@@ -80,13 +83,11 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
: mdiPuzzle}
|
: mdiPuzzle}
|
||||||
.iconTitle=${addon.installed
|
.iconTitle=${addon.installed
|
||||||
? addon.update_available
|
? addon.update_available
|
||||||
? this.supervisor.localize(
|
? "New version available"
|
||||||
"common.new_version_available"
|
: "Add-on is installed"
|
||||||
)
|
|
||||||
: this.supervisor.localize("addon.installed")
|
|
||||||
: addon.available
|
: addon.available
|
||||||
? this.supervisor.localize("addon.not_installed")
|
? "Add-on is not installed"
|
||||||
: this.supervisor.localize("addon.not_available")}
|
: "Add-on is not available on your system"}
|
||||||
.iconClass=${addon.installed
|
.iconClass=${addon.installed
|
||||||
? addon.update_available
|
? addon.update_available
|
||||||
? "update"
|
? "update"
|
||||||
@@ -120,10 +121,10 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _addonTapped(ev) {
|
private _addonTapped(ev) {
|
||||||
navigate(`/hassio/addon/${ev.currentTarget.addon.slug}`);
|
navigate(this, `/hassio/addon/${ev.currentTarget.addon.slug}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultArray {
|
||||||
return [
|
return [
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
css`
|
css`
|
||||||
|
@@ -4,27 +4,26 @@ import "@material/mwc-list/mwc-list-item";
|
|||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResult,
|
||||||
html,
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
} from "lit-element";
|
||||||
} from "lit";
|
import { html, TemplateResult } from "lit-html";
|
||||||
import { property, state } from "lit/decorators";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||||
import { navigate } from "../../../src/common/navigate";
|
|
||||||
import "../../../src/common/search/search-input";
|
import "../../../src/common/search/search-input";
|
||||||
import { extractSearchParam } from "../../../src/common/url/search-params";
|
|
||||||
import "../../../src/components/ha-button-menu";
|
import "../../../src/components/ha-button-menu";
|
||||||
import "../../../src/components/ha-svg-icon";
|
import "../../../src/components/ha-svg-icon";
|
||||||
import {
|
import {
|
||||||
|
fetchHassioAddonsInfo,
|
||||||
HassioAddonInfo,
|
HassioAddonInfo,
|
||||||
HassioAddonRepository,
|
HassioAddonRepository,
|
||||||
reloadHassioAddons,
|
reloadHassioAddons,
|
||||||
} from "../../../src/data/hassio/addon";
|
} from "../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
||||||
|
import { fetchHassioSupervisorInfo } from "../../../src/data/hassio/supervisor";
|
||||||
import "../../../src/layouts/hass-loading-screen";
|
import "../../../src/layouts/hass-loading-screen";
|
||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import { HomeAssistant, Route } from "../../../src/types";
|
import { HomeAssistant, Route } from "../../../src/types";
|
||||||
@@ -52,41 +51,58 @@ const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => {
|
|||||||
class HassioAddonStore extends LitElement {
|
class HassioAddonStore extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
@state() private _filter?: string;
|
@property({ attribute: false }) private _addons?: HassioAddonInfo[];
|
||||||
|
|
||||||
|
@property({ attribute: false }) private _repos?: HassioAddonRepository[];
|
||||||
|
|
||||||
|
@internalProperty() private _filter?: string;
|
||||||
|
|
||||||
public async refreshData() {
|
public async refreshData() {
|
||||||
|
this._repos = undefined;
|
||||||
|
this._addons = undefined;
|
||||||
|
this._filter = undefined;
|
||||||
await reloadHassioAddons(this.hass);
|
await reloadHassioAddons(this.hass);
|
||||||
await this._loadData();
|
await this._loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
let repos: TemplateResult[] = [];
|
const repos: TemplateResult[] = [];
|
||||||
|
|
||||||
if (this.supervisor.addon.repositories) {
|
if (this._repos) {
|
||||||
repos = this.addonRepositories(
|
for (const repo of this._repos) {
|
||||||
this.supervisor.addon.repositories,
|
const addons = this._addons!.filter(
|
||||||
this.supervisor.addon.addons,
|
(addon) => addon.repository === repo.slug
|
||||||
this._filter
|
);
|
||||||
);
|
|
||||||
|
if (addons.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
repos.push(html`
|
||||||
|
<hassio-addon-repository
|
||||||
|
.hass=${this.hass}
|
||||||
|
.repo=${repo}
|
||||||
|
.addons=${addons}
|
||||||
|
.filter=${this._filter!}
|
||||||
|
></hassio-addon-repository>
|
||||||
|
`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage
|
<hass-tabs-subpage
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.localizeFunc=${this.supervisor.localize}
|
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${supervisorTabs}
|
hassio
|
||||||
main-page
|
main-page
|
||||||
supervisor
|
.tabs=${supervisorTabs}
|
||||||
>
|
>
|
||||||
<span slot="header"> ${this.supervisor.localize("panel.store")} </span>
|
<span slot="header">Add-on Store</span>
|
||||||
<ha-button-menu
|
<ha-button-menu
|
||||||
corner="BOTTOM_START"
|
corner="BOTTOM_START"
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
@@ -96,15 +112,15 @@ class HassioAddonStore extends LitElement {
|
|||||||
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
||||||
</mwc-icon-button>
|
</mwc-icon-button>
|
||||||
<mwc-list-item>
|
<mwc-list-item>
|
||||||
${this.supervisor.localize("store.repositories")}
|
Repositories
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
<mwc-list-item>
|
<mwc-list-item>
|
||||||
${this.supervisor.localize("common.reload")}
|
Reload
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
${this.hass.userData?.showAdvanced &&
|
${this.hass.userData?.showAdvanced &&
|
||||||
atLeastVersion(this.hass.config.version, 0, 117)
|
atLeastVersion(this.hass.config.version, 0, 117)
|
||||||
? html`<mwc-list-item>
|
? html`<mwc-list-item>
|
||||||
${this.supervisor.localize("store.registries")}
|
Registries
|
||||||
</mwc-list-item>`
|
</mwc-list-item>`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
@@ -125,9 +141,11 @@ class HassioAddonStore extends LitElement {
|
|||||||
${!this.hass.userData?.showAdvanced
|
${!this.hass.userData?.showAdvanced
|
||||||
? html`
|
? html`
|
||||||
<div class="advanced">
|
<div class="advanced">
|
||||||
|
Missing add-ons? Enable advanced mode on
|
||||||
<a href="/profile" target="_top">
|
<a href="/profile" target="_top">
|
||||||
${this.supervisor.localize("store.missing_addons")}
|
your profile page
|
||||||
</a>
|
</a>
|
||||||
|
.
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@@ -137,45 +155,14 @@ class HassioAddonStore extends LitElement {
|
|||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
const repositoryUrl = extractSearchParam("repository_url");
|
|
||||||
navigate("/hassio/store", { replace: true });
|
|
||||||
if (repositoryUrl) {
|
|
||||||
this._manageRepositories(repositoryUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
||||||
this._loadData();
|
this._loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private addonRepositories = memoizeOne(
|
|
||||||
(
|
|
||||||
repositories: HassioAddonRepository[],
|
|
||||||
addons: HassioAddonInfo[],
|
|
||||||
filter?: string
|
|
||||||
) =>
|
|
||||||
repositories.sort(sortRepos).map((repo) => {
|
|
||||||
const filteredAddons = addons.filter(
|
|
||||||
(addon) => addon.repository === repo.slug
|
|
||||||
);
|
|
||||||
|
|
||||||
return filteredAddons.length !== 0
|
|
||||||
? html`
|
|
||||||
<hassio-addon-repository
|
|
||||||
.hass=${this.hass}
|
|
||||||
.repo=${repo}
|
|
||||||
.addons=${filteredAddons}
|
|
||||||
.filter=${filter!}
|
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-addon-repository>
|
|
||||||
`
|
|
||||||
: html``;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||||
switch (ev.detail.index) {
|
switch (ev.detail.index) {
|
||||||
case 0:
|
case 0:
|
||||||
this._manageRepositoriesClicked();
|
this._manageRepositories();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
this.refreshData();
|
this.refreshData();
|
||||||
@@ -192,33 +179,37 @@ class HassioAddonStore extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _manageRepositoriesClicked() {
|
private async _manageRepositories() {
|
||||||
this._manageRepositories();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _manageRepositories(url?: string) {
|
|
||||||
showRepositoriesDialog(this, {
|
showRepositoriesDialog(this, {
|
||||||
supervisor: this.supervisor,
|
repos: this._repos!,
|
||||||
url,
|
loadData: () => this._loadData(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _manageRegistries() {
|
private async _manageRegistries() {
|
||||||
showRegistriesDialog(this, { supervisor: this.supervisor });
|
showRegistriesDialog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _loadData() {
|
private async _loadData() {
|
||||||
fireEvent(this, "supervisor-collection-refresh", { collection: "addon" });
|
try {
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
const [addonsInfo, supervisor] = await Promise.all([
|
||||||
collection: "supervisor",
|
fetchHassioAddonsInfo(this.hass),
|
||||||
});
|
fetchHassioSupervisorInfo(this.hass),
|
||||||
|
]);
|
||||||
|
fireEvent(this, "supervisor-update", { supervisor });
|
||||||
|
this._repos = addonsInfo.repositories;
|
||||||
|
this._repos.sort(sortRepos);
|
||||||
|
this._addons = addonsInfo.addons;
|
||||||
|
} catch (err) {
|
||||||
|
alert(extractApiErrorMessage(err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _filterChanged(e) {
|
private async _filterChanged(e) {
|
||||||
this._filter = e.detail.value;
|
this._filter = e.detail.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
hassio-addon-repository {
|
hassio-addon-repository {
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
|
@@ -4,16 +4,17 @@ import "@polymer/paper-item/paper-item";
|
|||||||
import "@polymer/paper-listbox/paper-listbox";
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResult,
|
||||||
|
customElement,
|
||||||
html,
|
html,
|
||||||
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit-element";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import "web-animations-js/web-animations-next-lite.min";
|
import "web-animations-js/web-animations-next-lite.min";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../../src/components/ha-alert";
|
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
@@ -24,7 +25,6 @@ import {
|
|||||||
fetchHassioHardwareAudio,
|
fetchHassioHardwareAudio,
|
||||||
HassioHardwareAudioDevice,
|
HassioHardwareAudioDevice,
|
||||||
} from "../../../../src/data/hassio/hardware";
|
} from "../../../../src/data/hassio/hardware";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
|
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
|
||||||
@@ -34,34 +34,26 @@ import { hassioStyle } from "../../resources/hassio-style";
|
|||||||
class HassioAddonAudio extends LitElement {
|
class HassioAddonAudio extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _inputDevices?: HassioHardwareAudioDevice[];
|
@internalProperty() private _inputDevices?: HassioHardwareAudioDevice[];
|
||||||
|
|
||||||
@state() private _outputDevices?: HassioHardwareAudioDevice[];
|
@internalProperty() private _outputDevices?: HassioHardwareAudioDevice[];
|
||||||
|
|
||||||
@state() private _selectedInput!: null | string;
|
@internalProperty() private _selectedInput!: null | string;
|
||||||
|
|
||||||
@state() private _selectedOutput!: null | string;
|
@internalProperty() private _selectedOutput!: null | string;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card header="Audio">
|
||||||
.header=${this.supervisor.localize("addon.configuration.audio.header")}
|
|
||||||
>
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._error
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
|
||||||
: ""}
|
|
||||||
|
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
.label=${this.supervisor.localize(
|
label="Input"
|
||||||
"addon.configuration.audio.input"
|
|
||||||
)}
|
|
||||||
@iron-select=${this._setInputDevice}
|
@iron-select=${this._setInputDevice}
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
@@ -70,19 +62,17 @@ class HassioAddonAudio extends LitElement {
|
|||||||
.selected=${this._selectedInput!}
|
.selected=${this._selectedInput!}
|
||||||
>
|
>
|
||||||
${this._inputDevices &&
|
${this._inputDevices &&
|
||||||
this._inputDevices.map(
|
this._inputDevices.map((item) => {
|
||||||
(item) => html`
|
return html`
|
||||||
<paper-item device=${item.device || ""}>
|
<paper-item device=${item.device || ""}
|
||||||
${item.name}
|
>${item.name}</paper-item
|
||||||
</paper-item>
|
>
|
||||||
`
|
`;
|
||||||
)}
|
})}
|
||||||
</paper-listbox>
|
</paper-listbox>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
.label=${this.supervisor.localize(
|
label="Output"
|
||||||
"addon.configuration.audio.output"
|
|
||||||
)}
|
|
||||||
@iron-select=${this._setOutputDevice}
|
@iron-select=${this._setOutputDevice}
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
@@ -91,26 +81,26 @@ class HassioAddonAudio extends LitElement {
|
|||||||
.selected=${this._selectedOutput!}
|
.selected=${this._selectedOutput!}
|
||||||
>
|
>
|
||||||
${this._outputDevices &&
|
${this._outputDevices &&
|
||||||
this._outputDevices.map(
|
this._outputDevices.map((item) => {
|
||||||
(item) => html`
|
return html`
|
||||||
<paper-item device=${item.device || ""}
|
<paper-item device=${item.device || ""}
|
||||||
>${item.name}</paper-item
|
>${item.name}</paper-item
|
||||||
>
|
>
|
||||||
`
|
`;
|
||||||
)}
|
})}
|
||||||
</paper-listbox>
|
</paper-listbox>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<ha-progress-button @click=${this._saveSettings}>
|
<ha-progress-button @click=${this._saveSettings}>
|
||||||
${this.supervisor.localize("common.save")}
|
Save
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -120,6 +110,10 @@ class HassioAddonAudio extends LitElement {
|
|||||||
paper-dropdown-menu {
|
paper-dropdown-menu {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.errors {
|
||||||
|
color: var(--error-color);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
paper-item {
|
paper-item {
|
||||||
width: 450px;
|
width: 450px;
|
||||||
}
|
}
|
||||||
@@ -158,7 +152,7 @@ class HassioAddonAudio extends LitElement {
|
|||||||
|
|
||||||
const noDevice: HassioHardwareAudioDevice = {
|
const noDevice: HassioHardwareAudioDevice = {
|
||||||
device: "default",
|
device: "default",
|
||||||
name: this.supervisor.localize("addon.configuration.audio.default"),
|
name: "Default",
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -195,7 +189,7 @@ class HassioAddonAudio extends LitElement {
|
|||||||
try {
|
try {
|
||||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.addon);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
this._error = "Failed to set addon audio device";
|
this._error = "Failed to set addon audio device";
|
||||||
|
@@ -1,8 +1,14 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
@@ -14,28 +20,26 @@ import "./hassio-addon-network";
|
|||||||
class HassioAddonConfigDashboard extends LitElement {
|
class HassioAddonConfigDashboard extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress active></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
const hasConfiguration =
|
const hasOptions =
|
||||||
(this.addon.options && Object.keys(this.addon.options).length) ||
|
this.addon.options && Object.keys(this.addon.options).length;
|
||||||
(this.addon.schema && Object.keys(this.addon.schema).length);
|
const hasSchema =
|
||||||
|
this.addon.schema && Object.keys(this.addon.schema).length;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${hasConfiguration || this.addon.network || this.addon.audio
|
${hasOptions || hasSchema || this.addon.network || this.addon.audio
|
||||||
? html`
|
? html`
|
||||||
${hasConfiguration
|
${hasOptions || hasSchema
|
||||||
? html`
|
? html`
|
||||||
<hassio-addon-config
|
<hassio-addon-config
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-addon-config>
|
></hassio-addon-config>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@@ -44,7 +48,6 @@ class HassioAddonConfigDashboard extends LitElement {
|
|||||||
<hassio-addon-network
|
<hassio-addon-network
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-addon-network>
|
></hassio-addon-network>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@@ -53,17 +56,16 @@ class HassioAddonConfigDashboard extends LitElement {
|
|||||||
<hassio-addon-audio
|
<hassio-addon-audio
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-addon-audio>
|
></hassio-addon-audio>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
`
|
`
|
||||||
: this.supervisor.localize("addon.configuration.no_configuration")}
|
: "This add-on does not expose configuration for you to mess with.... 👋"}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
|
@@ -2,36 +2,32 @@ import "@material/mwc-button";
|
|||||||
import { ActionDetail } from "@material/mwc-list";
|
import { ActionDetail } from "@material/mwc-list";
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
import { DEFAULT_SCHEMA, Type } from "js-yaml";
|
import "@polymer/iron-autogrow-textarea/iron-autogrow-textarea";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResult,
|
||||||
|
customElement,
|
||||||
html,
|
html,
|
||||||
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
|
query,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit-element";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../../src/components/ha-button-menu";
|
import "../../../../src/components/ha-button-menu";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import "../../../../src/components/ha-alert";
|
|
||||||
import "../../../../src/components/ha-form/ha-form";
|
import "../../../../src/components/ha-form/ha-form";
|
||||||
import type { HaFormSchema } from "../../../../src/components/ha-form/ha-form";
|
|
||||||
import "../../../../src/components/ha-formfield";
|
|
||||||
import "../../../../src/components/ha-switch";
|
|
||||||
import "../../../../src/components/ha-yaml-editor";
|
import "../../../../src/components/ha-yaml-editor";
|
||||||
import type { HaYamlEditor } from "../../../../src/components/ha-yaml-editor";
|
import type { HaYamlEditor } from "../../../../src/components/ha-yaml-editor";
|
||||||
import {
|
import {
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
HassioAddonSetOptionParams,
|
HassioAddonSetOptionParams,
|
||||||
setHassioAddonOption,
|
setHassioAddonOption,
|
||||||
validateHassioAddonOption,
|
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { showConfirmationDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
import { showConfirmationDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../src/types";
|
import type { HomeAssistant } from "../../../../src/types";
|
||||||
@@ -40,137 +36,70 @@ import { hassioStyle } from "../../resources/hassio-style";
|
|||||||
|
|
||||||
const SUPPORTED_UI_TYPES = ["string", "select", "boolean", "integer", "float"];
|
const SUPPORTED_UI_TYPES = ["string", "select", "boolean", "integer", "float"];
|
||||||
|
|
||||||
const ADDON_YAML_SCHEMA = DEFAULT_SCHEMA.extend([
|
|
||||||
new Type("!secret", {
|
|
||||||
kind: "scalar",
|
|
||||||
construct: (data) => `!secret ${data}`,
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
@customElement("hassio-addon-config")
|
@customElement("hassio-addon-config")
|
||||||
class HassioAddonConfig extends LitElement {
|
class HassioAddonConfig extends LitElement {
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) private _configHasChanged = false;
|
@property({ type: Boolean }) private _configHasChanged = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) private _valid = true;
|
@property({ type: Boolean }) private _valid = true;
|
||||||
|
|
||||||
@state() private _canShowSchema = false;
|
@internalProperty() private _canShowSchema = false;
|
||||||
|
|
||||||
@state() private _showOptional = false;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _options?: Record<string, unknown>;
|
||||||
|
|
||||||
@state() private _options?: Record<string, unknown>;
|
@internalProperty() private _yamlMode = false;
|
||||||
|
|
||||||
@state() private _yamlMode = false;
|
|
||||||
|
|
||||||
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
|
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
|
||||||
|
|
||||||
public computeLabel = (entry: HaFormSchema): string =>
|
|
||||||
this.addon.translations[this.hass.language]?.configuration?.[entry.name]
|
|
||||||
?.name ||
|
|
||||||
this.addon.translations.en?.configuration?.[entry.name].name ||
|
|
||||||
entry.name;
|
|
||||||
|
|
||||||
private _filteredShchema = memoizeOne(
|
|
||||||
(options: Record<string, unknown>, schema: HaFormSchema[]) =>
|
|
||||||
schema.filter((entry) => entry.name in options || entry.required)
|
|
||||||
);
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const showForm =
|
|
||||||
!this._yamlMode && this._canShowSchema && this.addon.schema;
|
|
||||||
const hasHiddenOptions =
|
|
||||||
showForm &&
|
|
||||||
JSON.stringify(this.addon.schema) !==
|
|
||||||
JSON.stringify(
|
|
||||||
this._filteredShchema(this.addon.options, this.addon.schema!)
|
|
||||||
);
|
|
||||||
return html`
|
return html`
|
||||||
<h1>${this.addon.name}</h1>
|
<h1>${this.addon.name}</h1>
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h2>
|
<h2>Configuration</h2>
|
||||||
${this.supervisor.localize("addon.configuration.options.header")}
|
|
||||||
</h2>
|
|
||||||
<div class="card-menu">
|
<div class="card-menu">
|
||||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||||
<mwc-icon-button slot="trigger">
|
<mwc-icon-button slot="trigger">
|
||||||
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
||||||
</mwc-icon-button>
|
</mwc-icon-button>
|
||||||
<mwc-list-item .disabled=${!this._canShowSchema}>
|
<mwc-list-item .disabled=${!this._canShowSchema}>
|
||||||
${this._yamlMode
|
${this._yamlMode ? "Edit in UI" : "Edit in YAML"}
|
||||||
? this.supervisor.localize(
|
|
||||||
"addon.configuration.options.edit_in_ui"
|
|
||||||
)
|
|
||||||
: this.supervisor.localize(
|
|
||||||
"addon.configuration.options.edit_in_yaml"
|
|
||||||
)}
|
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
<mwc-list-item class="warning">
|
<mwc-list-item class="warning">
|
||||||
${this.supervisor.localize("common.reset_defaults")}
|
Reset to defaults
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${showForm
|
${!this._yamlMode && this._canShowSchema && this.addon.schema
|
||||||
? html`<ha-form
|
? html`<ha-form
|
||||||
.data=${this._options!}
|
.data=${this._options!}
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
.computeLabel=${this.computeLabel}
|
.schema=${this.addon.schema}
|
||||||
.schema=${this._showOptional
|
|
||||||
? this.addon.schema!
|
|
||||||
: this._filteredShchema(
|
|
||||||
this.addon.options,
|
|
||||||
this.addon.schema!
|
|
||||||
)}
|
|
||||||
></ha-form>`
|
></ha-form>`
|
||||||
: html` <ha-yaml-editor
|
: html` <ha-yaml-editor
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
.yamlSchema=${ADDON_YAML_SCHEMA}
|
|
||||||
></ha-yaml-editor>`}
|
></ha-yaml-editor>`}
|
||||||
${this._error
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
|
||||||
: ""}
|
|
||||||
${!this._yamlMode ||
|
${!this._yamlMode ||
|
||||||
(this._canShowSchema && this.addon.schema) ||
|
(this._canShowSchema && this.addon.schema) ||
|
||||||
this._valid
|
this._valid
|
||||||
? ""
|
? ""
|
||||||
: html`
|
: html` <div class="errors">Invalid YAML</div> `}
|
||||||
<ha-alert alert-type="error">
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.configuration.options.invalid_yaml"
|
|
||||||
)}
|
|
||||||
</ha-alert>
|
|
||||||
`}
|
|
||||||
</div>
|
</div>
|
||||||
${hasHiddenOptions
|
<div class="card-actions">
|
||||||
? html`<ha-formfield
|
|
||||||
class="show-additional"
|
|
||||||
.label=${this.supervisor.localize(
|
|
||||||
"addon.configuration.options.show_unused_optional"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<ha-switch
|
|
||||||
@change=${this._toggleOptional}
|
|
||||||
.checked=${this._showOptional}
|
|
||||||
>
|
|
||||||
</ha-switch>
|
|
||||||
</ha-formfield>`
|
|
||||||
: ""}
|
|
||||||
<div class="card-actions right">
|
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
@click=${this._saveTapped}
|
@click=${this._saveTapped}
|
||||||
.disabled=${!this._configHasChanged || !this._valid}
|
.disabled=${!this._configHasChanged || !this._valid}
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("common.save")}
|
Save
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
@@ -179,7 +108,7 @@ class HassioAddonConfig extends LitElement {
|
|||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
protected firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this._canShowSchema = !this.addon.schema!.find(
|
this._canShowSchema = !this.addon.schema.find(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
(entry) => !SUPPORTED_UI_TYPES.includes(entry.type) || entry.multiple
|
(entry) => !SUPPORTED_UI_TYPES.includes(entry.type) || entry.multiple
|
||||||
);
|
);
|
||||||
@@ -215,19 +144,17 @@ class HassioAddonConfig extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _toggleOptional() {
|
|
||||||
this._showOptional = !this._showOptional;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _configChanged(ev): void {
|
private _configChanged(ev): void {
|
||||||
if (this.addon.schema && this._canShowSchema && !this._yamlMode) {
|
if (this.addon.schema && this._canShowSchema && !this._yamlMode) {
|
||||||
this._valid = true;
|
this._valid = true;
|
||||||
this._configHasChanged = true;
|
this._configHasChanged = true;
|
||||||
this._options! = ev.detail.value;
|
|
||||||
} else {
|
} else {
|
||||||
this._configHasChanged = true;
|
this._configHasChanged = true;
|
||||||
this._valid = ev.detail.isValid;
|
this._valid = ev.detail.isValid;
|
||||||
}
|
}
|
||||||
|
if (this._valid) {
|
||||||
|
this._options! = ev.detail.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _resetTapped(ev: CustomEvent): Promise<void> {
|
private async _resetTapped(ev: CustomEvent): Promise<void> {
|
||||||
@@ -235,10 +162,10 @@ class HassioAddonConfig extends LitElement {
|
|||||||
button.progress = true;
|
button.progress = true;
|
||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
title: this.supervisor.localize("confirm.reset_options.title"),
|
title: this.addon.name,
|
||||||
text: this.supervisor.localize("confirm.reset_options.text"),
|
text: "Are you sure you want to reset all your options?",
|
||||||
confirmText: this.supervisor.localize("common.reset_options"),
|
confirmText: "reset options",
|
||||||
dismissText: this.supervisor.localize("common.cancel"),
|
dismissText: "no",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
@@ -260,59 +187,42 @@ class HassioAddonConfig extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to reset addon configuration, ${extractApiErrorMessage(
|
||||||
"addon.common.update_available",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _saveTapped(ev: CustomEvent): Promise<void> {
|
private async _saveTapped(ev: CustomEvent): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
const options: Record<string, unknown> = this._yamlMode
|
|
||||||
? this._editor?.value
|
|
||||||
: this._options;
|
|
||||||
const eventdata = {
|
|
||||||
success: true,
|
|
||||||
response: undefined,
|
|
||||||
path: "options",
|
|
||||||
};
|
|
||||||
button.progress = true;
|
button.progress = true;
|
||||||
|
|
||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const validation = await validateHassioAddonOption(
|
|
||||||
this.hass,
|
|
||||||
this.addon.slug,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
if (!validation.valid) {
|
|
||||||
throw Error(validation.message);
|
|
||||||
}
|
|
||||||
await setHassioAddonOption(this.hass, this.addon.slug, {
|
await setHassioAddonOption(this.hass, this.addon.slug, {
|
||||||
options,
|
options: this._options!,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._configHasChanged = false;
|
this._configHasChanged = false;
|
||||||
|
const eventdata = {
|
||||||
|
success: true,
|
||||||
|
response: undefined,
|
||||||
|
path: "options",
|
||||||
|
};
|
||||||
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to save addon configuration, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_save",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
eventdata.success = false;
|
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -327,7 +237,17 @@ class HassioAddonConfig extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
.errors {
|
||||||
|
color: var(--error-color);
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
iron-autogrow-textarea {
|
||||||
|
width: 100%;
|
||||||
|
font-family: var(--code-font-family, monospace);
|
||||||
|
}
|
||||||
|
.syntaxerror {
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
.card-menu {
|
.card-menu {
|
||||||
float: right;
|
float: right;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
@@ -351,13 +271,6 @@ class HassioAddonConfig extends LitElement {
|
|||||||
margin-block: 0px;
|
margin-block: 0px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
.card-actions.right {
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show-additional {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user