mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-15 12:19:25 +00:00
Compare commits
44 Commits
multiple-a
...
lit-grid-l
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2fef57f0b2 | ||
![]() |
9b279632f8 | ||
![]() |
480e781364 | ||
![]() |
adc10ff0c6 | ||
![]() |
57a718e409 | ||
![]() |
23462bacfa | ||
![]() |
d99f8b0da8 | ||
![]() |
991d1f0997 | ||
![]() |
54e99357b5 | ||
![]() |
d263b5550a | ||
![]() |
a2b6ce3437 | ||
![]() |
9458f7ae62 | ||
![]() |
4d2ae36b0d | ||
![]() |
ebf0050e81 | ||
![]() |
3d0f492d62 | ||
![]() |
f5d3237b06 | ||
![]() |
07671ba1d4 | ||
![]() |
354d74ce1d | ||
![]() |
e892d14af0 | ||
![]() |
8d034fb7e7 | ||
![]() |
249456e6a0 | ||
![]() |
d3a6f31310 | ||
![]() |
4c31aead8b | ||
![]() |
3caf91c5d3 | ||
![]() |
9c3e754d53 | ||
![]() |
f48765c2b6 | ||
![]() |
236f26e652 | ||
![]() |
0fed96aba3 | ||
![]() |
70b77833f1 | ||
![]() |
307694a820 | ||
![]() |
402391c3e1 | ||
![]() |
81b5866e4d | ||
![]() |
09985bf5f7 | ||
![]() |
71d12a9e7a | ||
![]() |
5fd733b6c9 | ||
![]() |
bc3f827b4a | ||
![]() |
a807a182e4 | ||
![]() |
0a1fb843ca | ||
![]() |
fceb1568f5 | ||
![]() |
74e93bbefc | ||
![]() |
5c0f4b564b | ||
![]() |
76734f7a0b | ||
![]() |
440d10e4cd | ||
![]() |
a901072695 |
@@ -1,13 +0,0 @@
|
|||||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/python-3/.devcontainer/base.Dockerfile
|
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.9
|
|
||||||
|
|
||||||
ENV \
|
|
||||||
DEBIAN_FRONTEND=noninteractive \
|
|
||||||
DEVCONTAINER=true \
|
|
||||||
PATH=$PATH:./node_modules/.bin
|
|
||||||
|
|
||||||
# Install nvm
|
|
||||||
COPY .nvmrc /tmp/.nvmrc
|
|
||||||
RUN \
|
|
||||||
su vscode -c \
|
|
||||||
"source /usr/local/share/nvm/nvm.sh && nvm install $(cat /tmp/.nvmrc) 2>&1"
|
|
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Home Assistant Frontend",
|
|
||||||
"build": {
|
|
||||||
"dockerfile": "Dockerfile",
|
|
||||||
"context": ".."
|
|
||||||
},
|
|
||||||
"appPort": 8123,
|
|
||||||
"context": "..",
|
|
||||||
"postCreateCommand": "script/bootstrap",
|
|
||||||
"extensions": [
|
|
||||||
"github.vscode-pull-request-github",
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"bierner.lit-html",
|
|
||||||
"runem.lit-plugin",
|
|
||||||
"ms-python.vscode-pylance"
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"terminal.integrated.shell.linux": "/bin/bash",
|
|
||||||
"files.eol": "\n",
|
|
||||||
"editor.tabSize": 2,
|
|
||||||
"editor.formatOnPaste": false,
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"editor.formatOnType": true,
|
|
||||||
"[typescript]": {
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
},
|
|
||||||
"files.trimTrailingWhitespace": true
|
|
||||||
}
|
|
||||||
}
|
|
10
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
10
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
@@ -74,12 +74,12 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Problem-relevant frontend configuration
|
## Problem-relevant configuration
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
An example configuration that caused the problem for you, e.g. the YAML configuration
|
An example configuration that caused the problem for you. Fill this out even
|
||||||
of the used cards. Fill this out even if it seems unimportant to you. Please be sure
|
if it seems unimportant to you. Please be sure to remove personal information
|
||||||
to remove personal information like passwords, private URLs and other credentials.
|
like passwords, private URLs and other credentials.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -89,7 +89,7 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
|
|||||||
## Javascript errors shown in your browser console/inspector
|
## Javascript errors shown in your browser console/inspector
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
If you come across any Javascript or other error logs, e.g. in your browser
|
If you come across any javascript or other error logs, e.g., in your browser
|
||||||
console/inspector please provide them.
|
console/inspector please provide them.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -18,8 +18,8 @@
|
|||||||
<!--
|
<!--
|
||||||
Describe the big picture of your changes here to communicate to the
|
Describe the big picture of your changes here to communicate to the
|
||||||
maintainers why we should accept this pull request. If it fixes a bug
|
maintainers why we should accept this pull request. If it fixes a bug
|
||||||
or resolves a feature request, be sure to link to that issue or discussion
|
or resolves a feature request, be sure to link to that issue in the
|
||||||
in the additional information section.
|
additional information section.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Type of change
|
## Type of change
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
- This PR fixes or closes issue: fixes #
|
- This PR fixes or closes issue: fixes #
|
||||||
- This PR is related to issue or discussion:
|
- This PR is related to issue:
|
||||||
- Link to documentation pull request:
|
- Link to documentation pull request:
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
27
.github/lock.yml
vendored
Normal file
27
.github/lock.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
|
||||||
|
|
||||||
|
# Number of days of inactivity before a closed issue or pull request is locked
|
||||||
|
daysUntilLock: 1
|
||||||
|
|
||||||
|
# Skip issues and pull requests created before a given timestamp. Timestamp must
|
||||||
|
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
|
||||||
|
skipCreatedBefore: 2020-01-01
|
||||||
|
|
||||||
|
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
|
||||||
|
exemptLabels: []
|
||||||
|
|
||||||
|
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
||||||
|
lockLabel: false
|
||||||
|
|
||||||
|
# Comment to post before locking. Set to `false` to disable
|
||||||
|
lockComment: false
|
||||||
|
|
||||||
|
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
||||||
|
setLockReason: false
|
||||||
|
|
||||||
|
# Limit to only `issues` or `pulls`
|
||||||
|
only: pulls
|
||||||
|
|
||||||
|
# Optionally, specify configuration settings just for `issues` or `pulls`
|
||||||
|
issues:
|
||||||
|
daysUntilLock: 30
|
56
.github/stale.yml
vendored
Normal file
56
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Configuration for probot-stale - https://github.com/probot/stale
|
||||||
|
|
||||||
|
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||||
|
daysUntilStale: 90
|
||||||
|
|
||||||
|
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||||
|
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||||
|
daysUntilClose: 7
|
||||||
|
|
||||||
|
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||||
|
onlyLabels: []
|
||||||
|
|
||||||
|
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||||
|
exemptLabels:
|
||||||
|
- feature request
|
||||||
|
- Help wanted
|
||||||
|
- to do
|
||||||
|
|
||||||
|
# Set to true to ignore issues in a project (defaults to false)
|
||||||
|
exemptProjects: true
|
||||||
|
|
||||||
|
# Set to true to ignore issues in a milestone (defaults to false)
|
||||||
|
exemptMilestones: true
|
||||||
|
|
||||||
|
# Set to true to ignore issues with an assignee (defaults to false)
|
||||||
|
exemptAssignees: false
|
||||||
|
|
||||||
|
# Label to use when marking as stale
|
||||||
|
staleLabel: stale
|
||||||
|
|
||||||
|
# Comment to post when marking as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
There hasn't been any activity on this issue recently. Due to the high number
|
||||||
|
of incoming GitHub notifications, we have to clean some of the old issues,
|
||||||
|
as many of them have already been resolved with the latest updates.
|
||||||
|
|
||||||
|
Please make sure to update to the latest Home Assistant version and check
|
||||||
|
if that solves the issue. Let us know if that works for you by adding a
|
||||||
|
comment 👍
|
||||||
|
|
||||||
|
This issue now has been marked as stale and will be closed if no further
|
||||||
|
activity occurs. Thank you for your contributions.
|
||||||
|
|
||||||
|
# Comment to post when removing the stale label.
|
||||||
|
# unmarkComment: >
|
||||||
|
# Your comment here.
|
||||||
|
|
||||||
|
# Comment to post when closing a stale Issue or Pull Request.
|
||||||
|
# closeComment: >
|
||||||
|
# Your comment here.
|
||||||
|
|
||||||
|
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||||
|
limitPerRun: 30
|
||||||
|
|
||||||
|
# Limit to only `issues` or `pulls`
|
||||||
|
only: issues
|
20
.github/workflows/lock.yml
vendored
20
.github/workflows/lock.yml
vendored
@@ -1,20 +0,0 @@
|
|||||||
name: Lock
|
|
||||||
|
|
||||||
# yamllint disable-line rule:truthy
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 * * * *"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lock:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: dessant/lock-threads@v2.0.1
|
|
||||||
with:
|
|
||||||
github-token: ${{ github.token }}
|
|
||||||
issue-lock-inactive-days: "30"
|
|
||||||
issue-exclude-created-before: "2020-10-01T00:00:00Z"
|
|
||||||
issue-lock-reason: ""
|
|
||||||
pr-lock-inactive-days: "1"
|
|
||||||
pr-exclude-created-before: "2020-11-01T00:00:00Z"
|
|
||||||
pr-lock-reason: ""
|
|
42
.github/workflows/stale.yml
vendored
42
.github/workflows/stale.yml
vendored
@@ -1,42 +0,0 @@
|
|||||||
name: Stale
|
|
||||||
|
|
||||||
# yamllint disable-line rule:truthy
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 * * * *"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: 90 days stale policy
|
|
||||||
uses: actions/stale@v3.0.13
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
days-before-stale: 90
|
|
||||||
days-before-close: 7
|
|
||||||
operations-per-run: 25
|
|
||||||
remove-stale-when-updated: true
|
|
||||||
stale-issue-label: "stale"
|
|
||||||
exempt-issue-labels: "no-stale,Help%20wanted,help-wanted,feature-request,feature%20request"
|
|
||||||
stale-issue-message: >
|
|
||||||
There hasn't been any activity on this issue recently. Due to the
|
|
||||||
high number of incoming GitHub notifications, we have to clean some
|
|
||||||
of the old issues, as many of them have already been resolved with
|
|
||||||
the latest updates.
|
|
||||||
|
|
||||||
Please make sure to update to the latest Home Assistant version and
|
|
||||||
check if that solves the issue. Let us know if that works for you by
|
|
||||||
adding a comment 👍
|
|
||||||
|
|
||||||
This issue has now been marked as stale and will be closed if no
|
|
||||||
further activity occurs. Thank you for your contributions.
|
|
||||||
|
|
||||||
stale-pr-label: "stale"
|
|
||||||
exempt-pr-labels: "no-stale"
|
|
||||||
stale-pr-message: >
|
|
||||||
There hasn't been any activity on this pull request recently. This
|
|
||||||
pull request has been automatically marked as stale because of that
|
|
||||||
and will be closed if no further activity occurs within 7 days.
|
|
||||||
|
|
||||||
Thank you for your contributions.
|
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -23,8 +23,6 @@ dist
|
|||||||
# vscode
|
# vscode
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
|
|
||||||
# Cast dev settings
|
# Cast dev settings
|
||||||
src/cast/dev_const.ts
|
src/cast/dev_const.ts
|
||||||
@@ -35,6 +33,3 @@ yarn-error.log
|
|||||||
|
|
||||||
#asdf
|
#asdf
|
||||||
.tool-versions
|
.tool-versions
|
||||||
|
|
||||||
# Home Assistant config
|
|
||||||
/config
|
|
||||||
|
6
.hound.yml
Normal file
6
.hound.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
jshint:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
eslint:
|
||||||
|
enabled: true
|
||||||
|
config_file: .eslintrc-hound.json
|
44
.vscode/launch.json
vendored
44
.vscode/launch.json
vendored
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
// https://github.com/microsoft/vscode-js-debug/blob/master/OPTIONS.md
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Debug Frontend",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "pwa-chrome",
|
|
||||||
"url": "http://localhost:8123/",
|
|
||||||
"webRoot": "${workspaceFolder}/hass_frontend",
|
|
||||||
"disableNetworkCache": true,
|
|
||||||
"preLaunchTask": "Develop Frontend",
|
|
||||||
"outFiles": [
|
|
||||||
"${workspaceFolder}/hass_frontend/frontend_latest/*.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Debug Gallery",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "pwa-chrome",
|
|
||||||
"url": "http://localhost:8100/",
|
|
||||||
"webRoot": "${workspaceFolder}/gallery/dist",
|
|
||||||
"disableNetworkCache": true,
|
|
||||||
"preLaunchTask": "Develop Gallery"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Debug Demo",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "pwa-chrome",
|
|
||||||
"url": "http://localhost:8090/",
|
|
||||||
"webRoot": "${workspaceFolder}/demo/dist",
|
|
||||||
"disableNetworkCache": true,
|
|
||||||
"preLaunchTask": "Develop Demo"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Debug Cast",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "pwa-chrome",
|
|
||||||
"url": "http://localhost:8080/",
|
|
||||||
"webRoot": "${workspaceFolder}/cast/dist",
|
|
||||||
"disableNetworkCache": true,
|
|
||||||
"preLaunchTask": "Develop Cast"
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
208
.vscode/tasks.json
vendored
208
.vscode/tasks.json
vendored
@@ -1,208 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"label": "Develop Frontend",
|
|
||||||
"type": "gulp",
|
|
||||||
"task": "develop-app",
|
|
||||||
// Sync changes here to other tasks until issue resolved
|
|
||||||
// https://github.com/Microsoft/vscode/issues/61497
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "ha-build",
|
|
||||||
"source": "ha-build",
|
|
||||||
"fileLocation": "absolute",
|
|
||||||
"severity": "error",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
|
|
||||||
"severity": 1,
|
|
||||||
"file": 2,
|
|
||||||
"message": 3,
|
|
||||||
"line": 4,
|
|
||||||
"column": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": "Changes detected. Starting compilation",
|
|
||||||
"endsPattern": "Build done @"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"isBackground": true,
|
|
||||||
"group": {
|
|
||||||
"kind": "build",
|
|
||||||
"isDefault": true
|
|
||||||
},
|
|
||||||
"runOptions": {
|
|
||||||
"instanceLimit": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Develop Supervisor panel",
|
|
||||||
"type": "gulp",
|
|
||||||
"task": "develop-hassio",
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "ha-build",
|
|
||||||
"source": "ha-build",
|
|
||||||
"fileLocation": "absolute",
|
|
||||||
"severity": "error",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
|
|
||||||
"severity": 1,
|
|
||||||
"file": 2,
|
|
||||||
"message": 3,
|
|
||||||
"line": 4,
|
|
||||||
"column": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": "Changes detected. Starting compilation",
|
|
||||||
"endsPattern": "Build done @"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"isBackground": true,
|
|
||||||
"group": "build",
|
|
||||||
"runOptions": {
|
|
||||||
"instanceLimit": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Develop Gallery",
|
|
||||||
"type": "gulp",
|
|
||||||
"task": "develop-gallery",
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "ha-build",
|
|
||||||
"source": "ha-build",
|
|
||||||
"fileLocation": "absolute",
|
|
||||||
"severity": "error",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
|
|
||||||
"severity": 1,
|
|
||||||
"file": 2,
|
|
||||||
"message": 3,
|
|
||||||
"line": 4,
|
|
||||||
"column": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": "Changes detected. Starting compilation",
|
|
||||||
"endsPattern": "Build done @"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"isBackground": true,
|
|
||||||
"group": "build",
|
|
||||||
"runOptions": {
|
|
||||||
"instanceLimit": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Develop Demo",
|
|
||||||
"type": "gulp",
|
|
||||||
"task": "develop-demo",
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "ha-build",
|
|
||||||
"source": "ha-build",
|
|
||||||
"fileLocation": "absolute",
|
|
||||||
"severity": "error",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
|
|
||||||
"severity": 1,
|
|
||||||
"file": 2,
|
|
||||||
"message": 3,
|
|
||||||
"line": 4,
|
|
||||||
"column": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": "Changes detected. Starting compilation",
|
|
||||||
"endsPattern": "Build done @"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"isBackground": true,
|
|
||||||
"group": "build",
|
|
||||||
"runOptions": {
|
|
||||||
"instanceLimit": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Develop Cast",
|
|
||||||
"type": "gulp",
|
|
||||||
"task": "develop-cast",
|
|
||||||
"problemMatcher": {
|
|
||||||
"owner": "ha-build",
|
|
||||||
"source": "ha-build",
|
|
||||||
"fileLocation": "absolute",
|
|
||||||
"severity": "error",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
|
|
||||||
"severity": 1,
|
|
||||||
"file": 2,
|
|
||||||
"message": 3,
|
|
||||||
"line": 4,
|
|
||||||
"column": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"background": {
|
|
||||||
"activeOnStart": true,
|
|
||||||
"beginsPattern": "Changes detected. Starting compilation",
|
|
||||||
"endsPattern": "Build done @"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"isBackground": true,
|
|
||||||
"group": "build",
|
|
||||||
"runOptions": {
|
|
||||||
"instanceLimit": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Run HA Core in devcontainer",
|
|
||||||
"type": "shell",
|
|
||||||
"command": "script/core",
|
|
||||||
"isBackground": true,
|
|
||||||
"group": {
|
|
||||||
"kind": "build",
|
|
||||||
"isDefault": true
|
|
||||||
},
|
|
||||||
"problemMatcher": [],
|
|
||||||
"runOptions": {
|
|
||||||
"instanceLimit": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Run HA Core for Supervisor in devcontainer",
|
|
||||||
"type": "shell",
|
|
||||||
"command": "HASSIO=${input:supervisorHost} HASSIO_TOKEN=${input:supervisorToken} script/core",
|
|
||||||
"isBackground": true,
|
|
||||||
"group": {
|
|
||||||
"kind": "build",
|
|
||||||
"isDefault": true
|
|
||||||
},
|
|
||||||
"problemMatcher": [],
|
|
||||||
"runOptions": {
|
|
||||||
"instanceLimit": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"id": "supervisorHost",
|
|
||||||
"type": "promptString",
|
|
||||||
"description": "The IP of the Supervisor host running the Remote API proxy add-on"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "supervisorToken",
|
|
||||||
"type": "promptString",
|
|
||||||
"description": "The token for the Remote API proxy add-on"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@@ -14,7 +14,7 @@ This is the repository for the official [Home Assistant](https://home-assistant.
|
|||||||
- Development: [Instructions](https://developers.home-assistant.io/docs/frontend/development/)
|
- Development: [Instructions](https://developers.home-assistant.io/docs/frontend/development/)
|
||||||
- Production build: `script/build_frontend`
|
- Production build: `script/build_frontend`
|
||||||
- Gallery: `cd gallery && script/develop_gallery`
|
- Gallery: `cd gallery && script/develop_gallery`
|
||||||
- Supervisor: [Instructions](https://developers.home-assistant.io/docs/supervisor/developing)
|
- Hass.io: [Instructions](https://developers.home-assistant.io/docs/en/hassio_hass.html)
|
||||||
|
|
||||||
## Frontend development
|
## Frontend development
|
||||||
|
|
||||||
|
@@ -1,39 +0,0 @@
|
|||||||
# Bundling Home Assistant Frontend
|
|
||||||
|
|
||||||
The Home Assistant build pipeline contains various steps to prepare a build.
|
|
||||||
|
|
||||||
- Generating icon files to be included
|
|
||||||
- Generating translation files to be included
|
|
||||||
- Converting TypeScript, CSS and JSON files to JavaScript
|
|
||||||
- Bundling
|
|
||||||
- Minifying the files
|
|
||||||
- Generating the HTML entrypoint files
|
|
||||||
- Generating the service worker
|
|
||||||
- Compressing the files
|
|
||||||
|
|
||||||
## Converting files
|
|
||||||
|
|
||||||
Currently in Home Assistant we use a bundler to convert TypeScript, CSS and JSON files to JavaScript files that the browser understands.
|
|
||||||
|
|
||||||
We currently rely on Webpack but also have experimental Rollup support. Both of these programs bundle the converted files in both production and development.
|
|
||||||
|
|
||||||
For development, bundling is optional. We just want to get the right files in the browser.
|
|
||||||
|
|
||||||
Responsibilities of the converter during development:
|
|
||||||
|
|
||||||
- Convert TypeScript to JavaScript
|
|
||||||
- Convert CSS to JavaScript that sets the content as the default export
|
|
||||||
- Convert JSON to JavaScript that sets the content as the default export
|
|
||||||
- Make sure import, dynamic import and web worker references work
|
|
||||||
- Add extensions where missing
|
|
||||||
- Resolve absolute package imports
|
|
||||||
- Filter out specific imports/packages
|
|
||||||
- Replace constants with values
|
|
||||||
|
|
||||||
In production, the following responsibilities are added:
|
|
||||||
|
|
||||||
- Minify HTML
|
|
||||||
- Bundle multiple imports so that the browser can fetch less files
|
|
||||||
- Generate a second version that is ES5 compatible
|
|
||||||
|
|
||||||
Configuration for all these steps are specified in [bundle.js](bundle.js).
|
|
@@ -44,7 +44,7 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
module.exports.terserOptions = (latestBuild) => ({
|
module.exports.terserOptions = (latestBuild) => ({
|
||||||
safari10: !latestBuild,
|
safari10: true,
|
||||||
ecma: latestBuild ? undefined : 5,
|
ecma: latestBuild ? undefined : 5,
|
||||||
output: { comments: false },
|
output: { comments: false },
|
||||||
});
|
});
|
||||||
@@ -117,7 +117,7 @@ BundleConfig {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports.config = {
|
module.exports.config = {
|
||||||
app({ isProdBuild, latestBuild, isStatsBuild, isWDS }) {
|
app({ isProdBuild, latestBuild, isStatsBuild }) {
|
||||||
return {
|
return {
|
||||||
entry: {
|
entry: {
|
||||||
service_worker: "./src/entrypoints/service_worker.ts",
|
service_worker: "./src/entrypoints/service_worker.ts",
|
||||||
@@ -132,7 +132,6 @@ module.exports.config = {
|
|||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
isStatsBuild,
|
isStatsBuild,
|
||||||
isWDS,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -6,9 +6,6 @@ module.exports = {
|
|||||||
useRollup() {
|
useRollup() {
|
||||||
return process.env.ROLLUP === "1";
|
return process.env.ROLLUP === "1";
|
||||||
},
|
},
|
||||||
useWDS() {
|
|
||||||
return process.env.WDS === "1";
|
|
||||||
},
|
|
||||||
isProdBuild() {
|
isProdBuild() {
|
||||||
return (
|
return (
|
||||||
process.env.NODE_ENV === "production" || module.exports.isStatsBuild()
|
process.env.NODE_ENV === "production" || module.exports.isStatsBuild()
|
||||||
|
@@ -12,7 +12,6 @@ require("./webpack.js");
|
|||||||
require("./service-worker.js");
|
require("./service-worker.js");
|
||||||
require("./entry-html.js");
|
require("./entry-html.js");
|
||||||
require("./rollup.js");
|
require("./rollup.js");
|
||||||
require("./wds.js");
|
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-app",
|
"develop-app",
|
||||||
@@ -29,11 +28,7 @@ gulp.task(
|
|||||||
"build-translations"
|
"build-translations"
|
||||||
),
|
),
|
||||||
"copy-static-app",
|
"copy-static-app",
|
||||||
env.useWDS()
|
env.useRollup() ? "rollup-watch-app" : "webpack-watch-app"
|
||||||
? "wds-watch-app"
|
|
||||||
: env.useRollup()
|
|
||||||
? "rollup-watch-app"
|
|
||||||
: "webpack-watch-app"
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -19,7 +19,6 @@ const renderTemplate = (pth, data = {}, pathFunc = templatePath) => {
|
|||||||
return compiled({
|
return compiled({
|
||||||
...data,
|
...data,
|
||||||
useRollup: env.useRollup(),
|
useRollup: env.useRollup(),
|
||||||
useWDS: env.useWDS(),
|
|
||||||
renderTemplate,
|
renderTemplate,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -91,23 +90,10 @@ gulp.task("gen-pages-prod", (done) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("gen-index-app-dev", (done) => {
|
gulp.task("gen-index-app-dev", (done) => {
|
||||||
let latestAppJS, latestCoreJS, latestCustomPanelJS;
|
|
||||||
|
|
||||||
if (env.useWDS()) {
|
|
||||||
latestAppJS = "http://localhost:8000/src/entrypoints/app.ts";
|
|
||||||
latestCoreJS = "http://localhost:8000/src/entrypoints/core.ts";
|
|
||||||
latestCustomPanelJS =
|
|
||||||
"http://localhost:8000/src/entrypoints/custom-panel.ts";
|
|
||||||
} else {
|
|
||||||
latestAppJS = "/frontend_latest/app.js";
|
|
||||||
latestCoreJS = "/frontend_latest/core.js";
|
|
||||||
latestCustomPanelJS = "/frontend_latest/custom-panel.js";
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = renderTemplate("index", {
|
const content = renderTemplate("index", {
|
||||||
latestAppJS,
|
latestAppJS: "/frontend_latest/app.js",
|
||||||
latestCoreJS,
|
latestCoreJS: "/frontend_latest/core.js",
|
||||||
latestCustomPanelJS,
|
latestCustomPanelJS: "/frontend_latest/custom-panel.js",
|
||||||
|
|
||||||
es5AppJS: "/frontend_es5/app.js",
|
es5AppJS: "/frontend_es5/app.js",
|
||||||
es5CoreJS: "/frontend_es5/core.js",
|
es5CoreJS: "/frontend_es5/core.js",
|
||||||
|
@@ -33,10 +33,21 @@ String.prototype.rsplit = function (sep, maxsplit) {
|
|||||||
: split;
|
: split;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Panel translations which should be split from the core translations.
|
// Panel translations which should be split from the core translations. These
|
||||||
const TRANSLATION_FRAGMENTS = Object.keys(
|
// should mirror the fragment definitions in polymer.json, so that we load
|
||||||
require("../../src/translations/en.json").ui.panel
|
// additional resources at equivalent points.
|
||||||
);
|
const TRANSLATION_FRAGMENTS = [
|
||||||
|
"config",
|
||||||
|
"history",
|
||||||
|
"logbook",
|
||||||
|
"mailbox",
|
||||||
|
"profile",
|
||||||
|
"shopping-list",
|
||||||
|
"page-authorize",
|
||||||
|
"page-demo",
|
||||||
|
"page-onboarding",
|
||||||
|
"developer-tools",
|
||||||
|
];
|
||||||
|
|
||||||
function recursiveFlatten(prefix, data) {
|
function recursiveFlatten(prefix, data) {
|
||||||
let output = {};
|
let output = {};
|
||||||
|
@@ -1,11 +0,0 @@
|
|||||||
// Tasks to run Rollup
|
|
||||||
const gulp = require("gulp");
|
|
||||||
const { startDevServer } = require("@web/dev-server");
|
|
||||||
|
|
||||||
gulp.task("wds-watch-app", () => {
|
|
||||||
startDevServer({
|
|
||||||
config: {
|
|
||||||
watch: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
@@ -18,14 +18,6 @@ const bothBuilds = (createConfigFunc, params) => [
|
|||||||
createConfigFunc({ ...params, latestBuild: false }),
|
createConfigFunc({ ...params, latestBuild: false }),
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {{
|
|
||||||
* compiler: import("webpack").Compiler,
|
|
||||||
* contentBase: string,
|
|
||||||
* port: number,
|
|
||||||
* listenHost?: string
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
const runDevServer = ({
|
const runDevServer = ({
|
||||||
compiler,
|
compiler,
|
||||||
contentBase,
|
contentBase,
|
||||||
@@ -41,13 +33,10 @@ const runDevServer = ({
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
// Server listening
|
// Server listening
|
||||||
log(
|
log("[webpack-dev-server]", `http://localhost:${port}`);
|
||||||
"[webpack-dev-server]",
|
|
||||||
`Project is running at http://localhost:${port}`
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const doneHandler = (done) => (err, stats) => {
|
const handler = (done) => (err, stats) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.error(err.stack || err);
|
log.error(err.stack || err);
|
||||||
if (err.details) {
|
if (err.details) {
|
||||||
@@ -56,31 +45,22 @@ const doneHandler = (done) => (err, stats) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats.hasErrors() || stats.hasWarnings()) {
|
|
||||||
console.log(stats.toString("minimal"));
|
|
||||||
}
|
|
||||||
|
|
||||||
log(`Build done @ ${new Date().toLocaleTimeString()}`);
|
log(`Build done @ ${new Date().toLocaleTimeString()}`);
|
||||||
|
|
||||||
|
if (stats.hasErrors() || stats.hasWarnings()) {
|
||||||
|
log.warn(stats.toString("minimal"));
|
||||||
|
}
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const prodBuild = (conf) =>
|
|
||||||
new Promise((resolve) => {
|
|
||||||
webpack(
|
|
||||||
conf,
|
|
||||||
// Resolve promise when done. Because we pass a callback, webpack closes itself
|
|
||||||
doneHandler(resolve)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("webpack-watch-app", () => {
|
gulp.task("webpack-watch-app", () => {
|
||||||
// This command will run forever because we don't close compiler
|
// we are not calling done, so this command will run forever
|
||||||
webpack(createAppConfig({ isProdBuild: false, latestBuild: true })).watch(
|
webpack(createAppConfig({ isProdBuild: false, latestBuild: true })).watch(
|
||||||
{ ignored: /build-translations/ },
|
{ ignored: /build-translations/ },
|
||||||
doneHandler()
|
handler()
|
||||||
);
|
);
|
||||||
gulp.watch(
|
gulp.watch(
|
||||||
path.join(paths.translations_src, "en.json"),
|
path.join(paths.translations_src, "en.json"),
|
||||||
@@ -88,12 +68,15 @@ gulp.task("webpack-watch-app", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-app", () =>
|
gulp.task(
|
||||||
prodBuild(
|
"webpack-prod-app",
|
||||||
bothBuilds(createAppConfig, {
|
() =>
|
||||||
isProdBuild: true,
|
new Promise((resolve) =>
|
||||||
})
|
webpack(
|
||||||
)
|
bothBuilds(createAppConfig, { isProdBuild: true }),
|
||||||
|
handler(resolve)
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("webpack-dev-server-demo", () => {
|
gulp.task("webpack-dev-server-demo", () => {
|
||||||
@@ -104,12 +87,17 @@ gulp.task("webpack-dev-server-demo", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-demo", () =>
|
gulp.task(
|
||||||
prodBuild(
|
"webpack-prod-demo",
|
||||||
bothBuilds(createDemoConfig, {
|
() =>
|
||||||
isProdBuild: true,
|
new Promise((resolve) =>
|
||||||
})
|
webpack(
|
||||||
)
|
bothBuilds(createDemoConfig, {
|
||||||
|
isProdBuild: true,
|
||||||
|
}),
|
||||||
|
handler(resolve)
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("webpack-dev-server-cast", () => {
|
gulp.task("webpack-dev-server-cast", () => {
|
||||||
@@ -122,30 +110,41 @@ gulp.task("webpack-dev-server-cast", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-cast", () =>
|
gulp.task(
|
||||||
prodBuild(
|
"webpack-prod-cast",
|
||||||
bothBuilds(createCastConfig, {
|
() =>
|
||||||
isProdBuild: true,
|
new Promise((resolve) =>
|
||||||
})
|
webpack(
|
||||||
)
|
bothBuilds(createCastConfig, {
|
||||||
|
isProdBuild: true,
|
||||||
|
}),
|
||||||
|
|
||||||
|
handler(resolve)
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("webpack-watch-hassio", () => {
|
gulp.task("webpack-watch-hassio", () => {
|
||||||
// This command will run forever because we don't close compiler
|
// we are not calling done, so this command will run forever
|
||||||
webpack(
|
webpack(
|
||||||
createHassioConfig({
|
createHassioConfig({
|
||||||
isProdBuild: false,
|
isProdBuild: false,
|
||||||
latestBuild: true,
|
latestBuild: true,
|
||||||
})
|
})
|
||||||
).watch({}, doneHandler());
|
).watch({}, handler());
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-hassio", () =>
|
gulp.task(
|
||||||
prodBuild(
|
"webpack-prod-hassio",
|
||||||
bothBuilds(createHassioConfig, {
|
() =>
|
||||||
isProdBuild: true,
|
new Promise((resolve) =>
|
||||||
})
|
webpack(
|
||||||
)
|
bothBuilds(createHassioConfig, {
|
||||||
|
isProdBuild: true,
|
||||||
|
}),
|
||||||
|
handler(resolve)
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("webpack-dev-server-gallery", () => {
|
gulp.task("webpack-dev-server-gallery", () => {
|
||||||
@@ -157,11 +156,17 @@ gulp.task("webpack-dev-server-gallery", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-gallery", () =>
|
gulp.task(
|
||||||
prodBuild(
|
"webpack-prod-gallery",
|
||||||
createGalleryConfig({
|
() =>
|
||||||
isProdBuild: true,
|
new Promise((resolve) =>
|
||||||
latestBuild: true,
|
webpack(
|
||||||
})
|
createGalleryConfig({
|
||||||
)
|
isProdBuild: true,
|
||||||
|
latestBuild: true,
|
||||||
|
}),
|
||||||
|
|
||||||
|
handler(resolve)
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
const path = require("path");
|
var path = require("path");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
polymer_dir: path.resolve(__dirname, ".."),
|
polymer_dir: path.resolve(__dirname, ".."),
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
const path = require("path");
|
||||||
|
|
||||||
module.exports = function (userOptions = {}) {
|
module.exports = function (userOptions = {}) {
|
||||||
// Files need to be absolute paths.
|
// Files need to be absolute paths.
|
||||||
// This only works if the file has no exports
|
// This only works if the file has no exports
|
||||||
|
@@ -3,7 +3,7 @@ const path = require("path");
|
|||||||
const commonjs = require("@rollup/plugin-commonjs");
|
const commonjs = require("@rollup/plugin-commonjs");
|
||||||
const resolve = require("@rollup/plugin-node-resolve");
|
const resolve = require("@rollup/plugin-node-resolve");
|
||||||
const json = require("@rollup/plugin-json");
|
const json = require("@rollup/plugin-json");
|
||||||
const babel = require("@rollup/plugin-babel").babel;
|
const babel = require("rollup-plugin-babel");
|
||||||
const replace = require("@rollup/plugin-replace");
|
const replace = require("@rollup/plugin-replace");
|
||||||
const visualizer = require("rollup-plugin-visualizer");
|
const visualizer = require("rollup-plugin-visualizer");
|
||||||
const { string } = require("rollup-plugin-string");
|
const { string } = require("rollup-plugin-string");
|
||||||
@@ -31,7 +31,6 @@ const createRollupConfig = ({
|
|||||||
isStatsBuild,
|
isStatsBuild,
|
||||||
publicPath,
|
publicPath,
|
||||||
dontHash,
|
dontHash,
|
||||||
isWDS,
|
|
||||||
}) => {
|
}) => {
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -62,7 +61,6 @@ const createRollupConfig = ({
|
|||||||
...bundle.babelOptions({ latestBuild }),
|
...bundle.babelOptions({ latestBuild }),
|
||||||
extensions,
|
extensions,
|
||||||
exclude: bundle.babelExclude(),
|
exclude: bundle.babelExclude(),
|
||||||
babelHelpers: isWDS ? "inline" : "bundled",
|
|
||||||
}),
|
}),
|
||||||
string({
|
string({
|
||||||
// Import certain extensions as strings
|
// Import certain extensions as strings
|
||||||
@@ -71,21 +69,19 @@ const createRollupConfig = ({
|
|||||||
replace(
|
replace(
|
||||||
bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })
|
bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })
|
||||||
),
|
),
|
||||||
!isWDS &&
|
manifest({
|
||||||
manifest({
|
publicPath,
|
||||||
publicPath,
|
}),
|
||||||
}),
|
worker(),
|
||||||
!isWDS && worker(),
|
dontHashPlugin({ dontHash }),
|
||||||
!isWDS && dontHashPlugin({ dontHash }),
|
isProdBuild && terser(bundle.terserOptions(latestBuild)),
|
||||||
!isWDS && isProdBuild && terser(bundle.terserOptions(latestBuild)),
|
isStatsBuild &&
|
||||||
!isWDS &&
|
|
||||||
isStatsBuild &&
|
|
||||||
visualizer({
|
visualizer({
|
||||||
// https://github.com/btd/rollup-plugin-visualizer#options
|
// https://github.com/btd/rollup-plugin-visualizer#options
|
||||||
open: true,
|
open: true,
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
}),
|
}),
|
||||||
].filter(Boolean),
|
],
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* @type { import("rollup").OutputOptions }
|
* @type { import("rollup").OutputOptions }
|
||||||
@@ -112,13 +108,12 @@ const createRollupConfig = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) => {
|
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
return createRollupConfig(
|
return createRollupConfig(
|
||||||
bundle.config.app({
|
bundle.config.app({
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
isStatsBuild,
|
isStatsBuild,
|
||||||
isWDS,
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -4,21 +4,6 @@ const TerserPlugin = require("terser-webpack-plugin");
|
|||||||
const ManifestPlugin = require("webpack-manifest-plugin");
|
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
const bundle = require("./bundle");
|
const bundle = require("./bundle");
|
||||||
const log = require("fancy-log");
|
|
||||||
|
|
||||||
class LogStartCompilePlugin {
|
|
||||||
ignoredFirst = false;
|
|
||||||
|
|
||||||
apply(compiler) {
|
|
||||||
compiler.hooks.beforeCompile.tap("LogStartCompilePlugin", () => {
|
|
||||||
if (!this.ignoredFirst) {
|
|
||||||
this.ignoredFirst = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log("Changes detected. Starting compilation");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const createWebpackConfig = ({
|
const createWebpackConfig = ({
|
||||||
entry,
|
entry,
|
||||||
@@ -36,7 +21,6 @@ const createWebpackConfig = ({
|
|||||||
const ignorePackages = bundle.ignorePackages({ latestBuild });
|
const ignorePackages = bundle.ignorePackages({ latestBuild });
|
||||||
return {
|
return {
|
||||||
mode: isProdBuild ? "production" : "development",
|
mode: isProdBuild ? "production" : "development",
|
||||||
target: ["web", latestBuild ? "es2017" : "es5"],
|
|
||||||
devtool: isProdBuild
|
devtool: isProdBuild
|
||||||
? "cheap-module-source-map"
|
? "cheap-module-source-map"
|
||||||
: "eval-cheap-module-source-map",
|
: "eval-cheap-module-source-map",
|
||||||
@@ -51,6 +35,9 @@ const createWebpackConfig = ({
|
|||||||
loader: "babel-loader",
|
loader: "babel-loader",
|
||||||
options: bundle.babelOptions({ latestBuild }),
|
options: bundle.babelOptions({ latestBuild }),
|
||||||
},
|
},
|
||||||
|
resolve: {
|
||||||
|
fullySpecified: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
@@ -120,8 +107,7 @@ const createWebpackConfig = ({
|
|||||||
),
|
),
|
||||||
path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js")
|
path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js")
|
||||||
),
|
),
|
||||||
!isProdBuild && new LogStartCompilePlugin(),
|
],
|
||||||
].filter(Boolean),
|
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".ts", ".js", ".json"],
|
extensions: [".ts", ".js", ".json"],
|
||||||
},
|
},
|
||||||
@@ -132,6 +118,22 @@ const createWebpackConfig = ({
|
|||||||
}
|
}
|
||||||
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
||||||
},
|
},
|
||||||
|
environment: {
|
||||||
|
// The environment supports arrow functions ('() => { ... }').
|
||||||
|
arrowFunction: latestBuild,
|
||||||
|
// The environment supports BigInt as literal (123n).
|
||||||
|
bigIntLiteral: false,
|
||||||
|
// The environment supports const and let for variable declarations.
|
||||||
|
const: latestBuild,
|
||||||
|
// The environment supports destructuring ('{ a, b } = obj').
|
||||||
|
destructuring: latestBuild,
|
||||||
|
// The environment supports an async import() function to import EcmaScript modules.
|
||||||
|
dynamicImport: latestBuild,
|
||||||
|
// The environment supports 'for of' iteration ('for (const x of array) { ... }').
|
||||||
|
forOf: latestBuild,
|
||||||
|
// The environment supports ECMAScript Module syntax to import ECMAScript modules (import ... from '...').
|
||||||
|
module: latestBuild,
|
||||||
|
},
|
||||||
chunkFilename:
|
chunkFilename:
|
||||||
isProdBuild && !isStatsBuild
|
isProdBuild && !isStatsBuild
|
||||||
? "chunk.[chunkhash].js"
|
? "chunk.[chunkhash].js"
|
||||||
|
@@ -3,10 +3,22 @@ import { Lovelace } from "../../../src/panels/lovelace/types";
|
|||||||
import { DemoConfig } from "./types";
|
import { DemoConfig } from "./types";
|
||||||
|
|
||||||
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
||||||
() => import("./arsaboo").then((mod) => mod.demoArsaboo),
|
() =>
|
||||||
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
|
import(/* webpackChunkName: "arsaboo" */ "./arsaboo").then(
|
||||||
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
(mod) => mod.demoArsaboo
|
||||||
() => import("./jimpower").then((mod) => mod.demoJimpower),
|
),
|
||||||
|
() =>
|
||||||
|
import(/* webpackChunkName: "teachingbirds" */ "./teachingbirds").then(
|
||||||
|
(mod) => mod.demoTeachingbirds
|
||||||
|
),
|
||||||
|
() =>
|
||||||
|
import(/* webpackChunkName: "kernehed" */ "./kernehed").then(
|
||||||
|
(mod) => mod.demoKernehed
|
||||||
|
),
|
||||||
|
() =>
|
||||||
|
import(/* webpackChunkName: "jimpower" */ "./jimpower").then(
|
||||||
|
(mod) => mod.demoJimpower
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-mutable-exports
|
// eslint-disable-next-line import/no-mutable-exports
|
||||||
|
@@ -9,5 +9,5 @@ export interface DemoConfig {
|
|||||||
authorUrl: string;
|
authorUrl: string;
|
||||||
lovelace: (localize: LocalizeFunc) => LovelaceConfig;
|
lovelace: (localize: LocalizeFunc) => LovelaceConfig;
|
||||||
entities: (localize: LocalizeFunc) => Entity[];
|
entities: (localize: LocalizeFunc) => Entity[];
|
||||||
theme: () => Record<string, string> | null;
|
theme: () => { [key: string]: string } | null;
|
||||||
}
|
}
|
||||||
|
@@ -7,5 +7,7 @@ import "./ha-demo";
|
|||||||
|
|
||||||
/* polyfill for paper-dropdown */
|
/* polyfill for paper-dropdown */
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
import("web-animations-js/web-animations-next-lite.min");
|
import(
|
||||||
|
/* webpackChunkName: "polyfill-web-animations-next" */ "web-animations-js/web-animations-next-lite.min"
|
||||||
|
);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 94 KiB |
@@ -21,16 +21,15 @@ class DemoCard extends PolymerElement {
|
|||||||
}
|
}
|
||||||
pre {
|
pre {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
margin: 0 16px;
|
margin: 16px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 800px) {
|
@media only screen and (max-width: 800px) {
|
||||||
.root {
|
.root {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
pre {
|
pre {
|
||||||
margin: 16px 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -9,55 +9,51 @@ class DemoMoreInfo extends PolymerElement {
|
|||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
.root {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
}
|
}
|
||||||
#card {
|
|
||||||
max-width: 400px;
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
ha-card {
|
ha-card {
|
||||||
width: 352px;
|
width: 333px;
|
||||||
padding: 20px 24px;
|
padding: 20px 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
state-card-content {
|
state-card-content {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
margin: 0 16px;
|
margin: 16px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) {
|
@media only screen and (max-width: 800px) {
|
||||||
.root {
|
:host {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
pre {
|
pre {
|
||||||
margin: 16px 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="root">
|
<ha-card>
|
||||||
<div id="card">
|
<state-card-content
|
||||||
<ha-card>
|
state-obj="[[_stateObj]]"
|
||||||
<state-card-content
|
hass="[[hass]]"
|
||||||
state-obj="[[_stateObj]]"
|
in-dialog
|
||||||
hass="[[hass]]"
|
></state-card-content>
|
||||||
in-dialog
|
|
||||||
></state-card-content>
|
|
||||||
|
|
||||||
<more-info-content
|
<more-info-content
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
state-obj="[[_stateObj]]"
|
state-obj="[[_stateObj]]"
|
||||||
></more-info-content>
|
></more-info-content>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</div>
|
<template is="dom-if" if="[[showConfig]]">
|
||||||
<template is="dom-if" if="[[showConfig]]">
|
<pre>[[_jsonEntity(_stateObj)]]</pre>
|
||||||
<pre>[[_jsonEntity(_stateObj)]]</pre>
|
</template>
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,18 +3,12 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|||||||
/* eslint-plugin-disable lit */
|
/* eslint-plugin-disable lit */
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import "../../../src/components/ha-switch";
|
import "../../../src/components/ha-switch";
|
||||||
import "../../../src/components/ha-formfield";
|
|
||||||
import "./demo-more-info";
|
import "./demo-more-info";
|
||||||
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
|
||||||
|
|
||||||
class DemoMoreInfos extends PolymerElement {
|
class DemoMoreInfos extends PolymerElement {
|
||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
#container {
|
|
||||||
min-height: calc(100vh - 128px);
|
|
||||||
background: var(--primary-background-color);
|
|
||||||
}
|
|
||||||
.cards {
|
.cards {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -29,31 +23,20 @@ class DemoMoreInfos extends PolymerElement {
|
|||||||
.filters {
|
.filters {
|
||||||
margin-left: 60px;
|
margin-left: 60px;
|
||||||
}
|
}
|
||||||
ha-formfield {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<app-toolbar>
|
<app-toolbar>
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<ha-formfield label="Show entities">
|
<ha-switch checked="{{_showConfig}}">Show entity</ha-switch>
|
||||||
<ha-switch checked="[[_showConfig]]" on-change="_showConfigToggled">
|
|
||||||
</ha-switch>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield label="Dark theme">
|
|
||||||
<ha-switch on-change="_darkThemeToggled"> </ha-switch>
|
|
||||||
</ha-formfield>
|
|
||||||
</div>
|
</div>
|
||||||
</app-toolbar>
|
</app-toolbar>
|
||||||
<div id="container">
|
<div class="cards">
|
||||||
<div class="cards">
|
<template is="dom-repeat" items="[[entities]]">
|
||||||
<template is="dom-repeat" items="[[entities]]">
|
<demo-more-info
|
||||||
<demo-more-info
|
entity-id="[[item]]"
|
||||||
entity-id="[[item]]"
|
show-config="[[_showConfig]]"
|
||||||
show-config="[[_showConfig]]"
|
hass="[[hass]]"
|
||||||
hass="[[hass]]"
|
></demo-more-info>
|
||||||
></demo-more-info>
|
</template>
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -68,16 +51,6 @@ class DemoMoreInfos extends PolymerElement {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_showConfigToggled(ev) {
|
|
||||||
this._showConfig = ev.target.checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
_darkThemeToggled(ev) {
|
|
||||||
applyThemesOnElement(this.$.container, { themes: {} }, "default", {
|
|
||||||
dark: ev.target.checked,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("demo-more-infos", DemoMoreInfos);
|
customElements.define("demo-more-infos", DemoMoreInfos);
|
||||||
|
@@ -6,8 +6,6 @@ export const createMediaPlayerEntities = () => [
|
|||||||
media_content_type: "music",
|
media_content_type: "music",
|
||||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||||
media_artist: "Technohead",
|
media_artist: "Technohead",
|
||||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
|
||||||
// Select Source + Stop + Clear + Play + Shuffle Set
|
|
||||||
supported_features: 64063,
|
supported_features: 64063,
|
||||||
entity_picture: "/images/album_cover_2.jpg",
|
entity_picture: "/images/album_cover_2.jpg",
|
||||||
media_duration: 300,
|
media_duration: 300,
|
||||||
@@ -16,16 +14,13 @@ export const createMediaPlayerEntities = () => [
|
|||||||
// 23 seconds in
|
// 23 seconds in
|
||||||
new Date().getTime() - 23000
|
new Date().getTime() - 23000
|
||||||
).toISOString(),
|
).toISOString(),
|
||||||
volume_level: 0.5,
|
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "music_playing", "playing", {
|
getEntity("media_player", "music_playing", "playing", {
|
||||||
friendly_name: "Playing The Music",
|
friendly_name: "Playing The Music",
|
||||||
media_content_type: "music",
|
media_content_type: "music",
|
||||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||||
media_artist: "Technohead",
|
media_artist: "Technohead",
|
||||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
supported_features: 64063,
|
||||||
// Select Source + Stop + Clear + Play + Shuffle Set + Browse Media
|
|
||||||
supported_features: 195135,
|
|
||||||
entity_picture: "/images/album_cover.jpg",
|
entity_picture: "/images/album_cover.jpg",
|
||||||
media_duration: 300,
|
media_duration: 300,
|
||||||
media_position: 0,
|
media_position: 0,
|
||||||
@@ -33,7 +28,6 @@ export const createMediaPlayerEntities = () => [
|
|||||||
// 23 seconds in
|
// 23 seconds in
|
||||||
new Date().getTime() - 23000
|
new Date().getTime() - 23000
|
||||||
).toISOString(),
|
).toISOString(),
|
||||||
volume_level: 0.5,
|
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "stream_playing", "playing", {
|
getEntity("media_player", "stream_playing", "playing", {
|
||||||
friendly_name: "Playing the Stream",
|
friendly_name: "Playing the Stream",
|
||||||
@@ -41,125 +35,50 @@ export const createMediaPlayerEntities = () => [
|
|||||||
media_title: "Epic sax guy 10 hours",
|
media_title: "Epic sax guy 10 hours",
|
||||||
app_name: "YouTube",
|
app_name: "YouTube",
|
||||||
entity_picture: "/images/frenck.jpg",
|
entity_picture: "/images/frenck.jpg",
|
||||||
// Pause + Next Track + Play + Browse Media
|
supported_features: 33,
|
||||||
supported_features: 147489,
|
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "stream_paused", "paused", {
|
getEntity("media_player", "living_room", "playing", {
|
||||||
friendly_name: "Paused the Stream",
|
friendly_name: "Pause, No skip, tvshow",
|
||||||
media_content_type: "movie",
|
|
||||||
media_title: "Epic sax guy 10 hours",
|
|
||||||
app_name: "YouTube",
|
|
||||||
entity_picture: "/images/frenck.jpg",
|
|
||||||
// Pause + Next Track + Play
|
|
||||||
supported_features: 16417,
|
|
||||||
}),
|
|
||||||
getEntity("media_player", "stream_playing_previous", "playing", {
|
|
||||||
friendly_name: 'Playing the Stream (with "previous" support)',
|
|
||||||
media_content_type: "movie",
|
|
||||||
media_title: "Epic sax guy 10 hours",
|
|
||||||
app_name: "YouTube",
|
|
||||||
entity_picture: "/images/frenck.jpg",
|
|
||||||
// Pause + Previous Track + Play
|
|
||||||
supported_features: 16401,
|
|
||||||
}),
|
|
||||||
getEntity("media_player", "tv_playing", "playing", {
|
|
||||||
friendly_name: "Playing non-skip TV Show",
|
|
||||||
media_content_type: "tvshow",
|
media_content_type: "tvshow",
|
||||||
media_title: "Chapter 1",
|
media_title: "Chapter 1",
|
||||||
media_series_title: "House of Cards",
|
media_series_title: "House of Cards",
|
||||||
app_name: "Netflix",
|
app_name: "Netflix",
|
||||||
entity_picture: "/images/netflix.jpg",
|
entity_picture: "/images/netflix.jpg",
|
||||||
// Pause
|
|
||||||
supported_features: 1,
|
supported_features: 1,
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "sonos_idle", "idle", {
|
getEntity("media_player", "sonos_idle", "idle", {
|
||||||
friendly_name: "Sonos Idle",
|
friendly_name: "Sonos Idle",
|
||||||
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
|
|
||||||
// Select Source + Stop + Clear + Play + Shuffle Set
|
|
||||||
supported_features: 64063,
|
supported_features: 64063,
|
||||||
volume_level: 0.33,
|
|
||||||
is_volume_muted: true,
|
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "idle_browse_media", "idle", {
|
getEntity("media_player", "theater", "off", {
|
||||||
friendly_name: "Idle waiting for Browse Media (e.g. Spotify)",
|
|
||||||
// Pause + Seek + Volume Set + Previous Track + Next Track + Play Media +
|
|
||||||
// Select Source + Play + Shuffle Set + Browse Media
|
|
||||||
supported_features: 182839,
|
|
||||||
volume_level: 0.79,
|
|
||||||
}),
|
|
||||||
getEntity("media_player", "theater_off", "off", {
|
|
||||||
friendly_name: "TV Off",
|
friendly_name: "TV Off",
|
||||||
// On + Off + Play + Next + Pause
|
|
||||||
supported_features: 16801,
|
|
||||||
}),
|
|
||||||
getEntity("media_player", "theater_on", "on", {
|
|
||||||
friendly_name: "TV On",
|
|
||||||
// On + Off + Play + Next + Pause
|
|
||||||
supported_features: 16801,
|
|
||||||
}),
|
|
||||||
getEntity("media_player", "theater_off_static", "off", {
|
|
||||||
friendly_name: "TV Off (cannot be switched on)",
|
|
||||||
// Off + Next + Pause
|
|
||||||
supported_features: 289,
|
|
||||||
}),
|
|
||||||
getEntity("media_player", "theater_on_static", "on", {
|
|
||||||
friendly_name: "TV On (cannot be switched off)",
|
|
||||||
// On + Next + Pause
|
|
||||||
supported_features: 161,
|
supported_features: 161,
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "android_cast", "playing", {
|
getEntity("media_player", "android_cast", "playing", {
|
||||||
friendly_name: "Casting App (no supported features)",
|
friendly_name: "Casting App",
|
||||||
media_title: "Android Screen Casting",
|
media_title: "Android Screen Casting",
|
||||||
app_name: "Screen Mirroring",
|
app_name: "Screen Mirroring",
|
||||||
}),
|
// supported_features: 21437,
|
||||||
getEntity("media_player", "image_display", "playing", {
|
|
||||||
friendly_name: "Digital Picture Frame",
|
|
||||||
media_content_type: "image",
|
|
||||||
media_title: "Famous Painting",
|
|
||||||
media_artist: "Famous Artist",
|
|
||||||
entity_picture: "/images/sunflowers.jpg",
|
|
||||||
// On + Off + Browse Media
|
|
||||||
supported_features: 131456,
|
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "unavailable", "unavailable", {
|
getEntity("media_player", "unavailable", "unavailable", {
|
||||||
friendly_name: "Player Unavailable",
|
friendly_name: "Player Unavailable",
|
||||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
|
||||||
// Play Media + Stop + Play
|
|
||||||
supported_features: 21437,
|
supported_features: 21437,
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "unknown", "unknown", {
|
getEntity("media_player", "unknown", "unknown", {
|
||||||
friendly_name: "Player Unknown",
|
friendly_name: "Player Unknown",
|
||||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
|
||||||
// Play Media + Stop + Play
|
|
||||||
supported_features: 21437,
|
supported_features: 21437,
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "playing", "playing", {
|
|
||||||
friendly_name: "Player Playing (no Pause support)",
|
|
||||||
// Volume Set + Volume Mute + Previous Track + Next Track +
|
|
||||||
// Play Media + Stop + Play
|
|
||||||
supported_features: 21436,
|
|
||||||
volume_level: 1,
|
|
||||||
}),
|
|
||||||
getEntity("media_player", "idle", "idle", {
|
|
||||||
friendly_name: "Player Idle",
|
|
||||||
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
|
|
||||||
// Play Media + Stop + Play
|
|
||||||
supported_features: 21437,
|
|
||||||
volume_level: 0,
|
|
||||||
}),
|
|
||||||
getEntity("media_player", "receiver_on", "on", {
|
getEntity("media_player", "receiver_on", "on", {
|
||||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||||
volume_level: 0.63,
|
volume_level: 0.63,
|
||||||
is_volume_muted: false,
|
is_volume_muted: false,
|
||||||
source: "TV",
|
source: "TV",
|
||||||
friendly_name: "Receiver (selectable sources)",
|
friendly_name: "Receiver",
|
||||||
// Volume Set + Volume Mute + On + Off + Select Source + Play + Sound Mode
|
|
||||||
supported_features: 84364,
|
supported_features: 84364,
|
||||||
}),
|
}),
|
||||||
getEntity("media_player", "receiver_off", "off", {
|
getEntity("media_player", "receiver_off", "off", {
|
||||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||||
friendly_name: "Receiver (selectable sources)",
|
friendly_name: "Receiver",
|
||||||
// Volume Set + Volume Mute + On + Off + Select Source + Play + Sound Mode
|
|
||||||
supported_features: 84364,
|
supported_features: 84364,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
@@ -1,72 +0,0 @@
|
|||||||
import { getEntity } from "../../../src/fake_data/entity";
|
|
||||||
|
|
||||||
export const createPlantEntities = () => [
|
|
||||||
getEntity("plant", "lemon_tree", "ok", {
|
|
||||||
problem: "none",
|
|
||||||
sensors: {
|
|
||||||
moisture: "sensor.lemon_tree_moisture",
|
|
||||||
battery: "sensor.lemon_tree_battery",
|
|
||||||
temperature: "sensor.lemon_tree_temperature",
|
|
||||||
conductivity: "sensor.lemon_tree_conductivity",
|
|
||||||
brightness: "sensor.lemon_tree_brightness",
|
|
||||||
},
|
|
||||||
unit_of_measurement_dict: {
|
|
||||||
temperature: "°C",
|
|
||||||
moisture: "%",
|
|
||||||
brightness: "lx",
|
|
||||||
battery: "%",
|
|
||||||
conductivity: "μS/cm",
|
|
||||||
},
|
|
||||||
moisture: 54,
|
|
||||||
battery: 95,
|
|
||||||
temperature: 15.6,
|
|
||||||
conductivity: 1,
|
|
||||||
brightness: 12,
|
|
||||||
max_brightness: 20,
|
|
||||||
friendly_name: "Lemon Tree",
|
|
||||||
}),
|
|
||||||
getEntity("plant", "apple_tree", "ok", {
|
|
||||||
problem: "brightness",
|
|
||||||
sensors: {
|
|
||||||
moisture: "sensor.apple_tree_moisture",
|
|
||||||
battery: "sensor.apple_tree_battery",
|
|
||||||
temperature: "sensor.apple_tree_temperature",
|
|
||||||
conductivity: "sensor.apple_tree_conductivity",
|
|
||||||
brightness: "sensor.apple_tree_brightness",
|
|
||||||
},
|
|
||||||
unit_of_measurement_dict: {
|
|
||||||
temperature: "°C",
|
|
||||||
moisture: "%",
|
|
||||||
brightness: "lx",
|
|
||||||
battery: "%",
|
|
||||||
conductivity: "μS/cm",
|
|
||||||
},
|
|
||||||
moisture: 54,
|
|
||||||
battery: 2,
|
|
||||||
temperature: 15.6,
|
|
||||||
conductivity: 1,
|
|
||||||
brightness: 25,
|
|
||||||
max_brightness: 20,
|
|
||||||
friendly_name: "Apple Tree",
|
|
||||||
}),
|
|
||||||
getEntity("plant", "sunflowers", "ok", {
|
|
||||||
problem: "moisture, temperature, conductivity",
|
|
||||||
sensors: {
|
|
||||||
moisture: "sensor.sunflowers_moisture",
|
|
||||||
temperature: "sensor.sunflowers_temperature",
|
|
||||||
conductivity: "sensor.sunflowers_conductivity",
|
|
||||||
brightness: "sensor.sunflowers_brightness",
|
|
||||||
},
|
|
||||||
unit_of_measurement_dict: {
|
|
||||||
temperature: "°C",
|
|
||||||
moisture: "%",
|
|
||||||
brightness: "lx",
|
|
||||||
conductivity: "μS/cm",
|
|
||||||
},
|
|
||||||
moisture: 54,
|
|
||||||
temperature: 15.6,
|
|
||||||
conductivity: 1,
|
|
||||||
brightness: 25,
|
|
||||||
entity_picture: "/images/sunflowers.jpg",
|
|
||||||
}),
|
|
||||||
];
|
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -76,19 +71,35 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-alarm-panel-card")
|
class DemoAlarmPanelEntity extends PolymerElement {
|
||||||
class DemoAlarmPanelEntity extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html`
|
||||||
|
<demo-cards
|
||||||
protected render(): TemplateResult {
|
id="demos"
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
hass="[[hass]]"
|
||||||
|
configs="[[_configs]]"
|
||||||
|
></demo-cards>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
hass.updateTranslations(null, "en");
|
type: Object,
|
||||||
hass.updateTranslations("lovelace", "en");
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
hass: Object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
this._setupDemo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _setupDemo() {
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
|
await hass.updateTranslations(null, "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -58,19 +53,31 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-conditional-card")
|
class DemoConditional extends PolymerElement {
|
||||||
class DemoConditional extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html`
|
||||||
|
<demo-cards
|
||||||
protected render(): TemplateResult {
|
id="demos"
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
hass="[[hass]]"
|
||||||
|
configs="[[_configs]]"
|
||||||
|
></demo-cards>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
hass: Object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -222,19 +217,24 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-entities-card")
|
class DemoEntities extends PolymerElement {
|
||||||
class DemoEntities extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -25,10 +20,10 @@ const CONFIGS = [
|
|||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "With Name (defined in card)",
|
heading: "With Name",
|
||||||
config: `
|
config: `
|
||||||
- type: button
|
- type: button
|
||||||
name: Custom Name
|
name: Bedroom
|
||||||
entity: light.bed_light
|
entity: light.bed_light
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
@@ -37,7 +32,7 @@ const CONFIGS = [
|
|||||||
config: `
|
config: `
|
||||||
- type: button
|
- type: button
|
||||||
entity: light.bed_light
|
entity: light.bed_light
|
||||||
icon: mdi:tools
|
icon: mdi:hotel
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -74,19 +69,31 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-entity-button-card")
|
class DemoButtonEntity extends PolymerElement {
|
||||||
class DemoButtonEntity extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html`
|
||||||
|
<demo-cards
|
||||||
protected render(): TemplateResult {
|
id="demos"
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
hass="[[hass]]"
|
||||||
|
configs="[[_configs]]"
|
||||||
|
></demo-cards>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
hass: Object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -94,21 +89,26 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-entity-filter-card")
|
class DemoFilter extends PolymerElement {
|
||||||
class DemoEntityFilter extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("demo-hui-entity-filter-card", DemoEntityFilter);
|
customElements.define("demo-hui-entity-filter-card", DemoFilter);
|
||||||
|
@@ -1,19 +1,12 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("sensor", "brightness", "12", {}),
|
getEntity("sensor", "brightness", "12", {}),
|
||||||
getEntity("sensor", "brightness_medium", "53", {}),
|
|
||||||
getEntity("sensor", "brightness_high", "87", {}),
|
|
||||||
getEntity("plant", "bonsai", "ok", {}),
|
getEntity("plant", "bonsai", "ok", {}),
|
||||||
getEntity("sensor", "not_working", "unavailable", {}),
|
getEntity("sensor", "not_working", "unavailable", {}),
|
||||||
getEntity("sensor", "outside_humidity", "54", {
|
getEntity("sensor", "outside_humidity", "54", {
|
||||||
@@ -28,10 +21,16 @@ const CONFIGS = [
|
|||||||
{
|
{
|
||||||
heading: "Basic example",
|
heading: "Basic example",
|
||||||
config: `
|
config: `
|
||||||
|
- type: gauge
|
||||||
|
entity: sensor.brightness
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "With title",
|
||||||
|
config: `
|
||||||
- type: gauge
|
- type: gauge
|
||||||
title: Humidity
|
title: Humidity
|
||||||
entity: sensor.outside_humidity
|
entity: sensor.outside_humidity
|
||||||
name: Outside Humidity
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -40,7 +39,6 @@ const CONFIGS = [
|
|||||||
- type: gauge
|
- type: gauge
|
||||||
entity: sensor.outside_temperature
|
entity: sensor.outside_temperature
|
||||||
unit_of_measurement: C
|
unit_of_measurement: C
|
||||||
name: Outside Temperature
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -48,45 +46,19 @@ const CONFIGS = [
|
|||||||
config: `
|
config: `
|
||||||
- type: gauge
|
- type: gauge
|
||||||
entity: sensor.brightness
|
entity: sensor.brightness
|
||||||
name: Brightness Low
|
|
||||||
severity:
|
severity:
|
||||||
red: 75
|
red: 32
|
||||||
green: 0
|
green: 0
|
||||||
yellow: 50
|
yellow: 23
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "Setting Severity Levels",
|
heading: "Setting Min and Max Values",
|
||||||
config: `
|
|
||||||
- type: gauge
|
|
||||||
entity: sensor.brightness_medium
|
|
||||||
name: Brightness Medium
|
|
||||||
severity:
|
|
||||||
red: 75
|
|
||||||
green: 0
|
|
||||||
yellow: 50
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Setting Severity Levels",
|
|
||||||
config: `
|
|
||||||
- type: gauge
|
|
||||||
entity: sensor.brightness_high
|
|
||||||
name: Brightness High
|
|
||||||
severity:
|
|
||||||
red: 75
|
|
||||||
green: 0
|
|
||||||
yellow: 50
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Setting Min (0) and Max (15) Values",
|
|
||||||
config: `
|
config: `
|
||||||
- type: gauge
|
- type: gauge
|
||||||
entity: sensor.brightness
|
entity: sensor.brightness
|
||||||
name: Brightness
|
|
||||||
min: 0
|
min: 0
|
||||||
max: 15
|
max: 38
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -112,19 +84,24 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-gauge-card")
|
class DemoGaugeEntity extends PolymerElement {
|
||||||
class DemoGaugeEntity extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -223,21 +218,26 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-glance-card")
|
class DemoPicEntity extends PolymerElement {
|
||||||
class DemoGlanceEntity extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("demo-hui-glance-card", DemoGlanceEntity);
|
customElements.define("demo-hui-glance-card", DemoPicEntity);
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
import { html, LitElement, customElement, TemplateResult } from "lit-element";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
|
/* eslint-plugin-disable lit */
|
||||||
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
@@ -35,10 +37,18 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-iframe-card")
|
class DemoIframe extends PolymerElement {
|
||||||
class DemoIframe extends LitElement {
|
static get template() {
|
||||||
protected render(): TemplateResult {
|
return html` <demo-cards configs="[[_configs]]"></demo-cards> `;
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -13,43 +8,29 @@ import "../components/demo-cards";
|
|||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "bed_light", "on", {
|
getEntity("light", "bed_light", "on", {
|
||||||
friendly_name: "Bed Light",
|
friendly_name: "Bed Light",
|
||||||
brightness: 255,
|
brightness: 130,
|
||||||
}),
|
}),
|
||||||
getEntity("light", "dim_on", "on", {
|
getEntity("light", "dim", "off", {
|
||||||
friendly_name: "Dining Room",
|
|
||||||
supported_features: 1,
|
|
||||||
brightness: 100,
|
|
||||||
}),
|
|
||||||
getEntity("light", "dim_off", "off", {
|
|
||||||
friendly_name: "Dining Room",
|
|
||||||
supported_features: 1,
|
supported_features: 1,
|
||||||
}),
|
}),
|
||||||
getEntity("light", "unavailable", "unavailable", {
|
getEntity("light", "unavailable", "unavailable", {
|
||||||
friendly_name: "Lost Light",
|
|
||||||
supported_features: 1,
|
supported_features: 1,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
{
|
{
|
||||||
heading: "Switchable Light",
|
heading: "Basic example",
|
||||||
config: `
|
config: `
|
||||||
- type: light
|
- type: light
|
||||||
entity: light.bed_light
|
entity: light.bed_light
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "Dimmable Light On",
|
heading: "Dim",
|
||||||
config: `
|
config: `
|
||||||
- type: light
|
- type: light
|
||||||
entity: light.dim_on
|
entity: light.dim
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Dimmable Light Off",
|
|
||||||
config: `
|
|
||||||
- type: light
|
|
||||||
entity: light.dim_off
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -68,19 +49,24 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-light-card")
|
class DemoLightEntity extends PolymerElement {
|
||||||
class DemoLightEntity extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -166,19 +161,31 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-map-card")
|
class DemoMap extends PolymerElement {
|
||||||
class DemoMap extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html`
|
||||||
|
<demo-cards
|
||||||
protected render(): TemplateResult {
|
id="demos"
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
hass="[[hass]]"
|
||||||
|
configs="[[_configs]]"
|
||||||
|
></demo-cards>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
hass: Object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { mockTemplate } from "../../../demo/src/stubs/template";
|
import { mockTemplate } from "../../../demo/src/stubs/template";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -259,19 +254,23 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-markdown-card")
|
class DemoMarkdown extends PolymerElement {
|
||||||
class DemoMarkdown extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
hass.updateTranslations(null, "en");
|
type: Object,
|
||||||
hass.updateTranslations("lovelace", "en");
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
mockTemplate(hass);
|
mockTemplate(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,72 +1,46 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
import { createMediaPlayerEntities } from "../data/media_players";
|
import { createMediaPlayerEntities } from "../data/media_players";
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
{
|
{
|
||||||
heading: "Paused Music",
|
heading: "Paused music",
|
||||||
config: `
|
config: `
|
||||||
- type: media-control
|
- type: media-control
|
||||||
entity: media_player.music_paused
|
entity: media_player.music_paused
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "Playing Music",
|
heading: "Playing music",
|
||||||
config: `
|
config: `
|
||||||
- type: media-control
|
- type: media-control
|
||||||
entity: media_player.music_playing
|
entity: media_player.music_playing
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "Playing Stream",
|
heading: "Playing stream",
|
||||||
config: `
|
config: `
|
||||||
- type: media-control
|
- type: media-control
|
||||||
entity: media_player.stream_playing
|
entity: media_player.stream_playing
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "Paused Stream",
|
heading: "Pause, No skip, tvshow",
|
||||||
config: `
|
config: `
|
||||||
- type: media-control
|
- type: media-control
|
||||||
entity: media_player.stream_paused
|
entity: media_player.living_room
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: 'Playing Stream (with "previous" support)',
|
heading: "Screen casting",
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.stream_playing_previous
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Playing non-skip TV Show",
|
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.tv_playing
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Screen Casting",
|
|
||||||
config: `
|
config: `
|
||||||
- type: media-control
|
- type: media-control
|
||||||
entity: media_player.android_cast
|
entity: media_player.android_cast
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
heading: "Digital Picture Frame",
|
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.image_display
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
heading: "Sonos Idle",
|
heading: "Sonos Idle",
|
||||||
config: `
|
config: `
|
||||||
@@ -74,53 +48,11 @@ const CONFIGS = [
|
|||||||
entity: media_player.sonos_idle
|
entity: media_player.sonos_idle
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
heading: "Idle waiting for Browse Media",
|
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.idle_browse_media
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
heading: "Player Off",
|
heading: "Player Off",
|
||||||
config: `
|
config: `
|
||||||
- type: media-control
|
- type: media-control
|
||||||
entity: media_player.theater_off
|
entity: media_player.theater
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Player On",
|
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.theater_on
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Player Off (cannot be switched on)",
|
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.theater_off_static
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Player On (cannot be switched off)",
|
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.theater_on_static
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Player Idle",
|
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.idle
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Player Playing",
|
|
||||||
config: `
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.playing
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -138,46 +70,48 @@ const CONFIGS = [
|
|||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "Receiver On (selectable sources)",
|
heading: "Receiver On",
|
||||||
config: `
|
config: `
|
||||||
- type: media-control
|
- type: media-control
|
||||||
entity: media_player.receiver_on
|
entity: media_player.receiver_on
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "Receiver Off (selectable sources)",
|
heading: "Receiver Off",
|
||||||
config: `
|
config: `
|
||||||
- type: media-control
|
- type: media-control
|
||||||
entity: media_player.receiver_off
|
entity: media_player.receiver_off
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
heading: "Grid Full Size",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 1
|
|
||||||
cards:
|
|
||||||
- type: media-control
|
|
||||||
entity: media_player.music_paused
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-media-control-card")
|
class DemoHuiMediControlCard extends PolymerElement {
|
||||||
class DemoHuiMediaControlCard extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html`
|
||||||
|
<demo-cards
|
||||||
protected render(): TemplateResult {
|
id="demos"
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
hass="[[hass]]"
|
||||||
|
configs="[[_configs]]"
|
||||||
|
></demo-cards>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
hass: Object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(createMediaPlayerEntities());
|
hass.addEntities(createMediaPlayerEntities());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("demo-hui-media-control-card", DemoHuiMediaControlCard);
|
customElements.define("demo-hui-media-control-card", DemoHuiMediControlCard);
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
import { createMediaPlayerEntities } from "../data/media_players";
|
import { createMediaPlayerEntities } from "../data/media_players";
|
||||||
@@ -17,64 +12,54 @@ const CONFIGS = [
|
|||||||
- type: entities
|
- type: entities
|
||||||
entities:
|
entities:
|
||||||
- entity: media_player.music_paused
|
- entity: media_player.music_paused
|
||||||
name: Paused Music
|
name: Paused music
|
||||||
- entity: media_player.music_playing
|
- entity: media_player.music_playing
|
||||||
name: Playing Music
|
name: Playing music
|
||||||
- entity: media_player.stream_playing
|
- entity: media_player.stream_playing
|
||||||
name: Playing Stream
|
name: Paused, no play
|
||||||
- entity: media_player.stream_paused
|
- entity: media_player.living_room
|
||||||
name: Paused Stream
|
name: Pause, No skip, tvshow
|
||||||
- entity: media_player.stream_playing_previous
|
|
||||||
name: Playing Stream (with "previous" support)
|
|
||||||
- entity: media_player.tv_playing
|
|
||||||
name: Playing non-skip TV Show
|
|
||||||
- entity: media_player.android_cast
|
- entity: media_player.android_cast
|
||||||
name: Screen casting
|
name: Screen casting
|
||||||
- entity: media_player.image_display
|
|
||||||
name: Digital Picture Frame
|
|
||||||
- entity: media_player.sonos_idle
|
- entity: media_player.sonos_idle
|
||||||
name: Sonos Idle
|
name: Chromcast Idle
|
||||||
- entity: media_player.idle_browse_media
|
- entity: media_player.theater
|
||||||
name: Idle waiting for Browse Media
|
|
||||||
- entity: media_player.theater_off
|
|
||||||
name: Player Off
|
name: Player Off
|
||||||
- entity: media_player.theater_on
|
|
||||||
name: Player On
|
|
||||||
- entity: media_player.theater_off_static
|
|
||||||
name: Player Off (cannot be switched on)
|
|
||||||
- entity: media_player.theater_on_static
|
|
||||||
name: Player On (cannot be switched off)
|
|
||||||
- entity: media_player.idle
|
|
||||||
name: Player Idle
|
|
||||||
- entity: media_player.playing
|
|
||||||
name: Player Playing
|
|
||||||
- entity: media_player.unavailable
|
- entity: media_player.unavailable
|
||||||
name: Player Unavailable
|
name: Player Unavailable
|
||||||
- entity: media_player.unknown
|
- entity: media_player.unknown
|
||||||
name: Player Unknown
|
name: Player Unknown
|
||||||
- entity: media_player.receiver_on
|
|
||||||
name: Receiver On (selectable sources)
|
|
||||||
- entity: media_player.receiver_off
|
|
||||||
name: Receiver Off (selectable sources)
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-media-player-row")
|
class DemoHuiMediaPlayerRows extends PolymerElement {
|
||||||
class DemoHuiMediaPlayerRow extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html`
|
||||||
|
<demo-cards
|
||||||
protected render(): TemplateResult {
|
id="demos"
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
hass="[[hass]]"
|
||||||
|
configs="[[_configs]]"
|
||||||
|
></demo-cards>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
hass: Object,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(createMediaPlayerEntities());
|
hass.addEntities(createMediaPlayerEntities());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("demo-hui-media-player-row", DemoHuiMediaPlayerRow);
|
customElements.define("demo-hui-media-player-rows", DemoHuiMediaPlayerRows);
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -130,21 +125,26 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-picture-elements-card")
|
class DemoPicElements extends PolymerElement {
|
||||||
class DemoPictureElements extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("demo-hui-picture-elements-card", DemoPictureElements);
|
customElements.define("demo-hui-picture-elements-card", DemoPicElements);
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -85,21 +80,26 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-picture-entity-card")
|
class DemoPicEntity extends PolymerElement {
|
||||||
class DemoPictureEntity extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("demo-hui-picture-entity-card", DemoPictureEntity);
|
customElements.define("demo-hui-picture-entity-card", DemoPicEntity);
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -126,21 +121,26 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-picture-glance-card")
|
class DemoPicGlance extends PolymerElement {
|
||||||
class DemoPictureGlance extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("demo-hui-picture-glance-card", DemoPictureGlance);
|
customElements.define("demo-hui-picture-glance-card", DemoPicGlance);
|
||||||
|
@@ -1,55 +0,0 @@
|
|||||||
import {
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import "../components/demo-cards";
|
|
||||||
import { createPlantEntities } from "../data/plants";
|
|
||||||
|
|
||||||
const CONFIGS = [
|
|
||||||
{
|
|
||||||
heading: "Basic example",
|
|
||||||
config: `
|
|
||||||
- type: plant-status
|
|
||||||
entity: plant.lemon_tree
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Problem (too bright) + low battery",
|
|
||||||
config: `
|
|
||||||
- type: plant-status
|
|
||||||
entity: plant.apple_tree
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "With picture + multiple problems",
|
|
||||||
config: `
|
|
||||||
- type: plant-status
|
|
||||||
entity: plant.sunflowers
|
|
||||||
name: Sunflowers Name Overwrite
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-hui-plant-card")
|
|
||||||
export class DemoPlantEntity 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(createPlantEntities());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("demo-hui-plant-card", DemoPlantEntity);
|
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
@@ -25,19 +20,24 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-shopping-list-card")
|
class DemoShoppingListEntity extends PolymerElement {
|
||||||
class DemoShoppingListEntity extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
|
|
||||||
hass.mockAPI("shopping_list", () => [
|
hass.mockAPI("shopping_list", () => [
|
||||||
{ name: "list", id: 1, complete: false },
|
{ name: "list", id: 1, complete: false },
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { mockHistory } from "../../../demo/src/stubs/history";
|
import { mockHistory } from "../../../demo/src/stubs/history";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
@@ -137,19 +132,24 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-stack-card")
|
class DemoStack extends PolymerElement {
|
||||||
class DemoStack extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
mockHistory(hass);
|
mockHistory(hass);
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -79,19 +74,24 @@ const CONFIGS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-thermostat-card")
|
class DemoThermostatEntity extends PolymerElement {
|
||||||
class DemoThermostatEntity extends LitElement {
|
static get template() {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_configs: {
|
||||||
|
type: Object,
|
||||||
|
value: CONFIGS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
const hass = provideHass(this.$.demos);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,27 +1,10 @@
|
|||||||
import {
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
html,
|
/* eslint-plugin-disable lit */
|
||||||
LitElement,
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
customElement,
|
|
||||||
property,
|
|
||||||
PropertyValues,
|
|
||||||
query,
|
|
||||||
TemplateResult,
|
|
||||||
} from "lit-element";
|
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import {
|
import { SUPPORT_BRIGHTNESS } from "../../../src/data/light";
|
||||||
SUPPORT_BRIGHTNESS,
|
|
||||||
SUPPORT_COLOR_TEMP,
|
|
||||||
SUPPORT_EFFECT,
|
|
||||||
SUPPORT_FLASH,
|
|
||||||
SUPPORT_COLOR,
|
|
||||||
SUPPORT_TRANSITION,
|
|
||||||
SUPPORT_WHITE_VALUE,
|
|
||||||
} from "../../../src/data/light";
|
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import {
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
provideHass,
|
|
||||||
MockHomeAssistant,
|
|
||||||
} from "../../../src/fake_data/provide_hass";
|
|
||||||
import "../components/demo-more-infos";
|
import "../components/demo-more-infos";
|
||||||
import "../../../src/dialogs/more-info/more-info-content";
|
import "../../../src/dialogs/more-info/more-info-content";
|
||||||
|
|
||||||
@@ -31,52 +14,38 @@ const ENTITIES = [
|
|||||||
}),
|
}),
|
||||||
getEntity("light", "kitchen_light", "on", {
|
getEntity("light", "kitchen_light", "on", {
|
||||||
friendly_name: "Brightness Light",
|
friendly_name: "Brightness Light",
|
||||||
brightness: 200,
|
brightness: 80,
|
||||||
supported_features: SUPPORT_BRIGHTNESS,
|
supported_features: SUPPORT_BRIGHTNESS,
|
||||||
}),
|
}),
|
||||||
getEntity("light", "color_temperature_light", "on", {
|
|
||||||
friendly_name: "White Color Temperature Light",
|
|
||||||
brightness: 128,
|
|
||||||
color_temp: 75,
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_BRIGHTNESS + SUPPORT_COLOR_TEMP,
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_effectslight", "on", {
|
|
||||||
friendly_name: "Color Effets Light",
|
|
||||||
brightness: 255,
|
|
||||||
hs_color: [30, 100],
|
|
||||||
white_value: 36,
|
|
||||||
supported_features:
|
|
||||||
SUPPORT_BRIGHTNESS +
|
|
||||||
SUPPORT_EFFECT +
|
|
||||||
SUPPORT_FLASH +
|
|
||||||
SUPPORT_COLOR +
|
|
||||||
SUPPORT_TRANSITION +
|
|
||||||
SUPPORT_WHITE_VALUE,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-more-info-light")
|
class DemoMoreInfoLight extends PolymerElement {
|
||||||
class DemoMoreInfoLight extends LitElement {
|
static get template() {
|
||||||
@property() public hass!: MockHomeAssistant;
|
|
||||||
|
|
||||||
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
return html`
|
||||||
<demo-more-infos
|
<demo-more-infos
|
||||||
.hass=${this.hass}
|
hass="[[hass]]"
|
||||||
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
entities="[[_entities]]"
|
||||||
></demo-more-infos>
|
></demo-more-infos>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues) {
|
static get properties() {
|
||||||
super.firstUpdated(changedProperties);
|
return {
|
||||||
const hass = provideHass(this._demoRoot);
|
_entities: {
|
||||||
hass.updateTranslations(null, "en");
|
type: Array,
|
||||||
|
value: ENTITIES.map((ent) => ent.entityId),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ready() {
|
||||||
|
super.ready();
|
||||||
|
this._setupDemo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _setupDemo() {
|
||||||
|
const hass = provideHass(this);
|
||||||
|
await hass.updateTranslations(null, "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,9 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { customElement, html, LitElement, TemplateResult } from "lit-element";
|
import { html, LitElement, TemplateResult } from "lit-element";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
||||||
import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive";
|
import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive";
|
||||||
|
|
||||||
@customElement("demo-util-long-press")
|
|
||||||
export class DemoUtilLongPress extends LitElement {
|
export class DemoUtilLongPress extends LitElement {
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
@@ -21,7 +20,7 @@ export class DemoUtilLongPress extends LitElement {
|
|||||||
|
|
||||||
<textarea></textarea>
|
<textarea></textarea>
|
||||||
|
|
||||||
<div>Try pressing and scrolling too!</div>
|
<div>(try pressing and scrolling too!)</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
@@ -63,3 +62,5 @@ export class DemoUtilLongPress extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
customElements.define("demo-util-long-press", DemoUtilLongPress);
|
||||||
|
@@ -14,51 +14,54 @@ import "../../src/styles/polymer-ha-style";
|
|||||||
// eslint-disable-next-line import/extensions
|
// eslint-disable-next-line import/extensions
|
||||||
import { DEMOS } from "../build/import-demos";
|
import { DEMOS } from "../build/import-demos";
|
||||||
|
|
||||||
|
const fixPath = (path) => path.substr(2, path.length - 5);
|
||||||
|
|
||||||
class HaGallery extends PolymerElement {
|
class HaGallery extends PolymerElement {
|
||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style include="iron-positioning ha-style">
|
<style include="iron-positioning ha-style">
|
||||||
:host {
|
:host {
|
||||||
-ms-user-select: initial;
|
-ms-user-select: initial;
|
||||||
-webkit-user-select: initial;
|
-webkit-user-select: initial;
|
||||||
-moz-user-select: initial;
|
-moz-user-select: initial;
|
||||||
}
|
}
|
||||||
app-header-layout {
|
app-header-layout {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
ha-icon-button.invisible {
|
ha-icon-button.invisible {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pickers {
|
.pickers {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pickers ha-card {
|
.pickers ha-card {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 16px 8px;
|
margin: 16px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pickers ha-card:last-child {
|
.pickers ha-card:last-child {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.intro {
|
.intro {
|
||||||
margin: -1em 0;
|
margin: -1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p a {
|
p a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<app-header-layout>
|
<app-header-layout>
|
||||||
@@ -67,42 +70,32 @@ class HaGallery extends PolymerElement {
|
|||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
icon="hass:arrow-left"
|
icon="hass:arrow-left"
|
||||||
on-click="_backTapped"
|
on-click="_backTapped"
|
||||||
class$="[[_computeHeaderButtonClass(_demo)]]"
|
class$='[[_computeHeaderButtonClass(_demo)]]'
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
<div main-title>
|
<div main-title>[[_withDefault(_demo, "Home Assistant Gallery")]]</div>
|
||||||
[[_withDefault(_demo, "Home Assistant Gallery")]]
|
|
||||||
</div>
|
|
||||||
</app-toolbar>
|
</app-toolbar>
|
||||||
</app-header>
|
</app-header>
|
||||||
|
|
||||||
<div class="content">
|
<div class='content'>
|
||||||
<div id="demo"></div>
|
<div id='demo'></div>
|
||||||
<template is="dom-if" if="[[!_demo]]">
|
<template is='dom-if' if='[[!_demo]]'>
|
||||||
<div class="pickers">
|
<div class='pickers'>
|
||||||
<ha-card header="Lovelace Card Demos">
|
<ha-card header="Lovelace card demos">
|
||||||
<div class="card-content intro">
|
<div class='card-content intro'>
|
||||||
<p>
|
<p>
|
||||||
Lovelace has many different cards. Each card allows the user
|
Lovelace has many different cards. Each card allows the user to tell a different story about what is going on in their house. These cards are very customizable, as no household is the same.
|
||||||
to tell a different story about what is going on in their
|
|
||||||
house. These cards are very customizable, as no household is
|
|
||||||
the same.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This gallery helps our developers and designers to see all
|
This gallery helps our developers and designers to see all the different states that each card can be in.
|
||||||
the different states that each card can be in.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Check
|
Check <a href='https://www.home-assistant.io/lovelace'>the official website</a> for instructions on how to get started with Lovelace.</a>.
|
||||||
<a href="https://www.home-assistant.io/lovelace"
|
|
||||||
>the official website</a
|
|
||||||
>
|
|
||||||
for instructions on how to get started with Lovelace.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<template is="dom-repeat" items="[[_lovelaceDemos]]">
|
<template is='dom-repeat' items='[[_lovelaceDemos]]'>
|
||||||
<a href="#[[item]]">
|
<a href='#[[item]]'>
|
||||||
<paper-item>
|
<paper-item>
|
||||||
<paper-item-body>{{ item }}</paper-item-body>
|
<paper-item-body>{{ item }}</paper-item-body>
|
||||||
<ha-icon icon="hass:chevron-right"></ha-icon>
|
<ha-icon icon="hass:chevron-right"></ha-icon>
|
||||||
@@ -111,14 +104,14 @@ class HaGallery extends PolymerElement {
|
|||||||
</template>
|
</template>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
|
||||||
<ha-card header="More Info Demos">
|
<ha-card header="More Info demos">
|
||||||
<div class="card-content intro">
|
<div class='card-content intro'>
|
||||||
<p>
|
<p>
|
||||||
More info screens show up when an entity is clicked.
|
More info screens show up when an entity is clicked.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<template is="dom-repeat" items="[[_moreInfoDemos]]">
|
<template is='dom-repeat' items='[[_moreInfoDemos]]'>
|
||||||
<a href="#[[item]]">
|
<a href='#[[item]]'>
|
||||||
<paper-item>
|
<paper-item>
|
||||||
<paper-item-body>{{ item }}</paper-item-body>
|
<paper-item-body>{{ item }}</paper-item-body>
|
||||||
<ha-icon icon="hass:chevron-right"></ha-icon>
|
<ha-icon icon="hass:chevron-right"></ha-icon>
|
||||||
@@ -127,14 +120,14 @@ class HaGallery extends PolymerElement {
|
|||||||
</template>
|
</template>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
|
||||||
<ha-card header="Util Demos">
|
<ha-card header="Util demos">
|
||||||
<div class="card-content intro">
|
<div class='card-content intro'>
|
||||||
<p>
|
<p>
|
||||||
Test pages for our utility functions.
|
Test pages for our utility functions.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<template is="dom-repeat" items="[[_utilDemos]]">
|
<template is='dom-repeat' items='[[_utilDemos]]'>
|
||||||
<a href="#[[item]]">
|
<a href='#[[item]]'>
|
||||||
<paper-item>
|
<paper-item>
|
||||||
<paper-item-body>{{ item }}</paper-item-body>
|
<paper-item-body>{{ item }}</paper-item-body>
|
||||||
<ha-icon icon="hass:chevron-right"></ha-icon>
|
<ha-icon icon="hass:chevron-right"></ha-icon>
|
||||||
@@ -146,10 +139,7 @@ class HaGallery extends PolymerElement {
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</app-header-layout>
|
</app-header-layout>
|
||||||
<notification-manager
|
<notification-manager hass=[[_fakeHass]] id='notifications'></notification-manager>
|
||||||
hass="[[_fakeHass]]"
|
|
||||||
id="notifications"
|
|
||||||
></notification-manager>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -69,7 +69,7 @@ const STAGE_ICON = {
|
|||||||
const PERMIS_DESC = {
|
const PERMIS_DESC = {
|
||||||
stage: {
|
stage: {
|
||||||
title: "Add-on Stage",
|
title: "Add-on Stage",
|
||||||
description: `Add-ons can have one of three stages:\n\n<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon> **Stable**: These are add-ons ready to be used in production.\n\n<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon> **Experimental**: These may contain bugs, and may be unfinished.\n\n<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon> **Deprecated**: These add-ons will no longer receive any updates.`,
|
description: `Add-ons can have one of three stages:\n\n<ha-svg-icon .path='${STAGE_ICON.stable}'></ha-svg-icon> **Stable**: These are add-ons ready to be used in production.\n\n<ha-svg-icon .path='${STAGE_ICON.experimental}'></ha-svg-icon> **Experimental**: These may contain bugs, and may be unfinished.\n\n<ha-svg-icon .path='${STAGE_ICON.deprecated}'></ha-svg-icon> **Deprecated**: These add-ons will no longer receive any updates.`,
|
||||||
},
|
},
|
||||||
rating: {
|
rating: {
|
||||||
title: "Add-on Security Rating",
|
title: "Add-on Security Rating",
|
||||||
|
@@ -27,8 +27,6 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_FILE_SIZE = 1 * 1024 * 1024 * 1024; // 1GB
|
|
||||||
|
|
||||||
@customElement("hassio-upload-snapshot")
|
@customElement("hassio-upload-snapshot")
|
||||||
export class HassioUploadSnapshot extends LitElement {
|
export class HassioUploadSnapshot extends LitElement {
|
||||||
public hass!: HomeAssistant;
|
public hass!: HomeAssistant;
|
||||||
@@ -53,20 +51,6 @@ export class HassioUploadSnapshot 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",
|
||||||
|
@@ -12,7 +12,7 @@ import { atLeastVersion } from "../../../src/common/config/version";
|
|||||||
import { navigate } from "../../../src/common/navigate";
|
import { navigate } from "../../../src/common/navigate";
|
||||||
import { compare } 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 { HassioAddonInfo } from "../../../src/data/hassio/addon";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
import "../components/hassio-card-content";
|
import "../components/hassio-card-content";
|
||||||
@@ -22,14 +22,14 @@ import { hassioStyle } from "../resources/hassio-style";
|
|||||||
class HassioAddons extends LitElement {
|
class HassioAddons extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@property({ attribute: false }) public addons?: HassioAddonInfo[];
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1>Add-ons</h1>
|
<h1>Add-ons</h1>
|
||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
${!this.supervisor.supervisor.addons?.length
|
${!this.addons?.length
|
||||||
? html`
|
? html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
@@ -41,7 +41,7 @@ class HassioAddons extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`
|
`
|
||||||
: this.supervisor.supervisor.addons
|
: this.addons
|
||||||
.sort((a, b) => compare(a.name, b.name))
|
.sort((a, b) => compare(a.name, b.name))
|
||||||
.map(
|
.map(
|
||||||
(addon) => html`
|
(addon) => html`
|
||||||
|
@@ -7,7 +7,11 @@ import {
|
|||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { HassioHassOSInfo } from "../../../src/data/hassio/host";
|
||||||
|
import {
|
||||||
|
HassioHomeAssistantInfo,
|
||||||
|
HassioSupervisorInfo,
|
||||||
|
} from "../../../src/data/hassio/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";
|
||||||
import { HomeAssistant, Route } from "../../../src/types";
|
import { HomeAssistant, Route } from "../../../src/types";
|
||||||
@@ -19,12 +23,16 @@ import "./hassio-update";
|
|||||||
class HassioDashboard extends LitElement {
|
class HassioDashboard extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassInfo!: HassioHomeAssistantInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage
|
<hass-tabs-subpage
|
||||||
@@ -39,11 +47,13 @@ class HassioDashboard extends LitElement {
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<hassio-update
|
<hassio-update
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
.hassInfo=${this.hassInfo}
|
||||||
|
.supervisorInfo=${this.supervisorInfo}
|
||||||
|
.hassOsInfo=${this.hassOsInfo}
|
||||||
></hassio-update>
|
></hassio-update>
|
||||||
<hassio-addons
|
<hassio-addons
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
.addons=${this.supervisorInfo.addons}
|
||||||
></hassio-addons>
|
></hassio-addons>
|
||||||
</div>
|
</div>
|
||||||
</hass-tabs-subpage>
|
</hass-tabs-subpage>
|
||||||
|
@@ -23,7 +23,6 @@ import {
|
|||||||
HassioHomeAssistantInfo,
|
HassioHomeAssistantInfo,
|
||||||
HassioSupervisorInfo,
|
HassioSupervisorInfo,
|
||||||
} from "../../../src/data/hassio/supervisor";
|
} from "../../../src/data/hassio/supervisor";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@@ -36,20 +35,31 @@ import { hassioStyle } from "../resources/hassio-style";
|
|||||||
export class HassioUpdate extends LitElement {
|
export class HassioUpdate extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@property({ attribute: false }) public hassInfo?: HassioHomeAssistantInfo;
|
||||||
|
|
||||||
private _pendingUpdates = memoizeOne((supervisor: Supervisor): number => {
|
@property({ attribute: false }) public hassOsInfo?: HassioHassOSInfo;
|
||||||
return Object.keys(supervisor).filter(
|
|
||||||
(value) => supervisor[value].update_available
|
@property({ attribute: false }) public supervisorInfo?: HassioSupervisorInfo;
|
||||||
).length;
|
|
||||||
});
|
private _pendingUpdates = memoizeOne(
|
||||||
|
(
|
||||||
|
core?: HassioHomeAssistantInfo,
|
||||||
|
supervisor?: HassioSupervisorInfo,
|
||||||
|
os?: HassioHassOSInfo
|
||||||
|
): number => {
|
||||||
|
return [core, supervisor, os].filter(
|
||||||
|
(value) => !!value && value?.update_available
|
||||||
|
).length;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.supervisor) {
|
const updatesAvailable = this._pendingUpdates(
|
||||||
return html``;
|
this.hassInfo,
|
||||||
}
|
this.supervisorInfo,
|
||||||
|
this.hassOsInfo
|
||||||
|
);
|
||||||
|
|
||||||
const updatesAvailable = this._pendingUpdates(this.supervisor);
|
|
||||||
if (!updatesAvailable) {
|
if (!updatesAvailable) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
@@ -64,24 +74,26 @@ export class HassioUpdate extends LitElement {
|
|||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
${this._renderUpdateCard(
|
${this._renderUpdateCard(
|
||||||
"Home Assistant Core",
|
"Home Assistant Core",
|
||||||
this.supervisor.core,
|
this.hassInfo!,
|
||||||
"hassio/homeassistant/update",
|
"hassio/homeassistant/update",
|
||||||
`https://${
|
`https://${
|
||||||
this.supervisor.core.version_latest.includes("b") ? "rc" : "www"
|
this.hassInfo?.version_latest.includes("b") ? "rc" : "www"
|
||||||
}.home-assistant.io/latest-release-notes/`
|
}.home-assistant.io/latest-release-notes/`
|
||||||
)}
|
)}
|
||||||
${this._renderUpdateCard(
|
${this._renderUpdateCard(
|
||||||
"Supervisor",
|
"Supervisor",
|
||||||
this.supervisor.supervisor,
|
this.supervisorInfo!,
|
||||||
"hassio/supervisor/update",
|
"hassio/supervisor/update",
|
||||||
`https://github.com//home-assistant/hassio/releases/tag/${this.supervisor.supervisor.version_latest}`
|
`https://github.com//home-assistant/hassio/releases/tag/${
|
||||||
|
this.supervisorInfo!.version_latest
|
||||||
|
}`
|
||||||
)}
|
)}
|
||||||
${this.supervisor.host.features.includes("hassos")
|
${this.hassOsInfo
|
||||||
? this._renderUpdateCard(
|
? this._renderUpdateCard(
|
||||||
"Operating System",
|
"Operating System",
|
||||||
this.supervisor.os,
|
this.hassOsInfo,
|
||||||
"hassio/os/update",
|
"hassio/os/update",
|
||||||
`https://github.com//home-assistant/hassos/releases/tag/${this.supervisor.os.version_latest}`
|
`https://github.com//home-assistant/hassos/releases/tag/${this.hassOsInfo.version_latest}`
|
||||||
)
|
)
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -11,7 +11,10 @@ export const showHassioMarkdownDialog = (
|
|||||||
): void => {
|
): void => {
|
||||||
fireEvent(element, "show-dialog", {
|
fireEvent(element, "show-dialog", {
|
||||||
dialogTag: "dialog-hassio-markdown",
|
dialogTag: "dialog-hassio-markdown",
|
||||||
dialogImport: () => import("./dialog-hassio-markdown"),
|
dialogImport: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "dialog-hassio-markdown" */ "./dialog-hassio-markdown"
|
||||||
|
),
|
||||||
dialogParams,
|
dialogParams,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
import "@material/mwc-icon-button";
|
import "@material/mwc-icon-button";
|
||||||
import "@material/mwc-list/mwc-list";
|
|
||||||
import "@material/mwc-list/mwc-list-item";
|
|
||||||
import "@material/mwc-tab";
|
import "@material/mwc-tab";
|
||||||
import "@material/mwc-tab-bar";
|
import "@material/mwc-tab-bar";
|
||||||
import { mdiClose } from "@mdi/js";
|
import { mdiClose } from "@mdi/js";
|
||||||
@@ -18,22 +16,18 @@ import {
|
|||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { cache } from "lit-html/directives/cache";
|
import { cache } from "lit-html/directives/cache";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/components/ha-chips";
|
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import "../../../../src/components/ha-dialog";
|
import "../../../../src/components/ha-dialog";
|
||||||
import "../../../../src/components/ha-expansion-panel";
|
|
||||||
import "../../../../src/components/ha-formfield";
|
import "../../../../src/components/ha-formfield";
|
||||||
import "../../../../src/components/ha-header-bar";
|
import "../../../../src/components/ha-header-bar";
|
||||||
import "../../../../src/components/ha-radio";
|
import "../../../../src/components/ha-radio";
|
||||||
|
import type { HaRadio } from "../../../../src/components/ha-radio";
|
||||||
import "../../../../src/components/ha-related-items";
|
import "../../../../src/components/ha-related-items";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
import "../../../../src/components/ha-svg-icon";
|
||||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||||
import {
|
import {
|
||||||
AccessPoints,
|
|
||||||
accesspointScan,
|
|
||||||
NetworkInterface,
|
NetworkInterface,
|
||||||
updateNetworkInterface,
|
updateNetworkInterface,
|
||||||
WifiConfiguration,
|
|
||||||
} from "../../../../src/data/hassio/network";
|
} from "../../../../src/data/hassio/network";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
@@ -44,51 +38,54 @@ import { haStyleDialog } from "../../../../src/resources/styles";
|
|||||||
import type { HomeAssistant } from "../../../../src/types";
|
import type { HomeAssistant } from "../../../../src/types";
|
||||||
import { HassioNetworkDialogParams } from "./show-dialog-network";
|
import { HassioNetworkDialogParams } from "./show-dialog-network";
|
||||||
|
|
||||||
const IP_VERSIONS = ["ipv4", "ipv6"];
|
|
||||||
|
|
||||||
@customElement("dialog-hassio-network")
|
@customElement("dialog-hassio-network")
|
||||||
export class DialogHassioNetwork extends LitElement
|
export class DialogHassioNetwork extends LitElement
|
||||||
implements HassDialog<HassioNetworkDialogParams> {
|
implements HassDialog<HassioNetworkDialogParams> {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@internalProperty() private _accessPoints?: AccessPoints;
|
@internalProperty() private _prosessing = false;
|
||||||
|
|
||||||
@internalProperty() private _curTabIndex = 0;
|
|
||||||
|
|
||||||
@internalProperty() private _dirty = false;
|
|
||||||
|
|
||||||
@internalProperty() private _interface?: NetworkInterface;
|
|
||||||
|
|
||||||
@internalProperty() private _interfaces!: NetworkInterface[];
|
|
||||||
|
|
||||||
@internalProperty() private _params?: HassioNetworkDialogParams;
|
@internalProperty() private _params?: HassioNetworkDialogParams;
|
||||||
|
|
||||||
@internalProperty() private _processing = false;
|
@internalProperty() private _network!: {
|
||||||
|
interface: string;
|
||||||
|
data: NetworkInterface;
|
||||||
|
}[];
|
||||||
|
|
||||||
@internalProperty() private _scanning = false;
|
@internalProperty() private _curTabIndex = 0;
|
||||||
|
|
||||||
@internalProperty() private _wifiConfiguration?: WifiConfiguration;
|
@internalProperty() private _device?: {
|
||||||
|
interface: string;
|
||||||
|
data: NetworkInterface;
|
||||||
|
};
|
||||||
|
|
||||||
|
@internalProperty() private _dirty = false;
|
||||||
|
|
||||||
public async showDialog(params: HassioNetworkDialogParams): Promise<void> {
|
public async showDialog(params: HassioNetworkDialogParams): Promise<void> {
|
||||||
this._params = params;
|
this._params = params;
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
this._curTabIndex = 0;
|
this._curTabIndex = 0;
|
||||||
this._interfaces = params.network.interfaces.sort((a, b) => {
|
this._network = Object.keys(params.network?.interfaces)
|
||||||
return a.primary > b.primary ? -1 : 1;
|
.map((device) => ({
|
||||||
});
|
interface: device,
|
||||||
this._interface = { ...this._interfaces[this._curTabIndex] };
|
data: params.network.interfaces[device],
|
||||||
|
}))
|
||||||
|
.sort((a, b) => {
|
||||||
|
return a.data.primary > b.data.primary ? -1 : 1;
|
||||||
|
});
|
||||||
|
this._device = this._network[this._curTabIndex];
|
||||||
|
this._device.data.nameservers = String(this._device.data.nameservers);
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeDialog(): void {
|
public closeDialog(): void {
|
||||||
this._params = undefined;
|
this._params = undefined;
|
||||||
this._processing = false;
|
this._prosessing = false;
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._params || !this._interface) {
|
if (!this._params || !this._network) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,11 +107,11 @@ export class DialogHassioNetwork extends LitElement
|
|||||||
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
||||||
</mwc-icon-button>
|
</mwc-icon-button>
|
||||||
</ha-header-bar>
|
</ha-header-bar>
|
||||||
${this._interfaces.length > 1
|
${this._network.length > 1
|
||||||
? html` <mwc-tab-bar
|
? html` <mwc-tab-bar
|
||||||
.activeIndex=${this._curTabIndex}
|
.activeIndex=${this._curTabIndex}
|
||||||
@MDCTabBar:activated=${this._handleTabActivated}
|
@MDCTabBar:activated=${this._handleTabActivated}
|
||||||
>${this._interfaces.map(
|
>${this._network.map(
|
||||||
(device) =>
|
(device) =>
|
||||||
html`<mwc-tab
|
html`<mwc-tab
|
||||||
.id=${device.interface}
|
.id=${device.interface}
|
||||||
@@ -132,302 +129,81 @@ export class DialogHassioNetwork extends LitElement
|
|||||||
|
|
||||||
private _renderTab() {
|
private _renderTab() {
|
||||||
return html` <div class="form container">
|
return html` <div class="form container">
|
||||||
${IP_VERSIONS.map((version) =>
|
<ha-formfield label="DHCP">
|
||||||
this._interface![version] ? this._renderIPConfiguration(version) : ""
|
<ha-radio
|
||||||
)}
|
@change=${this._handleRadioValueChanged}
|
||||||
${this._interface?.type === "wireless"
|
value="dhcp"
|
||||||
? html`
|
name="method"
|
||||||
<ha-expansion-panel header="Wi-Fi" outlined>
|
?checked=${this._device!.data.method === "dhcp"}
|
||||||
${this._interface?.wifi?.ssid
|
>
|
||||||
? html`<p>Connected to: ${this._interface?.wifi?.ssid}</p>`
|
</ha-radio>
|
||||||
: ""}
|
</ha-formfield>
|
||||||
<mwc-button
|
<ha-formfield label="Static">
|
||||||
class="scan"
|
<ha-radio
|
||||||
@click=${this._scanForAP}
|
@change=${this._handleRadioValueChanged}
|
||||||
.disabled=${this._scanning}
|
value="static"
|
||||||
>
|
name="method"
|
||||||
${this._scanning
|
?checked=${this._device!.data.method === "static"}
|
||||||
? html`<ha-circular-progress active size="small">
|
>
|
||||||
</ha-circular-progress>`
|
</ha-radio>
|
||||||
: "Scan for accesspoints"}
|
</ha-formfield>
|
||||||
</mwc-button>
|
${this._device!.data.method !== "dhcp"
|
||||||
${this._accessPoints &&
|
? html` <paper-input
|
||||||
this._accessPoints.accesspoints &&
|
|
||||||
this._accessPoints.accesspoints.length !== 0
|
|
||||||
? html`
|
|
||||||
<mwc-list>
|
|
||||||
${this._accessPoints.accesspoints
|
|
||||||
.filter((ap) => ap.ssid)
|
|
||||||
.map(
|
|
||||||
(ap) =>
|
|
||||||
html`
|
|
||||||
<mwc-list-item
|
|
||||||
twoline
|
|
||||||
@click=${this._selectAP}
|
|
||||||
.activated=${ap.ssid ===
|
|
||||||
this._wifiConfiguration?.ssid}
|
|
||||||
.ap=${ap}
|
|
||||||
>
|
|
||||||
<span>${ap.ssid}</span>
|
|
||||||
<span slot="secondary">
|
|
||||||
${ap.mac} - Strength: ${ap.signal}
|
|
||||||
</span>
|
|
||||||
</mwc-list-item>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</mwc-list>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._wifiConfiguration
|
|
||||||
? html`
|
|
||||||
<div class="radio-row">
|
|
||||||
<ha-formfield label="open">
|
|
||||||
<ha-radio
|
|
||||||
@change=${this._handleRadioValueChangedAp}
|
|
||||||
.ap=${this._wifiConfiguration}
|
|
||||||
value="open"
|
|
||||||
name="auth"
|
|
||||||
.checked=${this._wifiConfiguration.auth ===
|
|
||||||
undefined ||
|
|
||||||
this._wifiConfiguration.auth === "open"}
|
|
||||||
>
|
|
||||||
</ha-radio>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield label="wep">
|
|
||||||
<ha-radio
|
|
||||||
@change=${this._handleRadioValueChangedAp}
|
|
||||||
.ap=${this._wifiConfiguration}
|
|
||||||
value="wep"
|
|
||||||
name="auth"
|
|
||||||
.checked=${this._wifiConfiguration.auth === "wep"}
|
|
||||||
>
|
|
||||||
</ha-radio>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield label="wpa-psk">
|
|
||||||
<ha-radio
|
|
||||||
@change=${this._handleRadioValueChangedAp}
|
|
||||||
.ap=${this._wifiConfiguration}
|
|
||||||
value="wpa-psk"
|
|
||||||
name="auth"
|
|
||||||
.checked=${this._wifiConfiguration.auth ===
|
|
||||||
"wpa-psk"}
|
|
||||||
>
|
|
||||||
</ha-radio>
|
|
||||||
</ha-formfield>
|
|
||||||
</div>
|
|
||||||
${this._wifiConfiguration.auth === "wpa-psk" ||
|
|
||||||
this._wifiConfiguration.auth === "wep"
|
|
||||||
? html`
|
|
||||||
<paper-input
|
|
||||||
class="flex-auto"
|
|
||||||
type="password"
|
|
||||||
id="psk"
|
|
||||||
label="Password"
|
|
||||||
version="wifi"
|
|
||||||
@value-changed=${this
|
|
||||||
._handleInputValueChangedWifi}
|
|
||||||
>
|
|
||||||
</paper-input>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</ha-expansion-panel>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this._dirty
|
|
||||||
? html`<div class="warning">
|
|
||||||
If you are changing the Wi-Fi, IP or gateway addresses, you might
|
|
||||||
lose the connection!
|
|
||||||
</div>`
|
|
||||||
: ""}
|
|
||||||
</div>
|
|
||||||
<div class="buttons">
|
|
||||||
<mwc-button label="close" @click=${this.closeDialog}> </mwc-button>
|
|
||||||
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
|
||||||
${this._processing
|
|
||||||
? html`<ha-circular-progress active size="small">
|
|
||||||
</ha-circular-progress>`
|
|
||||||
: "Save"}
|
|
||||||
</mwc-button>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _selectAP(event) {
|
|
||||||
this._wifiConfiguration = event.currentTarget.ap;
|
|
||||||
this._dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _scanForAP() {
|
|
||||||
if (!this._interface) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._scanning = true;
|
|
||||||
try {
|
|
||||||
this._accessPoints = await accesspointScan(
|
|
||||||
this.hass,
|
|
||||||
this._interface.interface
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: "Failed to scan for accesspoints",
|
|
||||||
text: extractApiErrorMessage(err),
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
this._scanning = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _renderIPConfiguration(version: string) {
|
|
||||||
return html`
|
|
||||||
<ha-expansion-panel
|
|
||||||
.header=${`IPv${version.charAt(version.length - 1)}`}
|
|
||||||
outlined
|
|
||||||
>
|
|
||||||
<div class="radio-row">
|
|
||||||
<ha-formfield label="DHCP">
|
|
||||||
<ha-radio
|
|
||||||
@change=${this._handleRadioValueChanged}
|
|
||||||
.version=${version}
|
|
||||||
value="auto"
|
|
||||||
name="${version}method"
|
|
||||||
.checked=${this._interface![version]?.method === "auto"}
|
|
||||||
>
|
|
||||||
</ha-radio>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield label="Static">
|
|
||||||
<ha-radio
|
|
||||||
@change=${this._handleRadioValueChanged}
|
|
||||||
.version=${version}
|
|
||||||
value="static"
|
|
||||||
name="${version}method"
|
|
||||||
.checked=${this._interface![version]?.method === "static"}
|
|
||||||
>
|
|
||||||
</ha-radio>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield label="Disabled" class="warning">
|
|
||||||
<ha-radio
|
|
||||||
@change=${this._handleRadioValueChanged}
|
|
||||||
.version=${version}
|
|
||||||
value="disabled"
|
|
||||||
name="${version}method"
|
|
||||||
.checked=${this._interface![version]?.method === "disabled"}
|
|
||||||
>
|
|
||||||
</ha-radio>
|
|
||||||
</ha-formfield>
|
|
||||||
</div>
|
|
||||||
${this._interface![version].method === "static"
|
|
||||||
? html`
|
|
||||||
<paper-input
|
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
id="address"
|
id="ip_address"
|
||||||
label="IP address/Netmask"
|
label="IP address/Netmask"
|
||||||
.version=${version}
|
.value="${this._device!.data.ip_address}"
|
||||||
.value=${this._toString(this._interface![version].address)}
|
|
||||||
@value-changed=${this._handleInputValueChanged}
|
@value-changed=${this._handleInputValueChanged}
|
||||||
>
|
></paper-input>
|
||||||
</paper-input>
|
|
||||||
<paper-input
|
<paper-input
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
id="gateway"
|
id="gateway"
|
||||||
label="Gateway address"
|
label="Gateway address"
|
||||||
.version=${version}
|
.value="${this._device!.data.gateway}"
|
||||||
.value=${this._interface![version].gateway}
|
|
||||||
@value-changed=${this._handleInputValueChanged}
|
@value-changed=${this._handleInputValueChanged}
|
||||||
>
|
></paper-input>
|
||||||
</paper-input>
|
|
||||||
<paper-input
|
<paper-input
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
id="nameservers"
|
id="nameservers"
|
||||||
label="DNS servers"
|
label="DNS servers"
|
||||||
.version=${version}
|
.value="${this._device!.data.nameservers as string}"
|
||||||
.value=${this._toString(this._interface![version].nameservers)}
|
|
||||||
@value-changed=${this._handleInputValueChanged}
|
@value-changed=${this._handleInputValueChanged}
|
||||||
>
|
></paper-input>
|
||||||
</paper-input>
|
NB!: If you are changing IP or gateway addresses, you might lose
|
||||||
`
|
the connection.`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-expansion-panel>
|
</div>
|
||||||
`;
|
<div class="buttons">
|
||||||
}
|
<mwc-button label="close" @click=${this.closeDialog}> </mwc-button>
|
||||||
|
<mwc-button @click=${this._updateNetwork} ?disabled=${!this._dirty}>
|
||||||
_toArray(data: string | string[]): string[] {
|
${this._prosessing
|
||||||
if (Array.isArray(data)) {
|
? html`<ha-circular-progress active></ha-circular-progress>`
|
||||||
if (data && typeof data[0] === "string") {
|
: "Update"}
|
||||||
data = data[0];
|
</mwc-button>
|
||||||
}
|
</div>`;
|
||||||
}
|
|
||||||
if (!data) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
if (typeof data === "string") {
|
|
||||||
return data.replace(/ /g, "").split(",");
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
_toString(data: string | string[]): string {
|
|
||||||
if (!data) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if (Array.isArray(data)) {
|
|
||||||
return data.join(", ");
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _updateNetwork() {
|
private async _updateNetwork() {
|
||||||
this._processing = true;
|
this._prosessing = true;
|
||||||
let interfaceOptions: Partial<NetworkInterface> = {};
|
let options: Partial<NetworkInterface> = {
|
||||||
|
method: this._device!.data.method,
|
||||||
IP_VERSIONS.forEach((version) => {
|
};
|
||||||
interfaceOptions[version] = {
|
if (options.method !== "dhcp") {
|
||||||
method: this._interface![version]?.method || "auto",
|
options = {
|
||||||
|
...options,
|
||||||
|
address: this._device!.data.ip_address,
|
||||||
|
gateway: this._device!.data.gateway,
|
||||||
|
dns: String(this._device!.data.nameservers).split(","),
|
||||||
};
|
};
|
||||||
if (this._interface![version]?.method === "static") {
|
|
||||||
interfaceOptions[version] = {
|
|
||||||
...interfaceOptions[version],
|
|
||||||
address: this._toArray(this._interface![version]?.address),
|
|
||||||
gateway: this._interface![version]?.gateway,
|
|
||||||
nameservers: this._toArray(this._interface![version]?.nameservers),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this._wifiConfiguration) {
|
|
||||||
interfaceOptions = {
|
|
||||||
...interfaceOptions,
|
|
||||||
wifi: {
|
|
||||||
ssid: this._wifiConfiguration.ssid,
|
|
||||||
mode: this._wifiConfiguration.mode,
|
|
||||||
auth: this._wifiConfiguration.auth || "open",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (interfaceOptions.wifi!.auth !== "open") {
|
|
||||||
interfaceOptions.wifi = {
|
|
||||||
...interfaceOptions.wifi,
|
|
||||||
psk: this._wifiConfiguration.psk,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaceOptions.enabled =
|
|
||||||
this._wifiConfiguration !== undefined ||
|
|
||||||
interfaceOptions.ipv4?.method !== "disabled" ||
|
|
||||||
interfaceOptions.ipv6?.method !== "disabled";
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateNetworkInterface(
|
await updateNetworkInterface(this.hass, this._device!.interface, options);
|
||||||
this.hass,
|
|
||||||
this._interface!.interface,
|
|
||||||
interfaceOptions
|
|
||||||
);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to change network settings",
|
title: "Failed to change network settings",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
this._processing = false;
|
this._prosessing = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._params?.loadData();
|
this._params?.loadData();
|
||||||
@@ -443,73 +219,40 @@ export class DialogHassioNetwork extends LitElement
|
|||||||
dismissText: "no",
|
dismissText: "no",
|
||||||
});
|
});
|
||||||
if (!confirm) {
|
if (!confirm) {
|
||||||
this.requestUpdate("_interface");
|
this.requestUpdate("_device");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._curTabIndex = ev.detail.index;
|
this._curTabIndex = ev.detail.index;
|
||||||
this._interface = { ...this._interfaces[ev.detail.index] };
|
this._device = this._network[ev.detail.index];
|
||||||
|
this._device.data.nameservers = String(this._device.data.nameservers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleRadioValueChanged(ev: CustomEvent): void {
|
private _handleRadioValueChanged(ev: CustomEvent): void {
|
||||||
const value = (ev.target as any).value as "disabled" | "auto" | "static";
|
const value = (ev.target as HaRadio).value as "dhcp" | "static";
|
||||||
const version = (ev.target as any).version as "ipv4" | "ipv6";
|
|
||||||
|
|
||||||
if (
|
if (!value || !this._device || this._device!.data.method === value) {
|
||||||
!value ||
|
|
||||||
!this._interface ||
|
|
||||||
this._interface[version]!.method === value
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
|
|
||||||
this._interface[version]!.method = value;
|
this._device!.data.method = value;
|
||||||
this.requestUpdate("_interface");
|
this.requestUpdate("_device");
|
||||||
}
|
|
||||||
|
|
||||||
private _handleRadioValueChangedAp(ev: CustomEvent): void {
|
|
||||||
const value = ((ev.target as any).value as string) as
|
|
||||||
| "open"
|
|
||||||
| "wep"
|
|
||||||
| "wpa-psk";
|
|
||||||
this._wifiConfiguration!.auth = value;
|
|
||||||
this._dirty = true;
|
|
||||||
this.requestUpdate("_wifiConfiguration");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleInputValueChanged(ev: CustomEvent): void {
|
private _handleInputValueChanged(ev: CustomEvent): void {
|
||||||
const value: string | null | undefined = (ev.target as PaperInputElement)
|
const value: string | null | undefined = (ev.target as PaperInputElement)
|
||||||
.value;
|
.value;
|
||||||
const version = (ev.target as any).version as "ipv4" | "ipv6";
|
|
||||||
const id = (ev.target as PaperInputElement).id;
|
const id = (ev.target as PaperInputElement).id;
|
||||||
|
|
||||||
if (
|
if (!value || !this._device || this._device.data[id] === value) {
|
||||||
!value ||
|
|
||||||
!this._interface ||
|
|
||||||
this._toString(this._interface[version]![id]) === this._toString(value)
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
this._interface[version]![id] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleInputValueChangedWifi(ev: CustomEvent): void {
|
this._device.data[id] = value;
|
||||||
const value: string | null | undefined = (ev.target as PaperInputElement)
|
|
||||||
.value;
|
|
||||||
const id = (ev.target as PaperInputElement).id;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!value ||
|
|
||||||
!this._wifiConfiguration ||
|
|
||||||
this._wifiConfiguration![id] === value
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._dirty = true;
|
|
||||||
this._wifiConfiguration![id] = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
@@ -556,16 +299,12 @@ export class DialogHassioNetwork extends LitElement
|
|||||||
--mdc-theme-primary: var(--error-color);
|
--mdc-theme-primary: var(--error-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
mwc-button.scan {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([rtl]) app-toolbar {
|
:host([rtl]) app-toolbar {
|
||||||
direction: rtl;
|
direction: rtl;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
padding: 0 8px 4px;
|
padding: 20px 24px;
|
||||||
}
|
}
|
||||||
.form {
|
.form {
|
||||||
margin-bottom: 53px;
|
margin-bottom: 53px;
|
||||||
@@ -583,24 +322,6 @@ export class DialogHassioNetwork extends LitElement
|
|||||||
padding-bottom: max(env(safe-area-inset-bottom), 8px);
|
padding-bottom: max(env(safe-area-inset-bottom), 8px);
|
||||||
background-color: var(--mdc-theme-surface, #fff);
|
background-color: var(--mdc-theme-surface, #fff);
|
||||||
}
|
}
|
||||||
.warning {
|
|
||||||
color: var(--error-color);
|
|
||||||
--primary-color: var(--error-color);
|
|
||||||
}
|
|
||||||
div.warning {
|
|
||||||
margin: 12px 4px -12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-expansion-panel {
|
|
||||||
--expansion-panel-summary-padding: 0 16px;
|
|
||||||
margin: 4px 0;
|
|
||||||
}
|
|
||||||
paper-input {
|
|
||||||
padding: 0 14px;
|
|
||||||
}
|
|
||||||
mwc-list-item {
|
|
||||||
--mdc-list-side-padding: 10px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,10 @@ export const showNetworkDialog = (
|
|||||||
): void => {
|
): void => {
|
||||||
fireEvent(element, "show-dialog", {
|
fireEvent(element, "show-dialog", {
|
||||||
dialogTag: "dialog-hassio-network",
|
dialogTag: "dialog-hassio-network",
|
||||||
dialogImport: () => import("./dialog-hassio-network"),
|
dialogImport: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "dialog-hassio-network" */ "./dialog-hassio-network"
|
||||||
|
),
|
||||||
dialogParams,
|
dialogParams,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -4,7 +4,10 @@ import "./dialog-hassio-registries";
|
|||||||
export const showRegistriesDialog = (element: HTMLElement): void => {
|
export const showRegistriesDialog = (element: HTMLElement): void => {
|
||||||
fireEvent(element, "show-dialog", {
|
fireEvent(element, "show-dialog", {
|
||||||
dialogTag: "dialog-hassio-registries",
|
dialogTag: "dialog-hassio-registries",
|
||||||
dialogImport: () => import("./dialog-hassio-registries"),
|
dialogImport: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "dialog-hassio-registries" */ "./dialog-hassio-registries"
|
||||||
|
),
|
||||||
dialogParams: {},
|
dialogParams: {},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -13,7 +13,10 @@ export const showRepositoriesDialog = (
|
|||||||
): void => {
|
): void => {
|
||||||
fireEvent(element, "show-dialog", {
|
fireEvent(element, "show-dialog", {
|
||||||
dialogTag: "dialog-hassio-repositories",
|
dialogTag: "dialog-hassio-repositories",
|
||||||
dialogImport: () => import("./dialog-hassio-repositories"),
|
dialogImport: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "dialog-hassio-repositories" */ "./dialog-hassio-repositories"
|
||||||
|
),
|
||||||
dialogParams,
|
dialogParams,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -109,7 +109,7 @@ class HassioSnapshotDialog extends LitElement {
|
|||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog open @closing=${this._closeDialog} .heading=${true}>
|
<ha-dialog open stacked @closing=${this._closeDialog} .heading=${true}>
|
||||||
<div slot="heading">
|
<div slot="heading">
|
||||||
<ha-header-bar>
|
<ha-header-bar>
|
||||||
<span slot="title">
|
<span slot="title">
|
||||||
@@ -191,37 +191,47 @@ class HassioSnapshotDialog extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
${this._error ? html` <p class="error">Error: ${this._error}</p> ` : ""}
|
${this._error ? html` <p class="error">Error: ${this._error}</p> ` : ""}
|
||||||
|
|
||||||
<div class="button-row" slot="primaryAction">
|
<div>Actions:</div>
|
||||||
<mwc-button @click=${this._partialRestoreClicked}>
|
${!this._onboarding
|
||||||
<ha-svg-icon .path=${mdiHistory} class="icon"></ha-svg-icon>
|
? html`<mwc-button
|
||||||
Restore Selected
|
@click=${this._downloadClicked}
|
||||||
</mwc-button>
|
slot="primaryAction"
|
||||||
${!this._onboarding
|
>
|
||||||
? html`
|
<ha-svg-icon .path=${mdiDownload} class="icon"></ha-svg-icon>
|
||||||
<mwc-button @click=${this._deleteClicked}>
|
Download Snapshot
|
||||||
<ha-svg-icon .path=${mdiDelete} class="icon warning">
|
</mwc-button>`
|
||||||
</ha-svg-icon>
|
: ""}
|
||||||
<span class="warning">Delete Snapshot</span>
|
|
||||||
</mwc-button>
|
<mwc-button
|
||||||
`
|
@click=${this._partialRestoreClicked}
|
||||||
: ""}
|
slot="secondaryAction"
|
||||||
</div>
|
>
|
||||||
<div class="button-row" slot="secondaryAction">
|
<ha-svg-icon .path=${mdiHistory} class="icon"></ha-svg-icon>
|
||||||
${this._snapshot.type === "full"
|
Restore Selected
|
||||||
? html`
|
</mwc-button>
|
||||||
<mwc-button @click=${this._fullRestoreClicked}>
|
${this._snapshot.type === "full"
|
||||||
<ha-svg-icon .path=${mdiHistory} class="icon"></ha-svg-icon>
|
? html`
|
||||||
Restore Everything
|
<mwc-button
|
||||||
</mwc-button>
|
@click=${this._fullRestoreClicked}
|
||||||
`
|
slot="secondaryAction"
|
||||||
: ""}
|
>
|
||||||
${!this._onboarding
|
<ha-svg-icon .path=${mdiHistory} class="icon"></ha-svg-icon>
|
||||||
? html`<mwc-button @click=${this._downloadClicked}>
|
Wipe & restore
|
||||||
<ha-svg-icon .path=${mdiDownload} class="icon"></ha-svg-icon>
|
</mwc-button>
|
||||||
Download Snapshot
|
`
|
||||||
</mwc-button>`
|
: ""}
|
||||||
: ""}
|
${!this._onboarding
|
||||||
</div>
|
? html`<mwc-button
|
||||||
|
@click=${this._deleteClicked}
|
||||||
|
slot="secondaryAction"
|
||||||
|
>
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${mdiDelete}
|
||||||
|
class="icon warning"
|
||||||
|
></ha-svg-icon>
|
||||||
|
<span class="warning">Delete Snapshot</span>
|
||||||
|
</mwc-button>`
|
||||||
|
: ""}
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -235,14 +245,6 @@ class HassioSnapshotDialog extends LitElement {
|
|||||||
display: block;
|
display: block;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
}
|
}
|
||||||
mwc-button ha-svg-icon {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
.button-row {
|
|
||||||
display: grid;
|
|
||||||
gap: 8px;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
.details {
|
.details {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
@@ -250,6 +252,10 @@ class HassioSnapshotDialog extends LitElement {
|
|||||||
.error {
|
.error {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
.buttons li {
|
.buttons li {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,10 @@ export const showHassioSnapshotDialog = (
|
|||||||
): void => {
|
): void => {
|
||||||
fireEvent(element, "show-dialog", {
|
fireEvent(element, "show-dialog", {
|
||||||
dialogTag: "dialog-hassio-snapshot",
|
dialogTag: "dialog-hassio-snapshot",
|
||||||
dialogImport: () => import("./dialog-hassio-snapshot"),
|
dialogImport: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "dialog-hassio-snapshot" */ "./dialog-hassio-snapshot"
|
||||||
|
),
|
||||||
dialogParams,
|
dialogParams,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -13,7 +13,10 @@ export const showSnapshotUploadDialog = (
|
|||||||
): void => {
|
): void => {
|
||||||
fireEvent(element, "show-dialog", {
|
fireEvent(element, "show-dialog", {
|
||||||
dialogTag: "dialog-hassio-snapshot-upload",
|
dialogTag: "dialog-hassio-snapshot-upload",
|
||||||
dialogImport: () => import("./dialog-hassio-snapshot-upload"),
|
dialogImport: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "dialog-hassio-snapshot-upload" */ "./dialog-hassio-snapshot-upload"
|
||||||
|
),
|
||||||
dialogParams,
|
dialogParams,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -1,22 +1,29 @@
|
|||||||
import { html, PropertyValues, customElement, property } from "lit-element";
|
import {
|
||||||
|
html,
|
||||||
|
PropertyValues,
|
||||||
|
customElement,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
} from "lit-element";
|
||||||
import "./hassio-router";
|
import "./hassio-router";
|
||||||
|
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
|
||||||
|
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
|
||||||
import { HomeAssistant, Route } from "../../src/types";
|
import { HomeAssistant, Route } from "../../src/types";
|
||||||
import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
|
import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
|
||||||
import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element";
|
||||||
import { fireEvent } from "../../src/common/dom/fire_event";
|
import { fireEvent } from "../../src/common/dom/fire_event";
|
||||||
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
|
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
|
||||||
import { atLeastVersion } from "../../src/common/config/version";
|
import { atLeastVersion } from "../../src/common/config/version";
|
||||||
import { SupervisorBaseElement } from "./supervisor-base-element";
|
|
||||||
|
|
||||||
@customElement("hassio-main")
|
@customElement("hassio-main")
|
||||||
export class HassioMain extends SupervisorBaseElement {
|
export class HassioMain extends urlSyncMixin(ProvideHassLitMixin(LitElement)) {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public panel!: HassioPanelInfo;
|
@property() public panel!: HassioPanelInfo;
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property() public narrow!: boolean;
|
||||||
|
|
||||||
@property({ attribute: false }) public route?: Route;
|
@property() public route?: Route;
|
||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
@@ -70,13 +77,9 @@ export class HassioMain extends SupervisorBaseElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this.supervisor || !this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
return html`
|
||||||
<hassio-router
|
<hassio-router
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.panel=${this.panel}
|
.panel=${this.panel}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
import { customElement, property } from "lit-element";
|
import { customElement, property } from "lit-element";
|
||||||
import { Supervisor } from "../../src/data/supervisor/supervisor";
|
import { HassioHassOSInfo, HassioHostInfo } from "../../src/data/hassio/host";
|
||||||
|
import {
|
||||||
|
HassioHomeAssistantInfo,
|
||||||
|
HassioSupervisorInfo,
|
||||||
|
HassioInfo,
|
||||||
|
} from "../../src/data/hassio/supervisor";
|
||||||
import {
|
import {
|
||||||
HassRouterPage,
|
HassRouterPage,
|
||||||
RouterOptions,
|
RouterOptions,
|
||||||
@@ -16,12 +21,20 @@ import "./system/hassio-system";
|
|||||||
class HassioPanelRouter extends HassRouterPage {
|
class HassioPanelRouter extends HassRouterPage {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public supervisorInfo?: HassioSupervisorInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassioInfo!: HassioInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hostInfo?: HassioHostInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassInfo?: HassioHomeAssistantInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
|
||||||
|
|
||||||
protected routerOptions: RouterOptions = {
|
protected routerOptions: RouterOptions = {
|
||||||
routes: {
|
routes: {
|
||||||
dashboard: {
|
dashboard: {
|
||||||
@@ -41,9 +54,13 @@ class HassioPanelRouter extends HassRouterPage {
|
|||||||
|
|
||||||
protected updatePageEl(el) {
|
protected updatePageEl(el) {
|
||||||
el.hass = this.hass;
|
el.hass = this.hass;
|
||||||
el.supervisor = this.supervisor;
|
|
||||||
el.route = this.route;
|
el.route = this.route;
|
||||||
el.narrow = this.narrow;
|
el.narrow = this.narrow;
|
||||||
|
el.supervisorInfo = this.supervisorInfo;
|
||||||
|
el.hassioInfo = this.hassioInfo;
|
||||||
|
el.hostInfo = this.hostInfo;
|
||||||
|
el.hassInfo = this.hassInfo;
|
||||||
|
el.hassOsInfo = this.hassOsInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,13 +1,18 @@
|
|||||||
import {
|
import {
|
||||||
css,
|
|
||||||
CSSResult,
|
|
||||||
customElement,
|
customElement,
|
||||||
html,
|
html,
|
||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { Supervisor } from "../../src/data/supervisor/supervisor";
|
import { HassioHassOSInfo, HassioHostInfo } from "../../src/data/hassio/host";
|
||||||
|
import {
|
||||||
|
HassioHomeAssistantInfo,
|
||||||
|
HassioSupervisorInfo,
|
||||||
|
HassioInfo,
|
||||||
|
} from "../../src/data/hassio/supervisor";
|
||||||
import { HomeAssistant, Route } from "../../src/types";
|
import { HomeAssistant, Route } from "../../src/types";
|
||||||
import "./hassio-panel-router";
|
import "./hassio-panel-router";
|
||||||
|
|
||||||
@@ -15,19 +20,34 @@ import "./hassio-panel-router";
|
|||||||
class HassioPanel extends LitElement {
|
class HassioPanel extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassioInfo!: HassioInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hostInfo!: HassioHostInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassInfo!: HassioHomeAssistantInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (!this.supervisorInfo) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
return html`
|
return html`
|
||||||
<hassio-panel-router
|
<hassio-panel-router
|
||||||
.hass=${this.hass}
|
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
|
.hass=${this.hass}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
|
.supervisorInfo=${this.supervisorInfo}
|
||||||
|
.hassioInfo=${this.hassioInfo}
|
||||||
|
.hostInfo=${this.hostInfo}
|
||||||
|
.hassInfo=${this.hassInfo}
|
||||||
|
.hassOsInfo=${this.hassOsInfo}
|
||||||
></hassio-panel-router>
|
></hassio-panel-router>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,24 @@
|
|||||||
import { customElement, property } from "lit-element";
|
import {
|
||||||
import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
|
customElement,
|
||||||
import { Supervisor } from "../../src/data/supervisor/supervisor";
|
property,
|
||||||
|
internalProperty,
|
||||||
|
PropertyValues,
|
||||||
|
} from "lit-element";
|
||||||
|
import {
|
||||||
|
fetchHassioHassOsInfo,
|
||||||
|
fetchHassioHostInfo,
|
||||||
|
HassioHassOSInfo,
|
||||||
|
HassioHostInfo,
|
||||||
|
} from "../../src/data/hassio/host";
|
||||||
|
import {
|
||||||
|
fetchHassioHomeAssistantInfo,
|
||||||
|
fetchHassioSupervisorInfo,
|
||||||
|
fetchHassioInfo,
|
||||||
|
HassioHomeAssistantInfo,
|
||||||
|
HassioInfo,
|
||||||
|
HassioPanelInfo,
|
||||||
|
HassioSupervisorInfo,
|
||||||
|
} from "../../src/data/hassio/supervisor";
|
||||||
import {
|
import {
|
||||||
HassRouterPage,
|
HassRouterPage,
|
||||||
RouterOptions,
|
RouterOptions,
|
||||||
@@ -14,11 +32,9 @@ import "./hassio-panel";
|
|||||||
class HassioRouter extends HassRouterPage {
|
class HassioRouter extends HassRouterPage {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@property() public panel!: HassioPanelInfo;
|
||||||
|
|
||||||
@property({ attribute: false }) public panel!: HassioPanelInfo;
|
@property() public narrow!: boolean;
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
|
||||||
|
|
||||||
protected routerOptions: RouterOptions = {
|
protected routerOptions: RouterOptions = {
|
||||||
// Hass.io has a page with tabs, so we route all non-matching routes to it.
|
// Hass.io has a page with tabs, so we route all non-matching routes to it.
|
||||||
@@ -35,22 +51,47 @@ class HassioRouter extends HassRouterPage {
|
|||||||
system: "dashboard",
|
system: "dashboard",
|
||||||
addon: {
|
addon: {
|
||||||
tag: "hassio-addon-dashboard",
|
tag: "hassio-addon-dashboard",
|
||||||
load: () => import("./addon-view/hassio-addon-dashboard"),
|
load: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "hassio-addon-dashboard" */ "./addon-view/hassio-addon-dashboard"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
ingress: {
|
ingress: {
|
||||||
tag: "hassio-ingress-view",
|
tag: "hassio-ingress-view",
|
||||||
load: () => import("./ingress-view/hassio-ingress-view"),
|
load: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "hassio-ingress-view" */ "./ingress-view/hassio-ingress-view"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@internalProperty() private _supervisorInfo?: HassioSupervisorInfo;
|
||||||
|
|
||||||
|
@internalProperty() private _hostInfo?: HassioHostInfo;
|
||||||
|
|
||||||
|
@internalProperty() private _hassioInfo?: HassioInfo;
|
||||||
|
|
||||||
|
@internalProperty() private _hassOsInfo?: HassioHassOSInfo;
|
||||||
|
|
||||||
|
@internalProperty() private _hassInfo?: HassioHomeAssistantInfo;
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
|
||||||
|
}
|
||||||
|
|
||||||
protected updatePageEl(el) {
|
protected updatePageEl(el) {
|
||||||
// the tabs page does its own routing so needs full route.
|
// the tabs page does its own routing so needs full route.
|
||||||
const route = el.nodeName === "HASSIO-PANEL" ? this.route : this.routeTail;
|
const route = el.nodeName === "HASSIO-PANEL" ? this.route : this.routeTail;
|
||||||
|
|
||||||
el.hass = this.hass;
|
el.hass = this.hass;
|
||||||
el.supervisor = this.supervisor;
|
|
||||||
el.narrow = this.narrow;
|
el.narrow = this.narrow;
|
||||||
|
el.supervisorInfo = this._supervisorInfo;
|
||||||
|
el.hassioInfo = this._hassioInfo;
|
||||||
|
el.hostInfo = this._hostInfo;
|
||||||
|
el.hassInfo = this._hassInfo;
|
||||||
|
el.hassOsInfo = this._hassOsInfo;
|
||||||
el.route = route;
|
el.route = route;
|
||||||
|
|
||||||
if (el.localName === "hassio-ingress-view") {
|
if (el.localName === "hassio-ingress-view") {
|
||||||
@@ -61,12 +102,45 @@ class HassioRouter extends HassRouterPage {
|
|||||||
private async _fetchData() {
|
private async _fetchData() {
|
||||||
if (this.panel.config && this.panel.config.ingress) {
|
if (this.panel.config && this.panel.config.ingress) {
|
||||||
this._redirectIngress(this.panel.config.ingress);
|
this._redirectIngress(this.panel.config.ingress);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [supervisorInfo, hostInfo, hassInfo, hassioInfo] = await Promise.all([
|
||||||
|
fetchHassioSupervisorInfo(this.hass),
|
||||||
|
fetchHassioHostInfo(this.hass),
|
||||||
|
fetchHassioHomeAssistantInfo(this.hass),
|
||||||
|
fetchHassioInfo(this.hass),
|
||||||
|
]);
|
||||||
|
this._supervisorInfo = supervisorInfo;
|
||||||
|
this._hassioInfo = hassioInfo;
|
||||||
|
this._hostInfo = hostInfo;
|
||||||
|
this._hassInfo = hassInfo;
|
||||||
|
|
||||||
|
if (this._hostInfo.features && this._hostInfo.features.includes("hassos")) {
|
||||||
|
this._hassOsInfo = await fetchHassioHassOsInfo(this.hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _redirectIngress(addonSlug: string) {
|
private _redirectIngress(addonSlug: string) {
|
||||||
this.route = { prefix: "/hassio", path: `/ingress/${addonSlug}` };
|
this.route = { prefix: "/hassio", path: `/ingress/${addonSlug}` };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _apiCalled(ev) {
|
||||||
|
if (!ev.detail.success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tries = 1;
|
||||||
|
|
||||||
|
const tryUpdate = () => {
|
||||||
|
this._fetchData().catch(() => {
|
||||||
|
tries += 1;
|
||||||
|
setTimeout(tryUpdate, Math.min(tries, 5) * 1000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
tryUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@@ -13,10 +13,7 @@ import {
|
|||||||
fetchHassioAddonInfo,
|
fetchHassioAddonInfo,
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
} from "../../../src/data/hassio/addon";
|
} from "../../../src/data/hassio/addon";
|
||||||
import {
|
import { createHassioSession } from "../../../src/data/hassio/supervisor";
|
||||||
createHassioSession,
|
|
||||||
validateHassioSession,
|
|
||||||
} from "../../../src/data/hassio/ingress";
|
|
||||||
import "../../../src/layouts/hass-loading-screen";
|
import "../../../src/layouts/hass-loading-screen";
|
||||||
import "../../../src/layouts/hass-subpage";
|
import "../../../src/layouts/hass-subpage";
|
||||||
import { HomeAssistant, Route } from "../../../src/types";
|
import { HomeAssistant, Route } from "../../../src/types";
|
||||||
@@ -38,17 +35,6 @@ class HassioIngressView extends LitElement {
|
|||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
public narrow = false;
|
public narrow = false;
|
||||||
|
|
||||||
private _sessionKeepAlive?: number;
|
|
||||||
|
|
||||||
public disconnectedCallback() {
|
|
||||||
super.disconnectedCallback();
|
|
||||||
|
|
||||||
if (this._sessionKeepAlive) {
|
|
||||||
clearInterval(this._sessionKeepAlive);
|
|
||||||
this._sessionKeepAlive = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._addon) {
|
if (!this._addon) {
|
||||||
return html` <hass-loading-screen></hass-loading-screen> `;
|
return html` <hass-loading-screen></hass-loading-screen> `;
|
||||||
@@ -58,7 +44,6 @@ class HassioIngressView extends LitElement {
|
|||||||
|
|
||||||
if (!this.ingressPanel) {
|
if (!this.ingressPanel) {
|
||||||
return html`<hass-subpage
|
return html`<hass-subpage
|
||||||
.hass=${this.hass}
|
|
||||||
.header=${this._addon.name}
|
.header=${this._addon.name}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
>
|
>
|
||||||
@@ -98,7 +83,10 @@ class HassioIngressView extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchData(addonSlug: string) {
|
private async _fetchData(addonSlug: string) {
|
||||||
const createSessionPromise = createHassioSession(this.hass);
|
const createSessionPromise = createHassioSession(this.hass).then(
|
||||||
|
() => true,
|
||||||
|
() => false
|
||||||
|
);
|
||||||
|
|
||||||
let addon;
|
let addon;
|
||||||
|
|
||||||
@@ -131,11 +119,7 @@ class HassioIngressView extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let session;
|
if (!(await createSessionPromise)) {
|
||||||
|
|
||||||
try {
|
|
||||||
session = await createSessionPromise;
|
|
||||||
} catch (err) {
|
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
text: "Unable to create an Ingress session",
|
text: "Unable to create an Ingress session",
|
||||||
title: addon.name,
|
title: addon.name,
|
||||||
@@ -144,17 +128,6 @@ class HassioIngressView extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._sessionKeepAlive) {
|
|
||||||
clearInterval(this._sessionKeepAlive);
|
|
||||||
}
|
|
||||||
this._sessionKeepAlive = window.setInterval(async () => {
|
|
||||||
try {
|
|
||||||
await validateHassioSession(this.hass, session);
|
|
||||||
} catch (err) {
|
|
||||||
session = await createHassioSession(this.hass);
|
|
||||||
}
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
this._addon = addon;
|
this._addon = addon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,6 +26,7 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
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-button-menu";
|
import "../../../src/components/ha-button-menu";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
@@ -40,7 +41,7 @@ import {
|
|||||||
HassioSnapshot,
|
HassioSnapshot,
|
||||||
reloadHassioSnapshots,
|
reloadHassioSnapshots,
|
||||||
} from "../../../src/data/hassio/snapshot";
|
} from "../../../src/data/hassio/snapshot";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { HassioSupervisorInfo } from "../../../src/data/hassio/supervisor";
|
||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import { PolymerChangedEvent } from "../../../src/polymer-types";
|
import { PolymerChangedEvent } from "../../../src/polymer-types";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
@@ -66,7 +67,7 @@ class HassioSnapshots extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo;
|
||||||
|
|
||||||
@internalProperty() private _snapshotName = "";
|
@internalProperty() private _snapshotName = "";
|
||||||
|
|
||||||
@@ -265,7 +266,7 @@ class HassioSnapshots extends LitElement {
|
|||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
if (changedProps.has("supervisorInfo")) {
|
if (changedProps.has("supervisorInfo")) {
|
||||||
this._addonList = this.supervisor.supervisor.addons
|
this._addonList = this.supervisorInfo.addons
|
||||||
.map((addon) => ({
|
.map((addon) => ({
|
||||||
slug: addon.slug,
|
slug: addon.slug,
|
||||||
name: addon.name,
|
name: addon.name,
|
||||||
@@ -371,6 +372,7 @@ class HassioSnapshots extends LitElement {
|
|||||||
await createHassioPartialSnapshot(this.hass, data);
|
await createHassioPartialSnapshot(this.hass, data);
|
||||||
}
|
}
|
||||||
this._updateSnapshots();
|
this._updateSnapshots();
|
||||||
|
fireEvent(this, "hass-api-called", { success: true, response: null });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
}
|
}
|
||||||
|
@@ -1,69 +0,0 @@
|
|||||||
import { LitElement, property, PropertyValues } from "lit-element";
|
|
||||||
import {
|
|
||||||
fetchHassioHassOsInfo,
|
|
||||||
fetchHassioHostInfo,
|
|
||||||
} from "../../src/data/hassio/host";
|
|
||||||
import { fetchNetworkInfo } from "../../src/data/hassio/network";
|
|
||||||
import { fetchHassioResolution } from "../../src/data/hassio/resolution";
|
|
||||||
import {
|
|
||||||
fetchHassioHomeAssistantInfo,
|
|
||||||
fetchHassioInfo,
|
|
||||||
fetchHassioSupervisorInfo,
|
|
||||||
} from "../../src/data/hassio/supervisor";
|
|
||||||
import { Supervisor } from "../../src/data/supervisor/supervisor";
|
|
||||||
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
|
|
||||||
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HASSDomEvents {
|
|
||||||
"supervisor-update": Partial<Supervisor>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SupervisorBaseElement extends urlSyncMixin(
|
|
||||||
ProvideHassLitMixin(LitElement)
|
|
||||||
) {
|
|
||||||
@property({ attribute: false }) public supervisor?: Supervisor;
|
|
||||||
|
|
||||||
protected _updateSupervisor(obj: Partial<Supervisor>): void {
|
|
||||||
this.supervisor = { ...this.supervisor!, ...obj };
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues): void {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
this._initSupervisor();
|
|
||||||
this.addEventListener("supervisor-update", (ev) =>
|
|
||||||
this._updateSupervisor(ev.detail)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _initSupervisor(): Promise<void> {
|
|
||||||
const [
|
|
||||||
supervisor,
|
|
||||||
host,
|
|
||||||
core,
|
|
||||||
info,
|
|
||||||
os,
|
|
||||||
network,
|
|
||||||
resolution,
|
|
||||||
] = await Promise.all([
|
|
||||||
fetchHassioSupervisorInfo(this.hass),
|
|
||||||
fetchHassioHostInfo(this.hass),
|
|
||||||
fetchHassioHomeAssistantInfo(this.hass),
|
|
||||||
fetchHassioInfo(this.hass),
|
|
||||||
fetchHassioHassOsInfo(this.hass),
|
|
||||||
fetchNetworkInfo(this.hass),
|
|
||||||
fetchHassioResolution(this.hass),
|
|
||||||
]);
|
|
||||||
|
|
||||||
this.supervisor = {
|
|
||||||
supervisor,
|
|
||||||
host,
|
|
||||||
core,
|
|
||||||
info,
|
|
||||||
os,
|
|
||||||
network,
|
|
||||||
resolution,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@@ -8,12 +8,12 @@ import {
|
|||||||
CSSResult,
|
CSSResult,
|
||||||
customElement,
|
customElement,
|
||||||
html,
|
html,
|
||||||
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
|
||||||
import "../../../src/components/buttons/ha-progress-button";
|
import "../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../src/components/ha-button-menu";
|
import "../../../src/components/ha-button-menu";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
@@ -27,6 +27,8 @@ import {
|
|||||||
changeHostOptions,
|
changeHostOptions,
|
||||||
configSyncOS,
|
configSyncOS,
|
||||||
fetchHassioHostInfo,
|
fetchHassioHostInfo,
|
||||||
|
HassioHassOSInfo,
|
||||||
|
HassioHostInfo as HassioHostInfoType,
|
||||||
rebootHost,
|
rebootHost,
|
||||||
shutdownHost,
|
shutdownHost,
|
||||||
updateOS,
|
updateOS,
|
||||||
@@ -35,7 +37,7 @@ import {
|
|||||||
fetchNetworkInfo,
|
fetchNetworkInfo,
|
||||||
NetworkInfo,
|
NetworkInfo,
|
||||||
} from "../../../src/data/hassio/network";
|
} from "../../../src/data/hassio/network";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { HassioInfo } from "../../../src/data/hassio/supervisor";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@@ -51,22 +53,28 @@ import { hassioStyle } from "../resources/hassio-style";
|
|||||||
class HassioHostInfo extends LitElement {
|
class HassioHostInfo extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@property() public hostInfo!: HassioHostInfoType;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassioInfo!: HassioInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
|
||||||
|
|
||||||
|
@internalProperty() public _networkInfo?: NetworkInfo;
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
const primaryIpAddress = this.supervisor.host.features.includes("network")
|
const primaryIpAddress = this.hostInfo.features.includes("network")
|
||||||
? this._primaryIpAddress(this.supervisor.network!)
|
? this._primaryIpAddress(this._networkInfo!)
|
||||||
: "";
|
: "";
|
||||||
return html`
|
return html`
|
||||||
<ha-card header="Host System">
|
<ha-card header="Host System">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this.supervisor.host.features.includes("hostname")
|
${this.hostInfo.features.includes("hostname")
|
||||||
? html`<ha-settings-row>
|
? html`<ha-settings-row>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
Hostname
|
Hostname
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.host.hostname}
|
${this.hostInfo.hostname}
|
||||||
</span>
|
</span>
|
||||||
<mwc-button
|
<mwc-button
|
||||||
title="Change the hostname"
|
title="Change the hostname"
|
||||||
@@ -76,7 +84,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
</mwc-button>
|
</mwc-button>
|
||||||
</ha-settings-row>`
|
</ha-settings-row>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.supervisor.host.features.includes("network")
|
${this.hostInfo.features.includes("network")
|
||||||
? html` <ha-settings-row>
|
? html` <ha-settings-row>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
IP Address
|
IP Address
|
||||||
@@ -98,9 +106,10 @@ class HassioHostInfo extends LitElement {
|
|||||||
Operating System
|
Operating System
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.host.operating_system}
|
${this.hostInfo.operating_system}
|
||||||
</span>
|
</span>
|
||||||
${this.supervisor.os.update_available
|
${this.hostInfo.features.includes("hassos") &&
|
||||||
|
this.hassOsInfo.update_available
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
title="Update the host OS"
|
title="Update the host OS"
|
||||||
@@ -111,29 +120,29 @@ class HassioHostInfo extends LitElement {
|
|||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
${!this.supervisor.host.features.includes("hassos")
|
${!this.hostInfo.features.includes("hassos")
|
||||||
? html`<ha-settings-row>
|
? html`<ha-settings-row>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
Docker version
|
Docker version
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.info.docker}
|
${this.hassioInfo.docker}
|
||||||
</span>
|
</span>
|
||||||
</ha-settings-row>`
|
</ha-settings-row>`
|
||||||
: ""}
|
: ""}
|
||||||
${this.supervisor.host.deployment
|
${this.hostInfo.deployment
|
||||||
? html`<ha-settings-row>
|
? html`<ha-settings-row>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
Deployment
|
Deployment
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.host.deployment}
|
${this.hostInfo.deployment}
|
||||||
</span>
|
</span>
|
||||||
</ha-settings-row>`
|
</ha-settings-row>`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
${this.supervisor.host.features.includes("reboot")
|
${this.hostInfo.features.includes("reboot")
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
title="Reboot the host OS"
|
title="Reboot the host OS"
|
||||||
@@ -144,7 +153,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.supervisor.host.features.includes("shutdown")
|
${this.hostInfo.features.includes("shutdown")
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
title="Shutdown the host OS"
|
title="Shutdown the host OS"
|
||||||
@@ -166,7 +175,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
<mwc-list-item title="Show a list of hardware">
|
<mwc-list-item title="Show a list of hardware">
|
||||||
Hardware
|
Hardware
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
${this.supervisor.host.features.includes("hassos")
|
${this.hostInfo.features.includes("hassos")
|
||||||
? html`<mwc-list-item
|
? html`<mwc-list-item
|
||||||
title="Load HassOS configs or updates from USB"
|
title="Load HassOS configs or updates from USB"
|
||||||
>
|
>
|
||||||
@@ -184,10 +193,12 @@ class HassioHostInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _primaryIpAddress = memoizeOne((network_info: NetworkInfo) => {
|
private _primaryIpAddress = memoizeOne((network_info: NetworkInfo) => {
|
||||||
if (!network_info || !network_info.interfaces) {
|
if (!network_info) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return network_info.interfaces.find((a) => a.primary)?.ipv4?.address![0];
|
return Object.keys(network_info?.interfaces)
|
||||||
|
.map((device) => network_info.interfaces[device])
|
||||||
|
.find((device) => device.primary)?.ip_address;
|
||||||
});
|
});
|
||||||
|
|
||||||
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
||||||
@@ -305,13 +316,13 @@ class HassioHostInfo extends LitElement {
|
|||||||
|
|
||||||
private async _changeNetworkClicked(): Promise<void> {
|
private async _changeNetworkClicked(): Promise<void> {
|
||||||
showNetworkDialog(this, {
|
showNetworkDialog(this, {
|
||||||
network: this.supervisor.network!,
|
network: this._networkInfo!,
|
||||||
loadData: () => this._loadData(),
|
loadData: () => this._loadData(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _changeHostnameClicked(): Promise<void> {
|
private async _changeHostnameClicked(): Promise<void> {
|
||||||
const curHostname: string = this.supervisor.host.hostname;
|
const curHostname: string = this.hostInfo.hostname;
|
||||||
const hostname = await showPromptDialog(this, {
|
const hostname = await showPromptDialog(this, {
|
||||||
title: "Change Hostname",
|
title: "Change Hostname",
|
||||||
inputLabel: "Please enter a new hostname:",
|
inputLabel: "Please enter a new hostname:",
|
||||||
@@ -322,8 +333,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
if (hostname && hostname !== curHostname) {
|
if (hostname && hostname !== curHostname) {
|
||||||
try {
|
try {
|
||||||
await changeHostOptions(this.hass, { hostname });
|
await changeHostOptions(this.hass, { hostname });
|
||||||
const host = await fetchHassioHostInfo(this.hass);
|
this.hostInfo = await fetchHassioHostInfo(this.hass);
|
||||||
fireEvent(this, "supervisor-update", { host });
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Setting hostname failed",
|
title: "Setting hostname failed",
|
||||||
@@ -336,8 +346,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
private async _importFromUSB(): Promise<void> {
|
private async _importFromUSB(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await configSyncOS(this.hass);
|
await configSyncOS(this.hass);
|
||||||
const host = await fetchHassioHostInfo(this.hass);
|
this.hostInfo = await fetchHassioHostInfo(this.hass);
|
||||||
fireEvent(this, "supervisor-update", { host });
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to import from USB",
|
title: "Failed to import from USB",
|
||||||
@@ -347,8 +356,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _loadData(): Promise<void> {
|
private async _loadData(): Promise<void> {
|
||||||
const network = await fetchNetworkInfo(this.hass);
|
this._networkInfo = await fetchNetworkInfo(this.hass);
|
||||||
fireEvent(this, "supervisor-update", { network });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
|
@@ -13,15 +13,16 @@ import "../../../src/components/ha-card";
|
|||||||
import "../../../src/components/ha-settings-row";
|
import "../../../src/components/ha-settings-row";
|
||||||
import "../../../src/components/ha-switch";
|
import "../../../src/components/ha-switch";
|
||||||
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
||||||
|
import { HassioHostInfo as HassioHostInfoType } from "../../../src/data/hassio/host";
|
||||||
|
import { fetchHassioResolution } from "../../../src/data/hassio/resolution";
|
||||||
import {
|
import {
|
||||||
fetchHassioSupervisorInfo,
|
fetchHassioSupervisorInfo,
|
||||||
|
HassioSupervisorInfo as HassioSupervisorInfoType,
|
||||||
reloadSupervisor,
|
reloadSupervisor,
|
||||||
restartSupervisor,
|
|
||||||
setSupervisorOption,
|
setSupervisorOption,
|
||||||
SupervisorOptions,
|
SupervisorOptions,
|
||||||
updateSupervisor,
|
updateSupervisor,
|
||||||
} from "../../../src/data/hassio/supervisor";
|
} from "../../../src/data/hassio/supervisor";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@@ -31,7 +32,7 @@ import { HomeAssistant } from "../../../src/types";
|
|||||||
import { documentationUrl } from "../../../src/util/documentation-url";
|
import { documentationUrl } from "../../../src/util/documentation-url";
|
||||||
import { hassioStyle } from "../resources/hassio-style";
|
import { hassioStyle } from "../resources/hassio-style";
|
||||||
|
|
||||||
const UNSUPPORTED_REASON = {
|
const ISSUES = {
|
||||||
container: {
|
container: {
|
||||||
title: "Containers known to cause issues",
|
title: "Containers known to cause issues",
|
||||||
url: "/more-info/unsupported/container",
|
url: "/more-info/unsupported/container",
|
||||||
@@ -45,10 +46,6 @@ const UNSUPPORTED_REASON = {
|
|||||||
title: "Docker Version",
|
title: "Docker Version",
|
||||||
url: "/more-info/unsupported/docker_version",
|
url: "/more-info/unsupported/docker_version",
|
||||||
},
|
},
|
||||||
job_conditions: {
|
|
||||||
title: "Ignored job conditions",
|
|
||||||
url: "/more-info/unsupported/job_conditions",
|
|
||||||
},
|
|
||||||
lxc: { title: "LXC", url: "/more-info/unsupported/lxc" },
|
lxc: { title: "LXC", url: "/more-info/unsupported/lxc" },
|
||||||
network_manager: {
|
network_manager: {
|
||||||
title: "Network Manager",
|
title: "Network Manager",
|
||||||
@@ -62,30 +59,14 @@ const UNSUPPORTED_REASON = {
|
|||||||
systemd: { title: "Systemd", url: "/more-info/unsupported/systemd" },
|
systemd: { title: "Systemd", url: "/more-info/unsupported/systemd" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const UNHEALTHY_REASON = {
|
|
||||||
privileged: {
|
|
||||||
title: "Supervisor is not privileged",
|
|
||||||
url: "/more-info/unsupported/privileged",
|
|
||||||
},
|
|
||||||
supervisor: {
|
|
||||||
title: "Supervisor was not able to update",
|
|
||||||
url: "/more-info/unhealthy/supervisor",
|
|
||||||
},
|
|
||||||
setup: {
|
|
||||||
title: "Setup of the Supervisor failed",
|
|
||||||
url: "/more-info/unhealthy/setup",
|
|
||||||
},
|
|
||||||
docker: {
|
|
||||||
title: "The Docker environment is not working properly",
|
|
||||||
url: "/more-info/unhealthy/docker",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
@customElement("hassio-supervisor-info")
|
@customElement("hassio-supervisor-info")
|
||||||
class HassioSupervisorInfo extends LitElement {
|
class HassioSupervisorInfo extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@property({ attribute: false })
|
||||||
|
public supervisorInfo!: HassioSupervisorInfoType;
|
||||||
|
|
||||||
|
@property() public hostInfo!: HassioHostInfoType;
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
@@ -96,7 +77,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
Version
|
Version
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.supervisor.version}
|
${this.supervisorInfo.version}
|
||||||
</span>
|
</span>
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
<ha-settings-row>
|
<ha-settings-row>
|
||||||
@@ -104,9 +85,9 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
Newest Version
|
Newest Version
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.supervisor.version_latest}
|
${this.supervisorInfo.version_latest}
|
||||||
</span>
|
</span>
|
||||||
${this.supervisor.supervisor.update_available
|
${this.supervisorInfo.update_available
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
title="Update the supervisor"
|
title="Update the supervisor"
|
||||||
@@ -122,9 +103,9 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
Channel
|
Channel
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.supervisor.channel}
|
${this.supervisorInfo.channel}
|
||||||
</span>
|
</span>
|
||||||
${this.supervisor.supervisor.channel === "beta"
|
${this.supervisorInfo.channel === "beta"
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
@click=${this._toggleBeta}
|
@click=${this._toggleBeta}
|
||||||
@@ -133,7 +114,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
Leave beta channel
|
Leave beta channel
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
`
|
`
|
||||||
: this.supervisor.supervisor.channel === "stable"
|
: this.supervisorInfo.channel === "stable"
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
@click=${this._toggleBeta}
|
@click=${this._toggleBeta}
|
||||||
@@ -145,7 +126,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
|
|
||||||
${this.supervisor.supervisor.supported
|
${this.supervisorInfo?.supported
|
||||||
? html` <ha-settings-row three-line>
|
? html` <ha-settings-row three-line>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
Share Diagnostics
|
Share Diagnostics
|
||||||
@@ -162,7 +143,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
<ha-switch
|
<ha-switch
|
||||||
haptic
|
haptic
|
||||||
.checked=${this.supervisor.supervisor.diagnostics}
|
.checked=${this.supervisorInfo.diagnostics}
|
||||||
@change=${this._toggleDiagnostics}
|
@change=${this._toggleDiagnostics}
|
||||||
></ha-switch>
|
></ha-switch>
|
||||||
</ha-settings-row>`
|
</ha-settings-row>`
|
||||||
@@ -176,33 +157,14 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
Learn more
|
Learn more
|
||||||
</button>
|
</button>
|
||||||
</div>`}
|
</div>`}
|
||||||
${!this.supervisor.supervisor.healthy
|
|
||||||
? html`<div class="error">
|
|
||||||
Your installation is running in an unhealthy state.
|
|
||||||
<button
|
|
||||||
class="link"
|
|
||||||
title="Learn more about why your system is marked as unhealthy"
|
|
||||||
@click=${this._unhealthyDialog}
|
|
||||||
>
|
|
||||||
Learn more
|
|
||||||
</button>
|
|
||||||
</div>`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
@click=${this._supervisorReload}
|
@click=${this._supervisorReload}
|
||||||
title="Reload parts of the Supervisor"
|
title="Reload parts of the supervisor"
|
||||||
>
|
>
|
||||||
Reload
|
Reload
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
<ha-progress-button
|
|
||||||
class="warning"
|
|
||||||
@click=${this._supervisorRestart}
|
|
||||||
title="Restart the Supervisor"
|
|
||||||
>
|
|
||||||
Restart
|
|
||||||
</ha-progress-button>
|
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
@@ -212,7 +174,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
button.progress = true;
|
button.progress = true;
|
||||||
|
|
||||||
if (this.supervisor.supervisor.channel === "stable") {
|
if (this.supervisorInfo.channel === "stable") {
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
title: "WARNING",
|
title: "WARNING",
|
||||||
text: html` Beta releases are for testers and early adopters and can
|
text: html` Beta releases are for testers and early adopters and can
|
||||||
@@ -241,19 +203,18 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const data: Partial<SupervisorOptions> = {
|
const data: Partial<SupervisorOptions> = {
|
||||||
channel:
|
channel: this.supervisorInfo.channel === "stable" ? "beta" : "stable",
|
||||||
this.supervisor.supervisor.channel === "stable" ? "beta" : "stable",
|
|
||||||
};
|
};
|
||||||
await setSupervisorOption(this.hass, data);
|
await setSupervisorOption(this.hass, data);
|
||||||
await this._reloadSupervisor();
|
await reloadSupervisor(this.hass);
|
||||||
|
fireEvent(this, "hass-api-called", { success: true, response: null });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to set supervisor option",
|
title: "Failed to set supervisor option",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
} finally {
|
|
||||||
button.progress = false;
|
|
||||||
}
|
}
|
||||||
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _supervisorReload(ev: CustomEvent): Promise<void> {
|
private async _supervisorReload(ev: CustomEvent): Promise<void> {
|
||||||
@@ -261,37 +222,15 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
button.progress = true;
|
button.progress = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this._reloadSupervisor();
|
await reloadSupervisor(this.hass);
|
||||||
|
this.supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to reload the supervisor",
|
title: "Failed to reload the supervisor",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
} finally {
|
|
||||||
button.progress = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _reloadSupervisor(): Promise<void> {
|
|
||||||
await reloadSupervisor(this.hass);
|
|
||||||
const supervisor = await fetchHassioSupervisorInfo(this.hass);
|
|
||||||
fireEvent(this, "supervisor-update", { supervisor });
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _supervisorRestart(ev: CustomEvent): Promise<void> {
|
|
||||||
const button = ev.currentTarget as any;
|
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await restartSupervisor(this.hass);
|
|
||||||
} catch (err) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: "Failed to restart the supervisor",
|
|
||||||
text: extractApiErrorMessage(err),
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
button.progress = false;
|
|
||||||
}
|
}
|
||||||
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _supervisorUpdate(ev: CustomEvent): Promise<void> {
|
private async _supervisorUpdate(ev: CustomEvent): Promise<void> {
|
||||||
@@ -300,7 +239,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
title: "Update Supervisor",
|
title: "Update Supervisor",
|
||||||
text: `Are you sure you want to update supervisor to version ${this.supervisor.supervisor.version_latest}?`,
|
text: `Are you sure you want to update supervisor to version ${this.supervisorInfo.version_latest}?`,
|
||||||
confirmText: "update",
|
confirmText: "update",
|
||||||
dismissText: "cancel",
|
dismissText: "cancel",
|
||||||
});
|
});
|
||||||
@@ -317,9 +256,8 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
title: "Failed to update the supervisor",
|
title: "Failed to update the supervisor",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
} finally {
|
|
||||||
button.progress = false;
|
|
||||||
}
|
}
|
||||||
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _diagnosticsInformationDialog(): Promise<void> {
|
private async _diagnosticsInformationDialog(): Promise<void> {
|
||||||
@@ -338,53 +276,22 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _unsupportedDialog(): Promise<void> {
|
private async _unsupportedDialog(): Promise<void> {
|
||||||
|
const resolution = await fetchHassioResolution(this.hass);
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
title: "You are running an unsupported installation",
|
title: "You are running an unsupported installation",
|
||||||
text: html`Below is a list of issues found with your installation, click
|
text: html`Below is a list of issues found with your installation, click
|
||||||
on the links to learn how you can resolve the issues. <br /><br />
|
on the links to learn how you can resolve the issues. <br /><br />
|
||||||
<ul>
|
<ul>
|
||||||
${this.supervisor.resolution.unsupported.map(
|
${resolution.unsupported.map(
|
||||||
(issue) => html`
|
(issue) => html`
|
||||||
<li>
|
<li>
|
||||||
${UNSUPPORTED_REASON[issue]
|
${ISSUES[issue]
|
||||||
? html`<a
|
? html`<a
|
||||||
href="${documentationUrl(
|
href="${documentationUrl(this.hass, ISSUES[issue].url)}"
|
||||||
this.hass,
|
|
||||||
UNSUPPORTED_REASON[issue].url
|
|
||||||
)}"
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
${UNSUPPORTED_REASON[issue].title}
|
${ISSUES[issue].title}
|
||||||
</a>`
|
|
||||||
: issue}
|
|
||||||
</li>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ul>`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _unhealthyDialog(): Promise<void> {
|
|
||||||
await showAlertDialog(this, {
|
|
||||||
title: "Your installation is unhealthy",
|
|
||||||
text: html`Running an unhealthy installation will cause issues. Below is a
|
|
||||||
list of issues found with your installation, click on the links to learn
|
|
||||||
how you can resolve the issues. <br /><br />
|
|
||||||
<ul>
|
|
||||||
${this.supervisor.resolution.unhealthy.map(
|
|
||||||
(issue) => html`
|
|
||||||
<li>
|
|
||||||
${UNHEALTHY_REASON[issue]
|
|
||||||
? html`<a
|
|
||||||
href="${documentationUrl(
|
|
||||||
this.hass,
|
|
||||||
UNHEALTHY_REASON[issue].url
|
|
||||||
)}"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${UNHEALTHY_REASON[issue].title}
|
|
||||||
</a>`
|
</a>`
|
||||||
: issue}
|
: issue}
|
||||||
</li>
|
</li>
|
||||||
@@ -397,7 +304,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
private async _toggleDiagnostics(): Promise<void> {
|
private async _toggleDiagnostics(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const data: SupervisorOptions = {
|
const data: SupervisorOptions = {
|
||||||
diagnostics: !this.supervisor.supervisor?.diagnostics,
|
diagnostics: !this.supervisorInfo?.diagnostics,
|
||||||
};
|
};
|
||||||
await setSupervisorOption(this.hass, data);
|
await setSupervisorOption(this.hass, data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@@ -19,7 +19,6 @@ import "../../../src/components/ha-card";
|
|||||||
import "../../../src/components/ha-settings-row";
|
import "../../../src/components/ha-settings-row";
|
||||||
import { fetchHassioStats, HassioStats } from "../../../src/data/hassio/common";
|
import { fetchHassioStats, HassioStats } from "../../../src/data/hassio/common";
|
||||||
import { HassioHostInfo } from "../../../src/data/hassio/host";
|
import { HassioHostInfo } from "../../../src/data/hassio/host";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
import { bytesToString } from "../../../src/util/bytes-to-string";
|
import { bytesToString } from "../../../src/util/bytes-to-string";
|
||||||
@@ -33,7 +32,7 @@ import { hassioStyle } from "../resources/hassio-style";
|
|||||||
class HassioSystemMetrics extends LitElement {
|
class HassioSystemMetrics extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@property() public hostInfo!: HassioHostInfo;
|
||||||
|
|
||||||
@internalProperty() private _supervisorMetrics?: HassioStats;
|
@internalProperty() private _supervisorMetrics?: HassioStats;
|
||||||
|
|
||||||
@@ -65,8 +64,8 @@ class HassioSystemMetrics extends LitElement {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Used Space",
|
description: "Used Space",
|
||||||
value: this._getUsedSpace(this.supervisor.host),
|
value: this._getUsedSpace(this.hostInfo),
|
||||||
tooltip: `${this.supervisor.host.disk_used} GB/${this.supervisor.host.disk_total} GB`,
|
tooltip: `${this.hostInfo.disk_used} GB/${this.hostInfo.disk_total} GB`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -7,7 +7,14 @@ import {
|
|||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import {
|
||||||
|
HassioHassOSInfo,
|
||||||
|
HassioHostInfo,
|
||||||
|
} from "../../../src/data/hassio/host";
|
||||||
|
import {
|
||||||
|
HassioInfo,
|
||||||
|
HassioSupervisorInfo,
|
||||||
|
} from "../../../src/data/hassio/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";
|
||||||
import { HomeAssistant, Route } from "../../../src/types";
|
import { HomeAssistant, Route } from "../../../src/types";
|
||||||
@@ -22,12 +29,18 @@ import "./hassio-system-metrics";
|
|||||||
class HassioSystem extends LitElement {
|
class HassioSystem extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
|
@property() public supervisorInfo!: HassioSupervisorInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassioInfo!: HassioInfo;
|
||||||
|
|
||||||
|
@property() public hostInfo!: HassioHostInfo;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage
|
<hass-tabs-subpage
|
||||||
@@ -43,15 +56,18 @@ class HassioSystem extends LitElement {
|
|||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
<hassio-supervisor-info
|
<hassio-supervisor-info
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
.hostInfo=${this.hostInfo}
|
||||||
|
.supervisorInfo=${this.supervisorInfo}
|
||||||
></hassio-supervisor-info>
|
></hassio-supervisor-info>
|
||||||
<hassio-host-info
|
<hassio-host-info
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
.hassioInfo=${this.hassioInfo}
|
||||||
|
.hostInfo=${this.hostInfo}
|
||||||
|
.hassOsInfo=${this.hassOsInfo}
|
||||||
></hassio-host-info>
|
></hassio-host-info>
|
||||||
<hassio-system-metrics
|
<hassio-system-metrics
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
.hostInfo=${this.hostInfo}
|
||||||
></hassio-system-metrics>
|
></hassio-system-metrics>
|
||||||
</div>
|
</div>
|
||||||
<hassio-supervisor-log .hass=${this.hass}></hassio-supervisor-log>
|
<hassio-supervisor-log .hass=${this.hass}></hassio-supervisor-log>
|
||||||
|
49
package.json
49
package.json
@@ -29,22 +29,22 @@
|
|||||||
"@fullcalendar/daygrid": "5.1.0",
|
"@fullcalendar/daygrid": "5.1.0",
|
||||||
"@fullcalendar/interaction": "5.1.0",
|
"@fullcalendar/interaction": "5.1.0",
|
||||||
"@fullcalendar/list": "5.1.0",
|
"@fullcalendar/list": "5.1.0",
|
||||||
"@material/chips": "=9.0.0-canary.1c156d69d.0",
|
"@material/chips": "=8.0.0-canary.774dcfc8e.0",
|
||||||
"@material/mwc-button": "^0.20.0",
|
"@material/mwc-button": "^0.19.0",
|
||||||
"@material/mwc-checkbox": "^0.20.0",
|
"@material/mwc-checkbox": "^0.19.0",
|
||||||
"@material/mwc-circular-progress": "^0.20.0",
|
"@material/mwc-circular-progress": "^0.19.0",
|
||||||
"@material/mwc-dialog": "^0.20.0",
|
"@material/mwc-dialog": "^0.19.0",
|
||||||
"@material/mwc-fab": "^0.20.0",
|
"@material/mwc-fab": "^0.19.0",
|
||||||
"@material/mwc-formfield": "^0.20.0",
|
"@material/mwc-formfield": "^0.19.0",
|
||||||
"@material/mwc-icon-button": "^0.20.0",
|
"@material/mwc-icon-button": "^0.19.0",
|
||||||
"@material/mwc-list": "^0.20.0",
|
"@material/mwc-list": "^0.19.0",
|
||||||
"@material/mwc-menu": "^0.20.0",
|
"@material/mwc-menu": "^0.19.0",
|
||||||
"@material/mwc-radio": "^0.20.0",
|
"@material/mwc-radio": "^0.19.0",
|
||||||
"@material/mwc-ripple": "^0.20.0",
|
"@material/mwc-ripple": "^0.19.0",
|
||||||
"@material/mwc-switch": "^0.20.0",
|
"@material/mwc-switch": "^0.19.0",
|
||||||
"@material/mwc-tab": "^0.20.0",
|
"@material/mwc-tab": "^0.19.0",
|
||||||
"@material/mwc-tab-bar": "^0.20.0",
|
"@material/mwc-tab-bar": "^0.19.0",
|
||||||
"@material/top-app-bar": "=9.0.0-canary.1c156d69d.0",
|
"@material/top-app-bar": "=8.0.0-canary.774dcfc8e.0",
|
||||||
"@mdi/js": "5.6.55",
|
"@mdi/js": "5.6.55",
|
||||||
"@mdi/svg": "5.6.55",
|
"@mdi/svg": "5.6.55",
|
||||||
"@polymer/app-layout": "^3.0.2",
|
"@polymer/app-layout": "^3.0.2",
|
||||||
@@ -83,9 +83,6 @@
|
|||||||
"@types/sortablejs": "^1.10.6",
|
"@types/sortablejs": "^1.10.6",
|
||||||
"@vaadin/vaadin-combo-box": "^5.0.10",
|
"@vaadin/vaadin-combo-box": "^5.0.10",
|
||||||
"@vaadin/vaadin-date-picker": "^4.0.7",
|
"@vaadin/vaadin-date-picker": "^4.0.7",
|
||||||
"@vibrant/color": "^3.2.1-alpha.1",
|
|
||||||
"@vibrant/core": "^3.2.1-alpha.1",
|
|
||||||
"@vibrant/quantizer-mmcq": "^3.2.1-alpha.1",
|
|
||||||
"@vue/web-component-wrapper": "^1.2.0",
|
"@vue/web-component-wrapper": "^1.2.0",
|
||||||
"@webcomponents/webcomponentsjs": "^2.2.7",
|
"@webcomponents/webcomponentsjs": "^2.2.7",
|
||||||
"chart.js": "~2.8.0",
|
"chart.js": "~2.8.0",
|
||||||
@@ -93,6 +90,7 @@
|
|||||||
"codemirror": "^5.49.0",
|
"codemirror": "^5.49.0",
|
||||||
"comlink": "^4.3.0",
|
"comlink": "^4.3.0",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
|
"cpx": "^1.5.0",
|
||||||
"cropperjs": "^1.5.7",
|
"cropperjs": "^1.5.7",
|
||||||
"deep-clone-simple": "^1.1.1",
|
"deep-clone-simple": "^1.1.1",
|
||||||
"deep-freeze": "^0.0.1",
|
"deep-freeze": "^0.0.1",
|
||||||
@@ -107,12 +105,13 @@
|
|||||||
"leaflet": "^1.4.0",
|
"leaflet": "^1.4.0",
|
||||||
"leaflet-draw": "^1.0.4",
|
"leaflet-draw": "^1.0.4",
|
||||||
"lit-element": "^2.4.0",
|
"lit-element": "^2.4.0",
|
||||||
|
"lit-grid-layout": "^1.1.11",
|
||||||
"lit-html": "^1.3.0",
|
"lit-html": "^1.3.0",
|
||||||
"lit-virtualizer": "^0.4.2",
|
"lit-virtualizer": "^0.4.2",
|
||||||
"marked": "^1.1.1",
|
"marked": "^1.1.1",
|
||||||
"mdn-polyfills": "^5.16.0",
|
"mdn-polyfills": "^5.16.0",
|
||||||
"memoize-one": "^5.0.2",
|
"memoize-one": "^5.0.2",
|
||||||
"node-vibrant": "3.2.1-alpha.1",
|
"node-vibrant": "^3.1.6",
|
||||||
"proxy-polyfill": "^0.3.1",
|
"proxy-polyfill": "^0.3.1",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
"qrcode": "^1.4.4",
|
"qrcode": "^1.4.4",
|
||||||
@@ -123,8 +122,7 @@
|
|||||||
"superstruct": "^0.10.12",
|
"superstruct": "^0.10.12",
|
||||||
"tinykeys": "^1.1.1",
|
"tinykeys": "^1.1.1",
|
||||||
"unfetch": "^4.1.0",
|
"unfetch": "^4.1.0",
|
||||||
"vis-data": "^7.1.1",
|
"uuid": "^8.3.0",
|
||||||
"vis-network": "^8.5.4",
|
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue2-daterange-picker": "^0.5.1",
|
"vue2-daterange-picker": "^0.5.1",
|
||||||
"web-animations-js": "^2.3.2",
|
"web-animations-js": "^2.3.2",
|
||||||
@@ -146,9 +144,6 @@
|
|||||||
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
||||||
"@babel/preset-env": "^7.11.5",
|
"@babel/preset-env": "^7.11.5",
|
||||||
"@babel/preset-typescript": "^7.10.4",
|
"@babel/preset-typescript": "^7.10.4",
|
||||||
"@koa/cors": "^3.1.0",
|
|
||||||
"@open-wc/dev-server-hmr": "^0.0.2",
|
|
||||||
"@rollup/plugin-babel": "^5.2.1",
|
|
||||||
"@rollup/plugin-commonjs": "^11.1.0",
|
"@rollup/plugin-commonjs": "^11.1.0",
|
||||||
"@rollup/plugin-json": "^4.0.3",
|
"@rollup/plugin-json": "^4.0.3",
|
||||||
"@rollup/plugin-node-resolve": "^7.1.3",
|
"@rollup/plugin-node-resolve": "^7.1.3",
|
||||||
@@ -167,11 +162,8 @@
|
|||||||
"@types/webspeechapi": "^0.0.29",
|
"@types/webspeechapi": "^0.0.29",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.4.0",
|
"@typescript-eslint/eslint-plugin": "^4.4.0",
|
||||||
"@typescript-eslint/parser": "^4.4.0",
|
"@typescript-eslint/parser": "^4.4.0",
|
||||||
"@web/dev-server": "^0.0.24",
|
|
||||||
"@web/dev-server-rollup": "^0.2.11",
|
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"cpx": "^1.5.0",
|
|
||||||
"del": "^4.0.0",
|
"del": "^4.0.0",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"eslint-config-airbnb-typescript": "^7.2.1",
|
"eslint-config-airbnb-typescript": "^7.2.1",
|
||||||
@@ -205,6 +197,7 @@
|
|||||||
"raw-loader": "^2.0.0",
|
"raw-loader": "^2.0.0",
|
||||||
"require-dir": "^1.2.0",
|
"require-dir": "^1.2.0",
|
||||||
"rollup": "^2.8.2",
|
"rollup": "^2.8.2",
|
||||||
|
"rollup-plugin-babel": "^4.4.0",
|
||||||
"rollup-plugin-string": "^3.0.0",
|
"rollup-plugin-string": "^3.0.0",
|
||||||
"rollup-plugin-terser": "^5.3.0",
|
"rollup-plugin-terser": "^5.3.0",
|
||||||
"rollup-plugin-visualizer": "^4.0.4",
|
"rollup-plugin-visualizer": "^4.0.4",
|
||||||
|
41
polymer.json
Normal file
41
polymer.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"entrypoint": "index.html",
|
||||||
|
"shell": "src/entrypoints/app.js",
|
||||||
|
"fragments": [
|
||||||
|
"src/panels/config/ha-panel-config.js",
|
||||||
|
"src/panels/dev-event/ha-panel-dev-event.js",
|
||||||
|
"src/panels/dev-info/ha-panel-dev-info.js",
|
||||||
|
"src/panels/dev-mqtt/ha-panel-dev-mqtt.js",
|
||||||
|
"src/panels/dev-service/ha-panel-dev-service.js",
|
||||||
|
"src/panels/dev-state/ha-panel-dev-state.js",
|
||||||
|
"src/panels/dev-template/ha-panel-dev-template.js",
|
||||||
|
"src/panels/history/ha-panel-history.js",
|
||||||
|
"src/panels/iframe/ha-panel-iframe.js",
|
||||||
|
"src/panels/logbook/ha-panel-logbook.js",
|
||||||
|
"src/panels/map/ha-panel-map.js",
|
||||||
|
"src/panels/shopping-list/ha-panel-shopping-list.js",
|
||||||
|
"src/panels/mailbox/ha-panel-mailbox.js",
|
||||||
|
"hassio/src/entrypoint.js"
|
||||||
|
],
|
||||||
|
"sources": ["src/**/*", "!src/translations/*"],
|
||||||
|
"lint": {
|
||||||
|
"rules": ["polymer-3"],
|
||||||
|
"ignoreWarnings": ["could-not-resolve-reference", "could-not-load"],
|
||||||
|
"filesToIgnore": [
|
||||||
|
"**/*.html",
|
||||||
|
"**/src/panels/config/js/**/*.js",
|
||||||
|
"**/ha-iconset-svg.js",
|
||||||
|
"**/ha-script-editor.js",
|
||||||
|
"**/ha-automation-editor.js",
|
||||||
|
"**/ha-big-calendar.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"builds": [
|
||||||
|
{
|
||||||
|
"preset": "es5-bundled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"preset": "es6-bundled"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
55
script/core
55
script/core
@@ -1,55 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Helper to start Home Assistant Core inside the devcontainer
|
|
||||||
|
|
||||||
# Stop on errors
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ -z "${DEVCONTAINER}" ]; then
|
|
||||||
echo "This task should only run inside a devcontainer, for local install HA Core in a venv."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -z "${CODESPACES}" ]; then
|
|
||||||
WORKSPACE="/root/workspace/frontend"
|
|
||||||
else
|
|
||||||
WORKSPACE="/workspaces/frontend"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z $(which hass) ]; then
|
|
||||||
echo "Installing Home Asstant core from dev."
|
|
||||||
python3 -m pip install --upgrade \
|
|
||||||
colorlog \
|
|
||||||
git+git://github.com/home-assistant/home-assistant.git@dev
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "${WORKSPACE}/config" ]; then
|
|
||||||
echo "Creating default configuration."
|
|
||||||
mkdir -p "${WORKSPACE}/config";
|
|
||||||
hass --script ensure_config -c config
|
|
||||||
echo "demo:
|
|
||||||
|
|
||||||
logger:
|
|
||||||
default: info
|
|
||||||
logs:
|
|
||||||
homeassistant.components.frontend: debug
|
|
||||||
" >> "${WORKSPACE}/config/configuration.yaml"
|
|
||||||
|
|
||||||
if [ ! -z "${HASSIO}" ]; then
|
|
||||||
echo "
|
|
||||||
# frontend:
|
|
||||||
# development_repo: ${WORKSPACE}
|
|
||||||
|
|
||||||
hassio:
|
|
||||||
development_repo: ${WORKSPACE}" >> "${WORKSPACE}/config/configuration.yaml"
|
|
||||||
else
|
|
||||||
echo "
|
|
||||||
frontend:
|
|
||||||
development_repo: ${WORKSPACE}
|
|
||||||
|
|
||||||
# hassio:
|
|
||||||
# development_repo: ${WORKSPACE}" >> "${WORKSPACE}/config/configuration.yaml"
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
hass -c "${WORKSPACE}/config"
|
|
2
setup.py
2
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20201229.0",
|
version="20201021.1",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@@ -18,7 +18,7 @@ import "./ha-auth-flow";
|
|||||||
import { extractSearchParamsObject } from "../common/url/search-params";
|
import { extractSearchParamsObject } from "../common/url/search-params";
|
||||||
import punycode from "punycode";
|
import punycode from "punycode";
|
||||||
|
|
||||||
import("./ha-pick-auth-provider");
|
import(/* webpackChunkName: "pick-auth-provider" */ "./ha-pick-auth-provider");
|
||||||
|
|
||||||
class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
||||||
@property() public clientId?: string;
|
@property() public clientId?: string;
|
||||||
|
@@ -22,8 +22,3 @@ export const rgbContrast = (
|
|||||||
|
|
||||||
return (lum2 + 0.05) / (lum1 + 0.05);
|
return (lum2 + 0.05) / (lum1 + 0.05);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRGBContrastRatio = (
|
|
||||||
rgb1: [number, number, number],
|
|
||||||
rgb2: [number, number, number]
|
|
||||||
) => Math.round((rgbContrast(rgb1, rgb2) + Number.EPSILON) * 100) / 100;
|
|
||||||
|
@@ -1,18 +0,0 @@
|
|||||||
import { isComponentLoaded } from "./is_component_loaded";
|
|
||||||
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
|
||||||
import { HomeAssistant } from "../../types";
|
|
||||||
|
|
||||||
export const canShowPage = (hass: HomeAssistant, page: PageNavigation) => {
|
|
||||||
return (
|
|
||||||
(isCore(page) || isLoadedIntegration(hass, page)) &&
|
|
||||||
!hideAdvancedPage(hass, page)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const isLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
|
|
||||||
!page.component || isComponentLoaded(hass, page.component);
|
|
||||||
const isCore = (page: PageNavigation) => page.core;
|
|
||||||
const isAdvancedPage = (page: PageNavigation) => page.advancedOnly;
|
|
||||||
const userWantsAdvanced = (hass: HomeAssistant) => hass.userData?.showAdvanced;
|
|
||||||
const hideAdvancedPage = (hass: HomeAssistant, page: PageNavigation) =>
|
|
||||||
isAdvancedPage(page) && !userWantsAdvanced(hass);
|
|
@@ -1,6 +1,5 @@
|
|||||||
import { Theme } from "../../data/ws-themes";
|
|
||||||
import { darkStyles, derivedStyles } from "../../resources/styles";
|
import { darkStyles, derivedStyles } from "../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../types";
|
import { HomeAssistant, Theme } from "../../types";
|
||||||
import {
|
import {
|
||||||
hex2rgb,
|
hex2rgb,
|
||||||
lab2hex,
|
lab2hex,
|
||||||
@@ -14,10 +13,10 @@ import { rgbContrast } from "../color/rgb";
|
|||||||
|
|
||||||
interface ProcessedTheme {
|
interface ProcessedTheme {
|
||||||
keys: { [key: string]: "" };
|
keys: { [key: string]: "" };
|
||||||
styles: Record<string, string>;
|
styles: { [key: string]: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
let PROCESSED_THEMES: Record<string, ProcessedTheme> = {};
|
let PROCESSED_THEMES: { [key: string]: ProcessedTheme } = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a theme to an element by setting the CSS variables on it.
|
* Apply a theme to an element by setting the CSS variables on it.
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { directive, NodePart, Part } from "lit-html";
|
import { directive, NodePart, Part } from "lit-html";
|
||||||
|
|
||||||
export const dynamicElement = directive(
|
export const dynamicElement = directive(
|
||||||
(tag: string, properties?: Record<string, any>) => (part: Part): void => {
|
(tag: string, properties?: { [key: string]: any }) => (part: Part): void => {
|
||||||
if (!(part instanceof NodePart)) {
|
if (!(part instanceof NodePart)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"dynamicElementDirective can only be used in content bindings"
|
"dynamicElementDirective can only be used in content bindings"
|
||||||
|
@@ -13,12 +13,13 @@ export const setupLeafletMap = async (
|
|||||||
throw new Error("Cannot setup Leaflet map on disconnected element");
|
throw new Error("Cannot setup Leaflet map on disconnected element");
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const Leaflet = ((await import("leaflet")) as any)
|
const Leaflet = ((await import(
|
||||||
.default as LeafletModuleType;
|
/* webpackChunkName: "leaflet" */ "leaflet"
|
||||||
|
)) as any).default as LeafletModuleType;
|
||||||
Leaflet.Icon.Default.imagePath = "/static/images/leaflet/images/";
|
Leaflet.Icon.Default.imagePath = "/static/images/leaflet/images/";
|
||||||
|
|
||||||
if (draw) {
|
if (draw) {
|
||||||
await import("leaflet-draw");
|
await import(/* webpackChunkName: "leaflet-draw" */ "leaflet-draw");
|
||||||
}
|
}
|
||||||
|
|
||||||
const map = Leaflet.map(mapElement);
|
const map = Leaflet.map(mapElement);
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
export const ensureArray = (value?: any) => {
|
|
||||||
if (!value || Array.isArray(value)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return [value];
|
|
||||||
};
|
|
@@ -5,7 +5,7 @@ import { formatDateTime } from "../datetime/format_date_time";
|
|||||||
import { formatTime } from "../datetime/format_time";
|
import { formatTime } from "../datetime/format_time";
|
||||||
import { LocalizeFunc } from "../translations/localize";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
import { computeStateDomain } from "./compute_state_domain";
|
import { computeStateDomain } from "./compute_state_domain";
|
||||||
import { formatNumber } from "../string/format_number";
|
import { numberFormat } from "../string/number-format";
|
||||||
|
|
||||||
export const computeStateDisplay = (
|
export const computeStateDisplay = (
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
@@ -20,7 +20,7 @@ export const computeStateDisplay = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stateObj.attributes.unit_of_measurement) {
|
if (stateObj.attributes.unit_of_measurement) {
|
||||||
return `${formatNumber(compareState, language)} ${
|
return `${numberFormat(compareState, language)} ${
|
||||||
stateObj.attributes.unit_of_measurement
|
stateObj.attributes.unit_of_measurement
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
@@ -67,10 +67,6 @@ export const computeStateDisplay = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain === "counter") {
|
|
||||||
return formatNumber(compareState, language);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// Return device class translation
|
// Return device class translation
|
||||||
(stateObj.attributes.device_class &&
|
(stateObj.attributes.device_class &&
|
||||||
|
@@ -78,25 +78,3 @@ export const coverIcon = (state?: string, stateObj?: HassEntity): string => {
|
|||||||
return "hass:window-open";
|
return "hass:window-open";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const computeOpenIcon = (stateObj: HassEntity): string => {
|
|
||||||
switch (stateObj.attributes.device_class) {
|
|
||||||
case "awning":
|
|
||||||
case "door":
|
|
||||||
case "gate":
|
|
||||||
return "hass:arrow-expand-horizontal";
|
|
||||||
default:
|
|
||||||
return "hass:arrow-up";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const computeCloseIcon = (stateObj: HassEntity): string => {
|
|
||||||
switch (stateObj.attributes.device_class) {
|
|
||||||
case "awning":
|
|
||||||
case "door":
|
|
||||||
case "gate":
|
|
||||||
return "hass:arrow-collapse-horizontal";
|
|
||||||
default:
|
|
||||||
return "hass:arrow-down";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@@ -77,11 +77,6 @@ export const domainIcon = (
|
|||||||
return "hass:calendar";
|
return "hass:calendar";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "sun":
|
|
||||||
return stateObj?.state === "above_horizon"
|
|
||||||
? FIXED_DOMAIN_ICONS[domain]
|
|
||||||
: "hass:weather-night";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain in FIXED_DOMAIN_ICONS) {
|
if (domain in FIXED_DOMAIN_ICONS) {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { HassEntities } from "home-assistant-js-websocket";
|
import { HassEntities } from "home-assistant-js-websocket";
|
||||||
import type { GroupEntity } from "../../data/group";
|
import { GroupEntity } from "../../types";
|
||||||
import { DEFAULT_VIEW_ENTITY_ID } from "../const";
|
import { DEFAULT_VIEW_ENTITY_ID } from "../const";
|
||||||
|
|
||||||
// Return an ordered array of available views
|
// Return an ordered array of available views
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { HassEntities } from "home-assistant-js-websocket";
|
import { HassEntities } from "home-assistant-js-websocket";
|
||||||
import { GroupEntity } from "../../data/group";
|
import { GroupEntity } from "../../types";
|
||||||
|
|
||||||
export const getGroupEntities = (
|
export const getGroupEntities = (
|
||||||
entities: HassEntities,
|
entities: HassEntities,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { HassEntities } from "home-assistant-js-websocket";
|
import { HassEntities } from "home-assistant-js-websocket";
|
||||||
import { GroupEntity } from "../../data/group";
|
import { GroupEntity } from "../../types";
|
||||||
import { computeDomain } from "./compute_domain";
|
import { computeDomain } from "./compute_domain";
|
||||||
import { getGroupEntities } from "./get_group_entities";
|
import { getGroupEntities } from "./get_group_entities";
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { HassEntities } from "home-assistant-js-websocket";
|
import { HassEntities } from "home-assistant-js-websocket";
|
||||||
import { GroupEntity } from "../../data/group";
|
import { GroupEntity } from "../../types";
|
||||||
import { computeDomain } from "./compute_domain";
|
import { computeDomain } from "./compute_domain";
|
||||||
|
|
||||||
// Split a collection into a list of groups and a 'rest' list of ungrouped
|
// Split a collection into a list of groups and a 'rest' list of ungrouped
|
||||||
|
@@ -1,132 +0,0 @@
|
|||||||
import Vibrant from "node-vibrant/lib/browser";
|
|
||||||
import MMCQ from "@vibrant/quantizer-mmcq";
|
|
||||||
import { BasicPipeline } from "@vibrant/core/lib/pipeline";
|
|
||||||
import { Swatch, Vec3 } from "@vibrant/color";
|
|
||||||
import { getRGBContrastRatio } from "../color/rgb";
|
|
||||||
|
|
||||||
const CONTRAST_RATIO = 4.5;
|
|
||||||
|
|
||||||
// How much the total diff between 2 RGB colors can be
|
|
||||||
// to be considered similar.
|
|
||||||
const COLOR_SIMILARITY_THRESHOLD = 150;
|
|
||||||
|
|
||||||
// For debug purposes, is being tree shaken.
|
|
||||||
const DEBUG_COLOR = __DEV__ && false;
|
|
||||||
|
|
||||||
const logColor = (
|
|
||||||
color: Swatch,
|
|
||||||
label = `${color.hex} - ${color.population}`
|
|
||||||
) =>
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(
|
|
||||||
`%c${label}`,
|
|
||||||
`color: ${color.bodyTextColor}; background-color: ${color.hex}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const customGenerator = (colors: Swatch[]) => {
|
|
||||||
colors.sort((colorA, colorB) => colorB.population - colorA.population);
|
|
||||||
|
|
||||||
const backgroundColor = colors[0];
|
|
||||||
let foregroundColor: Vec3 | undefined;
|
|
||||||
|
|
||||||
const contrastRatios = new Map<string, number>();
|
|
||||||
const approvedContrastRatio = (hex: string, rgb: Swatch["rgb"]) => {
|
|
||||||
if (!contrastRatios.has(hex)) {
|
|
||||||
contrastRatios.set(hex, getRGBContrastRatio(backgroundColor.rgb, rgb));
|
|
||||||
}
|
|
||||||
|
|
||||||
return contrastRatios.get(hex)! > CONTRAST_RATIO;
|
|
||||||
};
|
|
||||||
|
|
||||||
// We take each next color and find one that has better contrast.
|
|
||||||
for (let i = 1; i < colors.length && foregroundColor === undefined; i++) {
|
|
||||||
// If this color matches, score, take it.
|
|
||||||
if (approvedContrastRatio(colors[i].hex, colors[i].rgb)) {
|
|
||||||
if (DEBUG_COLOR) {
|
|
||||||
logColor(colors[i], "PICKED");
|
|
||||||
}
|
|
||||||
foregroundColor = colors[i].rgb;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This color has the wrong contrast ratio, but it is the right color.
|
|
||||||
// Let's find similar colors that might have the right contrast ratio
|
|
||||||
|
|
||||||
const currentColor = colors[i];
|
|
||||||
if (DEBUG_COLOR) {
|
|
||||||
logColor(colors[i], "Finding similar color with better contrast");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = i + 1; j < colors.length; j++) {
|
|
||||||
const compareColor = colors[j];
|
|
||||||
|
|
||||||
// difference. 0 is same, 765 max difference
|
|
||||||
const diffScore =
|
|
||||||
Math.abs(currentColor.rgb[0] - compareColor.rgb[0]) +
|
|
||||||
Math.abs(currentColor.rgb[1] - compareColor.rgb[1]) +
|
|
||||||
Math.abs(currentColor.rgb[2] - compareColor.rgb[2]);
|
|
||||||
|
|
||||||
if (DEBUG_COLOR) {
|
|
||||||
logColor(colors[j], `${colors[j].hex} - ${diffScore}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (diffScore > COLOR_SIMILARITY_THRESHOLD) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (approvedContrastRatio(compareColor.hex, compareColor.rgb)) {
|
|
||||||
if (DEBUG_COLOR) {
|
|
||||||
logColor(compareColor, "PICKED");
|
|
||||||
}
|
|
||||||
foregroundColor = compareColor.rgb;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foregroundColor === undefined) {
|
|
||||||
foregroundColor =
|
|
||||||
// @ts-expect-error
|
|
||||||
backgroundColor.getYiq() < 200 ? [255, 255, 255] : [0, 0, 0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG_COLOR) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log();
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(
|
|
||||||
"%cPicked colors",
|
|
||||||
`color: ${foregroundColor}; background-color: ${backgroundColor.hex}; font-weight: bold; padding: 16px;`
|
|
||||||
);
|
|
||||||
colors.forEach((color) => logColor(color));
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
foreground: new Swatch(foregroundColor, 0),
|
|
||||||
background: backgroundColor,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
Vibrant.use(
|
|
||||||
new BasicPipeline().filter
|
|
||||||
.register(
|
|
||||||
"default",
|
|
||||||
(r: number, g: number, b: number, a: number) =>
|
|
||||||
a >= 125 && !(r > 250 && g > 250 && b > 250)
|
|
||||||
)
|
|
||||||
.quantizer.register("mmcq", MMCQ)
|
|
||||||
// Our generator has different output
|
|
||||||
// @ts-expect-error
|
|
||||||
.generator.register("default", customGenerator)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const extractColors = (url: string, downsampleColors = 16) =>
|
|
||||||
new Vibrant(url, {
|
|
||||||
colorCount: downsampleColors,
|
|
||||||
})
|
|
||||||
.getPalette()
|
|
||||||
.then(({ foreground, background }) => {
|
|
||||||
return { background: background!, foreground: foreground! };
|
|
||||||
});
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user