mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-15 12:19:25 +00:00
Compare commits
1 Commits
ha-formfie
...
checkbox-s
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0bfeb22209 |
102
.eslintrc.json
102
.eslintrc.json
@@ -1,10 +1,9 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
"airbnb-base",
|
|
||||||
"airbnb-typescript/base",
|
"airbnb-typescript/base",
|
||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
"plugin:wc/recommended",
|
"plugin:wc/recommended",
|
||||||
"plugin:lit/all",
|
"plugin:lit/recommended",
|
||||||
"prettier"
|
"prettier"
|
||||||
],
|
],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
@@ -29,7 +28,6 @@
|
|||||||
"__BUILD__": false,
|
"__BUILD__": false,
|
||||||
"__VERSION__": false,
|
"__VERSION__": false,
|
||||||
"__STATIC_PATH__": false,
|
"__STATIC_PATH__": false,
|
||||||
"__SUPERVISOR__": false,
|
|
||||||
"Polymer": true
|
"Polymer": true
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
@@ -37,51 +35,55 @@
|
|||||||
"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/explicit-module-boundary-types": 0,
|
||||||
"@typescript-eslint/no-shadow": ["error"],
|
"@typescript-eslint/no-shadow": ["error"],
|
||||||
"@typescript-eslint/naming-convention": [
|
"@typescript-eslint/naming-convention": [
|
||||||
"off",
|
0,
|
||||||
{
|
{
|
||||||
"selector": "default",
|
"selector": "default",
|
||||||
"format": ["camelCase", "snake_case"],
|
"format": ["camelCase", "snake_case"],
|
||||||
@@ -99,21 +101,9 @@
|
|||||||
"format": ["PascalCase"]
|
"format": ["PascalCase"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
"lit/attribute-value-entities": 0
|
||||||
"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",
|
|
||||||
"lit/no-template-map": "off"
|
|
||||||
},
|
},
|
||||||
"plugins": ["disable", "unused-imports"],
|
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
|
||||||
"processor": "disable/disable"
|
"processor": "disable/disable",
|
||||||
|
"ignorePatterns": ["src/resources/lit-virtualizer/*"]
|
||||||
}
|
}
|
||||||
|
82
.github/workflows/ci.yaml
vendored
82
.github/workflows/ci.yaml
vendored
@@ -10,64 +10,83 @@ on:
|
|||||||
- dev
|
- dev
|
||||||
- master
|
- master
|
||||||
|
|
||||||
env:
|
|
||||||
NODE_VERSION: 14
|
|
||||||
NODE_OPTIONS: --max_old_space_size=6144
|
|
||||||
|
|
||||||
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:
|
||||||
CI: true
|
CI: true
|
||||||
- name: Build resources
|
- name: Build resources
|
||||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data 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: yarn run lint:eslint
|
||||||
- name: Run tsc
|
- name: Run tsc
|
||||||
run: yarn run lint:types
|
run: yarn run lint:types
|
||||||
- name: Run prettier
|
- name: Run prettier
|
||||||
run: yarn run lint: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: Build resources
|
- name: Run Mocha
|
||||||
run: ./node_modules/.bin/gulp build-translations build-locale-data
|
run: npm run mocha
|
||||||
- name: Run Tests
|
|
||||||
run: yarn run test
|
|
||||||
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:
|
||||||
@@ -82,11 +101,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=6144
|
|
||||||
|
|
||||||
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:
|
||||||
|
14
.github/workflows/release.yaml
vendored
14
.github/workflows/release.yaml
vendored
@@ -7,8 +7,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: 3.8
|
PYTHON_VERSION: 3.8
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 12.1
|
||||||
NODE_OPTIONS: --max_old_space_size=6144
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
@@ -30,15 +29,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
|
||||||
@@ -73,7 +64,8 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
arch: ["aarch64", "armhf", "armv7", "amd64", "i386"]
|
arch: ["aarch64", "armhf", "armv7", "amd64", "i386"]
|
||||||
tag:
|
tag:
|
||||||
- "3.9-alpine3.14"
|
- "3.8-alpine3.12"
|
||||||
|
- "3.9-alpine3.13"
|
||||||
steps:
|
steps:
|
||||||
- name: Download requirements.txt
|
- name: Download requirements.txt
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
|
42
.github/workflows/translations.yaml
vendored
42
.github/workflows/translations.yaml
vendored
@@ -1,6 +1,8 @@
|
|||||||
name: Translations
|
name: Translations
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "30 0 * * *"
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
@@ -8,7 +10,7 @@ on:
|
|||||||
- src/translations/en.json
|
- src/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
|
||||||
|
11
.gitignore
vendored
11
.gitignore
vendored
@@ -3,19 +3,14 @@
|
|||||||
|
|
||||||
# build
|
# build
|
||||||
build
|
build
|
||||||
|
build-translations/*
|
||||||
hass_frontend/*
|
hass_frontend/*
|
||||||
dist
|
dist
|
||||||
|
|
||||||
# yarn
|
# yarn
|
||||||
.yarn/*
|
.yarn
|
||||||
!.yarn/patches
|
|
||||||
!.yarn/releases
|
|
||||||
!.yarn/plugins
|
|
||||||
!.yarn/sdks
|
|
||||||
!.yarn/versions
|
|
||||||
.pnp.*
|
|
||||||
node_modules/*
|
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
node_modules/*
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|
||||||
# Python stuff
|
# Python stuff
|
||||||
|
4
.mocharc.cjs
Normal file
4
.mocharc.cjs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module.exports = {
|
||||||
|
require: "test-mocha/testconf.js",
|
||||||
|
timeout: 10000,
|
||||||
|
};
|
@@ -1,4 +1,5 @@
|
|||||||
build
|
build
|
||||||
|
build-translations/*
|
||||||
translations/*
|
translations/*
|
||||||
node_modules/*
|
node_modules/*
|
||||||
hass_frontend/*
|
hass_frontend/*
|
||||||
|
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,12 +0,0 @@
|
|||||||
diff --git a/mwc-icon-button-base.js b/mwc-icon-button-base.js
|
|
||||||
index 45cdaab93ccc0a6daaaaabc01266dcdc32e46bfd..b3ea5b541597308d85f86ce6c23fd00785fda835 100644
|
|
||||||
--- a/mwc-icon-button-base.js
|
|
||||||
+++ b/mwc-icon-button-base.js
|
|
||||||
@@ -63,7 +63,6 @@ export class IconButtonBase extends LitElement {
|
|
||||||
@touchend="${this.handleRippleDeactivate}"
|
|
||||||
@touchcancel="${this.handleRippleDeactivate}"
|
|
||||||
>${this.renderRipple()}
|
|
||||||
- <i class="material-icons">${this.icon}</i>
|
|
||||||
<span
|
|
||||||
><slot></slot
|
|
||||||
></span>
|
|
@@ -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
631
.yarn/releases/yarn-3.0.2.cjs
vendored
631
.yarn/releases/yarn-3.0.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-3.0.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,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
@@ -5,6 +5,8 @@ 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 +20,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
|
||||||
@@ -35,7 +36,6 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
|
|||||||
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
||||||
__VERSION__: JSON.stringify(env.version()),
|
__VERSION__: JSON.stringify(env.version()),
|
||||||
__DEMO__: false,
|
__DEMO__: false,
|
||||||
__SUPERVISOR__: false,
|
|
||||||
__BACKWARDS_COMPAT__: false,
|
__BACKWARDS_COMPAT__: false,
|
||||||
__STATIC_PATH__: "/static/",
|
__STATIC_PATH__: "/static/",
|
||||||
"process.env.NODE_ENV": JSON.stringify(
|
"process.env.NODE_ENV": JSON.stringify(
|
||||||
@@ -58,23 +58,12 @@ module.exports.babelOptions = ({ latestBuild }) => ({
|
|||||||
"@babel/preset-env",
|
"@babel/preset-env",
|
||||||
{
|
{
|
||||||
useBuiltIns: "entry",
|
useBuiltIns: "entry",
|
||||||
corejs: "3.15",
|
corejs: "3.6",
|
||||||
bugfixes: true,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"@babel/preset-typescript",
|
"@babel/preset-typescript",
|
||||||
].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",
|
||||||
@@ -83,19 +72,12 @@ module.exports.babelOptions = ({ latestBuild }) => ({
|
|||||||
// Only support the syntax, Webpack will handle it.
|
// Only support the syntax, Webpack will handle it.
|
||||||
"@babel/plugin-syntax-import-meta",
|
"@babel/plugin-syntax-import-meta",
|
||||||
"@babel/plugin-syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
"@babel/plugin-syntax-top-level-await",
|
|
||||||
"@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-decorators", { decoratorsBeforeExport: true }],
|
||||||
["@babel/plugin-proposal-private-methods", { loose: true }],
|
["@babel/plugin-proposal-private-methods", { loose: true }],
|
||||||
["@babel/plugin-proposal-private-property-in-object", { loose: true }],
|
|
||||||
["@babel/plugin-proposal-class-properties", { loose: true }],
|
["@babel/plugin-proposal-class-properties", { loose: true }],
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
exclude: [
|
|
||||||
// \\ for Windows, / for Mac OS and Linux
|
|
||||||
/node_modules[\\/]core-js/,
|
|
||||||
/node_modules[\\/]webpack[\\/]buildin/,
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const outputPath = (outputRoot, latestBuild) =>
|
const outputPath = (outputRoot, latestBuild) =>
|
||||||
@@ -165,7 +147,6 @@ module.exports.config = {
|
|||||||
cast({ isProdBuild, latestBuild }) {
|
cast({ isProdBuild, latestBuild }) {
|
||||||
const entry = {
|
const entry = {
|
||||||
launcher: path.resolve(paths.cast_dir, "src/launcher/entrypoint.ts"),
|
launcher: path.resolve(paths.cast_dir, "src/launcher/entrypoint.ts"),
|
||||||
media: path.resolve(paths.cast_dir, "src/media/entrypoint.ts"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (latestBuild) {
|
if (latestBuild) {
|
||||||
@@ -196,9 +177,6 @@ module.exports.config = {
|
|||||||
publicPath: publicPath(latestBuild, paths.hassio_publicPath),
|
publicPath: publicPath(latestBuild, paths.hassio_publicPath),
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
defineOverlay: {
|
|
||||||
__SUPERVISOR__: true,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -211,9 +189,6 @@ module.exports.config = {
|
|||||||
publicPath: publicPath(latestBuild),
|
publicPath: publicPath(latestBuild),
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
defineOverlay: {
|
|
||||||
__DEMO__: true,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -5,7 +5,6 @@ const env = require("../env");
|
|||||||
|
|
||||||
require("./clean.js");
|
require("./clean.js");
|
||||||
require("./translations.js");
|
require("./translations.js");
|
||||||
require("./locale-data.js");
|
|
||||||
require("./gen-icons-json.js");
|
require("./gen-icons-json.js");
|
||||||
require("./gather-static.js");
|
require("./gather-static.js");
|
||||||
require("./compress.js");
|
require("./compress.js");
|
||||||
@@ -27,8 +26,7 @@ gulp.task(
|
|||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"gen-pages-dev",
|
"gen-pages-dev",
|
||||||
"gen-index-app-dev",
|
"gen-index-app-dev",
|
||||||
"build-translations",
|
"build-translations"
|
||||||
"build-locale-data"
|
|
||||||
),
|
),
|
||||||
"copy-static-app",
|
"copy-static-app",
|
||||||
env.useWDS()
|
env.useWDS()
|
||||||
@@ -46,11 +44,11 @@ gulp.task(
|
|||||||
process.env.NODE_ENV = "production";
|
process.env.NODE_ENV = "production";
|
||||||
},
|
},
|
||||||
"clean",
|
"clean",
|
||||||
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
|
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",
|
||||||
|
@@ -18,7 +18,7 @@ gulp.task(
|
|||||||
},
|
},
|
||||||
"clean-cast",
|
"clean-cast",
|
||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-cast",
|
"copy-static-cast",
|
||||||
"gen-index-cast-dev",
|
"gen-index-cast-dev",
|
||||||
env.useRollup() ? "rollup-dev-server-cast" : "webpack-dev-server-cast"
|
env.useRollup() ? "rollup-dev-server-cast" : "webpack-dev-server-cast"
|
||||||
@@ -33,7 +33,7 @@ gulp.task(
|
|||||||
},
|
},
|
||||||
"clean-cast",
|
"clean-cast",
|
||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-cast",
|
"copy-static-cast",
|
||||||
env.useRollup() ? "rollup-prod-cast" : "webpack-prod-cast",
|
env.useRollup() ? "rollup-prod-cast" : "webpack-prod-cast",
|
||||||
"gen-index-cast-prod"
|
"gen-index-cast-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]);
|
||||||
)
|
})
|
||||||
);
|
);
|
||||||
|
@@ -20,12 +20,7 @@ gulp.task(
|
|||||||
},
|
},
|
||||||
"clean-demo",
|
"clean-demo",
|
||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel(
|
gulp.parallel("gen-icons-json", "gen-index-demo-dev", "build-translations"),
|
||||||
"gen-icons-json",
|
|
||||||
"gen-index-demo-dev",
|
|
||||||
"build-translations",
|
|
||||||
"build-locale-data"
|
|
||||||
),
|
|
||||||
"copy-static-demo",
|
"copy-static-demo",
|
||||||
env.useRollup() ? "rollup-dev-server-demo" : "webpack-dev-server-demo"
|
env.useRollup() ? "rollup-dev-server-demo" : "webpack-dev-server-demo"
|
||||||
)
|
)
|
||||||
@@ -40,7 +35,7 @@ gulp.task(
|
|||||||
"clean-demo",
|
"clean-demo",
|
||||||
// Cast needs to be backwards compatible and older HA has no translations
|
// Cast needs to be backwards compatible and older HA has no translations
|
||||||
"translations-enable-merge-backend",
|
"translations-enable-merge-backend",
|
||||||
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
|
gulp.parallel("gen-icons-json", "build-translations"),
|
||||||
"copy-static-demo",
|
"copy-static-demo",
|
||||||
env.useRollup() ? "rollup-prod-demo" : "webpack-prod-demo",
|
env.useRollup() ? "rollup-prod-demo" : "webpack-prod-demo",
|
||||||
"gen-index-demo-prod"
|
"gen-index-demo-prod"
|
||||||
|
@@ -154,15 +154,6 @@ gulp.task("gen-index-cast-dev", (done) => {
|
|||||||
contentReceiver
|
contentReceiver
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentMedia = renderCastTemplate("media", {
|
|
||||||
latestMediaJS: "/frontend_latest/media.js",
|
|
||||||
es5MediaJS: "/frontend_es5/media.js",
|
|
||||||
});
|
|
||||||
fs.outputFileSync(
|
|
||||||
path.resolve(paths.cast_output_root, "media.html"),
|
|
||||||
contentMedia
|
|
||||||
);
|
|
||||||
|
|
||||||
const contentFAQ = renderCastTemplate("launcher-faq", {
|
const contentFAQ = renderCastTemplate("launcher-faq", {
|
||||||
latestLauncherJS: "/frontend_latest/launcher.js",
|
latestLauncherJS: "/frontend_latest/launcher.js",
|
||||||
es5LauncherJS: "/frontend_es5/launcher.js",
|
es5LauncherJS: "/frontend_es5/launcher.js",
|
||||||
@@ -201,15 +192,6 @@ gulp.task("gen-index-cast-prod", (done) => {
|
|||||||
contentReceiver
|
contentReceiver
|
||||||
);
|
);
|
||||||
|
|
||||||
const contentMedia = renderCastTemplate("media", {
|
|
||||||
latestMediaJS: latestManifest["media.js"],
|
|
||||||
es5MediaJS: es5Manifest["media.js"],
|
|
||||||
});
|
|
||||||
fs.outputFileSync(
|
|
||||||
path.resolve(paths.cast_output_root, "media.html"),
|
|
||||||
contentMedia
|
|
||||||
);
|
|
||||||
|
|
||||||
const contentFAQ = renderCastTemplate("launcher-faq", {
|
const contentFAQ = renderCastTemplate("launcher-faq", {
|
||||||
latestLauncherJS: latestManifest["launcher.js"],
|
latestLauncherJS: latestManifest["launcher.js"],
|
||||||
es5LauncherJS: es5Manifest["launcher.js"],
|
es5LauncherJS: es5Manifest["launcher.js"],
|
||||||
@@ -320,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" }
|
||||||
|
@@ -51,7 +51,6 @@ gulp.task(
|
|||||||
gulp.parallel(
|
gulp.parallel(
|
||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"build-translations",
|
"build-translations",
|
||||||
"build-locale-data",
|
|
||||||
"gather-gallery-demos"
|
"gather-gallery-demos"
|
||||||
),
|
),
|
||||||
"copy-static-gallery",
|
"copy-static-gallery",
|
||||||
@@ -71,7 +70,6 @@ gulp.task(
|
|||||||
gulp.parallel(
|
gulp.parallel(
|
||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"build-translations",
|
"build-translations",
|
||||||
"build-locale-data",
|
|
||||||
"gather-gallery-demos"
|
"gather-gallery-demos"
|
||||||
),
|
),
|
||||||
"copy-static-gallery",
|
"copy-static-gallery",
|
||||||
|
@@ -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,28 +13,19 @@ 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);
|
||||||
|
|
||||||
// Translation output
|
// Translation output
|
||||||
fs.copySync(
|
fs.copySync(
|
||||||
polyPath("build/translations/output"),
|
polyPath("build-translations/output"),
|
||||||
staticPath("translations")
|
staticPath("translations")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyLocaleData(staticDir) {
|
|
||||||
const staticPath = genStaticPath(staticDir);
|
|
||||||
|
|
||||||
// Locale data output
|
|
||||||
fs.copySync(polyPath("build/locale-data"), staticPath("locale-data"));
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyMdiIcons(staticDir) {
|
function copyMdiIcons(staticDir) {
|
||||||
const staticPath = genStaticPath(staticDir);
|
const staticPath = genStaticPath(staticDir);
|
||||||
|
|
||||||
@@ -70,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"),
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,11 +80,6 @@ function copyMapPanel(staticDir) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task("copy-locale-data", async () => {
|
|
||||||
const staticDir = paths.app_output_static;
|
|
||||||
copyLocaleData(staticDir);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("copy-translations-app", async () => {
|
gulp.task("copy-translations-app", async () => {
|
||||||
const staticDir = paths.app_output_static;
|
const staticDir = paths.app_output_static;
|
||||||
copyTranslations(staticDir);
|
copyTranslations(staticDir);
|
||||||
@@ -106,11 +90,6 @@ gulp.task("copy-translations-supervisor", async () => {
|
|||||||
copyTranslations(staticDir);
|
copyTranslations(staticDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("copy-locale-data-supervisor", async () => {
|
|
||||||
const staticDir = paths.hassio_output_static;
|
|
||||||
copyLocaleData(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
|
||||||
@@ -120,7 +99,6 @@ gulp.task("copy-static-app", async () => {
|
|||||||
copyPolyfills(staticDir);
|
copyPolyfills(staticDir);
|
||||||
copyFonts(staticDir);
|
copyFonts(staticDir);
|
||||||
copyTranslations(staticDir);
|
copyTranslations(staticDir);
|
||||||
copyLocaleData(staticDir);
|
|
||||||
copyMdiIcons(staticDir);
|
copyMdiIcons(staticDir);
|
||||||
|
|
||||||
// Panel assets
|
// Panel assets
|
||||||
@@ -141,7 +119,6 @@ gulp.task("copy-static-demo", async () => {
|
|||||||
copyMapPanel(paths.demo_output_static);
|
copyMapPanel(paths.demo_output_static);
|
||||||
copyFonts(paths.demo_output_static);
|
copyFonts(paths.demo_output_static);
|
||||||
copyTranslations(paths.demo_output_static);
|
copyTranslations(paths.demo_output_static);
|
||||||
copyLocaleData(paths.demo_output_static);
|
|
||||||
copyMdiIcons(paths.demo_output_static);
|
copyMdiIcons(paths.demo_output_static);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -156,7 +133,6 @@ gulp.task("copy-static-cast", async () => {
|
|||||||
copyMapPanel(paths.cast_output_static);
|
copyMapPanel(paths.cast_output_static);
|
||||||
copyFonts(paths.cast_output_static);
|
copyFonts(paths.cast_output_static);
|
||||||
copyTranslations(paths.cast_output_static);
|
copyTranslations(paths.cast_output_static);
|
||||||
copyLocaleData(paths.cast_output_static);
|
|
||||||
copyMdiIcons(paths.cast_output_static);
|
copyMdiIcons(paths.cast_output_static);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -172,6 +148,5 @@ gulp.task("copy-static-gallery", async () => {
|
|||||||
copyMapPanel(paths.gallery_output_static);
|
copyMapPanel(paths.gallery_output_static);
|
||||||
copyFonts(paths.gallery_output_static);
|
copyFonts(paths.gallery_output_static);
|
||||||
copyTranslations(paths.gallery_output_static);
|
copyTranslations(paths.gallery_output_static);
|
||||||
copyLocaleData(paths.gallery_output_static);
|
|
||||||
copyMdiIcons(paths.gallery_output_static);
|
copyMdiIcons(paths.gallery_output_static);
|
||||||
});
|
});
|
||||||
|
@@ -22,40 +22,17 @@ const getMeta = () => {
|
|||||||
const svg = fs.readFileSync(`${ICON_PATH}/${icon.name}.svg`, {
|
const svg = fs.readFileSync(`${ICON_PATH}/${icon.name}.svg`, {
|
||||||
encoding,
|
encoding,
|
||||||
});
|
});
|
||||||
return {
|
return { path: svg.match(/ d="([^"]+)"/)[1], name: icon.name };
|
||||||
path: svg.match(/ d="([^"]+)"/)[1],
|
|
||||||
name: icon.name,
|
|
||||||
tags: icon.tags,
|
|
||||||
aliases: icon.aliases,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addRemovedMeta = (meta) => {
|
const addRemovedMeta = (meta) => {
|
||||||
const file = fs.readFileSync(REMOVED_ICONS_PATH, { encoding });
|
const file = fs.readFileSync(REMOVED_ICONS_PATH, { encoding });
|
||||||
const removed = JSON.parse(file);
|
const removed = JSON.parse(file);
|
||||||
const removedMeta = removed.map((removeIcon) => ({
|
const combinedMeta = [...meta, ...removed];
|
||||||
path: removeIcon.path,
|
|
||||||
name: removeIcon.name,
|
|
||||||
tags: [],
|
|
||||||
aliases: [],
|
|
||||||
}));
|
|
||||||
const combinedMeta = [...meta, ...removedMeta];
|
|
||||||
return combinedMeta.sort((a, b) => a.name.localeCompare(b.name));
|
return combinedMeta.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
};
|
};
|
||||||
|
|
||||||
const homeAutomationTag = "Home Automation";
|
|
||||||
|
|
||||||
const orderMeta = (meta) => {
|
|
||||||
const homeAutomationMeta = meta.filter((icon) =>
|
|
||||||
icon.tags.includes(homeAutomationTag)
|
|
||||||
);
|
|
||||||
const otherMeta = meta.filter(
|
|
||||||
(icon) => !icon.tags.includes(homeAutomationTag)
|
|
||||||
);
|
|
||||||
return [...homeAutomationMeta, ...otherMeta];
|
|
||||||
};
|
|
||||||
|
|
||||||
const splitBySize = (meta) => {
|
const splitBySize = (meta) => {
|
||||||
const chunks = [];
|
const chunks = [];
|
||||||
const CHUNK_SIZE = 50000;
|
const CHUNK_SIZE = 50000;
|
||||||
@@ -100,10 +77,8 @@ const findDifferentiator = (curString, prevString) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
gulp.task("gen-icons-json", (done) => {
|
gulp.task("gen-icons-json", (done) => {
|
||||||
const meta = getMeta();
|
const meta = addRemovedMeta(getMeta());
|
||||||
|
const split = splitBySize(meta);
|
||||||
const metaAndRemoved = addRemovedMeta(meta);
|
|
||||||
const split = splitBySize(metaAndRemoved);
|
|
||||||
|
|
||||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||||
@@ -141,18 +116,5 @@ gulp.task("gen-icons-json", (done) => {
|
|||||||
JSON.stringify({ version: package.version, parts })
|
JSON.stringify({ version: package.version, parts })
|
||||||
);
|
);
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.resolve(OUTPUT_DIR, "iconList.json"),
|
|
||||||
JSON.stringify(
|
|
||||||
orderMeta(meta).map((icon) => ({
|
|
||||||
name: icon.name,
|
|
||||||
keywords: [
|
|
||||||
...icon.tags.map((t) => t.toLowerCase().replace(/\s\/\s/g, " ")),
|
|
||||||
...icon.aliases,
|
|
||||||
],
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
const env = require("../env");
|
const env = require("../env");
|
||||||
|
const paths = require("../paths");
|
||||||
|
|
||||||
require("./clean.js");
|
require("./clean.js");
|
||||||
require("./gen-icons-json.js");
|
require("./gen-icons-json.js");
|
||||||
@@ -17,11 +20,10 @@ gulp.task(
|
|||||||
process.env.NODE_ENV = "development";
|
process.env.NODE_ENV = "development";
|
||||||
},
|
},
|
||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
|
"gen-icons-json",
|
||||||
"gen-index-hassio-dev",
|
"gen-index-hassio-dev",
|
||||||
"build-supervisor-translations",
|
"build-supervisor-translations",
|
||||||
"copy-translations-supervisor",
|
"copy-translations-supervisor",
|
||||||
"build-locale-data",
|
|
||||||
"copy-locale-data-supervisor",
|
|
||||||
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -33,10 +35,9 @@ gulp.task(
|
|||||||
process.env.NODE_ENV = "production";
|
process.env.NODE_ENV = "production";
|
||||||
},
|
},
|
||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
|
"gen-icons-json",
|
||||||
"build-supervisor-translations",
|
"build-supervisor-translations",
|
||||||
"copy-translations-supervisor",
|
"copy-translations-supervisor",
|
||||||
"build-locale-data",
|
|
||||||
"copy-locale-data-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,74 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
|
|
||||||
const del = require("del");
|
|
||||||
const path = require("path");
|
|
||||||
const gulp = require("gulp");
|
|
||||||
const fs = require("fs");
|
|
||||||
const paths = require("../paths");
|
|
||||||
|
|
||||||
const outDir = "build/locale-data";
|
|
||||||
|
|
||||||
gulp.task("clean-locale-data", () => del([outDir]));
|
|
||||||
|
|
||||||
gulp.task("ensure-locale-data-build-dir", (done) => {
|
|
||||||
if (!fs.existsSync(outDir)) {
|
|
||||||
fs.mkdirSync(outDir, { recursive: true });
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
const modules = {
|
|
||||||
"intl-relativetimeformat": "RelativeTimeFormat",
|
|
||||||
"intl-datetimeformat": "DateTimeFormat",
|
|
||||||
"intl-numberformat": "NumberFormat",
|
|
||||||
};
|
|
||||||
|
|
||||||
gulp.task("create-locale-data", (done) => {
|
|
||||||
const translationMeta = JSON.parse(
|
|
||||||
fs.readFileSync(
|
|
||||||
path.join(paths.translations_src, "translationMetadata.json")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
Object.entries(modules).forEach(([module, className]) => {
|
|
||||||
Object.keys(translationMeta).forEach((lang) => {
|
|
||||||
try {
|
|
||||||
const localeData = String(
|
|
||||||
fs.readFileSync(
|
|
||||||
require.resolve(`@formatjs/${module}/locale-data/${lang}.js`)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.replace(
|
|
||||||
new RegExp(
|
|
||||||
`\\/\\*\\s*@generated\\s*\\*\\/\\s*\\/\\/\\s*prettier-ignore\\s*if\\s*\\(Intl\\.${className}\\s*&&\\s*typeof\\s*Intl\\.${className}\\.__addLocaleData\\s*===\\s*'function'\\)\\s*{\\s*Intl\\.${className}\\.__addLocaleData\\(`,
|
|
||||||
"im"
|
|
||||||
),
|
|
||||||
""
|
|
||||||
)
|
|
||||||
.replace(/\)\s*}/im, "");
|
|
||||||
// make sure we have valid JSON
|
|
||||||
JSON.parse(localeData);
|
|
||||||
if (!fs.existsSync(path.join(outDir, module))) {
|
|
||||||
fs.mkdirSync(path.join(outDir, module), { recursive: true });
|
|
||||||
}
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(outDir, `${module}/${lang}.json`),
|
|
||||||
localeData
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code !== "MODULE_NOT_FOUND") {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(
|
|
||||||
"build-locale-data",
|
|
||||||
gulp.series(
|
|
||||||
"clean-locale-data",
|
|
||||||
"ensure-locale-data-build-dir",
|
|
||||||
"create-locale-data"
|
|
||||||
)
|
|
||||||
);
|
|
@@ -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");
|
||||||
@@ -17,7 +15,7 @@ const paths = require("../paths");
|
|||||||
|
|
||||||
const inFrontendDir = "translations/frontend";
|
const inFrontendDir = "translations/frontend";
|
||||||
const inBackendDir = "translations/backend";
|
const inBackendDir = "translations/backend";
|
||||||
const workDir = "build/translations";
|
const workDir = "build-translations";
|
||||||
const fullDir = workDir + "/full";
|
const fullDir = workDir + "/full";
|
||||||
const coreDir = workDir + "/core";
|
const coreDir = workDir + "/core";
|
||||||
const outDir = workDir + "/output";
|
const outDir = workDir + "/output";
|
||||||
@@ -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,16 +118,18 @@ 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)) {
|
||||||
fs.mkdirSync(workDir, { recursive: true });
|
fs.mkdirSync(workDir);
|
||||||
}
|
}
|
||||||
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,18 +251,18 @@ 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];
|
||||||
});
|
});
|
||||||
@@ -255,14 +270,14 @@ gulp.task(taskName, () =>
|
|||||||
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 +285,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,43 +335,35 @@ 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");
|
gulp.task("build-translation-fragment-supervisor", function () {
|
||||||
stream.write(JSON.stringify(fingerprints));
|
return gulp
|
||||||
process.nextTick(() => stream.end());
|
|
||||||
return stream.pipe(vinylBuffer()).pipe(gulp.dest(workDir));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("build-translation-fragment-supervisor", () =>
|
|
||||||
gulp
|
|
||||||
.src(fullDir + "/*.json")
|
.src(fullDir + "/*.json")
|
||||||
.pipe(transform((data) => data.supervisor))
|
.pipe(transform((data) => data.supervisor))
|
||||||
.pipe(
|
.pipe(gulp.dest(workDir + "/supervisor"));
|
||||||
rename((filePath) => {
|
});
|
||||||
// In dev we create the file with the fake hash in the filename
|
|
||||||
if (!env.isProdBuild()) {
|
|
||||||
filePath.basename += "-dev";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(gulp.dest(workDir + "/supervisor"))
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task("build-translation-flatten-supervisor", () =>
|
gulp.task("build-translation-flatten-supervisor", function () {
|
||||||
gulp
|
return gulp
|
||||||
.src(workDir + "/supervisor/*.json")
|
.src(workDir + "/supervisor/*.json")
|
||||||
.pipe(
|
.pipe(
|
||||||
transform((data) =>
|
transform(function (data) {
|
||||||
// Polymer.AppLocalizeBehavior requires flattened json
|
// Polymer.AppLocalizeBehavior requires flattened json
|
||||||
flatten(data)
|
return flatten(data);
|
||||||
)
|
})
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(outDir))
|
.pipe(gulp.dest(outDir));
|
||||||
);
|
});
|
||||||
|
|
||||||
gulp.task("build-translation-write-metadata", () =>
|
gulp.task("build-translation-write-metadata", function writeMetadata() {
|
||||||
gulp
|
return gulp
|
||||||
.src(
|
.src(
|
||||||
[
|
[
|
||||||
path.join(paths.translations_src, "translationMetadata.json"),
|
path.join(paths.translations_src, "translationMetadata.json"),
|
||||||
@@ -371,14 +374,13 @@ gulp.task("build-translation-write-metadata", () =>
|
|||||||
)
|
)
|
||||||
.pipe(merge({}))
|
.pipe(merge({}))
|
||||||
.pipe(
|
.pipe(
|
||||||
transform((data) => {
|
transform(function (data) {
|
||||||
const newData = {};
|
const newData = {};
|
||||||
Object.entries(data).forEach(([key, value]) => {
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
// Filter out translations without native name.
|
// Filter out translations without native name.
|
||||||
if (value.nativeName) {
|
if (value.nativeName) {
|
||||||
newData[key] = value;
|
newData[key] = value;
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.warn(
|
console.warn(
|
||||||
`Skipping language ${key}. Native name was not translated.`
|
`Skipping language ${key}. Native name was not translated.`
|
||||||
);
|
);
|
||||||
@@ -394,26 +396,19 @@ gulp.task("build-translation-write-metadata", () =>
|
|||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
.pipe(rename("translationMetadata.json"))
|
.pipe(rename("translationMetadata.json"))
|
||||||
.pipe(gulp.dest(workDir))
|
.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(
|
||||||
"build-translations",
|
"build-translations",
|
||||||
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-master-translation",
|
||||||
|
"build-merged-translations",
|
||||||
|
gulp.parallel(...splitTasks),
|
||||||
|
"build-flattened-translations",
|
||||||
"build-translation-fingerprints",
|
"build-translation-fingerprints",
|
||||||
"build-translation-write-metadata"
|
"build-translation-write-metadata"
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
// Tasks to run webpack.
|
// Tasks to run webpack.
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
@@ -20,12 +19,10 @@ const bothBuilds = (createConfigFunc, params) => [
|
|||||||
createConfigFunc({ ...params, latestBuild: false }),
|
createConfigFunc({ ...params, latestBuild: false }),
|
||||||
];
|
];
|
||||||
|
|
||||||
const isWsl =
|
const isWsl = fs
|
||||||
fs.existsSync("/proc/version") &&
|
.readFileSync("/proc/version", "utf-8")
|
||||||
fs
|
.toLocaleLowerCase()
|
||||||
.readFileSync("/proc/version", "utf-8")
|
.includes("microsoft");
|
||||||
.toLocaleLowerCase()
|
|
||||||
.includes("microsoft");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {{
|
* @param {{
|
||||||
@@ -35,29 +32,26 @@ const isWsl =
|
|||||||
* listenHost?: string
|
* listenHost?: string
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
const runDevServer = async ({
|
const runDevServer = ({
|
||||||
compiler,
|
compiler,
|
||||||
contentBase,
|
contentBase,
|
||||||
port,
|
port,
|
||||||
listenHost = "localhost",
|
listenHost = "localhost",
|
||||||
}) => {
|
}) =>
|
||||||
const server = new WebpackDevServer(
|
new WebpackDevServer(compiler, {
|
||||||
{
|
open: true,
|
||||||
open: true,
|
watchContentBase: true,
|
||||||
host: listenHost,
|
contentBase,
|
||||||
port,
|
}).listen(port, listenHost, function (err) {
|
||||||
static: {
|
if (err) {
|
||||||
directory: contentBase,
|
throw err;
|
||||||
watch: true,
|
}
|
||||||
},
|
// Server listening
|
||||||
},
|
log(
|
||||||
compiler
|
"[webpack-dev-server]",
|
||||||
);
|
`Project is running at http://localhost:${port}`
|
||||||
|
);
|
||||||
await server.start();
|
});
|
||||||
// Server listening
|
|
||||||
log("[webpack-dev-server]", `Project is running at http://localhost:${port}`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const doneHandler = (done) => (err, stats) => {
|
const doneHandler = (done) => (err, stats) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -69,7 +63,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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,14 +84,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/, poll: isWsl },
|
||||||
? 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")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -110,13 +102,13 @@ gulp.task("webpack-prod-app", () =>
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("webpack-dev-server-demo", () =>
|
gulp.task("webpack-dev-server-demo", () => {
|
||||||
runDevServer({
|
runDevServer({
|
||||||
compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })),
|
compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })),
|
||||||
contentBase: paths.demo_output_root,
|
contentBase: paths.demo_output_root,
|
||||||
port: 8090,
|
port: 8090,
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-demo", () =>
|
gulp.task("webpack-prod-demo", () =>
|
||||||
prodBuild(
|
prodBuild(
|
||||||
@@ -126,15 +118,15 @@ gulp.task("webpack-prod-demo", () =>
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("webpack-dev-server-cast", () =>
|
gulp.task("webpack-dev-server-cast", () => {
|
||||||
runDevServer({
|
runDevServer({
|
||||||
compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })),
|
compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })),
|
||||||
contentBase: paths.cast_output_root,
|
contentBase: paths.cast_output_root,
|
||||||
port: 8080,
|
port: 8080,
|
||||||
// Accessible from the network, because that's how Cast hits it.
|
// Accessible from the network, because that's how Cast hits it.
|
||||||
listenHost: "0.0.0.0",
|
listenHost: "0.0.0.0",
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-cast", () =>
|
gulp.task("webpack-prod-cast", () =>
|
||||||
prodBuild(
|
prodBuild(
|
||||||
@@ -151,7 +143,7 @@ gulp.task("webpack-watch-hassio", () => {
|
|||||||
isProdBuild: false,
|
isProdBuild: false,
|
||||||
latestBuild: true,
|
latestBuild: true,
|
||||||
})
|
})
|
||||||
).watch({ ignored: /build/, poll: isWsl }, doneHandler());
|
).watch({ ignored: /build-translations/, poll: isWsl }, doneHandler());
|
||||||
|
|
||||||
gulp.watch(
|
gulp.watch(
|
||||||
path.join(paths.translations_src, "en.json"),
|
path.join(paths.translations_src, "en.json"),
|
||||||
@@ -167,15 +159,14 @@ gulp.task("webpack-prod-hassio", () =>
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("webpack-dev-server-gallery", () =>
|
gulp.task("webpack-dev-server-gallery", () => {
|
||||||
runDevServer({
|
runDevServer({
|
||||||
// We don't use the es5 build, but the dev server will fuck up the publicPath if we don't
|
// We don't use the es5 build, but the dev server will fuck up the publicPath if we don't
|
||||||
compiler: webpack(bothBuilds(createGalleryConfig, { isProdBuild: false })),
|
compiler: webpack(bothBuilds(createGalleryConfig, { isProdBuild: false })),
|
||||||
contentBase: paths.gallery_output_root,
|
contentBase: paths.gallery_output_root,
|
||||||
port: 8100,
|
port: 8100,
|
||||||
listenHost: "0.0.0.0",
|
});
|
||||||
})
|
});
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task("webpack-prod-gallery", () =>
|
gulp.task("webpack-prod-gallery", () =>
|
||||||
prodBuild(
|
prodBuild(
|
||||||
|
@@ -6,7 +6,6 @@ const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
|
|||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
const bundle = require("./bundle.js");
|
const bundle = require("./bundle.js");
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
const WebpackBar = require("webpackbar");
|
|
||||||
|
|
||||||
class LogStartCompilePlugin {
|
class LogStartCompilePlugin {
|
||||||
ignoredFirst = false;
|
ignoredFirst = false;
|
||||||
@@ -50,16 +49,12 @@ const createWebpackConfig = ({
|
|||||||
test: /\.m?js$|\.ts$/,
|
test: /\.m?js$|\.ts$/,
|
||||||
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",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -71,11 +66,8 @@ const createWebpackConfig = ({
|
|||||||
terserOptions: bundle.terserOptions(latestBuild),
|
terserOptions: bundle.terserOptions(latestBuild),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
moduleIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
|
||||||
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new WebpackBar({ fancy: !isProdBuild }),
|
|
||||||
new WebpackManifestPlugin({
|
new WebpackManifestPlugin({
|
||||||
// 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"),
|
||||||
@@ -120,6 +112,16 @@ 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(
|
||||||
|
path.resolve(
|
||||||
|
paths.polymer_dir,
|
||||||
|
"src/resources/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: {
|
||||||
@@ -127,33 +129,25 @@ const createWebpackConfig = ({
|
|||||||
alias: {
|
alias: {
|
||||||
"lit/decorators$": "lit/decorators.js",
|
"lit/decorators$": "lit/decorators.js",
|
||||||
"lit/directive$": "lit/directive.js",
|
"lit/directive$": "lit/directive.js",
|
||||||
"lit/directives/until$": "lit/directives/until.js",
|
|
||||||
"lit/directives/class-map$": "lit/directives/class-map.js",
|
|
||||||
"lit/directives/style-map$": "lit/directives/style-map.js",
|
|
||||||
"lit/directives/if-defined$": "lit/directives/if-defined.js",
|
|
||||||
"lit/directives/guard$": "lit/directives/guard.js",
|
|
||||||
"lit/directives/cache$": "lit/directives/cache.js",
|
|
||||||
"lit/directives/repeat$": "lit/directives/repeat.js",
|
|
||||||
"lit/polyfill-support$": "lit/polyfill-support.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
|
||||||
globalObject: "self",
|
globalObject: "self",
|
||||||
},
|
},
|
||||||
experiments: {
|
|
||||||
topLevelAwait: true,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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,46 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
--logo-image: url('https://www.home-assistant.io/images/home-assistant-logo.svg');
|
|
||||||
--logo-repeat: no-repeat;
|
|
||||||
--playback-logo-image: url('https://www.home-assistant.io/images/home-assistant-logo.svg');
|
|
||||||
--theme-hue: 200;
|
|
||||||
--progress-color: #03a9f4;
|
|
||||||
--splash-image: url('https://home-assistant.io/images/cast/splash.png');
|
|
||||||
--splash-size: cover;
|
|
||||||
--background-color: #41bdf5;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script>
|
|
||||||
var _gaq=[['_setAccount','UA-57927901-10'],['_trackPageview']];
|
|
||||||
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
|
||||||
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
|
|
||||||
s.parentNode.insertBefore(g,s)}(document,'script'));
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<%= renderTemplate('_js_base') %>
|
|
||||||
|
|
||||||
<cast-media-player></cast-media-player>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import("<%= latestMediaJS %>");
|
|
||||||
window.latestJS = true;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
if (!window.latestJS) {
|
|
||||||
<% if (useRollup) { %>
|
|
||||||
_ls("/static/js/s.min.js").onload = function() {
|
|
||||||
System.import("<%= es5MediaJS %>");
|
|
||||||
};
|
|
||||||
<% } else { %>
|
|
||||||
_ls("<%= es5MediaJS %>");
|
|
||||||
<% } %>
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1,5 +1,4 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
import { mdiCast, mdiCastConnected } from "@mdi/js";
|
|
||||||
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";
|
||||||
@@ -18,7 +17,6 @@ import {
|
|||||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||||
import { toggleAttribute } from "../../../../src/common/dom/toggle_attribute";
|
import { toggleAttribute } from "../../../../src/common/dom/toggle_attribute";
|
||||||
import "../../../../src/components/ha-icon";
|
import "../../../../src/components/ha-icon";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
|
||||||
import {
|
import {
|
||||||
getLegacyLovelaceCollection,
|
getLegacyLovelaceCollection,
|
||||||
getLovelaceCollection,
|
getLovelaceCollection,
|
||||||
@@ -75,7 +73,7 @@ class HcCast extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<p class="center-item">
|
<p class="center-item">
|
||||||
<mwc-button raised @click=${this._handleLaunch}>
|
<mwc-button raised @click=${this._handleLaunch}>
|
||||||
<ha-svg-icon .path=${mdiCast}></ha-svg-icon>
|
<ha-icon icon="hass:cast"></ha-icon>
|
||||||
Start Casting
|
Start Casting
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</p>
|
</p>
|
||||||
@@ -113,7 +111,7 @@ class HcCast extends LitElement {
|
|||||||
${this.castManager.status
|
${this.castManager.status
|
||||||
? html`
|
? html`
|
||||||
<mwc-button @click=${this._handleLaunch}>
|
<mwc-button @click=${this._handleLaunch}>
|
||||||
<ha-svg-icon .path=${mdiCastConnected}></ha-svg-icon>
|
<ha-icon icon="hass:cast-connected"></ha-icon>
|
||||||
Manage
|
Manage
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
`
|
`
|
||||||
@@ -193,7 +191,7 @@ class HcCast extends LitElement {
|
|||||||
}
|
}
|
||||||
this.connection.close();
|
this.connection.close();
|
||||||
location.reload();
|
location.reload();
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
alert("Unable to log out!");
|
alert("Unable to log out!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,7 +233,7 @@ class HcCast extends LitElement {
|
|||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
mwc-button ha-svg-icon {
|
mwc-button ha-icon {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { mdiCastConnected, mdiCast } from "@mdi/js";
|
|
||||||
import "@polymer/paper-input/paper-input";
|
import "@polymer/paper-input/paper-input";
|
||||||
import {
|
import {
|
||||||
Auth,
|
Auth,
|
||||||
@@ -20,7 +19,7 @@ import {
|
|||||||
loadTokens,
|
loadTokens,
|
||||||
saveTokens,
|
saveTokens,
|
||||||
} from "../../../../src/common/auth/token_storage";
|
} from "../../../../src/common/auth/token_storage";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
import "../../../../src/components/ha-icon";
|
||||||
import "../../../../src/layouts/hass-loading-screen";
|
import "../../../../src/layouts/hass-loading-screen";
|
||||||
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
||||||
import "./hc-layout";
|
import "./hc-layout";
|
||||||
@@ -128,11 +127,11 @@ export class HcConnect extends LitElement {
|
|||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button @click=${this._handleDemo}>
|
<mwc-button @click=${this._handleDemo}>
|
||||||
Show Demo
|
Show Demo
|
||||||
<ha-svg-icon
|
<ha-icon
|
||||||
.path=${this.castManager.castState === "CONNECTED"
|
.icon=${this.castManager.castState === "CONNECTED"
|
||||||
? mdiCastConnected
|
? "hass:cast-connected"
|
||||||
: mdiCast}
|
: "hass:cast"}
|
||||||
></ha-svg-icon>
|
></ha-icon>
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<mwc-button @click=${this._handleConnect}>Authorize</mwc-button>
|
<mwc-button @click=${this._handleConnect}>Authorize</mwc-button>
|
||||||
@@ -213,7 +212,7 @@ export class HcConnect extends LitElement {
|
|||||||
let url: URL;
|
let url: URL;
|
||||||
try {
|
try {
|
||||||
url = new URL(value);
|
url = new URL(value);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this.error = "Invalid URL";
|
this.error = "Invalid URL";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -241,7 +240,7 @@ export class HcConnect extends LitElement {
|
|||||||
try {
|
try {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
auth = await getAuth(options);
|
auth = await getAuth(options);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
if (init === "saved-tokens" && err === ERR_CANNOT_CONNECT) {
|
if (init === "saved-tokens" && err === ERR_CANNOT_CONNECT) {
|
||||||
this.cannotConnect = true;
|
this.cannotConnect = true;
|
||||||
return;
|
return;
|
||||||
@@ -260,7 +259,7 @@ export class HcConnect extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
conn = await createConnection({ auth });
|
conn = await createConnection({ auth });
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
// In case of saved tokens, silently solve problems.
|
// In case of saved tokens, silently solve problems.
|
||||||
if (init === "saved-tokens") {
|
if (init === "saved-tokens") {
|
||||||
if (err === ERR_CANNOT_CONNECT) {
|
if (err === ERR_CANNOT_CONNECT) {
|
||||||
@@ -286,7 +285,7 @@ export class HcConnect extends LitElement {
|
|||||||
try {
|
try {
|
||||||
saveTokens(null);
|
saveTokens(null);
|
||||||
location.reload();
|
location.reload();
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
alert("Unable to log out!");
|
alert("Unable to log out!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,7 +307,7 @@ export class HcConnect extends LitElement {
|
|||||||
color: darkred;
|
color: darkred;
|
||||||
}
|
}
|
||||||
|
|
||||||
mwc-button ha-svg-icon {
|
mwc-button ha-icon {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
const castContext = cast.framework.CastReceiverContext.getInstance();
|
|
||||||
|
|
||||||
const playerManager = castContext.getPlayerManager();
|
|
||||||
|
|
||||||
playerManager.setMessageInterceptor(
|
|
||||||
cast.framework.messages.MessageType.LOAD,
|
|
||||||
(loadRequestData) => {
|
|
||||||
const media = loadRequestData.media;
|
|
||||||
// Special handling if it came from Google Assistant
|
|
||||||
if (media.entity) {
|
|
||||||
media.contentId = media.entity;
|
|
||||||
media.streamType = cast.framework.messages.StreamType.LIVE;
|
|
||||||
media.contentType = "application/vnd.apple.mpegurl";
|
|
||||||
// @ts-ignore
|
|
||||||
media.hlsVideoSegmentFormat =
|
|
||||||
cast.framework.messages.HlsVideoSegmentFormat.FMP4;
|
|
||||||
}
|
|
||||||
return loadRequestData;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
castContext.start();
|
|
@@ -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: [
|
||||||
{
|
{
|
||||||
|
@@ -8,9 +8,6 @@ import { ReceivedMessage } from "./types";
|
|||||||
|
|
||||||
const lovelaceController = new HcMain();
|
const lovelaceController = new HcMain();
|
||||||
document.body.append(lovelaceController);
|
document.body.append(lovelaceController);
|
||||||
lovelaceController.addEventListener("cast-view-changed", (ev) => {
|
|
||||||
playDummyMedia(ev.detail.title);
|
|
||||||
});
|
|
||||||
|
|
||||||
const mediaPlayer = document.createElement("cast-media-player");
|
const mediaPlayer = document.createElement("cast-media-player");
|
||||||
mediaPlayer.style.display = "none";
|
mediaPlayer.style.display = "none";
|
||||||
@@ -31,31 +28,6 @@ const setTouchControlsVisibility = (visible: boolean) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let timeOut: number | undefined;
|
|
||||||
|
|
||||||
const playDummyMedia = (viewTitle?: string) => {
|
|
||||||
const loadRequestData = new cast.framework.messages.LoadRequestData();
|
|
||||||
loadRequestData.autoplay = true;
|
|
||||||
loadRequestData.media = new cast.framework.messages.MediaInformation();
|
|
||||||
loadRequestData.media.contentId =
|
|
||||||
"https://cast.home-assistant.io/images/google-nest-hub.png";
|
|
||||||
loadRequestData.media.contentType = "image/jpeg";
|
|
||||||
loadRequestData.media.streamType = cast.framework.messages.StreamType.NONE;
|
|
||||||
const metadata = new cast.framework.messages.GenericMediaMetadata();
|
|
||||||
metadata.title = viewTitle;
|
|
||||||
loadRequestData.media.metadata = metadata;
|
|
||||||
|
|
||||||
loadRequestData.requestId = 0;
|
|
||||||
playerManager.load(loadRequestData);
|
|
||||||
if (timeOut) {
|
|
||||||
clearTimeout(timeOut);
|
|
||||||
timeOut = undefined;
|
|
||||||
}
|
|
||||||
if (castContext.getDeviceCapabilities().touch_input_supported) {
|
|
||||||
timeOut = window.setTimeout(() => playDummyMedia(viewTitle), 540000); // repeat every 9 minutes to keep it active (gets deactivated after 10 minutes)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const showLovelaceController = () => {
|
const showLovelaceController = () => {
|
||||||
mediaPlayer.style.display = "none";
|
mediaPlayer.style.display = "none";
|
||||||
lovelaceController.style.display = "initial";
|
lovelaceController.style.display = "initial";
|
||||||
@@ -79,7 +51,6 @@ const showMediaPlayer = () => {
|
|||||||
--progress-color: #03a9f4;
|
--progress-color: #03a9f4;
|
||||||
--splash-image: url('https://home-assistant.io/images/cast/splash.png');
|
--splash-image: url('https://home-assistant.io/images/cast/splash.png');
|
||||||
--splash-size: cover;
|
--splash-size: cover;
|
||||||
--background-color: #41bdf5;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
@@ -92,6 +63,22 @@ options.customNamespaces = {
|
|||||||
[CAST_NS]: cast.framework.system.MessageType.JSON,
|
[CAST_NS]: cast.framework.system.MessageType.JSON,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The docs say we need to set options.touchScreenOptimizeApp = true
|
||||||
|
// https://developers.google.com/cast/docs/caf_receiver/customize_ui#accessing_ui_controls
|
||||||
|
// This doesn't work.
|
||||||
|
// @ts-ignore
|
||||||
|
options.touchScreenOptimizedApp = true;
|
||||||
|
|
||||||
|
// The class reference say we can set a uiConfig in options to set it
|
||||||
|
// https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverOptions#uiConfig
|
||||||
|
// This doesn't work either.
|
||||||
|
// @ts-ignore
|
||||||
|
options.uiConfig = new cast.framework.ui.UiConfig();
|
||||||
|
// @ts-ignore
|
||||||
|
options.uiConfig.touchScreenOptimizedApp = true;
|
||||||
|
|
||||||
|
castContext.setInactivityTimeout(86400); // 1 day
|
||||||
|
|
||||||
castContext.addCustomMessageListener(
|
castContext.addCustomMessageListener(
|
||||||
CAST_NS,
|
CAST_NS,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -116,12 +103,6 @@ const playerManager = castContext.getPlayerManager();
|
|||||||
playerManager.setMessageInterceptor(
|
playerManager.setMessageInterceptor(
|
||||||
cast.framework.messages.MessageType.LOAD,
|
cast.framework.messages.MessageType.LOAD,
|
||||||
(loadRequestData) => {
|
(loadRequestData) => {
|
||||||
if (
|
|
||||||
loadRequestData.media.contentId ===
|
|
||||||
"https://cast.home-assistant.io/images/google-nest-hub.png"
|
|
||||||
) {
|
|
||||||
return loadRequestData;
|
|
||||||
}
|
|
||||||
// We received a play media command, hide Lovelace and show media player
|
// We received a play media command, hide Lovelace and show media player
|
||||||
showMediaPlayer();
|
showMediaPlayer();
|
||||||
const media = loadRequestData.media;
|
const media = loadRequestData.media;
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|
||||||
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";
|
||||||
@@ -15,7 +14,7 @@ class HcLovelace extends LitElement {
|
|||||||
|
|
||||||
@property() public viewPath?: string | number;
|
@property() public viewPath?: string | number;
|
||||||
|
|
||||||
@property() public urlPath: string | null = null;
|
public urlPath?: string | null;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const index = this._viewIndex;
|
const index = this._viewIndex;
|
||||||
@@ -31,7 +30,7 @@ class HcLovelace extends LitElement {
|
|||||||
config: this.lovelaceConfig,
|
config: this.lovelaceConfig,
|
||||||
rawConfig: 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,
|
locale: this.hass.locale,
|
||||||
@@ -55,21 +54,6 @@ class HcLovelace extends LitElement {
|
|||||||
const index = this._viewIndex;
|
const index = this._viewIndex;
|
||||||
|
|
||||||
if (index !== undefined) {
|
if (index !== undefined) {
|
||||||
const dashboardTitle = this.lovelaceConfig.title || this.urlPath;
|
|
||||||
|
|
||||||
const viewTitle =
|
|
||||||
this.lovelaceConfig.views[index].title ||
|
|
||||||
this.lovelaceConfig.views[index].path;
|
|
||||||
|
|
||||||
fireEvent(this, "cast-view-changed", {
|
|
||||||
title:
|
|
||||||
dashboardTitle || viewTitle
|
|
||||||
? `${dashboardTitle || ""}${
|
|
||||||
dashboardTitle && viewTitle ? ": " : ""
|
|
||||||
}${viewTitle || ""}`
|
|
||||||
: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
const configBackground =
|
const configBackground =
|
||||||
this.lovelaceConfig.views[index].background ||
|
this.lovelaceConfig.views[index].background ||
|
||||||
this.lovelaceConfig.background;
|
this.lovelaceConfig.background;
|
||||||
@@ -117,15 +101,8 @@ class HcLovelace extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CastViewChanged {
|
|
||||||
title: string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hc-lovelace": HcLovelace;
|
"hc-lovelace": HcLovelace;
|
||||||
}
|
}
|
||||||
interface HASSDomEvents {
|
|
||||||
"cast-view-changed": CastViewChanged;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -13,11 +13,7 @@ import {
|
|||||||
ShowDemoMessage,
|
ShowDemoMessage,
|
||||||
ShowLovelaceViewMessage,
|
ShowLovelaceViewMessage,
|
||||||
} from "../../../../src/cast/receiver_messages";
|
} from "../../../../src/cast/receiver_messages";
|
||||||
import {
|
import { ReceiverStatusMessage } from "../../../../src/cast/sender_messages";
|
||||||
ReceiverErrorCode,
|
|
||||||
ReceiverErrorMessage,
|
|
||||||
ReceiverStatusMessage,
|
|
||||||
} from "../../../../src/cast/sender_messages";
|
|
||||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||||
import { isNavigationClick } from "../../../../src/common/dom/is-navigation-click";
|
import { isNavigationClick } from "../../../../src/common/dom/is-navigation-click";
|
||||||
import {
|
import {
|
||||||
@@ -44,10 +40,10 @@ export class HcMain extends HassElement {
|
|||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
@state() private _urlPath?: string | null;
|
|
||||||
|
|
||||||
private _unsubLovelace?: UnsubscribeFunc;
|
private _unsubLovelace?: UnsubscribeFunc;
|
||||||
|
|
||||||
|
private _urlPath?: string | null;
|
||||||
|
|
||||||
public processIncomingMessage(msg: HassMessage) {
|
public processIncomingMessage(msg: HassMessage) {
|
||||||
if (msg.type === "connect") {
|
if (msg.type === "connect") {
|
||||||
this._handleConnectMessage(msg);
|
this._handleConnectMessage(msg);
|
||||||
@@ -72,10 +68,8 @@ export class HcMain extends HassElement {
|
|||||||
!this._lovelaceConfig ||
|
!this._lovelaceConfig ||
|
||||||
this._lovelacePath === null ||
|
this._lovelacePath === null ||
|
||||||
// Guard against part of HA not being loaded yet.
|
// Guard against part of HA not being loaded yet.
|
||||||
!this.hass ||
|
(this.hass &&
|
||||||
!this.hass.states ||
|
(!this.hass.states || !this.hass.config || !this.hass.services))
|
||||||
!this.hass.config ||
|
|
||||||
!this.hass.services
|
|
||||||
) {
|
) {
|
||||||
return html`
|
return html`
|
||||||
<hc-launch-screen
|
<hc-launch-screen
|
||||||
@@ -113,7 +107,6 @@ export class HcMain extends HassElement {
|
|||||||
this._sendStatus();
|
this._sendStatus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.addEventListener("dialog-closed", this._dialogClosed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _sendStatus(senderId?: string) {
|
private _sendStatus(senderId?: string) {
|
||||||
@@ -125,7 +118,7 @@ export class HcMain extends HassElement {
|
|||||||
|
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
status.hassUrl = this.hass.auth.data.hassUrl;
|
status.hassUrl = this.hass.auth.data.hassUrl;
|
||||||
status.lovelacePath = this._lovelacePath;
|
status.lovelacePath = this._lovelacePath!;
|
||||||
status.urlPath = this._urlPath;
|
status.urlPath = this._urlPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,30 +131,6 @@ export class HcMain extends HassElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _sendError(
|
|
||||||
error_code: number,
|
|
||||||
error_message: string,
|
|
||||||
senderId?: string
|
|
||||||
) {
|
|
||||||
const error: ReceiverErrorMessage = {
|
|
||||||
type: "receiver_error",
|
|
||||||
error_code,
|
|
||||||
error_message,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (senderId) {
|
|
||||||
this.sendMessage(senderId, error);
|
|
||||||
} else {
|
|
||||||
for (const sender of castContext.getSenders()) {
|
|
||||||
this.sendMessage(sender.id, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dialogClosed = () => {
|
|
||||||
document.body.setAttribute("style", "overflow-y: auto !important");
|
|
||||||
};
|
|
||||||
|
|
||||||
private async _handleGetStatusMessage(msg: GetStatusMessage) {
|
private async _handleGetStatusMessage(msg: GetStatusMessage) {
|
||||||
this._sendStatus(msg.senderId!);
|
this._sendStatus(msg.senderId!);
|
||||||
}
|
}
|
||||||
@@ -179,19 +148,15 @@ export class HcMain extends HassElement {
|
|||||||
expires_in: 0,
|
expires_in: 0,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
const errorMessage = this._getErrorMessage(err);
|
this._error = this._getErrorMessage(err);
|
||||||
this._error = errorMessage;
|
|
||||||
this._sendError(err, errorMessage);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let connection;
|
let connection;
|
||||||
try {
|
try {
|
||||||
connection = await createConnection({ auth });
|
connection = await createConnection({ auth });
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
const errorMessage = this._getErrorMessage(err);
|
this._error = this._getErrorMessage(err);
|
||||||
this._error = errorMessage;
|
|
||||||
this._sendError(err, errorMessage);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
@@ -203,29 +168,24 @@ export class HcMain extends HassElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _handleShowLovelaceMessage(msg: ShowLovelaceViewMessage) {
|
private async _handleShowLovelaceMessage(msg: ShowLovelaceViewMessage) {
|
||||||
this._showDemo = false;
|
|
||||||
// We should not get this command before we are connected.
|
// We should not get this command before we are connected.
|
||||||
// Means a client got out of sync. Let's send status to them.
|
// Means a client got out of sync. Let's send status to them.
|
||||||
if (!this.hass) {
|
if (!this.hass) {
|
||||||
this._sendStatus(msg.senderId!);
|
this._sendStatus(msg.senderId!);
|
||||||
this._error = "Cannot show Lovelace because we're not connected.";
|
this._error = "Cannot show Lovelace because we're not connected.";
|
||||||
this._sendError(ReceiverErrorCode.NOT_CONNECTED, this._error);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._error = undefined;
|
|
||||||
if (msg.urlPath === "lovelace") {
|
if (msg.urlPath === "lovelace") {
|
||||||
msg.urlPath = null;
|
msg.urlPath = null;
|
||||||
}
|
}
|
||||||
this._lovelacePath = msg.viewPath;
|
|
||||||
if (!this._unsubLovelace || this._urlPath !== msg.urlPath) {
|
if (!this._unsubLovelace || this._urlPath !== msg.urlPath) {
|
||||||
this._urlPath = msg.urlPath;
|
this._urlPath = msg.urlPath;
|
||||||
this._lovelaceConfig = undefined;
|
|
||||||
if (this._unsubLovelace) {
|
if (this._unsubLovelace) {
|
||||||
this._unsubLovelace();
|
this._unsubLovelace();
|
||||||
}
|
}
|
||||||
const llColl = atLeastVersion(this.hass.connection.haVersion, 0, 107)
|
const llColl = atLeastVersion(this.hass.connection.haVersion, 0, 107)
|
||||||
? getLovelaceCollection(this.hass.connection, msg.urlPath)
|
? getLovelaceCollection(this.hass!.connection, msg.urlPath)
|
||||||
: getLegacyLovelaceCollection(this.hass.connection);
|
: getLegacyLovelaceCollection(this.hass!.connection);
|
||||||
// We first do a single refresh because we need to check if there is LL
|
// We first do a single refresh because we need to check if there is LL
|
||||||
// configuration.
|
// configuration.
|
||||||
try {
|
try {
|
||||||
@@ -233,17 +193,9 @@ export class HcMain extends HassElement {
|
|||||||
this._unsubLovelace = llColl.subscribe((lovelaceConfig) =>
|
this._unsubLovelace = llColl.subscribe((lovelaceConfig) =>
|
||||||
this._handleNewLovelaceConfig(lovelaceConfig)
|
this._handleNewLovelaceConfig(lovelaceConfig)
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
if (
|
// eslint-disable-next-line
|
||||||
atLeastVersion(this.hass.connection.haVersion, 0, 107) &&
|
console.log("Error fetching Lovelace configuration", err, msg);
|
||||||
err.code !== "config_not_found"
|
|
||||||
) {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
console.log("Error fetching Lovelace configuration", err, msg);
|
|
||||||
this._error = `Error fetching Lovelace configuration: ${err.message}`;
|
|
||||||
this._sendError(ReceiverErrorCode.FETCH_CONFIG_FAILED, this._error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Generate a Lovelace config.
|
// Generate a Lovelace config.
|
||||||
this._unsubLovelace = () => undefined;
|
this._unsubLovelace = () => undefined;
|
||||||
await this._generateLovelaceConfig();
|
await this._generateLovelaceConfig();
|
||||||
@@ -258,6 +210,8 @@ export class HcMain extends HassElement {
|
|||||||
loadLovelaceResources(resources, this.hass!.auth.data.hassUrl);
|
loadLovelaceResources(resources, this.hass!.auth.data.hassUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this._showDemo = false;
|
||||||
|
this._lovelacePath = msg.viewPath;
|
||||||
|
|
||||||
this._sendStatus();
|
this._sendStatus();
|
||||||
}
|
}
|
||||||
@@ -278,7 +232,7 @@ export class HcMain extends HassElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleNewLovelaceConfig(lovelaceConfig: LovelaceConfig) {
|
private _handleNewLovelaceConfig(lovelaceConfig: LovelaceConfig) {
|
||||||
castContext.setApplicationState(lovelaceConfig.title || "");
|
castContext.setApplicationState(lovelaceConfig.title!);
|
||||||
this._lovelaceConfig = lovelaceConfig;
|
this._lovelaceConfig = lovelaceConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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",
|
||||||
},
|
},
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import { mdiTelevision } from "@mdi/js";
|
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, state } from "lit/decorators";
|
import { customElement, state } from "lit/decorators";
|
||||||
import { CastManager } from "../../../src/cast/cast_manager";
|
import { CastManager } from "../../../src/cast/cast_manager";
|
||||||
@@ -28,7 +27,7 @@ class CastDemoRow extends LitElement implements LovelaceRow {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-svg-icon .path=${mdiTelevision}></ha-svg-icon>
|
<ha-icon icon="hademo:television"></ha-icon>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="name">Show Chromecast interface</div>
|
<div class="name">Show Chromecast interface</div>
|
||||||
<google-cast-launcher></google-cast-launcher>
|
<google-cast-launcher></google-cast-launcher>
|
||||||
@@ -73,7 +72,7 @@ class CastDemoRow extends LitElement implements LovelaceRow {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
ha-svg-icon {
|
ha-icon {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
color: var(--paper-item-icon-color);
|
color: var(--paper-item-icon-color);
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
@property({ attribute: false }) public hass!: MockHomeAssistant;
|
@property({ attribute: false }) public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
@state() private _switching = false;
|
@state() private _switching?: boolean;
|
||||||
|
|
||||||
private _hidden = localStorage.hide_demo_card;
|
private _hidden = localStorage.hide_demo_card;
|
||||||
|
|
||||||
@@ -27,7 +27,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) {
|
||||||
@@ -44,7 +49,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
(conf) => html`
|
(conf) => html`
|
||||||
${conf.name}
|
${conf.name}
|
||||||
<small>
|
<small>
|
||||||
<a target="_blank" href=${conf.authorUrl}>
|
<a target="_blank" href="${conf.authorUrl}">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.page-demo.cards.demo.demo_by",
|
"ui.panel.page-demo.cards.demo.demo_by",
|
||||||
"name",
|
"name",
|
||||||
@@ -94,7 +99,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
this._switching = true;
|
this._switching = true;
|
||||||
try {
|
try {
|
||||||
await setDemoConfig(this.hass, this.lovelace!, index);
|
await setDemoConfig(this.hass, this.lovelace!, index);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
alert("Failed to switch config :-(");
|
alert("Failed to switch config :-(");
|
||||||
} finally {
|
} finally {
|
||||||
this._switching = false;
|
this._switching = false;
|
||||||
|
@@ -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,9 +20,6 @@ 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 _initializeHass() {
|
||||||
@@ -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]) => {
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -1,7 +0,0 @@
|
|||||||
import { AreaRegistryEntry } from "../../../src/data/area_registry";
|
|
||||||
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
export const mockAreaRegistry = (
|
|
||||||
hass: MockHomeAssistant,
|
|
||||||
data: AreaRegistryEntry[] = []
|
|
||||||
) => hass.mockWS("config/area_registry/list", () => data);
|
|
@@ -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,7 +0,0 @@
|
|||||||
import { DeviceRegistryEntry } from "../../../src/data/device_registry";
|
|
||||||
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
export const mockDeviceRegistry = (
|
|
||||||
hass: MockHomeAssistant,
|
|
||||||
data: DeviceRegistryEntry[] = []
|
|
||||||
) => hass.mockWS("config/device_registry/list", () => data);
|
|
@@ -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,7 +0,0 @@
|
|||||||
import { EntityRegistryEntry } from "../../../src/data/entity_registry";
|
|
||||||
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
export const mockEntityRegistry = (
|
|
||||||
hass: MockHomeAssistant,
|
|
||||||
data: EntityRegistryEntry[] = []
|
|
||||||
) => hass.mockWS("config/entity_registry/list", () => data);
|
|
@@ -1,59 +0,0 @@
|
|||||||
import { HassioSupervisorInfo } from "../../../src/data/hassio/supervisor";
|
|
||||||
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
export const mockHassioSupervisor = (hass: MockHomeAssistant) => {
|
|
||||||
hass.config.components.push("hassio");
|
|
||||||
hass.mockWS("supervisor/api", (msg) => {
|
|
||||||
if (msg.endpoint === "/supervisor/info") {
|
|
||||||
const data: HassioSupervisorInfo = {
|
|
||||||
version: "2021.10.dev0805",
|
|
||||||
version_latest: "2021.10.dev0806",
|
|
||||||
update_available: true,
|
|
||||||
channel: "dev",
|
|
||||||
arch: "aarch64",
|
|
||||||
supported: true,
|
|
||||||
healthy: true,
|
|
||||||
ip_address: "172.30.32.2",
|
|
||||||
wait_boot: 5,
|
|
||||||
timezone: "America/Los_Angeles",
|
|
||||||
logging: "info",
|
|
||||||
debug: false,
|
|
||||||
debug_block: false,
|
|
||||||
diagnostics: true,
|
|
||||||
addons: [
|
|
||||||
{
|
|
||||||
name: "Visual Studio Code",
|
|
||||||
slug: "a0d7b954_vscode",
|
|
||||||
description:
|
|
||||||
"Fully featured VSCode experience, to edit your HA config in the browser, including auto-completion!",
|
|
||||||
state: "started",
|
|
||||||
version: "3.6.2",
|
|
||||||
version_latest: "3.6.2",
|
|
||||||
update_available: false,
|
|
||||||
repository: "a0d7b954",
|
|
||||||
icon: true,
|
|
||||||
logo: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Z-Wave JS",
|
|
||||||
slug: "core_zwave_js",
|
|
||||||
description:
|
|
||||||
"Control a ZWave network with Home Assistant Z-Wave JS",
|
|
||||||
state: "started",
|
|
||||||
version: "0.1.45",
|
|
||||||
version_latest: "0.1.45",
|
|
||||||
update_available: false,
|
|
||||||
repository: "core",
|
|
||||||
icon: true,
|
|
||||||
logo: true,
|
|
||||||
},
|
|
||||||
] as any,
|
|
||||||
addons_repositories: [
|
|
||||||
"https://github.com/hassio-addons/repository",
|
|
||||||
] as any,
|
|
||||||
};
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return Promise.reject(`${msg.method} ${msg.endpoint} is not implemented`);
|
|
||||||
});
|
|
||||||
};
|
|
@@ -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());
|
||||||
@@ -23,9 +24,9 @@ customElements.whenDefined("hui-view").then(() => {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const HUIView = customElements.get("hui-view");
|
const HUIView = customElements.get("hui-view");
|
||||||
// Patch HUI-VIEW to make the lovelace object available to the demo card
|
// Patch HUI-VIEW to make the lovelace object available to the demo card
|
||||||
const oldCreateCard = HUIView!.prototype.createCardElement;
|
const oldCreateCard = HUIView.prototype.createCardElement;
|
||||||
|
|
||||||
HUIView!.prototype.createCardElement = function (config) {
|
HUIView.prototype.createCardElement = function (config) {
|
||||||
const el = oldCreateCard.call(this, config);
|
const el = oldCreateCard.call(this, config);
|
||||||
if (el.tagName === "HA-DEMO-CARD") {
|
if (el.tagName === "HA-DEMO-CARD") {
|
||||||
(el as HADemoCard).lovelace = this.lovelace;
|
(el as HADemoCard).lovelace = this.lovelace;
|
||||||
|
@@ -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 },
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 147 KiB |
@@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
TARGET_LABEL="Needs gallery preview"
|
|
||||||
|
|
||||||
if [[ "$NETLIFY" != "true" ]]; then
|
|
||||||
echo "This script can only be run on Netlify"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
function createStatus() {
|
|
||||||
state="$1"
|
|
||||||
description="$2"
|
|
||||||
target_url="$3"
|
|
||||||
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
"https://api.github.com/repos/home-assistant/frontend/statuses/$COMMIT_REF" \
|
|
||||||
-d '{"state": "'"${state}"'", "context": "Netlify/Gallery Preview Build", "description": "'"$description"'", "target_url": "'"$target_url"'"}'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if [[ "${PULL_REQUEST}" == "false" ]]; then
|
|
||||||
gulp build-gallery
|
|
||||||
else
|
|
||||||
if [[ "$(curl -sSLf -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" \
|
|
||||||
"https://api.github.com/repos/home-assistant/frontend/pulls/${REVIEW_ID}" | jq '.labels[].name' -r)" =~ "$TARGET_LABEL" ]]; then
|
|
||||||
createStatus "pending" "Building gallery preview" "https://app.netlify.com/sites/home-assistant-gallery/deploys/$BUILD_ID"
|
|
||||||
gulp build-gallery
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
createStatus "success" "Build complete" "$DEPLOY_URL"
|
|
||||||
else
|
|
||||||
createStatus "error" "Build failed" "https://app.netlify.com/sites/home-assistant-gallery/deploys/$BUILD_ID"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
createStatus "success" "Build was not requested by PR label"
|
|
||||||
fi
|
|
||||||
fi
|
|
@@ -1,143 +0,0 @@
|
|||||||
import { Button } from "@material/mwc-button";
|
|
||||||
import { html, LitElement, css, TemplateResult } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
|
||||||
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
|
||||||
|
|
||||||
@customElement("demo-black-white-row")
|
|
||||||
class DemoBlackWhiteRow extends LitElement {
|
|
||||||
@property() title!: string;
|
|
||||||
|
|
||||||
@property() value!: any;
|
|
||||||
|
|
||||||
@property() disabled = false;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<div class="row">
|
|
||||||
<div class="content light">
|
|
||||||
<ha-card .header=${this.title}>
|
|
||||||
<div class="card-content">
|
|
||||||
<slot name="light"></slot>
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button
|
|
||||||
.disabled=${this.disabled}
|
|
||||||
@click=${this.handleSubmit}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
</div>
|
|
||||||
<div class="content dark">
|
|
||||||
<ha-card .header=${this.title}>
|
|
||||||
<div class="card-content">
|
|
||||||
<slot name="dark"></slot>
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<mwc-button
|
|
||||||
.disabled=${this.disabled}
|
|
||||||
@click=${this.handleSubmit}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
<pre>${JSON.stringify(this.value, undefined, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
applyThemesOnElement(
|
|
||||||
this.shadowRoot!.querySelector(".dark"),
|
|
||||||
{
|
|
||||||
default_theme: "default",
|
|
||||||
default_dark_theme: "default",
|
|
||||||
themes: {},
|
|
||||||
darkMode: false,
|
|
||||||
},
|
|
||||||
"default",
|
|
||||||
{ dark: true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSubmit(ev) {
|
|
||||||
const content = (ev.target as Button).closest(".content")!;
|
|
||||||
fireEvent(this, "submitted" as any, {
|
|
||||||
slot: content.classList.contains("light") ? "light" : "dark",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
padding: 50px 0;
|
|
||||||
background-color: var(--primary-background-color);
|
|
||||||
}
|
|
||||||
.light {
|
|
||||||
flex: 1;
|
|
||||||
padding-left: 50px;
|
|
||||||
padding-right: 50px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.light ha-card {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
.dark {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
padding-left: 50px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
ha-card {
|
|
||||||
width: 400px;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
width: 300px;
|
|
||||||
margin: 0 16px 0;
|
|
||||||
overflow: auto;
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
.card-actions {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 1500px) {
|
|
||||||
.light {
|
|
||||||
flex: initial;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 1000px) {
|
|
||||||
.light,
|
|
||||||
.dark {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
.row,
|
|
||||||
.dark {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
ha-card {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
margin: 16px auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-black-white-row": DemoBlackWhiteRow;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,91 +0,0 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import { LitElement, TemplateResult, html } from "lit";
|
|
||||||
import { customElement, state } from "lit/decorators";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import type { HomeAssistant } from "../../../src/types";
|
|
||||||
import "../components/demo-black-white-row";
|
|
||||||
import { mockEntityRegistry } from "../../../demo/src/stubs/entity_registry";
|
|
||||||
import { mockDeviceRegistry } from "../../../demo/src/stubs/device_registry";
|
|
||||||
import { mockAreaRegistry } from "../../../demo/src/stubs/area_registry";
|
|
||||||
import { mockHassioSupervisor } from "../../../demo/src/stubs/hassio_supervisor";
|
|
||||||
import "../../../src/panels/config/automation/action/ha-automation-action";
|
|
||||||
import { HaChooseAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-choose";
|
|
||||||
import { HaDelayAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-delay";
|
|
||||||
import { HaDeviceAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-device_id";
|
|
||||||
import { HaEventAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-event";
|
|
||||||
import { HaRepeatAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-repeat";
|
|
||||||
import { HaSceneAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-scene";
|
|
||||||
import { HaServiceAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-service";
|
|
||||||
import { HaWaitForTriggerAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger";
|
|
||||||
import { HaWaitAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-wait_template";
|
|
||||||
import { Action } from "../../../src/data/script";
|
|
||||||
import { HaConditionAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-condition";
|
|
||||||
|
|
||||||
const SCHEMAS: { name: string; actions: Action[] }[] = [
|
|
||||||
{ name: "Event", actions: [HaEventAction.defaultConfig] },
|
|
||||||
{ name: "Device", actions: [HaDeviceAction.defaultConfig] },
|
|
||||||
{ name: "Service", actions: [HaServiceAction.defaultConfig] },
|
|
||||||
{ name: "Condition", actions: [HaConditionAction.defaultConfig] },
|
|
||||||
{ name: "Delay", actions: [HaDelayAction.defaultConfig] },
|
|
||||||
{ name: "Scene", actions: [HaSceneAction.defaultConfig] },
|
|
||||||
{ name: "Wait", actions: [HaWaitAction.defaultConfig] },
|
|
||||||
{ name: "WaitForTrigger", actions: [HaWaitForTriggerAction.defaultConfig] },
|
|
||||||
{ name: "Repeat", actions: [HaRepeatAction.defaultConfig] },
|
|
||||||
{ name: "Choose", actions: [HaChooseAction.defaultConfig] },
|
|
||||||
{ name: "Variables", actions: [{ variables: { hello: "1" } }] },
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-editor-action")
|
|
||||||
class DemoHaAutomationEditorAction extends LitElement {
|
|
||||||
@state() private hass!: HomeAssistant;
|
|
||||||
|
|
||||||
private data: any = SCHEMAS.map((info) => info.actions);
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("config", "en");
|
|
||||||
mockEntityRegistry(hass);
|
|
||||||
mockDeviceRegistry(hass);
|
|
||||||
mockAreaRegistry(hass);
|
|
||||||
mockHassioSupervisor(hass);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
const valueChanged = (ev) => {
|
|
||||||
const sampleIdx = ev.target.sampleIdx;
|
|
||||||
this.data[sampleIdx] = ev.detail.value;
|
|
||||||
this.requestUpdate();
|
|
||||||
};
|
|
||||||
return html`
|
|
||||||
${SCHEMAS.map(
|
|
||||||
(info, sampleIdx) => html`
|
|
||||||
<demo-black-white-row
|
|
||||||
.title=${info.name}
|
|
||||||
.value=${this.data[sampleIdx]}
|
|
||||||
>
|
|
||||||
${["light", "dark"].map(
|
|
||||||
(slot) =>
|
|
||||||
html`
|
|
||||||
<ha-automation-action
|
|
||||||
slot=${slot}
|
|
||||||
.hass=${this.hass}
|
|
||||||
.actions=${this.data[sampleIdx]}
|
|
||||||
.sampleIdx=${sampleIdx}
|
|
||||||
@value-changed=${valueChanged}
|
|
||||||
></ha-automation-action>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</demo-black-white-row>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-automation-editor-action": DemoHaAutomationEditorAction;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,127 +0,0 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import { LitElement, TemplateResult, html } from "lit";
|
|
||||||
import { customElement, state } from "lit/decorators";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import type { HomeAssistant } from "../../../src/types";
|
|
||||||
import "../components/demo-black-white-row";
|
|
||||||
import { mockEntityRegistry } from "../../../demo/src/stubs/entity_registry";
|
|
||||||
import { mockDeviceRegistry } from "../../../demo/src/stubs/device_registry";
|
|
||||||
import { mockAreaRegistry } from "../../../demo/src/stubs/area_registry";
|
|
||||||
import { mockHassioSupervisor } from "../../../demo/src/stubs/hassio_supervisor";
|
|
||||||
import type { Condition } from "../../../src/data/automation";
|
|
||||||
import "../../../src/panels/config/automation/condition/ha-automation-condition";
|
|
||||||
import { HaDeviceCondition } from "../../../src/panels/config/automation/condition/types/ha-automation-condition-device";
|
|
||||||
import { HaLogicalCondition } from "../../../src/panels/config/automation/condition/types/ha-automation-condition-logical";
|
|
||||||
import HaNumericStateCondition from "../../../src/panels/config/automation/condition/types/ha-automation-condition-numeric_state";
|
|
||||||
import { HaStateCondition } from "../../../src/panels/config/automation/condition/types/ha-automation-condition-state";
|
|
||||||
import { HaSunCondition } from "../../../src/panels/config/automation/condition/types/ha-automation-condition-sun";
|
|
||||||
import { HaTemplateCondition } from "../../../src/panels/config/automation/condition/types/ha-automation-condition-template";
|
|
||||||
import { HaTimeCondition } from "../../../src/panels/config/automation/condition/types/ha-automation-condition-time";
|
|
||||||
import { HaTriggerCondition } from "../../../src/panels/config/automation/condition/types/ha-automation-condition-trigger";
|
|
||||||
import { HaZoneCondition } from "../../../src/panels/config/automation/condition/types/ha-automation-condition-zone";
|
|
||||||
|
|
||||||
const SCHEMAS: { name: string; conditions: Condition[] }[] = [
|
|
||||||
{
|
|
||||||
name: "State",
|
|
||||||
conditions: [{ condition: "state", ...HaStateCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Numeric State",
|
|
||||||
conditions: [
|
|
||||||
{ condition: "numeric_state", ...HaNumericStateCondition.defaultConfig },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Sun",
|
|
||||||
conditions: [{ condition: "sun", ...HaSunCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Zone",
|
|
||||||
conditions: [{ condition: "zone", ...HaZoneCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Time",
|
|
||||||
conditions: [{ condition: "time", ...HaTimeCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Template",
|
|
||||||
conditions: [
|
|
||||||
{ condition: "template", ...HaTemplateCondition.defaultConfig },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Device",
|
|
||||||
conditions: [{ condition: "device", ...HaDeviceCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "And",
|
|
||||||
conditions: [{ condition: "and", ...HaLogicalCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Or",
|
|
||||||
conditions: [{ condition: "or", ...HaLogicalCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Not",
|
|
||||||
conditions: [{ condition: "not", ...HaLogicalCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Trigger",
|
|
||||||
conditions: [{ condition: "trigger", ...HaTriggerCondition.defaultConfig }],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-editor-condition")
|
|
||||||
class DemoHaAutomationEditorCondition extends LitElement {
|
|
||||||
@state() private hass!: HomeAssistant;
|
|
||||||
|
|
||||||
private data: any = SCHEMAS.map((info) => info.conditions);
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("config", "en");
|
|
||||||
mockEntityRegistry(hass);
|
|
||||||
mockDeviceRegistry(hass);
|
|
||||||
mockAreaRegistry(hass);
|
|
||||||
mockHassioSupervisor(hass);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
const valueChanged = (ev) => {
|
|
||||||
const sampleIdx = ev.target.sampleIdx;
|
|
||||||
this.data[sampleIdx] = ev.detail.value;
|
|
||||||
this.requestUpdate();
|
|
||||||
};
|
|
||||||
return html`
|
|
||||||
${SCHEMAS.map(
|
|
||||||
(info, sampleIdx) => html`
|
|
||||||
<demo-black-white-row
|
|
||||||
.title=${info.name}
|
|
||||||
.value=${this.data[sampleIdx]}
|
|
||||||
>
|
|
||||||
${["light", "dark"].map(
|
|
||||||
(slot) =>
|
|
||||||
html`
|
|
||||||
<ha-automation-condition
|
|
||||||
slot=${slot}
|
|
||||||
.hass=${this.hass}
|
|
||||||
.conditions=${this.data[sampleIdx]}
|
|
||||||
.sampleIdx=${sampleIdx}
|
|
||||||
@value-changed=${valueChanged}
|
|
||||||
></ha-automation-condition>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</demo-black-white-row>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-automation-editor-condition": DemoHaAutomationEditorCondition;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,159 +0,0 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import { LitElement, TemplateResult, html } from "lit";
|
|
||||||
import { customElement, state } from "lit/decorators";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import type { HomeAssistant } from "../../../src/types";
|
|
||||||
import "../components/demo-black-white-row";
|
|
||||||
import { mockEntityRegistry } from "../../../demo/src/stubs/entity_registry";
|
|
||||||
import { mockDeviceRegistry } from "../../../demo/src/stubs/device_registry";
|
|
||||||
import { mockAreaRegistry } from "../../../demo/src/stubs/area_registry";
|
|
||||||
import { mockHassioSupervisor } from "../../../demo/src/stubs/hassio_supervisor";
|
|
||||||
import type { Trigger } from "../../../src/data/automation";
|
|
||||||
import { HaGeolocationTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location";
|
|
||||||
import { HaEventTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-event";
|
|
||||||
import { HaHassTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant";
|
|
||||||
import { HaNumericStateTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state";
|
|
||||||
import { HaSunTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-sun";
|
|
||||||
import { HaTagTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-tag";
|
|
||||||
import { HaTemplateTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-template";
|
|
||||||
import { HaTimeTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-time";
|
|
||||||
import { HaTimePatternTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern";
|
|
||||||
import { HaWebhookTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-webhook";
|
|
||||||
import { HaZoneTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-zone";
|
|
||||||
import { HaDeviceTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-device";
|
|
||||||
import { HaStateTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-state";
|
|
||||||
import { HaMQTTTrigger } from "../../../src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt";
|
|
||||||
import "../../../src/panels/config/automation/trigger/ha-automation-trigger";
|
|
||||||
|
|
||||||
const SCHEMAS: { name: string; triggers: Trigger[] }[] = [
|
|
||||||
{
|
|
||||||
name: "State",
|
|
||||||
triggers: [{ platform: "state", ...HaStateTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "MQTT",
|
|
||||||
triggers: [{ platform: "mqtt", ...HaMQTTTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "GeoLocation",
|
|
||||||
triggers: [
|
|
||||||
{ platform: "geo_location", ...HaGeolocationTrigger.defaultConfig },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Home Assistant",
|
|
||||||
triggers: [{ platform: "homeassistant", ...HaHassTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Numeric State",
|
|
||||||
triggers: [
|
|
||||||
{ platform: "numeric_state", ...HaNumericStateTrigger.defaultConfig },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Sun",
|
|
||||||
triggers: [{ platform: "sun", ...HaSunTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Time Pattern",
|
|
||||||
triggers: [
|
|
||||||
{ platform: "time_pattern", ...HaTimePatternTrigger.defaultConfig },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Webhook",
|
|
||||||
triggers: [{ platform: "webhook", ...HaWebhookTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Zone",
|
|
||||||
triggers: [{ platform: "zone", ...HaZoneTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Tag",
|
|
||||||
triggers: [{ platform: "tag", ...HaTagTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Time",
|
|
||||||
triggers: [{ platform: "time", ...HaTimeTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Template",
|
|
||||||
triggers: [{ platform: "template", ...HaTemplateTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Event",
|
|
||||||
triggers: [{ platform: "event", ...HaEventTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Device Trigger",
|
|
||||||
triggers: [{ platform: "device", ...HaDeviceTrigger.defaultConfig }],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-editor-trigger")
|
|
||||||
class DemoHaAutomationEditorTrigger extends LitElement {
|
|
||||||
@state() private hass!: HomeAssistant;
|
|
||||||
|
|
||||||
private data: any = SCHEMAS.map((info) => info.triggers);
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("config", "en");
|
|
||||||
mockEntityRegistry(hass);
|
|
||||||
mockDeviceRegistry(hass);
|
|
||||||
mockAreaRegistry(hass);
|
|
||||||
mockHassioSupervisor(hass);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
const valueChanged = (ev) => {
|
|
||||||
const sampleIdx = ev.target.sampleIdx;
|
|
||||||
this.data[sampleIdx] = ev.detail.value;
|
|
||||||
this.requestUpdate();
|
|
||||||
};
|
|
||||||
return html`
|
|
||||||
${SCHEMAS.map(
|
|
||||||
(info, sampleIdx) => html`
|
|
||||||
<demo-black-white-row
|
|
||||||
.title=${info.name}
|
|
||||||
.value=${this.data[sampleIdx]}
|
|
||||||
>
|
|
||||||
${["light", "dark"].map(
|
|
||||||
(slot) =>
|
|
||||||
html`
|
|
||||||
<ha-automation-trigger
|
|
||||||
slot=${slot}
|
|
||||||
.hass=${this.hass}
|
|
||||||
.triggers=${this.data[sampleIdx]}
|
|
||||||
.sampleIdx=${sampleIdx}
|
|
||||||
@value-changed=${valueChanged}
|
|
||||||
></ha-automation-trigger>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</demo-black-white-row>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-automation-editor-trigger": DemoHaAutomationEditorTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/trace/hat-script-graph";
|
import "../../../src/components/trace/hat-script-graph";
|
||||||
import "../../../src/components/trace/hat-trace-timeline";
|
import "../../../src/components/trace/hat-trace-timeline";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
import { DemoTrace } from "../data/traces/types";
|
import { DemoTrace } from "../data/traces/types";
|
||||||
import { basicTrace } from "../data/traces/basic_trace";
|
import { basicTrace } from "../data/traces/basic_trace";
|
||||||
import { motionLightTrace } from "../data/traces/motion-light-trace";
|
import { motionLightTrace } from "../data/traces/motion-light-trace";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
|
||||||
const traces: DemoTrace[] = [basicTrace, motionLightTrace];
|
const traces: DemoTrace[] = [basicTrace, motionLightTrace];
|
||||||
|
|
||||||
|
@@ -1,221 +0,0 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
|
||||||
import { css, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
|
||||||
import "../../../src/components/ha-alert";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import "../../../src/components/ha-logo-svg";
|
|
||||||
|
|
||||||
const alerts: {
|
|
||||||
title?: string;
|
|
||||||
description: string | TemplateResult;
|
|
||||||
type: "info" | "warning" | "error" | "success";
|
|
||||||
dismissable?: boolean;
|
|
||||||
rtl?: boolean;
|
|
||||||
iconSlot?: TemplateResult;
|
|
||||||
actionSlot?: TemplateResult;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
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",
|
|
||||||
actionSlot: html`<mwc-button slot="action" label="restart"></mwc-button>`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Unsaved data",
|
|
||||||
description: "You have unsaved data",
|
|
||||||
type: "warning",
|
|
||||||
actionSlot: html`<mwc-button slot="action" label="save"></mwc-button>`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Slotted icon",
|
|
||||||
description: "Alert with slotted icon",
|
|
||||||
type: "warning",
|
|
||||||
iconSlot: html`<span slot="icon" class="image">
|
|
||||||
<ha-logo-svg></ha-logo-svg>
|
|
||||||
</span>`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Slotted image",
|
|
||||||
description: "Alert with slotted image",
|
|
||||||
type: "warning",
|
|
||||||
iconSlot: html`<span slot="icon" class="image"
|
|
||||||
><img src="https://www.home-assistant.io/images/home-assistant-logo.svg"
|
|
||||||
/></span>`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Slotted action",
|
|
||||||
description: "Alert with slotted action",
|
|
||||||
type: "info",
|
|
||||||
actionSlot: html`<mwc-button slot="action" label="action"></mwc-button>`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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",
|
|
||||||
actionSlot: html`<mwc-button slot="action" label="restart"></mwc-button>`,
|
|
||||||
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`
|
|
||||||
${["light", "dark"].map(
|
|
||||||
(mode) => html`
|
|
||||||
<div class=${mode}>
|
|
||||||
<ha-card header="ha-alert ${mode} demo">
|
|
||||||
<div class="card-content">
|
|
||||||
${alerts.map(
|
|
||||||
(alert) => html`
|
|
||||||
<ha-alert
|
|
||||||
.title=${alert.title || ""}
|
|
||||||
.alertType=${alert.type}
|
|
||||||
.dismissable=${alert.dismissable || false}
|
|
||||||
.rtl=${alert.rtl || false}
|
|
||||||
>
|
|
||||||
${alert.iconSlot} ${alert.description} ${alert.actionSlot}
|
|
||||||
</ha-alert>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
applyThemesOnElement(
|
|
||||||
this.shadowRoot!.querySelector(".dark"),
|
|
||||||
{
|
|
||||||
default_theme: "default",
|
|
||||||
default_dark_theme: "default",
|
|
||||||
themes: {},
|
|
||||||
darkMode: false,
|
|
||||||
},
|
|
||||||
"default",
|
|
||||||
{ dark: true }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
:host {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.dark,
|
|
||||||
.light {
|
|
||||||
display: block;
|
|
||||||
background-color: var(--primary-background-color);
|
|
||||||
padding: 0 50px;
|
|
||||||
}
|
|
||||||
ha-card {
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
ha-alert {
|
|
||||||
display: block;
|
|
||||||
margin: 24px 0;
|
|
||||||
}
|
|
||||||
.condition {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.image {
|
|
||||||
display: inline-flex;
|
|
||||||
height: 100%;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
max-height: 24px;
|
|
||||||
width: 24px;
|
|
||||||
}
|
|
||||||
mwc-button {
|
|
||||||
--mdc-theme-primary: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-alert": DemoHaAlert;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,85 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import { classMap } from "lit/directives/class-map";
|
|
||||||
import "../../../src/components/ha-bar";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
|
|
||||||
const bars: {
|
|
||||||
min?: number;
|
|
||||||
max?: number;
|
|
||||||
value: number;
|
|
||||||
warning?: number;
|
|
||||||
error?: number;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
value: 33,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
min: -10,
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 80,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 200,
|
|
||||||
max: 13,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 4,
|
|
||||||
min: 13,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-ha-bar")
|
|
||||||
export class DemoHaBar extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
${bars
|
|
||||||
.map((bar) => ({ min: 0, max: 100, warning: 70, error: 90, ...bar }))
|
|
||||||
.map(
|
|
||||||
(bar) => html`
|
|
||||||
<ha-card>
|
|
||||||
<div class="card-content">
|
|
||||||
<pre>Config: ${JSON.stringify(bar)}</pre>
|
|
||||||
<ha-bar
|
|
||||||
class=${classMap({
|
|
||||||
warning: bar.value > bar.warning,
|
|
||||||
error: bar.value > bar.error,
|
|
||||||
})}
|
|
||||||
.min=${bar.min}
|
|
||||||
.max=${bar.max}
|
|
||||||
.value=${bar.value}
|
|
||||||
>
|
|
||||||
</ha-bar>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.warning {
|
|
||||||
--ha-bar-primary-color: var(--warning-color);
|
|
||||||
}
|
|
||||||
.error {
|
|
||||||
--ha-bar-primary-color: var(--error-color);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-bar": DemoHaBar;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,86 +0,0 @@
|
|||||||
import { mdiHomeAssistant } from "@mdi/js";
|
|
||||||
import { css, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import "../../../src/components/ha-chip";
|
|
||||||
import "../../../src/components/ha-chip-set";
|
|
||||||
import "../../../src/components/ha-svg-icon";
|
|
||||||
|
|
||||||
const chips: {
|
|
||||||
icon?: string;
|
|
||||||
content?: string;
|
|
||||||
}[] = [
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
icon: mdiHomeAssistant,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
content: "Content",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: mdiHomeAssistant,
|
|
||||||
content: "Content",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-ha-chips")
|
|
||||||
export class DemoHaChips extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="ha-chip demo">
|
|
||||||
<div class="card-content">
|
|
||||||
${chips.map(
|
|
||||||
(chip) => html`
|
|
||||||
<ha-chip .hasIcon=${chip.icon !== undefined}>
|
|
||||||
${chip.icon
|
|
||||||
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
|
||||||
</ha-svg-icon>`
|
|
||||||
: ""}
|
|
||||||
${chip.content}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
<ha-card header="ha-chip-set demo">
|
|
||||||
<div class="card-content">
|
|
||||||
<ha-chip-set>
|
|
||||||
${chips.map(
|
|
||||||
(chip) => html`
|
|
||||||
<ha-chip .hasIcon=${chip.icon !== undefined}>
|
|
||||||
${chip.icon
|
|
||||||
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
|
||||||
</ha-svg-icon>`
|
|
||||||
: ""}
|
|
||||||
${chip.content}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-chip-set>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
ha-chip {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
.card-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-chips": DemoHaChips;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,306 +0,0 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import "@material/mwc-button";
|
|
||||||
import { LitElement, TemplateResult, html } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import { computeInitialHaFormData } from "../../../src/components/ha-form/compute-initial-ha-form-data";
|
|
||||||
import type { HaFormSchema } from "../../../src/components/ha-form/types";
|
|
||||||
import "../../../src/components/ha-form/ha-form";
|
|
||||||
import "../components/demo-black-white-row";
|
|
||||||
|
|
||||||
const SCHEMAS: {
|
|
||||||
title: string;
|
|
||||||
translations?: Record<string, string>;
|
|
||||||
error?: Record<string, string>;
|
|
||||||
schema: HaFormSchema[];
|
|
||||||
data?: Record<string, any>;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
title: "Authentication",
|
|
||||||
translations: {
|
|
||||||
username: "Username",
|
|
||||||
password: "Password",
|
|
||||||
invalid_login: "Invalid username or password",
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
base: "invalid_login",
|
|
||||||
},
|
|
||||||
schema: [
|
|
||||||
{
|
|
||||||
type: "string",
|
|
||||||
name: "username",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "string",
|
|
||||||
name: "password",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title: "One of each",
|
|
||||||
schema: [
|
|
||||||
{
|
|
||||||
type: "constant",
|
|
||||||
value: "Constant Value",
|
|
||||||
name: "constant",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "boolean",
|
|
||||||
name: "bool",
|
|
||||||
optional: true,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "integer",
|
|
||||||
name: "int",
|
|
||||||
optional: true,
|
|
||||||
default: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "float",
|
|
||||||
name: "float",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "string",
|
|
||||||
name: "string",
|
|
||||||
optional: true,
|
|
||||||
default: "Default",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
options: [
|
|
||||||
["default", "default"],
|
|
||||||
["other", "other"],
|
|
||||||
],
|
|
||||||
name: "select",
|
|
||||||
optional: true,
|
|
||||||
default: "default",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "multi_select",
|
|
||||||
options: {
|
|
||||||
default: "Default",
|
|
||||||
other: "Other",
|
|
||||||
},
|
|
||||||
name: "multi",
|
|
||||||
optional: true,
|
|
||||||
default: ["default"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "positive_time_period_dict",
|
|
||||||
name: "time",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Numbers",
|
|
||||||
schema: [
|
|
||||||
{
|
|
||||||
type: "integer",
|
|
||||||
name: "int",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "integer",
|
|
||||||
name: "int with default",
|
|
||||||
optional: true,
|
|
||||||
default: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "integer",
|
|
||||||
name: "int range required",
|
|
||||||
required: true,
|
|
||||||
default: 5,
|
|
||||||
valueMin: 0,
|
|
||||||
valueMax: 10,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "integer",
|
|
||||||
name: "int range optional",
|
|
||||||
optional: true,
|
|
||||||
valueMin: 0,
|
|
||||||
valueMax: 10,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "select",
|
|
||||||
schema: [
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
options: [
|
|
||||||
["default", "Default"],
|
|
||||||
["other", "Other"],
|
|
||||||
],
|
|
||||||
name: "select",
|
|
||||||
required: true,
|
|
||||||
default: "default",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
options: [
|
|
||||||
["default", "Default"],
|
|
||||||
["other", "Other"],
|
|
||||||
],
|
|
||||||
name: "select optional",
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
options: [
|
|
||||||
["default", "Default"],
|
|
||||||
["other", "Other"],
|
|
||||||
["uno", "mas"],
|
|
||||||
["one", "more"],
|
|
||||||
["and", "another_one"],
|
|
||||||
["option", "1000"],
|
|
||||||
],
|
|
||||||
name: "select many otions",
|
|
||||||
optional: true,
|
|
||||||
default: "default",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Multi select",
|
|
||||||
schema: [
|
|
||||||
{
|
|
||||||
type: "multi_select",
|
|
||||||
options: {
|
|
||||||
default: "Default",
|
|
||||||
other: "Other",
|
|
||||||
},
|
|
||||||
name: "multi",
|
|
||||||
required: true,
|
|
||||||
default: ["default"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "multi_select",
|
|
||||||
options: {
|
|
||||||
default: "Default",
|
|
||||||
other: "Other",
|
|
||||||
uno: "mas",
|
|
||||||
one: "more",
|
|
||||||
and: "another_one",
|
|
||||||
option: "1000",
|
|
||||||
},
|
|
||||||
name: "multi many otions",
|
|
||||||
optional: true,
|
|
||||||
default: ["default"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Field specific error",
|
|
||||||
data: {
|
|
||||||
new_password: "hello",
|
|
||||||
new_password_2: "bye",
|
|
||||||
},
|
|
||||||
translations: {
|
|
||||||
new_password: "New Password",
|
|
||||||
new_password_2: "Re-type Password",
|
|
||||||
not_match: "The passwords do not match",
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
new_password_2: "not_match",
|
|
||||||
},
|
|
||||||
schema: [
|
|
||||||
{
|
|
||||||
type: "string",
|
|
||||||
name: "new_password",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "string",
|
|
||||||
name: "new_password_2",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "OctoPrint",
|
|
||||||
translations: {
|
|
||||||
username: "Username",
|
|
||||||
host: "Host",
|
|
||||||
port: "Port Number",
|
|
||||||
path: "Application Path",
|
|
||||||
ssl: "Use SSL",
|
|
||||||
},
|
|
||||||
schema: [
|
|
||||||
{ type: "string", name: "username", required: true, default: "" },
|
|
||||||
{ type: "string", name: "host", required: true, default: "" },
|
|
||||||
{
|
|
||||||
type: "integer",
|
|
||||||
valueMin: 1,
|
|
||||||
valueMax: 65535,
|
|
||||||
name: "port",
|
|
||||||
optional: true,
|
|
||||||
default: 80,
|
|
||||||
},
|
|
||||||
{ type: "string", name: "path", optional: true, default: "/" },
|
|
||||||
{ type: "boolean", name: "ssl", optional: true, default: false },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-ha-form")
|
|
||||||
class DemoHaForm extends LitElement {
|
|
||||||
private data = SCHEMAS.map(
|
|
||||||
({ schema, data }) => data || computeInitialHaFormData(schema)
|
|
||||||
);
|
|
||||||
|
|
||||||
private disabled = SCHEMAS.map(() => false);
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
${SCHEMAS.map((info, idx) => {
|
|
||||||
const translations = info.translations || {};
|
|
||||||
return html`
|
|
||||||
<demo-black-white-row
|
|
||||||
.title=${info.title}
|
|
||||||
.value=${this.data[idx]}
|
|
||||||
.disabled=${this.disabled[idx]}
|
|
||||||
@submitted=${() => {
|
|
||||||
this.disabled[idx] = true;
|
|
||||||
this.requestUpdate();
|
|
||||||
setTimeout(() => {
|
|
||||||
this.disabled[idx] = false;
|
|
||||||
this.requestUpdate();
|
|
||||||
}, 2000);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
${["light", "dark"].map(
|
|
||||||
(slot) => html`
|
|
||||||
<ha-form
|
|
||||||
slot=${slot}
|
|
||||||
.data=${this.data[idx]}
|
|
||||||
.schema=${info.schema}
|
|
||||||
.error=${info.error}
|
|
||||||
.disabled=${this.disabled[idx]}
|
|
||||||
.computeError=${(error) => translations[error] || error}
|
|
||||||
.computeLabel=${(schema) =>
|
|
||||||
translations[schema.name] || schema.name}
|
|
||||||
@value-changed=${(e) => {
|
|
||||||
this.data[idx] = e.detail.value;
|
|
||||||
this.requestUpdate();
|
|
||||||
}}
|
|
||||||
></ha-form>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</demo-black-white-row>
|
|
||||||
`;
|
|
||||||
})}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-form": DemoHaForm;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,122 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-label-badge";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
|
|
||||||
const colors = ["#03a9f4", "#ffa600", "#43a047"];
|
|
||||||
|
|
||||||
const badges: {
|
|
||||||
label?: string;
|
|
||||||
description?: string;
|
|
||||||
image?: string;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
label: "label",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "label",
|
|
||||||
description: "Description",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Description",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "label",
|
|
||||||
description: "Description",
|
|
||||||
image: "/images/living_room.png",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "Description",
|
|
||||||
image: "/images/living_room.png",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "label",
|
|
||||||
image: "/images/living_room.png",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
image: "/images/living_room.png",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "big label",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "big label",
|
|
||||||
description: "Description",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "big label",
|
|
||||||
description: "Description",
|
|
||||||
image: "/images/living_room.png",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-ha-label-badge")
|
|
||||||
export class DemoHaLabelBadge extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card>
|
|
||||||
<div class="card-content">
|
|
||||||
${badges.map(
|
|
||||||
(badge) => html`
|
|
||||||
<ha-label-badge
|
|
||||||
style="--ha-label-badge-color: ${colors[
|
|
||||||
Math.floor(Math.random() * colors.length)
|
|
||||||
]}"
|
|
||||||
.label=${badge.label}
|
|
||||||
.description=${badge.description}
|
|
||||||
.image=${badge.image}
|
|
||||||
>
|
|
||||||
</ha-label-badge>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
<ha-card>
|
|
||||||
<div class="card-content">
|
|
||||||
${badges.map(
|
|
||||||
(badge) => html`
|
|
||||||
<div class="badge">
|
|
||||||
<ha-label-badge
|
|
||||||
style="--ha-label-badge-color: ${colors[
|
|
||||||
Math.floor(Math.random() * colors.length)
|
|
||||||
]}"
|
|
||||||
.label=${badge.label}
|
|
||||||
.description=${badge.description}
|
|
||||||
.image=${badge.image}
|
|
||||||
>
|
|
||||||
</ha-label-badge>
|
|
||||||
<pre>${JSON.stringify(badge, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
margin-left: 16px;
|
|
||||||
background-color: var(--markdown-code-background-color);
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
.badge {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-label-badge": DemoHaLabelBadge;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,131 +0,0 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import "@material/mwc-button";
|
|
||||||
import { LitElement, TemplateResult, css, html } from "lit";
|
|
||||||
import { customElement, state } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-selector/ha-selector";
|
|
||||||
import "../../../src/components/ha-settings-row";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import type { HomeAssistant } from "../../../src/types";
|
|
||||||
import "../components/demo-black-white-row";
|
|
||||||
import { BlueprintInput } from "../../../src/data/blueprint";
|
|
||||||
import { mockEntityRegistry } from "../../../demo/src/stubs/entity_registry";
|
|
||||||
import { mockDeviceRegistry } from "../../../demo/src/stubs/device_registry";
|
|
||||||
import { mockAreaRegistry } from "../../../demo/src/stubs/area_registry";
|
|
||||||
import { mockHassioSupervisor } from "../../../demo/src/stubs/hassio_supervisor";
|
|
||||||
|
|
||||||
const SCHEMAS: {
|
|
||||||
name: string;
|
|
||||||
input: Record<string, BlueprintInput | null>;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
name: "One of each",
|
|
||||||
input: {
|
|
||||||
entity: { name: "Entity", selector: { entity: {} } },
|
|
||||||
device: { name: "Device", selector: { device: {} } },
|
|
||||||
addon: { name: "Addon", selector: { addon: {} } },
|
|
||||||
area: { name: "Area", selector: { area: {} } },
|
|
||||||
target: { name: "Target", selector: { target: {} } },
|
|
||||||
number_box: {
|
|
||||||
name: "Number Box",
|
|
||||||
selector: {
|
|
||||||
number: {
|
|
||||||
min: 0,
|
|
||||||
max: 10,
|
|
||||||
mode: "box",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
number_slider: {
|
|
||||||
name: "Number Slider",
|
|
||||||
selector: {
|
|
||||||
number: {
|
|
||||||
min: 0,
|
|
||||||
max: 10,
|
|
||||||
mode: "slider",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
boolean: { name: "Boolean", selector: { boolean: {} } },
|
|
||||||
time: { name: "Time", selector: { time: {} } },
|
|
||||||
action: { name: "Action", selector: { action: {} } },
|
|
||||||
text: { name: "Text", selector: { text: { multiline: false } } },
|
|
||||||
text_multiline: {
|
|
||||||
name: "Text multiline",
|
|
||||||
selector: { text: { multiline: true } },
|
|
||||||
},
|
|
||||||
object: { name: "Object", selector: { object: {} } },
|
|
||||||
select: {
|
|
||||||
name: "Select",
|
|
||||||
selector: { select: { options: ["Option 1", "Option 2"] } },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-ha-selector")
|
|
||||||
class DemoHaSelector extends LitElement {
|
|
||||||
@state() private hass!: HomeAssistant;
|
|
||||||
|
|
||||||
private data = SCHEMAS.map(() => ({}));
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("config", "en");
|
|
||||||
mockEntityRegistry(hass);
|
|
||||||
mockDeviceRegistry(hass);
|
|
||||||
mockAreaRegistry(hass);
|
|
||||||
mockHassioSupervisor(hass);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
${SCHEMAS.map((info, idx) => {
|
|
||||||
const data = this.data[idx];
|
|
||||||
const valueChanged = (ev) => {
|
|
||||||
this.data[idx] = {
|
|
||||||
...data,
|
|
||||||
[ev.target.key]: ev.detail.value,
|
|
||||||
};
|
|
||||||
this.requestUpdate();
|
|
||||||
};
|
|
||||||
return html`
|
|
||||||
<demo-black-white-row .title=${info.name} .value=${this.data[idx]}>
|
|
||||||
${["light", "dark"].map((slot) =>
|
|
||||||
Object.entries(info.input).map(
|
|
||||||
([key, value]) =>
|
|
||||||
html`
|
|
||||||
<ha-settings-row narrow slot=${slot}>
|
|
||||||
<span slot="heading">${value?.name || key}</span>
|
|
||||||
<span slot="description">${value?.description}</span>
|
|
||||||
<ha-selector
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selector=${value!.selector}
|
|
||||||
.key=${key}
|
|
||||||
.value=${data[key] ?? value!.default}
|
|
||||||
@value-changed=${valueChanged}
|
|
||||||
></ha-selector>
|
|
||||||
</ha-settings-row>
|
|
||||||
`
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</demo-black-white-row>
|
|
||||||
`;
|
|
||||||
})}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
paper-input,
|
|
||||||
ha-selector {
|
|
||||||
width: 60;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-selector": DemoHaSelector;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,156 +0,0 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
|
||||||
import { customElement, query } from "lit/decorators";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import "../components/demo-cards";
|
|
||||||
|
|
||||||
const ENTITIES = [
|
|
||||||
getEntity("light", "bed_light", "on", {
|
|
||||||
friendly_name: "Bed Light",
|
|
||||||
}),
|
|
||||||
getEntity("switch", "bed_ac", "on", {
|
|
||||||
friendly_name: "Ecobee",
|
|
||||||
}),
|
|
||||||
getEntity("sensor", "bed_temp", "72", {
|
|
||||||
friendly_name: "Bedroom Temp",
|
|
||||||
device_class: "temperature",
|
|
||||||
unit_of_measurement: "°F",
|
|
||||||
}),
|
|
||||||
getEntity("light", "living_room_light", "off", {
|
|
||||||
friendly_name: "Living Room Light",
|
|
||||||
}),
|
|
||||||
getEntity("fan", "living_room", "on", {
|
|
||||||
friendly_name: "Living Room Fan",
|
|
||||||
}),
|
|
||||||
getEntity("sensor", "office_humidity", "73", {
|
|
||||||
friendly_name: "Office Humidity",
|
|
||||||
device_class: "humidity",
|
|
||||||
unit_of_measurement: "%",
|
|
||||||
}),
|
|
||||||
getEntity("light", "office", "on", {
|
|
||||||
friendly_name: "Office Light",
|
|
||||||
}),
|
|
||||||
getEntity("fan", "kitchen", "on", {
|
|
||||||
friendly_name: "Second Office Fan",
|
|
||||||
}),
|
|
||||||
getEntity("binary_sensor", "kitchen_door", "on", {
|
|
||||||
friendly_name: "Office Door",
|
|
||||||
device_class: "door",
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
// TODO: Update image here
|
|
||||||
const CONFIGS = [
|
|
||||||
{
|
|
||||||
heading: "Bedroom",
|
|
||||||
config: `
|
|
||||||
- type: area
|
|
||||||
area: bedroom
|
|
||||||
image: "/images/bed.png"
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Living Room",
|
|
||||||
config: `
|
|
||||||
- type: area
|
|
||||||
area: living_room
|
|
||||||
image: "/images/living_room.png"
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Office",
|
|
||||||
config: `
|
|
||||||
- type: area
|
|
||||||
area: office
|
|
||||||
image: "/images/office.jpg"
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Kitchen",
|
|
||||||
config: `
|
|
||||||
- type: area
|
|
||||||
area: kitchen
|
|
||||||
image: "/images/kitchen.png"
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-hui-area-card")
|
|
||||||
class DemoArea extends LitElement {
|
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
|
||||||
super.firstUpdated(changedProperties);
|
|
||||||
const hass = provideHass(this._demoRoot);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
|
||||||
hass.mockWS("config/area_registry/list", () => [
|
|
||||||
{
|
|
||||||
name: "Bedroom",
|
|
||||||
area_id: "bedroom",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Living Room",
|
|
||||||
area_id: "living_room",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Office",
|
|
||||||
area_id: "office",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Second Office",
|
|
||||||
area_id: "kitchen",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
hass.mockWS("config/device_registry/list", () => []);
|
|
||||||
hass.mockWS("config/entity_registry/list", () => [
|
|
||||||
{
|
|
||||||
area_id: "bedroom",
|
|
||||||
entity_id: "light.bed_light",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
area_id: "bedroom",
|
|
||||||
entity_id: "switch.bed_ac",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
area_id: "bedroom",
|
|
||||||
entity_id: "sensor.bed_temp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
area_id: "living_room",
|
|
||||||
entity_id: "light.living_room_light",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
area_id: "living_room",
|
|
||||||
entity_id: "fan.living_room",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
area_id: "office",
|
|
||||||
entity_id: "light.office",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
area_id: "office",
|
|
||||||
entity_id: "sensor.office_humidity",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
area_id: "kitchen",
|
|
||||||
entity_id: "fan.kitchen",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
area_id: "kitchen",
|
|
||||||
entity_id: "binary_sensor.kitchen_door",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-area-card": DemoArea;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,8 +2,6 @@ import { html, css, LitElement, TemplateResult } from "lit";
|
|||||||
import "../../../src/components/ha-formfield";
|
import "../../../src/components/ha-formfield";
|
||||||
import "../../../src/components/ha-switch";
|
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 { IntegrationManifest } from "../../../src/data/integration";
|
||||||
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
@@ -17,6 +15,8 @@ import type {
|
|||||||
} from "../../../src/panels/config/integrations/ha-config-integrations";
|
} from "../../../src/panels/config/integrations/ha-config-integrations";
|
||||||
import { DeviceRegistryEntry } from "../../../src/data/device_registry";
|
import { DeviceRegistryEntry } from "../../../src/data/device_registry";
|
||||||
import { EntityRegistryEntry } from "../../../src/data/entity_registry";
|
import { EntityRegistryEntry } from "../../../src/data/entity_registry";
|
||||||
|
import { classMap } from "lit/directives/class-map";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
|
||||||
const createConfigEntry = (
|
const createConfigEntry = (
|
||||||
title: string,
|
title: string,
|
||||||
@@ -187,7 +187,6 @@ const createEntityRegistryEntries = (
|
|||||||
device_id: "mock-device-id",
|
device_id: "mock-device-id",
|
||||||
area_id: null,
|
area_id: null,
|
||||||
disabled_by: null,
|
disabled_by: null,
|
||||||
entity_category: null,
|
|
||||||
entity_id: "binary_sensor.updater",
|
entity_id: "binary_sensor.updater",
|
||||||
name: null,
|
name: null,
|
||||||
icon: null,
|
icon: null,
|
||||||
@@ -212,7 +211,6 @@ const createDeviceRegistryEntries = (
|
|||||||
area_id: null,
|
area_id: null,
|
||||||
name_by_user: null,
|
name_by_user: null,
|
||||||
disabled_by: null,
|
disabled_by: null,
|
||||||
configuration_url: null,
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, html, LitElement, TemplateResult } from "lit";
|
import { html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement } from "lit/decorators";
|
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";
|
||||||
@@ -9,6 +9,7 @@ import { actionHandler } from "../../../src/panels/lovelace/common/directives/ac
|
|||||||
export class DemoUtilLongPress extends LitElement {
|
export class DemoUtilLongPress extends LitElement {
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
|
${this.renderStyle()}
|
||||||
${[1, 2, 3].map(
|
${[1, 2, 3].map(
|
||||||
() => html`
|
() => html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
@@ -40,22 +41,26 @@ export class DemoUtilLongPress extends LitElement {
|
|||||||
area.scrollTop = area.scrollHeight;
|
area.scrollTop = area.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
private renderStyle() {
|
||||||
ha-card {
|
return html`
|
||||||
width: 200px;
|
<style>
|
||||||
margin: calc(42vh - 140px) auto;
|
ha-card {
|
||||||
padding: 8px;
|
width: 200px;
|
||||||
text-align: center;
|
margin: calc(42vh - 140px) auto;
|
||||||
}
|
padding: 8px;
|
||||||
ha-card:first-of-type {
|
text-align: center;
|
||||||
margin-top: 16px;
|
}
|
||||||
}
|
ha-card:first-of-type {
|
||||||
ha-card:last-of-type {
|
margin-top: 16px;
|
||||||
margin-bottom: 16px;
|
}
|
||||||
}
|
ha-card:last-of-type {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
`;
|
</style>
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -65,11 +65,10 @@ class HaGallery extends PolymerElement {
|
|||||||
<app-header slot="header" fixed>
|
<app-header slot="header" fixed>
|
||||||
<app-toolbar>
|
<app-toolbar>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
|
icon="hass:arrow-left"
|
||||||
on-click="_backTapped"
|
on-click="_backTapped"
|
||||||
class$="[[_computeHeaderButtonClass(_demo)]]"
|
class$="[[_computeHeaderButtonClass(_demo)]]"
|
||||||
>
|
></ha-icon-button>
|
||||||
<ha-icon icon="hass:arrow-left"></ha-icon>
|
|
||||||
</ha-icon-button>
|
|
||||||
<div main-title>
|
<div main-title>
|
||||||
[[_withDefault(_demo, "Home Assistant Gallery")]]
|
[[_withDefault(_demo, "Home Assistant Gallery")]]
|
||||||
</div>
|
</div>
|
||||||
@@ -173,9 +172,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("hass-more-info", (ev) => {
|
this.addEventListener("hass-more-info", (ev) => {
|
||||||
if (ev.detail.entityId) {
|
if (ev.detail.entityId) {
|
||||||
this.$.notifications.showDialog({
|
this.$.notifications.showDialog({
|
||||||
|
@@ -4,7 +4,6 @@ import { property } from "lit/decorators";
|
|||||||
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";
|
||||||
import { caseInsensitiveStringCompare } from "../../../src/common/string/compare";
|
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
HassioAddonInfo,
|
HassioAddonInfo,
|
||||||
@@ -33,7 +32,7 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
return filterAndSort(addons, filter);
|
return filterAndSort(addons, filter);
|
||||||
}
|
}
|
||||||
return addons.sort((a, b) =>
|
return addons.sort((a, b) =>
|
||||||
caseInsensitiveStringCompare(a.name, b.name)
|
a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import "@material/mwc-icon-button/mwc-icon-button";
|
||||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
@@ -17,7 +18,7 @@ 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 { extractSearchParam } from "../../../src/common/url/search-params";
|
||||||
import "../../../src/components/ha-button-menu";
|
import "../../../src/components/ha-button-menu";
|
||||||
import "../../../src/components/ha-icon-button";
|
import "../../../src/components/ha-svg-icon";
|
||||||
import {
|
import {
|
||||||
HassioAddonInfo,
|
HassioAddonInfo,
|
||||||
HassioAddonRepository,
|
HassioAddonRepository,
|
||||||
@@ -25,10 +26,11 @@ import {
|
|||||||
} from "../../../src/data/hassio/addon";
|
} from "../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import "../../../src/layouts/hass-loading-screen";
|
import "../../../src/layouts/hass-loading-screen";
|
||||||
import "../../../src/layouts/hass-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import { HomeAssistant, Route } from "../../../src/types";
|
import { HomeAssistant, Route } from "../../../src/types";
|
||||||
import { showRegistriesDialog } from "../dialogs/registries/show-dialog-registries";
|
import { showRegistriesDialog } from "../dialogs/registries/show-dialog-registries";
|
||||||
import { showRepositoriesDialog } from "../dialogs/repositories/show-dialog-repositories";
|
import { showRepositoriesDialog } from "../dialogs/repositories/show-dialog-repositories";
|
||||||
|
import { supervisorTabs } from "../hassio-tabs";
|
||||||
import "./hassio-addon-repository";
|
import "./hassio-addon-repository";
|
||||||
|
|
||||||
const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => {
|
const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => {
|
||||||
@@ -75,22 +77,24 @@ class HassioAddonStore extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-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}
|
||||||
.header=${this.supervisor.localize("panel.store")}
|
.tabs=${supervisorTabs}
|
||||||
|
main-page
|
||||||
|
supervisor
|
||||||
>
|
>
|
||||||
|
<span slot="header"> ${this.supervisor.localize("panel.store")} </span>
|
||||||
<ha-button-menu
|
<ha-button-menu
|
||||||
corner="BOTTOM_START"
|
corner="BOTTOM_START"
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
@action=${this._handleAction}
|
@action=${this._handleAction}
|
||||||
>
|
>
|
||||||
<ha-icon-button
|
<mwc-icon-button slot="trigger" alt="menu">
|
||||||
.label=${this.supervisor.localize("common.menu")}
|
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
||||||
.path=${mdiDotsVertical}
|
</mwc-icon-button>
|
||||||
slot="trigger"
|
|
||||||
></ha-icon-button>
|
|
||||||
<mwc-list-item>
|
<mwc-list-item>
|
||||||
${this.supervisor.localize("store.repositories")}
|
${this.supervisor.localize("store.repositories")}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
@@ -109,7 +113,6 @@ class HassioAddonStore extends LitElement {
|
|||||||
: html`
|
: html`
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<search-input
|
<search-input
|
||||||
.hass=${this.hass}
|
|
||||||
no-label-float
|
no-label-float
|
||||||
no-underline
|
no-underline
|
||||||
.filter=${this._filter}
|
.filter=${this._filter}
|
||||||
@@ -128,7 +131,7 @@ class HassioAddonStore extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</hass-subpage>
|
</hass-tabs-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,6 @@ import {
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
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,
|
||||||
@@ -54,9 +53,7 @@ class HassioAddonAudio extends LitElement {
|
|||||||
.header=${this.supervisor.localize("addon.configuration.audio.header")}
|
.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=${this.supervisor.localize(
|
||||||
@@ -120,6 +117,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;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ 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 "@polymer/iron-autogrow-textarea/iron-autogrow-textarea";
|
||||||
import { DEFAULT_SCHEMA, Type } from "js-yaml";
|
import { DEFAULT_SCHEMA, Type } from "js-yaml";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
@@ -15,13 +16,11 @@ import { customElement, property, query, state } from "lit/decorators";
|
|||||||
import memoizeOne from "memoize-one";
|
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-alert";
|
|
||||||
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-form/ha-form";
|
import "../../../../src/components/ha-form/ha-form";
|
||||||
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
|
import type { HaFormSchema } from "../../../../src/components/ha-form/ha-form";
|
||||||
import "../../../../src/components/ha-formfield";
|
import "../../../../src/components/ha-formfield";
|
||||||
import "../../../../src/components/ha-icon-button";
|
|
||||||
import "../../../../src/components/ha-switch";
|
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";
|
||||||
@@ -78,18 +77,6 @@ class HassioAddonConfig extends LitElement {
|
|||||||
this.addon.translations.en?.configuration?.[entry.name].name ||
|
this.addon.translations.en?.configuration?.[entry.name].name ||
|
||||||
entry.name;
|
entry.name;
|
||||||
|
|
||||||
private _schema = memoizeOne((schema: HaFormSchema[]): HaFormSchema[] =>
|
|
||||||
// @ts-expect-error supervisor does not implement [string, string] for select.options[]
|
|
||||||
schema.map((entry) =>
|
|
||||||
entry.type === "select"
|
|
||||||
? {
|
|
||||||
...entry,
|
|
||||||
options: entry.options.map((option) => [option, option]),
|
|
||||||
}
|
|
||||||
: entry
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
private _filteredShchema = memoizeOne(
|
private _filteredShchema = memoizeOne(
|
||||||
(options: Record<string, unknown>, schema: HaFormSchema[]) =>
|
(options: Record<string, unknown>, schema: HaFormSchema[]) =>
|
||||||
schema.filter((entry) => entry.name in options || entry.required)
|
schema.filter((entry) => entry.name in options || entry.required)
|
||||||
@@ -113,11 +100,9 @@ class HassioAddonConfig extends LitElement {
|
|||||||
</h2>
|
</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}>
|
||||||
<ha-icon-button
|
<mwc-icon-button slot="trigger">
|
||||||
.label=${this.hass.localize("common.menu")}
|
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
||||||
.path=${mdiDotsVertical}
|
</mwc-icon-button>
|
||||||
slot="trigger"
|
|
||||||
></ha-icon-button>
|
|
||||||
<mwc-list-item .disabled=${!this._canShowSchema}>
|
<mwc-list-item .disabled=${!this._canShowSchema}>
|
||||||
${this._yamlMode
|
${this._yamlMode
|
||||||
? this.supervisor.localize(
|
? this.supervisor.localize(
|
||||||
@@ -140,32 +125,28 @@ class HassioAddonConfig extends LitElement {
|
|||||||
.data=${this._options!}
|
.data=${this._options!}
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
.computeLabel=${this.computeLabel}
|
.computeLabel=${this.computeLabel}
|
||||||
.schema=${this._schema(
|
.schema=${this._showOptional
|
||||||
this._showOptional
|
? this.addon.schema!
|
||||||
? this.addon.schema!
|
: this._filteredShchema(
|
||||||
: this._filteredShchema(
|
this.addon.options,
|
||||||
this.addon.options,
|
this.addon.schema!
|
||||||
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}
|
.schema=${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`
|
||||||
<ha-alert alert-type="error">
|
<div class="errors">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.configuration.options.invalid_yaml"
|
"addon.configuration.options.invalid_yaml"
|
||||||
)}
|
)}
|
||||||
</ha-alert>
|
</div>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
${hasHiddenOptions
|
${hasHiddenOptions
|
||||||
@@ -276,7 +257,7 @@ class HassioAddonConfig extends LitElement {
|
|||||||
path: "options",
|
path: "options",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.common.update_available",
|
"addon.common.update_available",
|
||||||
"error",
|
"error",
|
||||||
@@ -288,9 +269,6 @@ class HassioAddonConfig extends LitElement {
|
|||||||
|
|
||||||
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 = {
|
const eventdata = {
|
||||||
success: true,
|
success: true,
|
||||||
response: undefined,
|
response: undefined,
|
||||||
@@ -304,20 +282,20 @@ class HassioAddonConfig extends LitElement {
|
|||||||
const validation = await validateHassioAddonOption(
|
const validation = await validateHassioAddonOption(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.addon.slug,
|
this.addon.slug,
|
||||||
options
|
this._editor?.value
|
||||||
);
|
);
|
||||||
if (!validation.valid) {
|
if (!validation.valid) {
|
||||||
throw Error(validation.message);
|
throw Error(validation.message);
|
||||||
}
|
}
|
||||||
await setHassioAddonOption(this.hass, this.addon.slug, {
|
await setHassioAddonOption(this.hass, this.addon.slug, {
|
||||||
options,
|
options: this._yamlMode ? this._editor?.value : this._options,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._configHasChanged = false;
|
this._configHasChanged = false;
|
||||||
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.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -344,7 +322,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;
|
||||||
|
@@ -10,7 +10,6 @@ import {
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
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-alert";
|
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
@@ -63,9 +62,7 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<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>`
|
|
||||||
: ""}
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -89,9 +86,9 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
<td>
|
<td>
|
||||||
<paper-input
|
<paper-input
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
placeholder=${this.supervisor.localize(
|
placeholder="${this.supervisor.localize(
|
||||||
"addon.configuration.network.disabled"
|
"addon.configuration.network.disabled"
|
||||||
)}
|
)}"
|
||||||
.value=${item.host ? String(item.host) : ""}
|
.value=${item.host ? String(item.host) : ""}
|
||||||
.container=${item.container}
|
.container=${item.container}
|
||||||
no-label-float
|
no-label-float
|
||||||
@@ -171,7 +168,7 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
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.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_reset",
|
"addon.failed_to_reset",
|
||||||
"error",
|
"error",
|
||||||
@@ -207,7 +204,7 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
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.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -228,6 +225,10 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
ha-card {
|
ha-card {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.errors {
|
||||||
|
color: var(--error-color);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
.card-actions {
|
.card-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import "../../../../src/components/ha-alert";
|
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import "../../../../src/components/ha-markdown";
|
import "../../../../src/components/ha-markdown";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import {
|
import {
|
||||||
fetchHassioAddonDocumentation,
|
fetchHassioAddonDocumentation,
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
@@ -14,6 +12,7 @@ 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";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
|
||||||
@customElement("hassio-addon-documentation-tab")
|
@customElement("hassio-addon-documentation-tab")
|
||||||
class HassioAddonDocumentationDashboard extends LitElement {
|
class HassioAddonDocumentationDashboard extends LitElement {
|
||||||
@@ -39,9 +38,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._error
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
|
||||||
: ""}
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._content
|
${this._content
|
||||||
? html`<ha-markdown .content=${this._content}></ha-markdown>`
|
? html`<ha-markdown .content=${this._content}></ha-markdown>`
|
||||||
@@ -79,7 +76,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
this.hass,
|
this.hass,
|
||||||
this.addon!.slug
|
this.addon!.slug
|
||||||
);
|
);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.documentation.get_logs",
|
"addon.documentation.get_logs",
|
||||||
"error",
|
"error",
|
||||||
|
@@ -108,6 +108,7 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.localizeFunc=${this.supervisor.localize}
|
.localizeFunc=${this.supervisor.localize}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
|
.backPath=${this.addon.version ? "/hassio/dashboard" : "/hassio/store"}
|
||||||
.route=${route}
|
.route=${route}
|
||||||
.tabs=${addonTabs}
|
.tabs=${addonTabs}
|
||||||
supervisor
|
supervisor
|
||||||
@@ -221,7 +222,7 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
try {
|
try {
|
||||||
const addoninfo = await fetchHassioAddonInfo(this.hass, addon);
|
const addoninfo = await fetchHassioAddonInfo(this.hass, addon);
|
||||||
this.addon = addoninfo;
|
this.addon = addoninfo;
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`;
|
this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`;
|
||||||
this.addon = undefined;
|
this.addon = undefined;
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@ 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 { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
import "./hassio-addon-info";
|
import "./hassio-addon-info";
|
||||||
|
|
||||||
@@ -12,8 +12,6 @@ import "./hassio-addon-info";
|
|||||||
class HassioAddonInfoDashboard extends LitElement {
|
class HassioAddonInfoDashboard extends LitElement {
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@property({ attribute: false }) public supervisor!: Supervisor;
|
||||||
@@ -29,7 +27,6 @@ class HassioAddonInfoDashboard extends LitElement {
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<hassio-addon-info
|
<hassio-addon-info
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.route=${this.route}
|
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
.supervisor=${this.supervisor}
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import {
|
import {
|
||||||
|
mdiArrowUpBoldCircle,
|
||||||
mdiCheckCircle,
|
mdiCheckCircle,
|
||||||
mdiChip,
|
mdiChip,
|
||||||
mdiCircle,
|
mdiCircle,
|
||||||
@@ -10,12 +11,6 @@ import {
|
|||||||
mdiHomeAssistant,
|
mdiHomeAssistant,
|
||||||
mdiKey,
|
mdiKey,
|
||||||
mdiNetwork,
|
mdiNetwork,
|
||||||
mdiNumeric1,
|
|
||||||
mdiNumeric2,
|
|
||||||
mdiNumeric3,
|
|
||||||
mdiNumeric4,
|
|
||||||
mdiNumeric5,
|
|
||||||
mdiNumeric6,
|
|
||||||
mdiPound,
|
mdiPound,
|
||||||
mdiShield,
|
mdiShield,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
@@ -28,9 +23,8 @@ import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|||||||
import { navigate } from "../../../../src/common/navigate";
|
import { navigate } from "../../../../src/common/navigate";
|
||||||
import "../../../../src/components/buttons/ha-call-api-button";
|
import "../../../../src/components/buttons/ha-call-api-button";
|
||||||
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 "../../../../src/components/ha-chip";
|
import "../../../../src/components/ha-label-badge";
|
||||||
import "../../../../src/components/ha-markdown";
|
import "../../../../src/components/ha-markdown";
|
||||||
import "../../../../src/components/ha-settings-row";
|
import "../../../../src/components/ha-settings-row";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
import "../../../../src/components/ha-svg-icon";
|
||||||
@@ -48,6 +42,7 @@ import {
|
|||||||
startHassioAddon,
|
startHassioAddon,
|
||||||
stopHassioAddon,
|
stopHassioAddon,
|
||||||
uninstallHassioAddon,
|
uninstallHassioAddon,
|
||||||
|
updateHassioAddon,
|
||||||
validateHassioAddonOption,
|
validateHassioAddonOption,
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import {
|
import {
|
||||||
@@ -62,14 +57,14 @@ import {
|
|||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
} from "../../../../src/dialogs/generic/show-dialog-box";
|
} from "../../../../src/dialogs/generic/show-dialog-box";
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { bytesToString } from "../../../../src/util/bytes-to-string";
|
import { bytesToString } from "../../../../src/util/bytes-to-string";
|
||||||
import "../../components/hassio-card-content";
|
import "../../components/hassio-card-content";
|
||||||
import "../../components/supervisor-metric";
|
import "../../components/supervisor-metric";
|
||||||
import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown";
|
import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown";
|
||||||
|
import { showDialogSupervisorUpdate } from "../../dialogs/update/show-dialog-update";
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
import "../../update-available/update-available-card";
|
import { addonArchIsSupported } from "../../util/addon";
|
||||||
import { addonArchIsSupported, extractChangelog } from "../../util/addon";
|
|
||||||
|
|
||||||
const STAGE_ICON = {
|
const STAGE_ICON = {
|
||||||
stable: mdiCheckCircle,
|
stable: mdiCheckCircle,
|
||||||
@@ -77,21 +72,10 @@ const STAGE_ICON = {
|
|||||||
deprecated: mdiExclamationThick,
|
deprecated: mdiExclamationThick,
|
||||||
};
|
};
|
||||||
|
|
||||||
const RATING_ICON = {
|
|
||||||
1: mdiNumeric1,
|
|
||||||
2: mdiNumeric2,
|
|
||||||
3: mdiNumeric3,
|
|
||||||
4: mdiNumeric4,
|
|
||||||
5: mdiNumeric5,
|
|
||||||
6: mdiNumeric6,
|
|
||||||
};
|
|
||||||
|
|
||||||
@customElement("hassio-addon-info")
|
@customElement("hassio-addon-info")
|
||||||
class HassioAddonInfo extends LitElement {
|
class HassioAddonInfo extends LitElement {
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
@@ -128,35 +112,91 @@ class HassioAddonInfo extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
${this.addon.update_available
|
${this.addon.update_available
|
||||||
? html`
|
? html`
|
||||||
<update-available-card
|
<ha-card
|
||||||
.hass=${this.hass}
|
.header="${this.supervisor.localize(
|
||||||
.narrow=${this.narrow}
|
"common.update_available",
|
||||||
.supervisor=${this.supervisor}
|
"count",
|
||||||
.addonSlug=${this.addon.slug}
|
1
|
||||||
></update-available-card>
|
)}🎉"
|
||||||
|
>
|
||||||
|
<div class="card-content">
|
||||||
|
<hassio-card-content
|
||||||
|
.hass=${this.hass}
|
||||||
|
.title="${this.supervisor.localize(
|
||||||
|
"addon.dashboard.new_update_available",
|
||||||
|
"name",
|
||||||
|
this.addon.name,
|
||||||
|
"version",
|
||||||
|
this.addon.version_latest
|
||||||
|
)}"
|
||||||
|
.description="${this.supervisor.localize(
|
||||||
|
"common.running_version",
|
||||||
|
"version",
|
||||||
|
this.addon.version
|
||||||
|
)}"
|
||||||
|
icon=${mdiArrowUpBoldCircle}
|
||||||
|
iconClass="update"
|
||||||
|
></hassio-card-content>
|
||||||
|
${!this.addon.available && addonStoreInfo
|
||||||
|
? !addonArchIsSupported(
|
||||||
|
this.supervisor.info.supported_arch,
|
||||||
|
this.addon.arch
|
||||||
|
)
|
||||||
|
? html`
|
||||||
|
<p class="warning">
|
||||||
|
${this.supervisor.localize(
|
||||||
|
"addon.dashboard.not_available_arch"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<p class="warning">
|
||||||
|
${this.supervisor.localize(
|
||||||
|
"addon.dashboard.not_available_arch",
|
||||||
|
"core_version_installed",
|
||||||
|
this.supervisor.core.version,
|
||||||
|
"core_version_needed",
|
||||||
|
addonStoreInfo.homeassistant
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
${this.addon.changelog
|
||||||
|
? html`
|
||||||
|
<mwc-button @click=${this._openChangelog}>
|
||||||
|
${this.supervisor.localize("addon.dashboard.changelog")}
|
||||||
|
</mwc-button>
|
||||||
|
`
|
||||||
|
: html`<span></span>`}
|
||||||
|
<mwc-button @click=${this._updateClicked}>
|
||||||
|
${this.supervisor.localize("common.update")}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${!this.addon.protected
|
${!this.addon.protected
|
||||||
? html`
|
? html`
|
||||||
<ha-alert
|
<ha-card class="warning">
|
||||||
alert-type="error"
|
<h1 class="card-header">${this.supervisor.localize(
|
||||||
.title=${this.supervisor.localize(
|
"addon.dashboard.protection_mode.title"
|
||||||
"addon.dashboard.protection_mode.title"
|
)}
|
||||||
)}
|
</h1>
|
||||||
>
|
<div class="card-content">
|
||||||
|
${this.supervisor.localize("addon.dashboard.protection_mode.content")}
|
||||||
|
</div>
|
||||||
|
<div class="card-actions protection-enable">
|
||||||
|
<mwc-button @click=${this._protectionToggled}>
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.protection_mode.content"
|
"addon.dashboard.protection_mode.enable"
|
||||||
)}
|
)}
|
||||||
<mwc-button
|
|
||||||
slot="action"
|
|
||||||
.label=${this.supervisor.localize(
|
|
||||||
"addon.dashboard.protection_mode.enable"
|
|
||||||
)}
|
|
||||||
@click=${this._protectionToggled}
|
|
||||||
>
|
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</ha-alert>
|
</div>
|
||||||
`
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
|
||||||
<ha-card>
|
<ha-card>
|
||||||
@@ -208,169 +248,12 @@ class HassioAddonInfo extends LitElement {
|
|||||||
>`}
|
>`}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="capabilities">
|
|
||||||
${this.addon.stage !== "stable"
|
|
||||||
? html` <ha-chip
|
|
||||||
hasIcon
|
|
||||||
class=${classMap({
|
|
||||||
yellow: this.addon.stage === "experimental",
|
|
||||||
red: this.addon.stage === "deprecated",
|
|
||||||
})}
|
|
||||||
@click=${this._showMoreInfo}
|
|
||||||
id="stage"
|
|
||||||
>
|
|
||||||
<ha-svg-icon
|
|
||||||
slot="icon"
|
|
||||||
.path=${STAGE_ICON[this.addon.stage]}
|
|
||||||
>
|
|
||||||
</ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
`addon.dashboard.capability.stages.${this.addon.stage}`
|
|
||||||
)}
|
|
||||||
</ha-chip>`
|
|
||||||
: ""}
|
|
||||||
|
|
||||||
<ha-chip
|
|
||||||
hasIcon
|
|
||||||
class=${classMap({
|
|
||||||
green: [5, 6].includes(Number(this.addon.rating)),
|
|
||||||
yellow: [3, 4].includes(Number(this.addon.rating)),
|
|
||||||
red: [1, 2].includes(Number(this.addon.rating)),
|
|
||||||
})}
|
|
||||||
@click=${this._showMoreInfo}
|
|
||||||
id="rating"
|
|
||||||
>
|
|
||||||
<ha-svg-icon slot="icon" .path=${RATING_ICON[this.addon.rating]}>
|
|
||||||
</ha-svg-icon>
|
|
||||||
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.rating"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
${this.addon.host_network
|
|
||||||
? html`
|
|
||||||
<ha-chip
|
|
||||||
hasIcon
|
|
||||||
@click=${this._showMoreInfo}
|
|
||||||
id="host_network"
|
|
||||||
>
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiNetwork}> </ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.host"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this.addon.full_access
|
|
||||||
? html`
|
|
||||||
<ha-chip
|
|
||||||
hasIcon
|
|
||||||
@click=${this._showMoreInfo}
|
|
||||||
id="full_access"
|
|
||||||
>
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiChip}></ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.hardware"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this.addon.homeassistant_api
|
|
||||||
? html`
|
|
||||||
<ha-chip
|
|
||||||
hasIcon
|
|
||||||
@click=${this._showMoreInfo}
|
|
||||||
id="homeassistant_api"
|
|
||||||
>
|
|
||||||
<ha-svg-icon
|
|
||||||
slot="icon"
|
|
||||||
.path=${mdiHomeAssistant}
|
|
||||||
></ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.core"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._computeHassioApi
|
|
||||||
? html`
|
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="hassio_api">
|
|
||||||
<ha-svg-icon
|
|
||||||
slot="icon"
|
|
||||||
.path=${mdiHomeAssistant}
|
|
||||||
></ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
`addon.dashboard.capability.role.${this.addon.hassio_role}`
|
|
||||||
) || this.addon.hassio_role}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this.addon.docker_api
|
|
||||||
? html`
|
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="docker_api">
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiDocker}></ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.docker"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this.addon.host_pid
|
|
||||||
? html`
|
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="host_pid">
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiPound}></ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.host_pid"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this.addon.apparmor !== "default"
|
|
||||||
? html`
|
|
||||||
<ha-chip
|
|
||||||
hasIcon
|
|
||||||
@click=${this._showMoreInfo}
|
|
||||||
class=${this._computeApparmorClassName}
|
|
||||||
id="apparmor"
|
|
||||||
>
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiShield}></ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.apparmor"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this.addon.auth_api
|
|
||||||
? html`
|
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="auth_api">
|
|
||||||
<ha-svg-icon slot="icon" .path=${mdiKey}></ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.auth"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this.addon.ingress
|
|
||||||
? html`
|
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="ingress">
|
|
||||||
<ha-svg-icon
|
|
||||||
slot="icon"
|
|
||||||
.path=${mdiCursorDefaultClickOutline}
|
|
||||||
></ha-svg-icon>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.ingress"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="description light-color">
|
<div class="description light-color">
|
||||||
${this.addon.description}.<br />
|
${this.addon.description}.<br />
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.visit_addon_page",
|
"addon.dashboard.visit_addon_page",
|
||||||
"name",
|
"name",
|
||||||
html`<a href=${this.addon.url!} target="_blank" rel="noreferrer"
|
html`<a href="${this.addon.url!}" target="_blank" rel="noreferrer"
|
||||||
>${this.addon.name}</a
|
>${this.addon.name}</a
|
||||||
>`
|
>`
|
||||||
)}
|
)}
|
||||||
@@ -385,13 +268,178 @@ class HassioAddonInfo extends LitElement {
|
|||||||
/>
|
/>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
<div class="security">
|
||||||
|
${this.addon.stage !== "stable"
|
||||||
|
? html` <ha-label-badge
|
||||||
|
class=${classMap({
|
||||||
|
yellow: this.addon.stage === "experimental",
|
||||||
|
red: this.addon.stage === "deprecated",
|
||||||
|
})}
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="stage"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.stage"
|
||||||
|
)}
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${STAGE_ICON[this.addon.stage]}
|
||||||
|
></ha-svg-icon>
|
||||||
|
</ha-label-badge>`
|
||||||
|
: ""}
|
||||||
|
|
||||||
|
<ha-label-badge
|
||||||
|
class=${classMap({
|
||||||
|
green: [5, 6].includes(Number(this.addon.rating)),
|
||||||
|
yellow: [3, 4].includes(Number(this.addon.rating)),
|
||||||
|
red: [1, 2].includes(Number(this.addon.rating)),
|
||||||
|
})}
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="rating"
|
||||||
|
.value=${this.addon.rating}
|
||||||
|
label="rating"
|
||||||
|
description=""
|
||||||
|
></ha-label-badge>
|
||||||
|
${this.addon.host_network
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="host_network"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.host"
|
||||||
|
)}
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiNetwork}></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this.addon.full_access
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="full_access"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.hardware"
|
||||||
|
)}
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiChip}></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this.addon.homeassistant_api
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="homeassistant_api"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.hass"
|
||||||
|
)}
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this._computeHassioApi
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="hassio_api"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.hassio"
|
||||||
|
)}
|
||||||
|
.description=${this.supervisor.localize(
|
||||||
|
`addon.dashboard.capability.role.${this.addon.hassio_role}`
|
||||||
|
) || this.addon.hassio_role}
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this.addon.docker_api
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="docker_api"
|
||||||
|
.label=".${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.docker"
|
||||||
|
)}"
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiDocker}></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this.addon.host_pid
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="host_pid"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.host_pid"
|
||||||
|
)}
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiPound}></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this.addon.apparmor
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
class=${this._computeApparmorClassName}
|
||||||
|
id="apparmor"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.apparmor"
|
||||||
|
)}
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiShield}></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this.addon.auth_api
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="auth_api"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.auth"
|
||||||
|
)}
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiKey}></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${this.addon.ingress
|
||||||
|
? html`
|
||||||
|
<ha-label-badge
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="ingress"
|
||||||
|
.label=${this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.ingress"
|
||||||
|
)}
|
||||||
|
description=""
|
||||||
|
>
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${mdiCursorDefaultClickOutline}
|
||||||
|
></ha-svg-icon>
|
||||||
|
</ha-label-badge>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
|
||||||
${this.addon.version
|
${this.addon.version
|
||||||
? html`
|
? html`
|
||||||
<div
|
<div
|
||||||
class=${classMap({
|
class="${classMap({
|
||||||
"addon-options": true,
|
"addon-options": true,
|
||||||
started: this.addon.state === "started",
|
started: this.addon.state === "started",
|
||||||
})}
|
})}"
|
||||||
>
|
>
|
||||||
<ha-settings-row ?three-line=${this.narrow}>
|
<ha-settings-row ?three-line=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
@@ -521,23 +569,21 @@ class HassioAddonInfo extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${this._error
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
|
||||||
: ""}
|
|
||||||
${!this.addon.version && addonStoreInfo && !this.addon.available
|
${!this.addon.version && addonStoreInfo && !this.addon.available
|
||||||
? !addonArchIsSupported(
|
? !addonArchIsSupported(
|
||||||
this.supervisor.info.supported_arch,
|
this.supervisor.info.supported_arch,
|
||||||
this.addon.arch
|
this.addon.arch
|
||||||
)
|
)
|
||||||
? html`
|
? html`
|
||||||
<ha-alert alert-type="warning">
|
<p class="warning">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.not_available_arch"
|
"addon.dashboard.not_available_arch"
|
||||||
)}
|
)}
|
||||||
</ha-alert>
|
</p>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<ha-alert alert-type="warning">
|
<p class="warning">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.not_available_version",
|
"addon.dashboard.not_available_version",
|
||||||
"core_version_installed",
|
"core_version_installed",
|
||||||
@@ -545,7 +591,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
"core_version_needed",
|
"core_version_needed",
|
||||||
addonStoreInfo!.homeassistant
|
addonStoreInfo!.homeassistant
|
||||||
)}
|
)}
|
||||||
</ha-alert>
|
</p>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
@@ -747,7 +793,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -769,7 +815,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -791,7 +837,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -813,7 +859,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "security",
|
path: "security",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -835,7 +881,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -850,12 +896,11 @@ class HassioAddonInfo extends LitElement {
|
|||||||
this.hass,
|
this.hass,
|
||||||
this.addon.slug
|
this.addon.slug
|
||||||
);
|
);
|
||||||
|
|
||||||
showHassioMarkdownDialog(this, {
|
showHassioMarkdownDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.changelog"),
|
title: this.supervisor.localize("addon.dashboard.changelog"),
|
||||||
content: extractChangelog(this.addon, content),
|
content,
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"addon.dashboard.action_error.get_changelog"
|
"addon.dashboard.action_error.get_changelog"
|
||||||
@@ -877,7 +922,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "install",
|
path: "install",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.install"),
|
title: this.supervisor.localize("addon.dashboard.action_error.install"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -898,7 +943,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "stop",
|
path: "stop",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.stop"),
|
title: this.supervisor.localize("addon.dashboard.action_error.stop"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -919,7 +964,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "stop",
|
path: "stop",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.restart"),
|
title: this.supervisor.localize("addon.dashboard.action_error.restart"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -928,6 +973,34 @@ class HassioAddonInfo extends LitElement {
|
|||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _updateClicked(): Promise<void> {
|
||||||
|
showDialogSupervisorUpdate(this, {
|
||||||
|
supervisor: this.supervisor,
|
||||||
|
name: this.addon.name,
|
||||||
|
slug: this.addon.slug,
|
||||||
|
version: this.addon.version_latest,
|
||||||
|
snapshotParams: {
|
||||||
|
name: `addon_${this.addon.slug}_${this.addon.version}`,
|
||||||
|
addons: [this.addon.slug],
|
||||||
|
homeassistant: false,
|
||||||
|
},
|
||||||
|
updateHandler: async () => this._updateAddon(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _updateAddon(): Promise<void> {
|
||||||
|
await updateHassioAddon(this.hass, this.addon.slug);
|
||||||
|
fireEvent(this, "supervisor-collection-refresh", {
|
||||||
|
collection: "addon",
|
||||||
|
});
|
||||||
|
const eventdata = {
|
||||||
|
success: true,
|
||||||
|
response: undefined,
|
||||||
|
path: "update",
|
||||||
|
};
|
||||||
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
|
}
|
||||||
|
|
||||||
private async _startClicked(ev: CustomEvent): Promise<void> {
|
private async _startClicked(ev: CustomEvent): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
button.progress = true;
|
button.progress = true;
|
||||||
@@ -951,7 +1024,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
button.progress = false;
|
button.progress = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to validate addon configuration",
|
title: "Failed to validate addon configuration",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -969,7 +1042,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "start",
|
path: "start",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.start"),
|
title: this.supervisor.localize("addon.dashboard.action_error.start"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -1007,7 +1080,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "uninstall",
|
path: "uninstall",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"addon.dashboard.action_error.uninstall"
|
"addon.dashboard.action_error.uninstall"
|
||||||
@@ -1068,7 +1141,6 @@ class HassioAddonInfo extends LitElement {
|
|||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
img.logo {
|
img.logo {
|
||||||
max-width: 100%;
|
|
||||||
max-height: 60px;
|
max-height: 60px;
|
||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
display: block;
|
display: block;
|
||||||
@@ -1078,10 +1150,10 @@ class HassioAddonInfo extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
ha-svg-icon.running {
|
ha-svg-icon.running {
|
||||||
color: var(--success-color);
|
color: var(--paper-green-400);
|
||||||
}
|
}
|
||||||
ha-svg-icon.stopped {
|
ha-svg-icon.stopped {
|
||||||
color: var(--error-color);
|
color: var(--google-red-300);
|
||||||
}
|
}
|
||||||
ha-call-api-button {
|
ha-call-api-button {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -1093,31 +1165,34 @@ class HassioAddonInfo extends LitElement {
|
|||||||
.description a {
|
.description a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
ha-chip {
|
|
||||||
text-transform: capitalize;
|
|
||||||
--ha-chip-text-color: var(--text-primary-color);
|
|
||||||
--ha-chip-background-color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
.red {
|
||||||
--ha-chip-background-color: var(--label-badge-red, #df4c1e);
|
--ha-label-badge-color: var(--label-badge-red, #df4c1e);
|
||||||
}
|
}
|
||||||
.blue {
|
.blue {
|
||||||
--ha-chip-background-color: var(--label-badge-blue, #039be5);
|
--ha-label-badge-color: var(--label-badge-blue, #039be5);
|
||||||
}
|
}
|
||||||
.green {
|
.green {
|
||||||
--ha-chip-background-color: var(--label-badge-green, #0da035);
|
--ha-label-badge-color: var(--label-badge-green, #0da035);
|
||||||
}
|
}
|
||||||
.yellow {
|
.yellow {
|
||||||
--ha-chip-background-color: var(--label-badge-yellow, #f4b400);
|
--ha-label-badge-color: var(--label-badge-yellow, #f4b400);
|
||||||
}
|
}
|
||||||
.capabilities {
|
.security {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
.card-actions {
|
.card-actions {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
.security h3 {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.security ha-label-badge {
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 4px;
|
||||||
|
--ha-label-badge-padding: 8px 0 0 0;
|
||||||
|
}
|
||||||
.changelog {
|
.changelog {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
@@ -1156,21 +1231,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
align-self: end;
|
align-self: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-alert mwc-button {
|
|
||||||
--mdc-theme-primary: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
update-available-card {
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
ha-chip {
|
|
||||||
line-height: 36px;
|
|
||||||
}
|
|
||||||
.addon-options {
|
.addon-options {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import "../../../../src/components/ha-alert";
|
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
fetchHassioAddonLogs,
|
fetchHassioAddonLogs,
|
||||||
@@ -35,9 +34,7 @@ class HassioAddonLogs extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<h1>${this.addon.name}</h1>
|
<h1>${this.addon.name}</h1>
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._error
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
|
||||||
: ""}
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._content
|
${this._content
|
||||||
? html`<hassio-ansi-to-html
|
? html`<hassio-ansi-to-html
|
||||||
@@ -63,6 +60,10 @@ class HassioAddonLogs extends LitElement {
|
|||||||
ha-card {
|
ha-card {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
.errors {
|
||||||
|
color: var(--error-color);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -71,7 +72,7 @@ class HassioAddonLogs extends LitElement {
|
|||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
try {
|
try {
|
||||||
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
|
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.logs.get_logs",
|
"addon.logs.get_logs",
|
||||||
"error",
|
"error",
|
||||||
|
@@ -41,16 +41,16 @@ class HassioAnsiToHtml extends LitElement {
|
|||||||
text-decoration: underline line-through;
|
text-decoration: underline line-through;
|
||||||
}
|
}
|
||||||
.fg-red {
|
.fg-red {
|
||||||
color: var(--error-color);
|
color: rgb(222, 56, 43);
|
||||||
}
|
}
|
||||||
.fg-green {
|
.fg-green {
|
||||||
color: var(--success-color);
|
color: rgb(57, 181, 74);
|
||||||
}
|
}
|
||||||
.fg-yellow {
|
.fg-yellow {
|
||||||
color: var(--warning-color);
|
color: rgb(255, 199, 6);
|
||||||
}
|
}
|
||||||
.fg-blue {
|
.fg-blue {
|
||||||
color: var(--info-color);
|
color: rgb(0, 111, 184);
|
||||||
}
|
}
|
||||||
.fg-magenta {
|
.fg-magenta {
|
||||||
color: rgb(118, 38, 113);
|
color: rgb(118, 38, 113);
|
||||||
@@ -65,16 +65,16 @@ class HassioAnsiToHtml extends LitElement {
|
|||||||
background-color: rgb(0, 0, 0);
|
background-color: rgb(0, 0, 0);
|
||||||
}
|
}
|
||||||
.bg-red {
|
.bg-red {
|
||||||
background-color: var(--error-color);
|
background-color: rgb(222, 56, 43);
|
||||||
}
|
}
|
||||||
.bg-green {
|
.bg-green {
|
||||||
background-color: var(--success-color);
|
background-color: rgb(57, 181, 74);
|
||||||
}
|
}
|
||||||
.bg-yellow {
|
.bg-yellow {
|
||||||
background-color: var(--warning-color);
|
background-color: rgb(255, 199, 6);
|
||||||
}
|
}
|
||||||
.bg-blue {
|
.bg-blue {
|
||||||
background-color: var(--info-color);
|
background-color: rgb(0, 111, 184);
|
||||||
}
|
}
|
||||||
.bg-magenta {
|
.bg-magenta {
|
||||||
background-color: rgb(118, 38, 113);
|
background-color: rgb(118, 38, 113);
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { mdiHelpCircle } from "@mdi/js";
|
import { mdiHelpCircle } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import "../../../src/components/ha-relative-time";
|
||||||
import "../../../src/components/ha-svg-icon";
|
import "../../../src/components/ha-svg-icon";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@ class HassioCardContent extends LitElement {
|
|||||||
|
|
||||||
@property() public topbarClass?: string;
|
@property() public topbarClass?: string;
|
||||||
|
|
||||||
|
@property() public datetime?: string;
|
||||||
|
|
||||||
@property() public iconTitle?: string;
|
@property() public iconTitle?: string;
|
||||||
|
|
||||||
@property() public iconClass?: string;
|
@property() public iconClass?: string;
|
||||||
@@ -34,7 +37,7 @@ class HassioCardContent extends LitElement {
|
|||||||
${this.iconImage
|
${this.iconImage
|
||||||
? html`
|
? html`
|
||||||
<div class="icon_image ${this.iconClass}">
|
<div class="icon_image ${this.iconClass}">
|
||||||
<img src=${this.iconImage} .title=${this.iconTitle} />
|
<img src="${this.iconImage}" .title=${this.iconTitle} />
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -53,6 +56,15 @@ class HassioCardContent extends LitElement {
|
|||||||
/* treat as available when undefined */
|
/* treat as available when undefined */
|
||||||
this.available === false ? " (Not available)" : ""
|
this.available === false ? " (Not available)" : ""
|
||||||
}
|
}
|
||||||
|
${this.datetime
|
||||||
|
? html`
|
||||||
|
<ha-relative-time
|
||||||
|
.hass=${this.hass}
|
||||||
|
class="addition"
|
||||||
|
.datetime=${this.datetime}
|
||||||
|
></ha-relative-time>
|
||||||
|
`
|
||||||
|
: undefined}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -68,14 +80,14 @@ class HassioCardContent extends LitElement {
|
|||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
ha-svg-icon.update {
|
ha-svg-icon.update {
|
||||||
color: var(--warning-color);
|
color: var(--paper-orange-400);
|
||||||
}
|
}
|
||||||
ha-svg-icon.running,
|
ha-svg-icon.running,
|
||||||
ha-svg-icon.installed {
|
ha-svg-icon.installed {
|
||||||
color: var(--success-color);
|
color: var(--paper-green-400);
|
||||||
}
|
}
|
||||||
ha-svg-icon.hassupdate,
|
ha-svg-icon.hassupdate,
|
||||||
ha-svg-icon.backup {
|
ha-svg-icon.snapshot {
|
||||||
color: var(--paper-item-icon-color);
|
color: var(--paper-item-icon-color);
|
||||||
}
|
}
|
||||||
ha-svg-icon.not_available {
|
ha-svg-icon.not_available {
|
||||||
@@ -94,6 +106,9 @@ class HassioCardContent extends LitElement {
|
|||||||
height: 2.4em;
|
height: 2.4em;
|
||||||
line-height: 1.2em;
|
line-height: 1.2em;
|
||||||
}
|
}
|
||||||
|
ha-relative-time {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.icon_image img {
|
.icon_image img {
|
||||||
max-height: 40px;
|
max-height: 40px;
|
||||||
max-width: 40px;
|
max-width: 40px;
|
||||||
@@ -107,7 +122,7 @@ class HassioCardContent extends LitElement {
|
|||||||
}
|
}
|
||||||
.dot {
|
.dot {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: var(--warning-color);
|
background-color: var(--paper-orange-400);
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
|
@@ -1,24 +1,32 @@
|
|||||||
|
import "@material/mwc-icon-button/mwc-icon-button";
|
||||||
import { mdiFolderUpload } from "@mdi/js";
|
import { mdiFolderUpload } from "@mdi/js";
|
||||||
|
import "@polymer/iron-input/iron-input";
|
||||||
import "@polymer/paper-input/paper-input-container";
|
import "@polymer/paper-input/paper-input-container";
|
||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, state } from "lit/decorators";
|
import { customElement, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||||
import "../../../src/components/ha-circular-progress";
|
import "../../../src/components/ha-circular-progress";
|
||||||
import "../../../src/components/ha-file-upload";
|
import "../../../src/components/ha-file-upload";
|
||||||
import { HassioBackup, uploadBackup } from "../../../src/data/hassio/backup";
|
import "../../../src/components/ha-svg-icon";
|
||||||
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
||||||
|
import {
|
||||||
|
HassioSnapshot,
|
||||||
|
uploadSnapshot,
|
||||||
|
} from "../../../src/data/hassio/snapshot";
|
||||||
import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box";
|
import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HASSDomEvents {
|
interface HASSDomEvents {
|
||||||
"backup-uploaded": { backup: HassioBackup };
|
"snapshot-uploaded": { snapshot: HassioSnapshot };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("hassio-upload-backup")
|
const MAX_FILE_SIZE = 1 * 1024 * 1024 * 1024; // 1GB
|
||||||
export class HassioUploadBackup extends LitElement {
|
|
||||||
public hass?: HomeAssistant;
|
@customElement("hassio-upload-snapshot")
|
||||||
|
export class HassioUploadSnapshot extends LitElement {
|
||||||
|
public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() public value: string | null = null;
|
@state() public value: string | null = null;
|
||||||
|
|
||||||
@@ -27,11 +35,10 @@ export class HassioUploadBackup extends LitElement {
|
|||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-file-upload
|
<ha-file-upload
|
||||||
.hass=${this.hass}
|
|
||||||
.uploading=${this._uploading}
|
.uploading=${this._uploading}
|
||||||
.icon=${mdiFolderUpload}
|
.icon=${mdiFolderUpload}
|
||||||
accept="application/x-tar"
|
accept="application/x-tar"
|
||||||
label="Upload backup"
|
label="Upload snapshot"
|
||||||
@file-picked=${this._uploadFile}
|
@file-picked=${this._uploadFile}
|
||||||
auto-open-file-dialog
|
auto-open-file-dialog
|
||||||
></ha-file-upload>
|
></ha-file-upload>
|
||||||
@@ -41,19 +48,33 @@ export class HassioUploadBackup extends LitElement {
|
|||||||
private async _uploadFile(ev) {
|
private async _uploadFile(ev) {
|
||||||
const file = ev.detail.files[0];
|
const file = ev.detail.files[0];
|
||||||
|
|
||||||
|
if (file.size > MAX_FILE_SIZE) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: "Snapshot file is too big",
|
||||||
|
text: html`The maximum allowed filesize is 1GB.<br />
|
||||||
|
<a
|
||||||
|
href="https://www.home-assistant.io/hassio/haos_common_tasks/#restoring-a-snapshot-on-a-new-install"
|
||||||
|
target="_blank"
|
||||||
|
>Have a look here on how to restore it.</a
|
||||||
|
>`,
|
||||||
|
confirmText: "ok",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!["application/x-tar"].includes(file.type)) {
|
if (!["application/x-tar"].includes(file.type)) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Unsupported file format",
|
title: "Unsupported file format",
|
||||||
text: "Please choose a Home Assistant backup file (.tar)",
|
text: "Please choose a Home Assistant snapshot file (.tar)",
|
||||||
confirmText: "ok",
|
confirmText: "ok",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._uploading = true;
|
this._uploading = true;
|
||||||
try {
|
try {
|
||||||
const backup = await uploadBackup(this.hass, file);
|
const snapshot = await uploadSnapshot(this.hass, file);
|
||||||
fireEvent(this, "backup-uploaded", { backup: backup.data });
|
fireEvent(this, "snapshot-uploaded", { snapshot: snapshot.data });
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Upload failed",
|
title: "Upload failed",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -67,6 +88,6 @@ export class HassioUploadBackup extends LitElement {
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"hassio-upload-backup": HassioUploadBackup;
|
"hassio-upload-snapshot": HassioUploadSnapshot;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -20,10 +20,10 @@ class SupervisorMetric extends LitElement {
|
|||||||
<div slot="description" .title=${this.tooltip ?? ""}>
|
<div slot="description" .title=${this.tooltip ?? ""}>
|
||||||
<span class="value"> ${roundedValue} % </span>
|
<span class="value"> ${roundedValue} % </span>
|
||||||
<ha-bar
|
<ha-bar
|
||||||
class=${classMap({
|
class="${classMap({
|
||||||
"target-warning": roundedValue > 50,
|
"target-warning": roundedValue > 50,
|
||||||
"target-critical": roundedValue > 85,
|
"target-critical": roundedValue > 85,
|
||||||
})}
|
})}"
|
||||||
.value=${this.value}
|
.value=${this.value}
|
||||||
></ha-bar>
|
></ha-bar>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -11,10 +11,10 @@ import "../../../src/components/ha-formfield";
|
|||||||
import "../../../src/components/ha-radio";
|
import "../../../src/components/ha-radio";
|
||||||
import type { HaRadio } from "../../../src/components/ha-radio";
|
import type { HaRadio } from "../../../src/components/ha-radio";
|
||||||
import {
|
import {
|
||||||
HassioFullBackupCreateParams,
|
HassioFullSnapshotCreateParams,
|
||||||
HassioPartialBackupCreateParams,
|
HassioPartialSnapshotCreateParams,
|
||||||
HassioBackupDetail,
|
HassioSnapshotDetail,
|
||||||
} from "../../../src/data/hassio/backup";
|
} from "../../../src/data/hassio/snapshot";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import { PolymerChangedEvent } from "../../../src/polymer-types";
|
import { PolymerChangedEvent } from "../../../src/polymer-types";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
@@ -64,17 +64,17 @@ const _computeAddons = (addons): AddonCheckboxItem[] =>
|
|||||||
}))
|
}))
|
||||||
.sort((a, b) => (a.name > b.name ? 1 : -1));
|
.sort((a, b) => (a.name > b.name ? 1 : -1));
|
||||||
|
|
||||||
@customElement("supervisor-backup-content")
|
@customElement("supervisor-snapshot-content")
|
||||||
export class SupervisorBackupContent extends LitElement {
|
export class SupervisorSnapshotContent extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public localize?: LocalizeFunc;
|
@property() public localize?: LocalizeFunc;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor?: Supervisor;
|
@property({ attribute: false }) public supervisor?: Supervisor;
|
||||||
|
|
||||||
@property({ attribute: false }) public backup?: HassioBackupDetail;
|
@property({ attribute: false }) public snapshot?: HassioSnapshotDetail;
|
||||||
|
|
||||||
@property() public backupType: HassioBackupDetail["type"] = "full";
|
@property() public snapshotType: HassioSnapshotDetail["type"] = "full";
|
||||||
|
|
||||||
@property({ attribute: false }) public folders?: CheckboxItem[];
|
@property({ attribute: false }) public folders?: CheckboxItem[];
|
||||||
|
|
||||||
@@ -82,35 +82,37 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public homeAssistant = false;
|
@property({ type: Boolean }) public homeAssistant = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) public backupHasPassword = false;
|
@property({ type: Boolean }) public snapshotHasPassword = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) public onboarding = false;
|
@property({ type: Boolean }) public onboarding = false;
|
||||||
|
|
||||||
@property() public backupName = "";
|
@property() public snapshotName = "";
|
||||||
|
|
||||||
@property() public backupPassword = "";
|
@property() public snapshotPassword = "";
|
||||||
|
|
||||||
@property() public confirmBackupPassword = "";
|
@property() public confirmSnapshotPassword = "";
|
||||||
|
|
||||||
public willUpdate(changedProps) {
|
public willUpdate(changedProps) {
|
||||||
super.willUpdate(changedProps);
|
super.willUpdate(changedProps);
|
||||||
if (!this.hasUpdated) {
|
if (!this.hasUpdated) {
|
||||||
this.folders = _computeFolders(
|
this.folders = _computeFolders(
|
||||||
this.backup
|
this.snapshot
|
||||||
? this.backup.folders
|
? this.snapshot.folders
|
||||||
: ["homeassistant", "ssl", "share", "media", "addons/local"]
|
: ["homeassistant", "ssl", "share", "media", "addons/local"]
|
||||||
);
|
);
|
||||||
this.addons = _computeAddons(
|
this.addons = _computeAddons(
|
||||||
this.backup ? this.backup.addons : this.supervisor?.supervisor.addons
|
this.snapshot
|
||||||
|
? this.snapshot.addons
|
||||||
|
: this.supervisor?.supervisor.addons
|
||||||
);
|
);
|
||||||
this.backupType = this.backup?.type || "full";
|
this.snapshotType = this.snapshot?.type || "full";
|
||||||
this.backupName = this.backup?.name || "";
|
this.snapshotName = this.snapshot?.name || "";
|
||||||
this.backupHasPassword = this.backup?.protected || false;
|
this.snapshotHasPassword = this.snapshot?.protected || false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _localize = (string: string) =>
|
private _localize = (string: string) =>
|
||||||
this.supervisor?.localize(`backup.${string}`) ||
|
this.supervisor?.localize(`snapshot.${string}`) ||
|
||||||
this.localize!(`ui.panel.page-onboarding.restore.${string}`);
|
this.localize!(`ui.panel.page-onboarding.restore.${string}`);
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@@ -118,70 +120,72 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
const foldersSection =
|
const foldersSection =
|
||||||
this.backupType === "partial" ? this._getSection("folders") : undefined;
|
this.snapshotType === "partial" ? this._getSection("folders") : undefined;
|
||||||
const addonsSection =
|
const addonsSection =
|
||||||
this.backupType === "partial" ? this._getSection("addons") : undefined;
|
this.snapshotType === "partial" ? this._getSection("addons") : undefined;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${this.backup
|
${this.snapshot
|
||||||
? html`<div class="details">
|
? html`<div class="details">
|
||||||
${this.backup.type === "full"
|
${this.snapshot.type === "full"
|
||||||
? this._localize("full_backup")
|
? this._localize("full_snapshot")
|
||||||
: this._localize("partial_backup")}
|
: this._localize("partial_snapshot")}
|
||||||
(${Math.ceil(this.backup.size * 10) / 10 + " MB"})<br />
|
(${Math.ceil(this.snapshot.size * 10) / 10 + " MB"})<br />
|
||||||
${this.hass
|
${this.hass
|
||||||
? formatDateTime(new Date(this.backup.date), this.hass.locale)
|
? formatDateTime(new Date(this.snapshot.date), this.hass.locale)
|
||||||
: this.backup.date}
|
: this.snapshot.date}
|
||||||
</div>`
|
</div>`
|
||||||
: html`<paper-input
|
: html`<paper-input
|
||||||
name="backupName"
|
name="snapshotName"
|
||||||
.label=${this._localize("name")}
|
.label=${this.supervisor?.localize("snapshot.name") || "Name"}
|
||||||
.value=${this.backupName}
|
.value=${this.snapshotName}
|
||||||
@value-changed=${this._handleTextValueChanged}
|
@value-changed=${this._handleTextValueChanged}
|
||||||
>
|
>
|
||||||
</paper-input>`}
|
</paper-input>`}
|
||||||
${!this.backup || this.backup.type === "full"
|
${!this.snapshot || this.snapshot.type === "full"
|
||||||
? html`<div class="sub-header">
|
? html`<div class="sub-header">
|
||||||
${!this.backup
|
${!this.snapshot
|
||||||
? this._localize("type")
|
? this._localize("type")
|
||||||
: this._localize("select_type")}
|
: this._localize("select_type")}
|
||||||
</div>
|
</div>
|
||||||
<div class="backup-types">
|
<div class="snapshot-types">
|
||||||
<ha-formfield .label=${this._localize("full_backup")}>
|
<ha-formfield .label=${this._localize("full_snapshot")}>
|
||||||
<ha-radio
|
<ha-radio
|
||||||
@change=${this._handleRadioValueChanged}
|
@change=${this._handleRadioValueChanged}
|
||||||
value="full"
|
value="full"
|
||||||
name="backupType"
|
name="snapshotType"
|
||||||
.checked=${this.backupType === "full"}
|
.checked=${this.snapshotType === "full"}
|
||||||
>
|
>
|
||||||
</ha-radio>
|
</ha-radio>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
<ha-formfield .label=${this._localize("partial_backup")}>
|
<ha-formfield .label=${this._localize("partial_snapshot")}>
|
||||||
<ha-radio
|
<ha-radio
|
||||||
@change=${this._handleRadioValueChanged}
|
@change=${this._handleRadioValueChanged}
|
||||||
value="partial"
|
value="partial"
|
||||||
name="backupType"
|
name="snapshotType"
|
||||||
.checked=${this.backupType === "partial"}
|
.checked=${this.snapshotType === "partial"}
|
||||||
>
|
>
|
||||||
</ha-radio>
|
</ha-radio>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
</div>`
|
</div>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.backupType === "partial"
|
${this.snapshotType === "partial"
|
||||||
? html`<div class="partial-picker">
|
? html`<div class="partial-picker">
|
||||||
${this.backup && this.backup.homeassistant
|
${this.snapshot && this.snapshot.homeassistant
|
||||||
? html`
|
? html`
|
||||||
<ha-formfield
|
<ha-formfield
|
||||||
.label=${html`<supervisor-formfield-label
|
.label=${html`<supervisor-formfield-label
|
||||||
label="Home Assistant"
|
label="Home Assistant"
|
||||||
.iconPath=${mdiHomeAssistant}
|
.iconPath=${mdiHomeAssistant}
|
||||||
.version=${this.backup.homeassistant}
|
.version=${this.snapshot.homeassistant}
|
||||||
>
|
>
|
||||||
</supervisor-formfield-label>`}
|
</supervisor-formfield-label>`}
|
||||||
>
|
>
|
||||||
<ha-checkbox
|
<ha-checkbox
|
||||||
.checked=${this.homeAssistant}
|
.checked=${this.homeAssistant}
|
||||||
@click=${this.toggleHomeAssistant}
|
@click=${() => {
|
||||||
|
this.homeAssistant = !this.homeAssistant;
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
</ha-checkbox>
|
</ha-checkbox>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
@@ -229,38 +233,38 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
</div> `
|
</div> `
|
||||||
: ""}
|
: ""}
|
||||||
${this.backupType === "partial" &&
|
${this.snapshotType === "partial" &&
|
||||||
(!this.backup || this.backupHasPassword)
|
(!this.snapshot || this.snapshotHasPassword)
|
||||||
? html`<hr />`
|
? html`<hr />`
|
||||||
: ""}
|
: ""}
|
||||||
${!this.backup
|
${!this.snapshot
|
||||||
? html`<ha-formfield
|
? html`<ha-formfield
|
||||||
class="password"
|
class="password"
|
||||||
.label=${this._localize("password_protection")}
|
.label=${this._localize("password_protection")}
|
||||||
>
|
>
|
||||||
<ha-checkbox
|
<ha-checkbox
|
||||||
.checked=${this.backupHasPassword}
|
.checked=${this.snapshotHasPassword}
|
||||||
@change=${this._toggleHasPassword}
|
@change=${this._toggleHasPassword}
|
||||||
>
|
>
|
||||||
</ha-checkbox>
|
</ha-checkbox>
|
||||||
</ha-formfield>`
|
</ha-formfield>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.backupHasPassword
|
${this.snapshotHasPassword
|
||||||
? html`
|
? html`
|
||||||
<paper-input
|
<paper-input
|
||||||
.label=${this._localize("password")}
|
.label=${this._localize("password")}
|
||||||
type="password"
|
type="password"
|
||||||
name="backupPassword"
|
name="snapshotPassword"
|
||||||
.value=${this.backupPassword}
|
.value=${this.snapshotPassword}
|
||||||
@value-changed=${this._handleTextValueChanged}
|
@value-changed=${this._handleTextValueChanged}
|
||||||
>
|
>
|
||||||
</paper-input>
|
</paper-input>
|
||||||
${!this.backup
|
${!this.snapshot
|
||||||
? html` <paper-input
|
? html` <paper-input
|
||||||
.label=${this._localize("confirm_password")}
|
.label=${this.supervisor?.localize("confirm_password")}
|
||||||
type="password"
|
type="password"
|
||||||
name="confirmBackupPassword"
|
name="confirmSnapshotPassword"
|
||||||
.value=${this.confirmBackupPassword}
|
.value=${this.confirmSnapshotPassword}
|
||||||
@value-changed=${this._handleTextValueChanged}
|
@value-changed=${this._handleTextValueChanged}
|
||||||
>
|
>
|
||||||
</paper-input>`
|
</paper-input>`
|
||||||
@@ -270,10 +274,6 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private toggleHomeAssistant() {
|
|
||||||
this.homeAssistant = !this.homeAssistant;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
.partial-picker ha-formfield {
|
.partial-picker ha-formfield {
|
||||||
@@ -307,7 +307,7 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
display: block;
|
display: block;
|
||||||
margin: 0 -14px -16px;
|
margin: 0 -14px -16px;
|
||||||
}
|
}
|
||||||
.backup-types {
|
.snapshot-types {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-left: -13px;
|
margin-left: -13px;
|
||||||
}
|
}
|
||||||
@@ -317,23 +317,23 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public backupDetails():
|
public snapshotDetails():
|
||||||
| HassioPartialBackupCreateParams
|
| HassioPartialSnapshotCreateParams
|
||||||
| HassioFullBackupCreateParams {
|
| HassioFullSnapshotCreateParams {
|
||||||
const data: any = {};
|
const data: any = {};
|
||||||
|
|
||||||
if (!this.backup) {
|
if (!this.snapshot) {
|
||||||
data.name = this.backupName || formatDate(new Date(), this.hass.locale);
|
data.name = this.snapshotName || formatDate(new Date(), this.hass.locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.backupHasPassword) {
|
if (this.snapshotHasPassword) {
|
||||||
data.password = this.backupPassword;
|
data.password = this.snapshotPassword;
|
||||||
if (!this.backup) {
|
if (!this.snapshot) {
|
||||||
data.confirm_password = this.confirmBackupPassword;
|
data.confirm_password = this.confirmSnapshotPassword;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.backupType === "full") {
|
if (this.snapshotType === "full") {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,7 +415,7 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _toggleHasPassword(): void {
|
private _toggleHasPassword(): void {
|
||||||
this.backupHasPassword = !this.backupHasPassword;
|
this.snapshotHasPassword = !this.snapshotHasPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _toggleSection(ev): void {
|
private _toggleSection(ev): void {
|
||||||
@@ -445,6 +445,6 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"supervisor-backup-content": SupervisorBackupContent;
|
"supervisor-snapshot-content": SupervisorSnapshotContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -3,7 +3,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
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";
|
||||||
import { caseInsensitiveStringCompare } from "../../../src/common/string/compare";
|
import { compare } from "../../../src/common/string/compare";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
@@ -20,9 +20,7 @@ class HassioAddons extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${!atLeastVersion(this.hass.config.version, 2021, 12)
|
<h1>${this.supervisor.localize("dashboard.addons")}</h1>
|
||||||
? html` <h1>${this.supervisor.localize("dashboard.addons")}</h1> `
|
|
||||||
: ""}
|
|
||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
${!this.supervisor.supervisor.addons?.length
|
${!this.supervisor.supervisor.addons?.length
|
||||||
? html`
|
? html`
|
||||||
@@ -35,7 +33,7 @@ class HassioAddons extends LitElement {
|
|||||||
</ha-card>
|
</ha-card>
|
||||||
`
|
`
|
||||||
: this.supervisor.supervisor.addons
|
: this.supervisor.supervisor.addons
|
||||||
.sort((a, b) => caseInsensitiveStringCompare(a.name, b.name))
|
.sort((a, b) => compare(a.name, b.name))
|
||||||
.map(
|
.map(
|
||||||
(addon) => html`
|
(addon) => html`
|
||||||
<ha-card .addon=${addon} @click=${this._addonTapped}>
|
<ha-card .addon=${addon} @click=${this._addonTapped}>
|
||||||
|
@@ -1,8 +1,5 @@
|
|||||||
import { mdiStorePlus } from "@mdi/js";
|
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
|
||||||
import "../../../src/components/ha-fab";
|
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
@@ -28,37 +25,23 @@ class HassioDashboard extends LitElement {
|
|||||||
.localizeFunc=${this.supervisor.localize}
|
.localizeFunc=${this.supervisor.localize}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${supervisorTabs(this.hass)}
|
.tabs=${supervisorTabs}
|
||||||
main-page
|
main-page
|
||||||
supervisor
|
supervisor
|
||||||
hasFab
|
|
||||||
>
|
>
|
||||||
<span slot="header">
|
<span slot="header">
|
||||||
${this.supervisor.localize("panel.dashboard")}
|
${this.supervisor.localize("panel.dashboard")}
|
||||||
</span>
|
</span>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${this.hass.config.version.includes("dev") ||
|
<hassio-update
|
||||||
!atLeastVersion(this.hass.config.version, 2021, 12)
|
.hass=${this.hass}
|
||||||
? html`
|
.supervisor=${this.supervisor}
|
||||||
<hassio-update
|
></hassio-update>
|
||||||
.hass=${this.hass}
|
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-update>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<hassio-addons
|
<hassio-addons
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
.supervisor=${this.supervisor}
|
||||||
></hassio-addons>
|
></hassio-addons>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="/hassio/store" slot="fab">
|
|
||||||
<ha-fab .label=${this.supervisor.localize("panel.store")} extended>
|
|
||||||
<ha-svg-icon
|
|
||||||
slot="icon"
|
|
||||||
.path=${mdiStorePlus}
|
|
||||||
></ha-svg-icon> </ha-fab
|
|
||||||
></a>
|
|
||||||
</hass-tabs-subpage>
|
</hass-tabs-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@@ -3,18 +3,34 @@ import { mdiHomeAssistant } from "@mdi/js";
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
|
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-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/ha-settings-row";
|
import "../../../src/components/ha-settings-row";
|
||||||
import "../../../src/components/ha-svg-icon";
|
import "../../../src/components/ha-svg-icon";
|
||||||
|
import {
|
||||||
|
extractApiErrorMessage,
|
||||||
|
HassioResponse,
|
||||||
|
ignoreSupervisorError,
|
||||||
|
} from "../../../src/data/hassio/common";
|
||||||
import { HassioHassOSInfo } from "../../../src/data/hassio/host";
|
import { HassioHassOSInfo } from "../../../src/data/hassio/host";
|
||||||
import {
|
import {
|
||||||
HassioHomeAssistantInfo,
|
HassioHomeAssistantInfo,
|
||||||
HassioSupervisorInfo,
|
HassioSupervisorInfo,
|
||||||
} from "../../../src/data/hassio/supervisor";
|
} from "../../../src/data/hassio/supervisor";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { updateCore } from "../../../src/data/supervisor/core";
|
||||||
|
import {
|
||||||
|
Supervisor,
|
||||||
|
supervisorApiWsRequest,
|
||||||
|
} from "../../../src/data/supervisor/supervisor";
|
||||||
|
import {
|
||||||
|
showAlertDialog,
|
||||||
|
showConfirmationDialog,
|
||||||
|
} from "../../../src/dialogs/generic/show-dialog-box";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
|
import { showDialogSupervisorUpdate } from "../dialogs/update/show-dialog-update";
|
||||||
import { hassioStyle } from "../resources/hassio-style";
|
import { hassioStyle } from "../resources/hassio-style";
|
||||||
|
|
||||||
const computeVersion = (key: string, version: string): string =>
|
const computeVersion = (key: string, version: string): string =>
|
||||||
@@ -57,18 +73,26 @@ export class HassioUpdate extends LitElement {
|
|||||||
${this._renderUpdateCard(
|
${this._renderUpdateCard(
|
||||||
"Home Assistant Core",
|
"Home Assistant Core",
|
||||||
"core",
|
"core",
|
||||||
this.supervisor.core
|
this.supervisor.core,
|
||||||
|
"hassio/homeassistant/update",
|
||||||
|
`https://${
|
||||||
|
this.supervisor.core.version_latest.includes("b") ? "rc" : "www"
|
||||||
|
}.home-assistant.io/latest-release-notes/`
|
||||||
)}
|
)}
|
||||||
${this._renderUpdateCard(
|
${this._renderUpdateCard(
|
||||||
"Supervisor",
|
"Supervisor",
|
||||||
"supervisor",
|
"supervisor",
|
||||||
this.supervisor.supervisor
|
this.supervisor.supervisor,
|
||||||
|
"hassio/supervisor/update",
|
||||||
|
`https://github.com//home-assistant/hassio/releases/tag/${this.supervisor.supervisor.version_latest}`
|
||||||
)}
|
)}
|
||||||
${this.supervisor.host.features.includes("haos")
|
${this.supervisor.host.features.includes("hassos")
|
||||||
? this._renderUpdateCard(
|
? this._renderUpdateCard(
|
||||||
"Operating System",
|
"Operating System",
|
||||||
"os",
|
"os",
|
||||||
this.supervisor.os
|
this.supervisor.os,
|
||||||
|
"hassio/os/update",
|
||||||
|
`https://github.com//home-assistant/hassos/releases/tag/${this.supervisor.os.version_latest}`
|
||||||
)
|
)
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
@@ -79,7 +103,9 @@ export class HassioUpdate extends LitElement {
|
|||||||
private _renderUpdateCard(
|
private _renderUpdateCard(
|
||||||
name: string,
|
name: string,
|
||||||
key: string,
|
key: string,
|
||||||
object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo
|
object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo,
|
||||||
|
apiPath: string,
|
||||||
|
releaseNotesUrl: string
|
||||||
): TemplateResult {
|
): TemplateResult {
|
||||||
if (!object.update_available) {
|
if (!object.update_available) {
|
||||||
return html``;
|
return html``;
|
||||||
@@ -110,15 +136,97 @@ export class HassioUpdate extends LitElement {
|
|||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<a href="/hassio/update-available/${key}">
|
<a href="${releaseNotesUrl}" target="_blank" rel="noreferrer">
|
||||||
<mwc-button .label=${this.supervisor.localize("common.show")}>
|
<mwc-button>
|
||||||
|
${this.supervisor.localize("common.release_notes")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</a>
|
</a>
|
||||||
|
<ha-progress-button
|
||||||
|
.apiPath=${apiPath}
|
||||||
|
.name=${name}
|
||||||
|
.key=${key}
|
||||||
|
.version=${object.version_latest}
|
||||||
|
@click=${this._confirmUpdate}
|
||||||
|
>
|
||||||
|
${this.supervisor.localize("common.update")}
|
||||||
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _confirmUpdate(ev): Promise<void> {
|
||||||
|
const item = ev.currentTarget;
|
||||||
|
if (item.key === "core") {
|
||||||
|
showDialogSupervisorUpdate(this, {
|
||||||
|
supervisor: this.supervisor,
|
||||||
|
name: "Home Assistant Core",
|
||||||
|
slug: "core",
|
||||||
|
version: this.supervisor.core.version_latest,
|
||||||
|
snapshotParams: {
|
||||||
|
name: `core_${this.supervisor.core.version}`,
|
||||||
|
folders: ["homeassistant"],
|
||||||
|
homeassistant: true,
|
||||||
|
},
|
||||||
|
updateHandler: async () => this._updateCore(),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item.progress = true;
|
||||||
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
|
title: this.supervisor.localize(
|
||||||
|
"confirm.update.title",
|
||||||
|
"name",
|
||||||
|
item.name
|
||||||
|
),
|
||||||
|
text: this.supervisor.localize(
|
||||||
|
"confirm.update.text",
|
||||||
|
"name",
|
||||||
|
item.name,
|
||||||
|
"version",
|
||||||
|
computeVersion(item.key, item.version)
|
||||||
|
),
|
||||||
|
confirmText: this.supervisor.localize("common.update"),
|
||||||
|
dismissText: this.supervisor.localize("common.cancel"),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) {
|
||||||
|
item.progress = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
|
||||||
|
await supervisorApiWsRequest(this.hass.connection, {
|
||||||
|
method: "post",
|
||||||
|
endpoint: item.apiPath.replace("hassio", ""),
|
||||||
|
timeout: null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await this.hass.callApi<HassioResponse<void>>("POST", item.apiPath);
|
||||||
|
}
|
||||||
|
fireEvent(this, "supervisor-collection-refresh", {
|
||||||
|
collection: item.key,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// Only show an error if the status code was not expected (user behind proxy)
|
||||||
|
// or no status at all(connection terminated)
|
||||||
|
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.supervisor.localize("common.error.update_failed"),
|
||||||
|
text: extractApiErrorMessage(err),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.progress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _updateCore(): Promise<void> {
|
||||||
|
await updateCore(this.hass);
|
||||||
|
fireEvent(this, "supervisor-collection-refresh", {
|
||||||
|
collection: "core",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|
||||||
import "./dialog-hassio-backup-upload";
|
|
||||||
|
|
||||||
export interface HassioBackupUploadDialogParams {
|
|
||||||
showBackup: (slug: string) => void;
|
|
||||||
reloadBackup?: () => Promise<void>;
|
|
||||||
onboarding?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const showBackupUploadDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
dialogParams: HassioBackupUploadDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-hassio-backup-upload",
|
|
||||||
dialogImport: () => import("./dialog-hassio-backup-upload"),
|
|
||||||
dialogParams,
|
|
||||||
});
|
|
||||||
};
|
|
@@ -1,180 +0,0 @@
|
|||||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
|
||||||
import "@polymer/paper-item/paper-item";
|
|
||||||
import "@polymer/paper-listbox/paper-listbox";
|
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|
||||||
import "../../../../src/components/ha-circular-progress";
|
|
||||||
import "../../../../src/components/ha-markdown";
|
|
||||||
import {
|
|
||||||
extractApiErrorMessage,
|
|
||||||
ignoreSupervisorError,
|
|
||||||
} from "../../../../src/data/hassio/common";
|
|
||||||
import {
|
|
||||||
DatadiskList,
|
|
||||||
listDatadisks,
|
|
||||||
moveDatadisk,
|
|
||||||
} from "../../../../src/data/hassio/host";
|
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
|
||||||
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
|
||||||
import { HassioDatatiskDialogParams } from "./show-dialog-hassio-datadisk";
|
|
||||||
|
|
||||||
const calculateMoveTime = memoizeOne((supervisor: Supervisor): number => {
|
|
||||||
const speed = supervisor.host.disk_life_time !== "" ? 30 : 10;
|
|
||||||
const moveTime = (supervisor.host.disk_used * 1000) / 60 / speed;
|
|
||||||
const rebootTime = (supervisor.host.startup_time * 4) / 60;
|
|
||||||
return Math.ceil((moveTime + rebootTime) / 10) * 10;
|
|
||||||
});
|
|
||||||
|
|
||||||
@customElement("dialog-hassio-datadisk")
|
|
||||||
class HassioDatadiskDialog extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private dialogParams?: HassioDatatiskDialogParams;
|
|
||||||
|
|
||||||
@state() private selectedDevice?: string;
|
|
||||||
|
|
||||||
@state() private devices?: DatadiskList["devices"];
|
|
||||||
|
|
||||||
@state() private moving = false;
|
|
||||||
|
|
||||||
public showDialog(params: HassioDatatiskDialogParams) {
|
|
||||||
this.dialogParams = params;
|
|
||||||
listDatadisks(this.hass).then((data) => {
|
|
||||||
this.devices = data.devices;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeDialog(): void {
|
|
||||||
this.dialogParams = undefined;
|
|
||||||
this.selectedDevice = undefined;
|
|
||||||
this.devices = undefined;
|
|
||||||
this.moving = false;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.dialogParams) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<ha-dialog
|
|
||||||
open
|
|
||||||
scrimClickAction
|
|
||||||
escapeKeyAction
|
|
||||||
.heading=${this.moving
|
|
||||||
? this.dialogParams.supervisor.localize("dialog.datadisk_move.moving")
|
|
||||||
: this.dialogParams.supervisor.localize("dialog.datadisk_move.title")}
|
|
||||||
@closed=${this.closeDialog}
|
|
||||||
?hideActions=${this.moving}
|
|
||||||
>
|
|
||||||
${this.moving
|
|
||||||
? html` <ha-circular-progress alt="Moving" size="large" active>
|
|
||||||
</ha-circular-progress>
|
|
||||||
<p class="progress-text">
|
|
||||||
${this.dialogParams.supervisor.localize(
|
|
||||||
"dialog.datadisk_move.moving_desc"
|
|
||||||
)}
|
|
||||||
</p>`
|
|
||||||
: html` ${this.devices?.length
|
|
||||||
? html`
|
|
||||||
${this.dialogParams.supervisor.localize(
|
|
||||||
"dialog.datadisk_move.description",
|
|
||||||
{
|
|
||||||
current_path: this.dialogParams.supervisor.os.data_disk,
|
|
||||||
time: calculateMoveTime(this.dialogParams.supervisor),
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
<br /><br />
|
|
||||||
|
|
||||||
<paper-dropdown-menu
|
|
||||||
.label=${this.dialogParams.supervisor.localize(
|
|
||||||
"dialog.datadisk_move.select_device"
|
|
||||||
)}
|
|
||||||
@value-changed=${this._select_device}
|
|
||||||
>
|
|
||||||
<paper-listbox slot="dropdown-content">
|
|
||||||
${this.devices.map(
|
|
||||||
(device) => html`<paper-item>${device}</paper-item>`
|
|
||||||
)}
|
|
||||||
</paper-listbox>
|
|
||||||
</paper-dropdown-menu>
|
|
||||||
`
|
|
||||||
: this.devices === undefined
|
|
||||||
? this.dialogParams.supervisor.localize(
|
|
||||||
"dialog.datadisk_move.loading_devices"
|
|
||||||
)
|
|
||||||
: this.dialogParams.supervisor.localize(
|
|
||||||
"dialog.datadisk_move.no_devices"
|
|
||||||
)}
|
|
||||||
|
|
||||||
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
|
|
||||||
${this.dialogParams.supervisor.localize(
|
|
||||||
"dialog.datadisk_move.cancel"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
|
||||||
|
|
||||||
<mwc-button
|
|
||||||
.disabled=${!this.selectedDevice}
|
|
||||||
slot="primaryAction"
|
|
||||||
@click=${this._moveDatadisk}
|
|
||||||
>
|
|
||||||
${this.dialogParams.supervisor.localize(
|
|
||||||
"dialog.datadisk_move.move"
|
|
||||||
)}
|
|
||||||
</mwc-button>`}
|
|
||||||
</ha-dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _select_device(event) {
|
|
||||||
this.selectedDevice = event.detail.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _moveDatadisk() {
|
|
||||||
this.moving = true;
|
|
||||||
try {
|
|
||||||
await moveDatadisk(this.hass, this.selectedDevice!);
|
|
||||||
} catch (err: any) {
|
|
||||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: this.dialogParams!.supervisor.localize(
|
|
||||||
"system.host.failed_to_move"
|
|
||||||
),
|
|
||||||
text: extractApiErrorMessage(err),
|
|
||||||
});
|
|
||||||
this.closeDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return [
|
|
||||||
haStyle,
|
|
||||||
haStyleDialog,
|
|
||||||
css`
|
|
||||||
paper-dropdown-menu {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
ha-circular-progress {
|
|
||||||
display: block;
|
|
||||||
margin: 32px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-text {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"dialog-hassio-datadisk": HassioDatadiskDialog;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
|
|
||||||
export interface HassioDatatiskDialogParams {
|
|
||||||
supervisor: Supervisor;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const showHassioDatadiskDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
dialogParams: HassioDatatiskDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-hassio-datadisk",
|
|
||||||
dialogImport: () => import("./dialog-hassio-datadisk"),
|
|
||||||
dialogParams,
|
|
||||||
});
|
|
||||||
};
|
|
@@ -4,10 +4,9 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/common/search/search-input";
|
import "../../../../src/common/search/search-input";
|
||||||
import { stringCompare } from "../../../../src/common/string/compare";
|
import { compare } from "../../../../src/common/string/compare";
|
||||||
import "../../../../src/components/ha-dialog";
|
import "../../../../src/components/ha-dialog";
|
||||||
import "../../../../src/components/ha-expansion-panel";
|
import "../../../../src/components/ha-expansion-panel";
|
||||||
import "../../../../src/components/ha-icon-button";
|
|
||||||
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
|
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
|
||||||
import { dump } from "../../../../src/resources/js-yaml-dump";
|
import { dump } from "../../../../src/resources/js-yaml-dump";
|
||||||
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
||||||
@@ -28,7 +27,7 @@ const _filterDevices = memoizeOne(
|
|||||||
.toLocaleLowerCase()
|
.toLocaleLowerCase()
|
||||||
.includes(filter))
|
.includes(filter))
|
||||||
)
|
)
|
||||||
.sort((a, b) => stringCompare(a.name, b.name))
|
.sort((a, b) => compare(a.name, b.name))
|
||||||
);
|
);
|
||||||
|
|
||||||
@customElement("dialog-hassio-hardware")
|
@customElement("dialog-hassio-hardware")
|
||||||
@@ -71,13 +70,10 @@ class HassioHardwareDialog extends LitElement {
|
|||||||
<h2>
|
<h2>
|
||||||
${this._dialogParams.supervisor.localize("dialog.hardware.title")}
|
${this._dialogParams.supervisor.localize("dialog.hardware.title")}
|
||||||
</h2>
|
</h2>
|
||||||
<ha-icon-button
|
<mwc-icon-button dialogAction="close">
|
||||||
.label=${this.hass.localize("common.close")}
|
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
||||||
.path=${mdiClose}
|
</mwc-icon-button>
|
||||||
dialogAction="close"
|
|
||||||
></ha-icon-button>
|
|
||||||
<search-input
|
<search-input
|
||||||
.hass=${this.hass}
|
|
||||||
autofocus
|
autofocus
|
||||||
no-label-float
|
no-label-float
|
||||||
.filter=${this._filter}
|
.filter=${this._filter}
|
||||||
@@ -145,7 +141,7 @@ class HassioHardwareDialog extends LitElement {
|
|||||||
haStyle,
|
haStyle,
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
css`
|
css`
|
||||||
ha-icon-button {
|
mwc-icon-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
|
@@ -47,6 +47,11 @@ class HassioMarkdownDialog extends LitElement {
|
|||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
css`
|
css`
|
||||||
|
ha-paper-dialog {
|
||||||
|
min-width: 350px;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
app-toolbar {
|
app-toolbar {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
@@ -56,7 +61,24 @@ class HassioMarkdownDialog extends LitElement {
|
|||||||
app-toolbar [main-title] {
|
app-toolbar [main-title] {
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
}
|
}
|
||||||
|
paper-checkbox {
|
||||||
|
display: block;
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||||
|
ha-paper-dialog {
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
ha-paper-dialog::before {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
z-index: -1;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
app-toolbar {
|
app-toolbar {
|
||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user