mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-27 18:19:28 +00:00
Compare commits
3 Commits
20210601.1
...
fix-number
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a63e788ced | ||
![]() |
c377c01c65 | ||
![]() |
aaf65e0599 |
@@ -4,7 +4,7 @@
|
|||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
"context": ".."
|
"context": ".."
|
||||||
},
|
},
|
||||||
"appPort": "8124:8123",
|
"appPort": 8123,
|
||||||
"context": "..",
|
"context": "..",
|
||||||
"postCreateCommand": "script/bootstrap",
|
"postCreateCommand": "script/bootstrap",
|
||||||
"extensions": [
|
"extensions": [
|
||||||
|
@@ -4,7 +4,8 @@
|
|||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
"plugin:wc/recommended",
|
"plugin:wc/recommended",
|
||||||
"plugin:lit/recommended",
|
"plugin:lit/recommended",
|
||||||
"prettier"
|
"prettier",
|
||||||
|
"prettier/@typescript-eslint"
|
||||||
],
|
],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
@@ -28,7 +29,9 @@
|
|||||||
"__BUILD__": false,
|
"__BUILD__": false,
|
||||||
"__VERSION__": false,
|
"__VERSION__": false,
|
||||||
"__STATIC_PATH__": false,
|
"__STATIC_PATH__": false,
|
||||||
"Polymer": true
|
"Polymer": true,
|
||||||
|
"webkitSpeechRecognition": false,
|
||||||
|
"ResizeObserver": false
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
@@ -81,29 +84,8 @@
|
|||||||
"@typescript-eslint/no-unused-vars": 0,
|
"@typescript-eslint/no-unused-vars": 0,
|
||||||
"@typescript-eslint/explicit-function-return-type": 0,
|
"@typescript-eslint/explicit-function-return-type": 0,
|
||||||
"@typescript-eslint/explicit-module-boundary-types": 0,
|
"@typescript-eslint/explicit-module-boundary-types": 0,
|
||||||
"@typescript-eslint/no-shadow": ["error"],
|
"@typescript-eslint/no-shadow": ["error"]
|
||||||
"@typescript-eslint/naming-convention": [
|
|
||||||
0,
|
|
||||||
{
|
|
||||||
"selector": "default",
|
|
||||||
"format": ["camelCase", "snake_case"],
|
|
||||||
"leadingUnderscore": "allow",
|
|
||||||
"trailingUnderscore": "allow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": ["variable"],
|
|
||||||
"format": ["camelCase", "snake_case", "UPPER_CASE"],
|
|
||||||
"leadingUnderscore": "allow",
|
|
||||||
"trailingUnderscore": "allow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "typeLike",
|
|
||||||
"format": ["PascalCase"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"lit/attribute-value-entities": 0
|
|
||||||
},
|
},
|
||||||
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
|
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
|
||||||
"processor": "disable/disable",
|
"processor": "disable/disable"
|
||||||
"ignorePatterns": ["src/resources/lit-virtualizer/*"]
|
|
||||||
}
|
}
|
||||||
|
121
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
121
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,121 +0,0 @@
|
|||||||
name: Report a bug with the UI, Frontend or Lovelace
|
|
||||||
description: Report an issue related to the Home Assistant frontend.
|
|
||||||
labels: bug
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Make sure you are running the [latest version of Home Assistant][releases] before reporting an issue.
|
|
||||||
|
|
||||||
If you have a feature or enhancement request for the frontend, please [start an discussion][fr] instead of creating an issue.
|
|
||||||
|
|
||||||
**Please not not report issues for custom Lovelace cards.**
|
|
||||||
|
|
||||||
[fr]: https://github.com/home-assistant/frontend/discussions
|
|
||||||
[releases]: https://github.com/home-assistant/home-assistant/releases
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Checklist
|
|
||||||
description: Please verify that you've followed these steps
|
|
||||||
options:
|
|
||||||
- label: I have updated to the latest available Home Assistant version.
|
|
||||||
required: true
|
|
||||||
- label: I have cleared the cache of my browser.
|
|
||||||
required: true
|
|
||||||
- label: I have tried a different browser to see if it is related to my browser.
|
|
||||||
required: true
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
## The problem
|
|
||||||
- type: textarea
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
attributes:
|
|
||||||
label: Describe the issue you are experiencing
|
|
||||||
description: Provide a clear and concise description of what the bug is.
|
|
||||||
- type: textarea
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
attributes:
|
|
||||||
label: Describe the behavior you expected
|
|
||||||
description: Describe what you expected to happen or it should look/behave.
|
|
||||||
- type: textarea
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
attributes:
|
|
||||||
label: Steps to reproduce the issue
|
|
||||||
description: |
|
|
||||||
Please tell us exactly how to reproduce your issue.
|
|
||||||
Provide clear and concise step by step instructions and add code snippets if needed.
|
|
||||||
value: |
|
|
||||||
1.
|
|
||||||
2.
|
|
||||||
3.
|
|
||||||
...
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
## Environment
|
|
||||||
- type: input
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
attributes:
|
|
||||||
label: What version of Home Assistant Core has the issue?
|
|
||||||
placeholder: core-
|
|
||||||
description: >
|
|
||||||
Can be found in the Configuration panel -> Info.
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: What was the last working version of Home Assistant Core?
|
|
||||||
placeholder: core-
|
|
||||||
description: >
|
|
||||||
If known, otherwise leave blank.
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: In which browser are you experiencing the issue with?
|
|
||||||
placeholder: Google Chrome 88.0.4324.150
|
|
||||||
description: >
|
|
||||||
Provide the full name and don't forget to add the version!
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: Which operating system are you using to run this browser?
|
|
||||||
placeholder: macOS Big Sur (1.11)
|
|
||||||
description: >
|
|
||||||
Don't forget to add the version!
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
# Details
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: State of relevant entities
|
|
||||||
description: >
|
|
||||||
If your issue is about how an entity is shown in the UI, please add the
|
|
||||||
state and attributes for all situations. You can find this information
|
|
||||||
at Developer Tools -> States.
|
|
||||||
render: txt
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Problem-relevant frontend configuration
|
|
||||||
description: >
|
|
||||||
An example configuration that caused the problem for you, e.g., the YAML
|
|
||||||
configuration of the used cards. Fill this out even if it seems
|
|
||||||
unimportant to you. Please be sure to remove personal information like
|
|
||||||
passwords, private URLs and other credentials.
|
|
||||||
render: yaml
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Javascript errors shown in your browser console/inspector
|
|
||||||
description: >
|
|
||||||
If you come across any Javascript or other error logs, e.g., in your
|
|
||||||
browser console/inspector please provide them.
|
|
||||||
render: txt
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional information
|
|
||||||
description: >
|
|
||||||
If you have any additional information for us, use the field below.
|
|
||||||
Please note, you can attach screenshots or screen recordings here, by
|
|
||||||
dragging and dropping files in the field below.
|
|
6
.github/workflows/ci.yaml
vendored
6
.github/workflows/ci.yaml
vendored
@@ -37,11 +37,9 @@ jobs:
|
|||||||
- name: Build resources
|
- name: Build resources
|
||||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations gather-gallery-demos
|
run: ./node_modules/.bin/gulp gen-icons-json build-translations gather-gallery-demos
|
||||||
- name: Run eslint
|
- name: Run eslint
|
||||||
run: yarn run lint:eslint
|
run: ./node_modules/.bin/eslint '{**/src,src}/**/*.{js,ts,html}' --ignore-path .gitignore
|
||||||
- name: Run tsc
|
- name: Run tsc
|
||||||
run: yarn run lint:types
|
run: ./node_modules/.bin/tsc
|
||||||
- name: Run prettier
|
|
||||||
run: yarn run lint:prettier
|
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
@@ -6,8 +6,8 @@ on:
|
|||||||
- published
|
- published
|
||||||
|
|
||||||
env:
|
env:
|
||||||
WHEELS_TAG: 3.8-alpine3.12
|
WHEELS_TAG: 3.7-alpine3.11
|
||||||
PYTHON_VERSION: 3.8
|
PYTHON_VERSION: 3.7
|
||||||
NODE_VERSION: 12.1
|
NODE_VERSION: 12.1
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
2
.github/workflows/translations.yaml
vendored
2
.github/workflows/translations.yaml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
paths:
|
paths:
|
||||||
- src/translations/en.json
|
- translations/en.json
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 12
|
NODE_VERSION: 12
|
||||||
|
21
.gitignore
vendored
21
.gitignore
vendored
@@ -1,17 +1,10 @@
|
|||||||
.DS_Store
|
|
||||||
.reify-cache
|
|
||||||
|
|
||||||
# build
|
|
||||||
build
|
build
|
||||||
build-translations/*
|
build-translations/*
|
||||||
hass_frontend/*
|
|
||||||
dist
|
|
||||||
|
|
||||||
# yarn
|
|
||||||
.yarn
|
|
||||||
yarn-error.log
|
|
||||||
node_modules/*
|
node_modules/*
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
.DS_Store
|
||||||
|
hass_frontend/*
|
||||||
|
.reify-cache
|
||||||
|
|
||||||
# Python stuff
|
# Python stuff
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
@@ -21,8 +14,11 @@ npm-debug.log
|
|||||||
# venv stuff
|
# venv stuff
|
||||||
pyvenv.cfg
|
pyvenv.cfg
|
||||||
pip-selfcheck.json
|
pip-selfcheck.json
|
||||||
venv/*
|
venv
|
||||||
.venv
|
.venv
|
||||||
|
lib
|
||||||
|
bin
|
||||||
|
dist
|
||||||
|
|
||||||
# vscode
|
# vscode
|
||||||
.vscode/*
|
.vscode/*
|
||||||
@@ -35,8 +31,9 @@ src/cast/dev_const.ts
|
|||||||
|
|
||||||
# Secrets
|
# Secrets
|
||||||
.lokalise_token
|
.lokalise_token
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
# asdf
|
#asdf
|
||||||
.tool-versions
|
.tool-versions
|
||||||
|
|
||||||
# Home Assistant config
|
# Home Assistant config
|
||||||
|
@@ -1,4 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
require: "test-mocha/testconf.js",
|
|
||||||
timeout: 10000,
|
|
||||||
};
|
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const env = require("./env.js");
|
const env = require("./env.js");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
@@ -54,13 +53,13 @@ module.exports.babelOptions = ({ latestBuild }) => ({
|
|||||||
babelrc: false,
|
babelrc: false,
|
||||||
presets: [
|
presets: [
|
||||||
!latestBuild && [
|
!latestBuild && [
|
||||||
"@babel/preset-env",
|
require("@babel/preset-env").default,
|
||||||
{
|
{
|
||||||
useBuiltIns: "entry",
|
useBuiltIns: "entry",
|
||||||
corejs: "3.6",
|
corejs: "3.6",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"@babel/preset-typescript",
|
require("@babel/preset-typescript").default,
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
plugins: [
|
plugins: [
|
||||||
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
// Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2})
|
||||||
@@ -73,9 +72,14 @@ module.exports.babelOptions = ({ latestBuild }) => ({
|
|||||||
"@babel/plugin-syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
"@babel/plugin-proposal-optional-chaining",
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
|
[
|
||||||
["@babel/plugin-proposal-private-methods", { loose: true }],
|
require("@babel/plugin-proposal-decorators").default,
|
||||||
["@babel/plugin-proposal-class-properties", { loose: true }],
|
{ decoratorsBeforeExport: true },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
require("@babel/plugin-proposal-class-properties").default,
|
||||||
|
{ loose: true },
|
||||||
|
],
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
|
@@ -85,11 +85,6 @@ gulp.task("copy-translations-app", async () => {
|
|||||||
copyTranslations(staticDir);
|
copyTranslations(staticDir);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("copy-translations-supervisor", async () => {
|
|
||||||
const staticDir = paths.hassio_output_static;
|
|
||||||
copyTranslations(staticDir);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("copy-static-app", async () => {
|
gulp.task("copy-static-app", async () => {
|
||||||
const staticDir = paths.app_output_static;
|
const staticDir = paths.app_output_static;
|
||||||
// Basic static files
|
// Basic static files
|
||||||
|
@@ -10,8 +10,6 @@ require("./gen-icons-json.js");
|
|||||||
require("./webpack.js");
|
require("./webpack.js");
|
||||||
require("./compress.js");
|
require("./compress.js");
|
||||||
require("./rollup.js");
|
require("./rollup.js");
|
||||||
require("./gather-static.js");
|
|
||||||
require("./translations.js");
|
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-hassio",
|
"develop-hassio",
|
||||||
@@ -22,8 +20,6 @@ gulp.task(
|
|||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"gen-index-hassio-dev",
|
"gen-index-hassio-dev",
|
||||||
"build-supervisor-translations",
|
|
||||||
"copy-translations-supervisor",
|
|
||||||
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -36,8 +32,6 @@ gulp.task(
|
|||||||
},
|
},
|
||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"build-supervisor-translations",
|
|
||||||
"copy-translations-supervisor",
|
|
||||||
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
|
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
|
||||||
"gen-index-hassio-prod",
|
"gen-index-hassio-prod",
|
||||||
...// Don't compress running tests
|
...// Don't compress running tests
|
||||||
|
@@ -266,7 +266,6 @@ gulp.task(taskName, function () {
|
|||||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||||
delete data.ui.panel[fragment];
|
delete data.ui.panel[fragment];
|
||||||
});
|
});
|
||||||
delete data.supervisor;
|
|
||||||
return data;
|
return data;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -343,26 +342,18 @@ gulp.task(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("build-translation-fragment-supervisor", function () {
|
gulp.task(
|
||||||
return gulp
|
"build-translations",
|
||||||
.src(fullDir + "/*.json")
|
gulp.series(
|
||||||
.pipe(transform((data) => data.supervisor))
|
"clean-translations",
|
||||||
.pipe(gulp.dest(workDir + "/supervisor"));
|
"ensure-translations-build-dir",
|
||||||
});
|
env.isProdBuild() ? (done) => done() : "create-test-translation",
|
||||||
|
"build-master-translation",
|
||||||
gulp.task("build-translation-flatten-supervisor", function () {
|
"build-merged-translations",
|
||||||
return gulp
|
gulp.parallel(...splitTasks),
|
||||||
.src(workDir + "/supervisor/*.json")
|
"build-flattened-translations",
|
||||||
.pipe(
|
"build-translation-fingerprints",
|
||||||
transform(function (data) {
|
function writeMetadata() {
|
||||||
// Polymer.AppLocalizeBehavior requires flattened json
|
|
||||||
return flatten(data);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(gulp.dest(outDir));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("build-translation-write-metadata", function writeMetadata() {
|
|
||||||
return gulp
|
return gulp
|
||||||
.src(
|
.src(
|
||||||
[
|
[
|
||||||
@@ -378,13 +369,14 @@ gulp.task("build-translation-write-metadata", function writeMetadata() {
|
|||||||
const newData = {};
|
const newData = {};
|
||||||
Object.entries(data).forEach(([key, value]) => {
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
// Filter out translations without native name.
|
// Filter out translations without native name.
|
||||||
if (value.nativeName) {
|
if (data[key].nativeName) {
|
||||||
newData[key] = value;
|
newData[key] = data[key];
|
||||||
} else {
|
} else {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Skipping language ${key}. Native name was not translated.`
|
`Skipping language ${key}. Native name was not translated.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (data[key]) newData[key] = value;
|
||||||
});
|
});
|
||||||
return newData;
|
return newData;
|
||||||
})
|
})
|
||||||
@@ -397,33 +389,6 @@ gulp.task("build-translation-write-metadata", function writeMetadata() {
|
|||||||
)
|
)
|
||||||
.pipe(rename("translationMetadata.json"))
|
.pipe(rename("translationMetadata.json"))
|
||||||
.pipe(gulp.dest(workDir));
|
.pipe(gulp.dest(workDir));
|
||||||
});
|
}
|
||||||
|
|
||||||
gulp.task(
|
|
||||||
"build-translations",
|
|
||||||
gulp.series(
|
|
||||||
"clean-translations",
|
|
||||||
"ensure-translations-build-dir",
|
|
||||||
env.isProdBuild() ? (done) => done() : "create-test-translation",
|
|
||||||
"build-master-translation",
|
|
||||||
"build-merged-translations",
|
|
||||||
gulp.parallel(...splitTasks),
|
|
||||||
"build-flattened-translations",
|
|
||||||
"build-translation-fingerprints",
|
|
||||||
"build-translation-write-metadata"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task(
|
|
||||||
"build-supervisor-translations",
|
|
||||||
gulp.series(
|
|
||||||
"clean-translations",
|
|
||||||
"ensure-translations-build-dir",
|
|
||||||
"build-master-translation",
|
|
||||||
"build-merged-translations",
|
|
||||||
"build-translation-fragment-supervisor",
|
|
||||||
"build-translation-flatten-supervisor",
|
|
||||||
"build-translation-fingerprints",
|
|
||||||
"build-translation-write-metadata"
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@@ -137,12 +137,7 @@ gulp.task("webpack-watch-hassio", () => {
|
|||||||
isProdBuild: false,
|
isProdBuild: false,
|
||||||
latestBuild: true,
|
latestBuild: true,
|
||||||
})
|
})
|
||||||
).watch({ ignored: /build-translations/ }, doneHandler());
|
).watch({}, doneHandler());
|
||||||
|
|
||||||
gulp.watch(
|
|
||||||
path.join(paths.translations_src, "en.json"),
|
|
||||||
gulp.series("build-supervisor-translations", "copy-translations-supervisor")
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("webpack-prod-hassio", () =>
|
gulp.task("webpack-prod-hassio", () =>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -35,7 +34,6 @@ module.exports = {
|
|||||||
|
|
||||||
hassio_dir: path.resolve(__dirname, "../hassio"),
|
hassio_dir: path.resolve(__dirname, "../hassio"),
|
||||||
hassio_output_root: path.resolve(__dirname, "../hassio/build"),
|
hassio_output_root: path.resolve(__dirname, "../hassio/build"),
|
||||||
hassio_output_static: path.resolve(__dirname, "../hassio/build/static"),
|
|
||||||
hassio_output_latest: path.resolve(
|
hassio_output_latest: path.resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
"../hassio/build/frontend_latest"
|
"../hassio/build/frontend_latest"
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
const commonjs = require("@rollup/plugin-commonjs");
|
const commonjs = require("@rollup/plugin-commonjs");
|
||||||
@@ -33,7 +32,8 @@ const createRollupConfig = ({
|
|||||||
publicPath,
|
publicPath,
|
||||||
dontHash,
|
dontHash,
|
||||||
isWDS,
|
isWDS,
|
||||||
}) => ({
|
}) => {
|
||||||
|
return {
|
||||||
/**
|
/**
|
||||||
* @type { import("rollup").InputOptions }
|
* @type { import("rollup").InputOptions }
|
||||||
*/
|
*/
|
||||||
@@ -52,7 +52,11 @@ const createRollupConfig = ({
|
|||||||
browser: true,
|
browser: true,
|
||||||
rootDir: paths.polymer_dir,
|
rootDir: paths.polymer_dir,
|
||||||
}),
|
}),
|
||||||
commonjs(),
|
commonjs({
|
||||||
|
namedExports: {
|
||||||
|
"js-yaml": ["safeDump", "safeLoad"],
|
||||||
|
},
|
||||||
|
}),
|
||||||
json(),
|
json(),
|
||||||
babel({
|
babel({
|
||||||
...bundle.babelOptions({ latestBuild }),
|
...bundle.babelOptions({ latestBuild }),
|
||||||
@@ -64,7 +68,9 @@ const createRollupConfig = ({
|
|||||||
// Import certain extensions as strings
|
// Import certain extensions as strings
|
||||||
include: [path.join(paths.polymer_dir, "node_modules/**/*.css")],
|
include: [path.join(paths.polymer_dir, "node_modules/**/*.css")],
|
||||||
}),
|
}),
|
||||||
replace(bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })),
|
replace(
|
||||||
|
bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })
|
||||||
|
),
|
||||||
!isWDS &&
|
!isWDS &&
|
||||||
manifest({
|
manifest({
|
||||||
publicPath,
|
publicPath,
|
||||||
@@ -96,15 +102,18 @@ const createRollupConfig = ({
|
|||||||
// https://rollupjs.org/guide/en/#outputassetfilenames
|
// https://rollupjs.org/guide/en/#outputassetfilenames
|
||||||
entryFileNames:
|
entryFileNames:
|
||||||
isProdBuild && !isStatsBuild ? "[name]-[hash].js" : "[name].js",
|
isProdBuild && !isStatsBuild ? "[name]-[hash].js" : "[name].js",
|
||||||
chunkFileNames: isProdBuild && !isStatsBuild ? "c.[hash].js" : "[name].js",
|
chunkFileNames:
|
||||||
assetFileNames: isProdBuild && !isStatsBuild ? "a.[hash].js" : "[name].js",
|
isProdBuild && !isStatsBuild ? "c.[hash].js" : "[name].js",
|
||||||
|
assetFileNames:
|
||||||
|
isProdBuild && !isStatsBuild ? "a.[hash].js" : "[name].js",
|
||||||
// https://rollupjs.org/guide/en/#outputsourcemap
|
// https://rollupjs.org/guide/en/#outputsourcemap
|
||||||
sourcemap: isProdBuild ? true : "inline",
|
sourcemap: isProdBuild ? true : "inline",
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) =>
|
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) => {
|
||||||
createRollupConfig(
|
return createRollupConfig(
|
||||||
bundle.config.app({
|
bundle.config.app({
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
@@ -112,24 +121,31 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) =>
|
|||||||
isWDS,
|
isWDS,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
|
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
createRollupConfig(
|
return createRollupConfig(
|
||||||
bundle.config.demo({
|
bundle.config.demo({
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
isStatsBuild,
|
isStatsBuild,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createCastConfig = ({ isProdBuild, latestBuild }) =>
|
const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createRollupConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
return createRollupConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
||||||
|
};
|
||||||
|
|
||||||
const createHassioConfig = ({ isProdBuild, latestBuild }) =>
|
const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createRollupConfig(bundle.config.hassio({ isProdBuild, latestBuild }));
|
return createRollupConfig(bundle.config.hassio({ isProdBuild, latestBuild }));
|
||||||
|
};
|
||||||
|
|
||||||
const createGalleryConfig = ({ isProdBuild, latestBuild }) =>
|
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createRollupConfig(bundle.config.gallery({ isProdBuild, latestBuild }));
|
return createRollupConfig(
|
||||||
|
bundle.config.gallery({ isProdBuild, latestBuild })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createAppConfig,
|
createAppConfig,
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
|
@@ -1,10 +1,9 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const TerserPlugin = require("terser-webpack-plugin");
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
|
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
const bundle = require("./bundle.js");
|
const bundle = require("./bundle");
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
|
|
||||||
class LogStartCompilePlugin {
|
class LogStartCompilePlugin {
|
||||||
@@ -69,7 +68,7 @@ const createWebpackConfig = ({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new WebpackManifestPlugin({
|
new ManifestPlugin({
|
||||||
// Only include the JS of entrypoints
|
// Only include the JS of entrypoints
|
||||||
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
||||||
}),
|
}),
|
||||||
@@ -95,7 +94,6 @@ const createWebpackConfig = ({
|
|||||||
? path.resolve(context, resource)
|
? path.resolve(context, resource)
|
||||||
: require.resolve(resource);
|
: require.resolve(resource);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(
|
console.error(
|
||||||
"Error in Home Assistant ignore plugin",
|
"Error in Home Assistant ignore plugin",
|
||||||
resource,
|
resource,
|
||||||
@@ -116,9 +114,8 @@ const createWebpackConfig = ({
|
|||||||
// We need to change the import of the polyfill for EventTarget, so we replace the polyfill file with our customized one
|
// We need to change the import of the polyfill for EventTarget, so we replace the polyfill file with our customized one
|
||||||
new webpack.NormalModuleReplacementPlugin(
|
new webpack.NormalModuleReplacementPlugin(
|
||||||
new RegExp(
|
new RegExp(
|
||||||
path.resolve(
|
require.resolve(
|
||||||
paths.polymer_dir,
|
"lit-virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js"
|
||||||
"src/resources/lit-virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js"
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js")
|
path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js")
|
||||||
@@ -127,11 +124,6 @@ const createWebpackConfig = ({
|
|||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".ts", ".js", ".json"],
|
extensions: [".ts", ".js", ".json"],
|
||||||
alias: {
|
|
||||||
"lit/decorators$": "lit/decorators.js",
|
|
||||||
"lit/directive$": "lit/directive.js",
|
|
||||||
"lit/polyfill-support$": "lit/polyfill-support.js",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: ({ chunk }) => {
|
filename: ({ chunk }) => {
|
||||||
@@ -152,24 +144,33 @@ const createWebpackConfig = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
|
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
createWebpackConfig(
|
return createWebpackConfig(
|
||||||
bundle.config.app({ isProdBuild, latestBuild, isStatsBuild })
|
bundle.config.app({ isProdBuild, latestBuild, isStatsBuild })
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
|
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||||
createWebpackConfig(
|
return createWebpackConfig(
|
||||||
bundle.config.demo({ isProdBuild, latestBuild, isStatsBuild })
|
bundle.config.demo({ isProdBuild, latestBuild, isStatsBuild })
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createCastConfig = ({ isProdBuild, latestBuild }) =>
|
const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
return createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild }));
|
||||||
|
};
|
||||||
|
|
||||||
const createHassioConfig = ({ isProdBuild, latestBuild }) =>
|
const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createWebpackConfig(bundle.config.hassio({ isProdBuild, latestBuild }));
|
return createWebpackConfig(
|
||||||
|
bundle.config.hassio({ isProdBuild, latestBuild })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const createGalleryConfig = ({ isProdBuild, latestBuild }) =>
|
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
||||||
createWebpackConfig(bundle.config.gallery({ isProdBuild, latestBuild }));
|
return createWebpackConfig(
|
||||||
|
bundle.config.gallery({ isProdBuild, latestBuild })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createAppConfig,
|
createAppConfig,
|
||||||
|
@@ -1,9 +1,16 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
|
||||||
import "@polymer/paper-item/paper-icon-item";
|
import "@polymer/paper-item/paper-icon-item";
|
||||||
import "@polymer/paper-listbox/paper-listbox";
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
import { Auth, Connection } from "home-assistant-js-websocket";
|
import { Auth, Connection } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
internalProperty,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { CastManager } from "../../../../src/cast/cast_manager";
|
import { CastManager } from "../../../../src/cast/cast_manager";
|
||||||
import {
|
import {
|
||||||
castSendShowLovelaceView,
|
castSendShowLovelaceView,
|
||||||
@@ -25,6 +32,7 @@ import {
|
|||||||
import "../../../../src/layouts/hass-loading-screen";
|
import "../../../../src/layouts/hass-loading-screen";
|
||||||
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
||||||
import "./hc-layout";
|
import "./hc-layout";
|
||||||
|
import "@material/mwc-button/mwc-button";
|
||||||
|
|
||||||
@customElement("hc-cast")
|
@customElement("hc-cast")
|
||||||
class HcCast extends LitElement {
|
class HcCast extends LitElement {
|
||||||
@@ -34,19 +42,21 @@ class HcCast extends LitElement {
|
|||||||
|
|
||||||
@property() public castManager!: CastManager;
|
@property() public castManager!: CastManager;
|
||||||
|
|
||||||
@state() private askWrite = false;
|
@internalProperty() private askWrite = false;
|
||||||
|
|
||||||
@state() private lovelaceConfig?: LovelaceConfig | null;
|
@internalProperty() private lovelaceConfig?: LovelaceConfig | null;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (this.lovelaceConfig === undefined) {
|
if (this.lovelaceConfig === undefined) {
|
||||||
return html`<hass-loading-screen no-toolbar></hass-loading-screen>`;
|
return html` <hass-loading-screen no-toolbar></hass-loading-screen>> `;
|
||||||
}
|
}
|
||||||
|
|
||||||
const error =
|
const error =
|
||||||
this.castManager.castState === "NO_DEVICES_AVAILABLE"
|
this.castManager.castState === "NO_DEVICES_AVAILABLE"
|
||||||
? html`
|
? html`
|
||||||
<p>There were no suitable Chromecast devices to cast to found.</p>
|
<p>
|
||||||
|
There were no suitable Chromecast devices to cast to found.
|
||||||
|
</p>
|
||||||
`
|
`
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
@@ -196,7 +206,7 @@ class HcCast extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
.center-item {
|
.center-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@@ -11,8 +11,15 @@ import {
|
|||||||
getAuth,
|
getAuth,
|
||||||
getAuthOptions,
|
getAuthOptions,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
internalProperty,
|
||||||
|
} from "lit-element";
|
||||||
import { CastManager, getCastManager } from "../../../../src/cast/cast_manager";
|
import { CastManager, getCastManager } from "../../../../src/cast/cast_manager";
|
||||||
import { castSendShowDemo } from "../../../../src/cast/receiver_messages";
|
import { castSendShowDemo } from "../../../../src/cast/receiver_messages";
|
||||||
import {
|
import {
|
||||||
@@ -53,19 +60,19 @@ const INTRO = html`
|
|||||||
|
|
||||||
@customElement("hc-connect")
|
@customElement("hc-connect")
|
||||||
export class HcConnect extends LitElement {
|
export class HcConnect extends LitElement {
|
||||||
@state() private loading = false;
|
@internalProperty() private loading = false;
|
||||||
|
|
||||||
// If we had stored credentials but we cannot connect,
|
// If we had stored credentials but we cannot connect,
|
||||||
// show a screen asking retry or logout.
|
// show a screen asking retry or logout.
|
||||||
@state() private cannotConnect = false;
|
@internalProperty() private cannotConnect = false;
|
||||||
|
|
||||||
@state() private error?: string | TemplateResult;
|
@internalProperty() private error?: string | TemplateResult;
|
||||||
|
|
||||||
@state() private auth?: Auth;
|
@internalProperty() private auth?: Auth;
|
||||||
|
|
||||||
@state() private connection?: Connection;
|
@internalProperty() private connection?: Connection;
|
||||||
|
|
||||||
@state() private castManager?: CastManager | null;
|
@internalProperty() private castManager?: CastManager | null;
|
||||||
|
|
||||||
private openDemo = false;
|
private openDemo = false;
|
||||||
|
|
||||||
@@ -79,7 +86,9 @@ export class HcConnect extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<mwc-button> Retry </mwc-button>
|
<mwc-button>
|
||||||
|
Retry
|
||||||
|
</mwc-button>
|
||||||
</a>
|
</a>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<mwc-button @click=${this._handleLogout}>Log out</mwc-button>
|
<mwc-button @click=${this._handleLogout}>Log out</mwc-button>
|
||||||
@@ -290,7 +299,7 @@ export class HcConnect extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
.card-content a {
|
.card-content a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
@@ -4,8 +4,15 @@ import {
|
|||||||
getUser,
|
getUser,
|
||||||
HassUser,
|
HassUser,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
|
|
||||||
@customElement("hc-layout")
|
@customElement("hc-layout")
|
||||||
@@ -62,7 +69,7 @@ class HcLayout extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -91,12 +98,8 @@ class HcLayout extends LitElement {
|
|||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
padding: 24px 16px 16px;
|
padding: 24px 16px 16px;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero {
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
}
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
import { html, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { mockHistory } from "../../../../demo/src/stubs/history";
|
import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||||
import {
|
import {
|
||||||
@@ -16,7 +21,7 @@ import "./hc-lovelace";
|
|||||||
class HcDemo extends HassElement {
|
class HcDemo extends HassElement {
|
||||||
@property({ attribute: false }) public lovelacePath!: string;
|
@property({ attribute: false }) public lovelacePath!: string;
|
||||||
|
|
||||||
@state() private _lovelaceConfig?: LovelaceConfig;
|
@internalProperty() private _lovelaceConfig?: LovelaceConfig;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._lovelaceConfig) {
|
if (!this._lovelaceConfig) {
|
||||||
@@ -33,10 +38,10 @@ class HcDemo extends HassElement {
|
|||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
protected firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this._initializeHass();
|
this._initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _initializeHass() {
|
private async _initialize() {
|
||||||
const initial: Partial<MockHomeAssistant> = {
|
const initial: Partial<MockHomeAssistant> = {
|
||||||
// Override updateHass so that the correct hass lifecycle methods are called
|
// Override updateHass so that the correct hass lifecycle methods are called
|
||||||
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
|
||||||
@customElement("hc-launch-screen")
|
@customElement("hc-launch-screen")
|
||||||
@@ -22,7 +29,7 @@ class HcLaunchScreen extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||||
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
||||||
import "../../../../src/panels/lovelace/views/hui-view";
|
import "../../../../src/panels/lovelace/views/hui-view";
|
||||||
@@ -28,12 +35,11 @@ class HcLovelace extends LitElement {
|
|||||||
}
|
}
|
||||||
const lovelace: Lovelace = {
|
const lovelace: Lovelace = {
|
||||||
config: this.lovelaceConfig,
|
config: this.lovelaceConfig,
|
||||||
rawConfig: this.lovelaceConfig,
|
|
||||||
editMode: false,
|
editMode: false,
|
||||||
urlPath: this.urlPath!,
|
urlPath: this.urlPath!,
|
||||||
enableFullEditMode: () => undefined,
|
enableFullEditMode: () => undefined,
|
||||||
mode: "storage",
|
mode: "storage",
|
||||||
locale: this.hass.locale,
|
language: "en",
|
||||||
saveConfig: async () => undefined,
|
saveConfig: async () => undefined,
|
||||||
deleteConfig: async () => undefined,
|
deleteConfig: async () => undefined,
|
||||||
setEditMode: () => undefined,
|
setEditMode: () => undefined,
|
||||||
@@ -84,11 +90,10 @@ class HcLovelace extends LitElement {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
height: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@@ -3,8 +3,12 @@ import {
|
|||||||
getAuth,
|
getAuth,
|
||||||
UnsubscribeFunc,
|
UnsubscribeFunc,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { html, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, state } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { CAST_NS } from "../../../../src/cast/const";
|
import { CAST_NS } from "../../../../src/cast/const";
|
||||||
import {
|
import {
|
||||||
ConnectMessage,
|
ConnectMessage,
|
||||||
@@ -32,13 +36,13 @@ let resourcesLoaded = false;
|
|||||||
|
|
||||||
@customElement("hc-main")
|
@customElement("hc-main")
|
||||||
export class HcMain extends HassElement {
|
export class HcMain extends HassElement {
|
||||||
@state() private _showDemo = false;
|
@internalProperty() private _showDemo = false;
|
||||||
|
|
||||||
@state() private _lovelaceConfig?: LovelaceConfig;
|
@internalProperty() private _lovelaceConfig?: LovelaceConfig;
|
||||||
|
|
||||||
@state() private _lovelacePath: string | number | null = null;
|
@internalProperty() private _lovelacePath: string | number | null = null;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
private _unsubLovelace?: UnsubscribeFunc;
|
private _unsubLovelace?: UnsubscribeFunc;
|
||||||
|
|
||||||
@@ -217,17 +221,11 @@ export class HcMain extends HassElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _generateLovelaceConfig() {
|
private async _generateLovelaceConfig() {
|
||||||
const { generateLovelaceDashboardStrategy } = await import(
|
const { generateLovelaceConfigFromHass } = await import(
|
||||||
"../../../../src/panels/lovelace/strategies/get-strategy"
|
"../../../../src/panels/lovelace/common/generate-lovelace-config"
|
||||||
);
|
);
|
||||||
this._handleNewLovelaceConfig(
|
this._handleNewLovelaceConfig(
|
||||||
await generateLovelaceDashboardStrategy(
|
await generateLovelaceConfigFromHass(this.hass!)
|
||||||
{
|
|
||||||
hass: this.hass!,
|
|
||||||
narrow: false,
|
|
||||||
},
|
|
||||||
"original-states"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -246,15 +246,11 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
|
|
||||||
"light.living_room_lights": {
|
"light.living_room_lights": {
|
||||||
entity_id: "light.living_room_lights",
|
entity_id: "light.living_room_lights",
|
||||||
state: "on",
|
state: "off",
|
||||||
attributes: {
|
attributes: {
|
||||||
min_mireds: 111,
|
min_mireds: 111,
|
||||||
max_mireds: 400,
|
max_mireds: 400,
|
||||||
brightness: 175,
|
|
||||||
color_temp: 300,
|
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
friendly_name: "Living Room Lights",
|
friendly_name: "Living Room Lights",
|
||||||
color_mode: "color_temp",
|
|
||||||
supported_features: 55,
|
supported_features: 55,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -267,27 +263,13 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
},
|
},
|
||||||
"light.kitchen_lights": {
|
"light.kitchen_lights": {
|
||||||
entity_id: "light.kitchen_lights",
|
entity_id: "light.kitchen_lights",
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
min_mireds: 111,
|
|
||||||
max_mireds: 400,
|
|
||||||
brightness: 200,
|
|
||||||
rgb_color: [255, 175, 96],
|
|
||||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
|
||||||
color_mode: "rgb",
|
|
||||||
friendly_name: "Kitchen Lights",
|
|
||||||
supported_features: 55,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"light.lifx5": {
|
|
||||||
entity_id: "light.lifx5",
|
|
||||||
state: "off",
|
state: "off",
|
||||||
attributes: {
|
attributes: {
|
||||||
supported_color_modes: ["brightness"],
|
friendly_name: "Kitchen Lights",
|
||||||
friendly_name: "Garage Lights",
|
|
||||||
supported_features: 1,
|
supported_features: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"sensor.plexspy": {
|
"sensor.plexspy": {
|
||||||
entity_id: "sensor.plexspy",
|
entity_id: "sensor.plexspy",
|
||||||
state: "0",
|
state: "0",
|
||||||
@@ -500,6 +482,16 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
icon: "hademo:history",
|
icon: "hademo:history",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"light.lifx5": {
|
||||||
|
entity_id: "light.lifx5",
|
||||||
|
state: "on",
|
||||||
|
attributes: {
|
||||||
|
min_mireds: 111,
|
||||||
|
max_mireds: 400,
|
||||||
|
friendly_name: "Garage Lights",
|
||||||
|
supported_features: 55,
|
||||||
|
},
|
||||||
|
},
|
||||||
"sensor.alok_to_home": {
|
"sensor.alok_to_home": {
|
||||||
entity_id: "sensor.alok_to_home",
|
entity_id: "sensor.alok_to_home",
|
||||||
state: "41",
|
state: "41",
|
||||||
|
@@ -1114,9 +1114,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
min_mireds: 153,
|
min_mireds: 153,
|
||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
brightness: 63,
|
brightness: 63,
|
||||||
color_temp: 200,
|
|
||||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
|
||||||
color_mode: "color_temp",
|
|
||||||
friendly_name: "Upstairs lights",
|
friendly_name: "Upstairs lights",
|
||||||
supported_features: 63,
|
supported_features: 63,
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
@@ -1128,7 +1125,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
friendly_name: "Walk in closet lights",
|
friendly_name: "Walk in closet lights",
|
||||||
supported_features: 41,
|
supported_features: 41,
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:wall-sconce",
|
icon: "mdi:wall-sconce",
|
||||||
},
|
},
|
||||||
@@ -1140,8 +1136,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
brightness: 254,
|
brightness: 254,
|
||||||
friendly_name: "Outdoor lights",
|
friendly_name: "Outdoor lights",
|
||||||
supported_features: 41,
|
supported_features: 41,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
color_mode: "brightness",
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:wall-sconce",
|
icon: "mdi:wall-sconce",
|
||||||
},
|
},
|
||||||
@@ -1154,8 +1148,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
brightness: 128,
|
brightness: 128,
|
||||||
color_temp: 366,
|
color_temp: 366,
|
||||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
|
||||||
color_mode: "color_temp",
|
|
||||||
effect_list: ["colorloop"],
|
effect_list: ["colorloop"],
|
||||||
friendly_name: "Downstairs lights",
|
friendly_name: "Downstairs lights",
|
||||||
supported_features: 63,
|
supported_features: 63,
|
||||||
@@ -1315,7 +1307,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
min_mireds: 153,
|
min_mireds: 153,
|
||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
friendly_name: "Bedside Lamp",
|
friendly_name: "Bedside Lamp",
|
||||||
supported_features: 63,
|
supported_features: 63,
|
||||||
@@ -1329,7 +1320,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
min_mireds: 153,
|
min_mireds: 153,
|
||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
friendly_name: "Floorlamp Reading Light",
|
friendly_name: "Floorlamp Reading Light",
|
||||||
supported_features: 43,
|
supported_features: 43,
|
||||||
@@ -1345,8 +1335,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
brightness: 128,
|
brightness: 128,
|
||||||
color_temp: 366,
|
color_temp: 366,
|
||||||
supported_color_modes: ["brightness", "color_temp", "rgb"],
|
|
||||||
color_mode: "color_temp",
|
|
||||||
effect_list: ["colorloop"],
|
effect_list: ["colorloop"],
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
friendly_name: "Hallway window light",
|
friendly_name: "Hallway window light",
|
||||||
@@ -1361,7 +1349,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
brightness: 77,
|
brightness: 77,
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
friendly_name: "Isa Ceiling Light",
|
friendly_name: "Isa Ceiling Light",
|
||||||
supported_features: 41,
|
supported_features: 41,
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
@@ -1376,8 +1363,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
max_mireds: 500,
|
max_mireds: 500,
|
||||||
brightness: 150,
|
brightness: 150,
|
||||||
color_temp: 366,
|
color_temp: 366,
|
||||||
supported_color_modes: ["brightness", "color_temp"],
|
|
||||||
color_mode: "color_temp",
|
|
||||||
effect_list: ["colorloop"],
|
effect_list: ["colorloop"],
|
||||||
is_deconz_group: false,
|
is_deconz_group: false,
|
||||||
friendly_name: "Floorlamp",
|
friendly_name: "Floorlamp",
|
||||||
@@ -1392,7 +1377,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
friendly_name: "Bedroom Ceiling Light",
|
friendly_name: "Bedroom Ceiling Light",
|
||||||
supported_features: 41,
|
supported_features: 41,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:ceiling-light",
|
icon: "mdi:ceiling-light",
|
||||||
},
|
},
|
||||||
@@ -1403,7 +1387,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
friendly_name: "Nightlight",
|
friendly_name: "Nightlight",
|
||||||
supported_features: 17,
|
supported_features: 17,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:lamp",
|
icon: "mdi:lamp",
|
||||||
},
|
},
|
||||||
@@ -1770,7 +1753,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 2.2,
|
power_consumption: 2.2,
|
||||||
friendly_name: "Upstairs Hallway Light",
|
friendly_name: "Upstairs Hallway Light",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:ceiling-light",
|
icon: "mdi:ceiling-light",
|
||||||
},
|
},
|
||||||
@@ -1786,7 +1768,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 0,
|
power_consumption: 0,
|
||||||
friendly_name: "Dining Room Light",
|
friendly_name: "Dining Room Light",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:ceiling-light",
|
icon: "mdi:ceiling-light",
|
||||||
},
|
},
|
||||||
@@ -1802,7 +1783,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 0,
|
power_consumption: 0,
|
||||||
friendly_name: "Living room Spotlights",
|
friendly_name: "Living room Spotlights",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:track-light",
|
icon: "mdi:track-light",
|
||||||
},
|
},
|
||||||
@@ -1819,7 +1799,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 2.5,
|
power_consumption: 2.5,
|
||||||
friendly_name: "Passage Lights",
|
friendly_name: "Passage Lights",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:track-light",
|
icon: "mdi:track-light",
|
||||||
},
|
},
|
||||||
@@ -1864,7 +1843,6 @@ export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
|||||||
power_consumption: 37.4,
|
power_consumption: 37.4,
|
||||||
friendly_name: "Kitchen Lights",
|
friendly_name: "Kitchen Lights",
|
||||||
supported_features: 33,
|
supported_features: 33,
|
||||||
supported_color_modes: ["brightness"],
|
|
||||||
custom_ui_state_card: "state-card-custom-ui",
|
custom_ui_state_card: "state-card-custom-ui",
|
||||||
icon: "mdi:track-light",
|
icon: "mdi:track-light",
|
||||||
},
|
},
|
||||||
|
@@ -440,8 +440,8 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
type: "horizontal-stack",
|
type: "horizontal-stack",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "grid",
|
cards: [
|
||||||
columns: 2,
|
{
|
||||||
cards: [
|
cards: [
|
||||||
{
|
{
|
||||||
graph: "line",
|
graph: "line",
|
||||||
@@ -454,6 +454,11 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
name: "S's room",
|
name: "S's room",
|
||||||
entity: "sensor.temperature_stefan",
|
entity: "sensor.temperature_stefan",
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
type: "horizontal-stack",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cards: [
|
||||||
{
|
{
|
||||||
graph: "line",
|
graph: "line",
|
||||||
type: "sensor",
|
type: "sensor",
|
||||||
@@ -465,6 +470,11 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
name: "Bathroom",
|
name: "Bathroom",
|
||||||
entity: "sensor.temperature_downstairs_bathroom",
|
entity: "sensor.temperature_downstairs_bathroom",
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
type: "horizontal-stack",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cards: [
|
||||||
{
|
{
|
||||||
graph: "line",
|
graph: "line",
|
||||||
type: "sensor",
|
type: "sensor",
|
||||||
@@ -477,6 +487,10 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
entity: "sensor.refrigerator",
|
entity: "sensor.refrigerator",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
type: "horizontal-stack",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "vertical-stack",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
entities: [
|
entities: [
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { LitElement } from "lit";
|
import { LitElement } from "lit-element";
|
||||||
import "./card-tools";
|
import "./card-tools";
|
||||||
|
|
||||||
class CardModder extends LitElement {
|
class CardModder extends LitElement {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { html, LitElement } from "lit";
|
import { html, LitElement } from "lit-element";
|
||||||
|
|
||||||
if (!window.cardTools) {
|
if (!window.cardTools) {
|
||||||
const version = 0.2;
|
const version = 0.2;
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { CastManager } from "../../../src/cast/cast_manager";
|
import { CastManager } from "../../../src/cast/cast_manager";
|
||||||
import { castSendShowDemo } from "../../../src/cast/receiver_messages";
|
import { castSendShowDemo } from "../../../src/cast/receiver_messages";
|
||||||
import "../../../src/components/ha-icon";
|
import "../../../src/components/ha-icon";
|
||||||
@@ -13,7 +20,7 @@ import { HomeAssistant } from "../../../src/types";
|
|||||||
class CastDemoRow extends LitElement implements LovelaceRow {
|
class CastDemoRow extends LitElement implements LovelaceRow {
|
||||||
public hass!: HomeAssistant;
|
public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() private _castManager?: CastManager | null;
|
@internalProperty() private _castManager?: CastManager | null;
|
||||||
|
|
||||||
public setConfig(_config: CastConfig): void {
|
public setConfig(_config: CastConfig): void {
|
||||||
// No config possible.
|
// No config possible.
|
||||||
@@ -66,7 +73,7 @@ class CastDemoRow extends LitElement implements LovelaceRow {
|
|||||||
this.style.display = this._castManager ? "" : "none";
|
this.style.display = this._castManager ? "" : "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@@ -1,7 +1,14 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { property, state } from "lit/decorators";
|
css,
|
||||||
import { until } from "lit/directives/until";
|
CSSResult,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/ha-circular-progress";
|
import "../../../src/components/ha-circular-progress";
|
||||||
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
||||||
@@ -19,7 +26,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
@property({ attribute: false }) public hass!: MockHomeAssistant;
|
@property({ attribute: false }) public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
@state() private _switching?: boolean;
|
@internalProperty() private _switching?: boolean;
|
||||||
|
|
||||||
private _hidden = localStorage.hide_demo_card;
|
private _hidden = localStorage.hide_demo_card;
|
||||||
|
|
||||||
@@ -106,7 +113,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
css`
|
css`
|
||||||
a {
|
a {
|
||||||
|
@@ -22,9 +22,9 @@ import { mockTemplate } from "./stubs/template";
|
|||||||
import { mockTranslations } from "./stubs/translations";
|
import { mockTranslations } from "./stubs/translations";
|
||||||
|
|
||||||
class HaDemo extends HomeAssistantAppEl {
|
class HaDemo extends HomeAssistantAppEl {
|
||||||
protected async _initializeHass() {
|
protected async _initialize() {
|
||||||
const initial: Partial<MockHomeAssistant> = {
|
const initial: Partial<MockHomeAssistant> = {
|
||||||
panelUrl: (this as any)._panelUrl,
|
panelUrl: (this as any).panelUrl,
|
||||||
// Override updateHass so that the correct hass lifecycle methods are called
|
// Override updateHass so that the correct hass lifecycle methods are called
|
||||||
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
||||||
this._updateHass(hassUpdate),
|
this._updateHass(hassUpdate),
|
||||||
@@ -70,7 +70,7 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
navigate(href);
|
navigate(this, href);
|
||||||
},
|
},
|
||||||
{ capture: true }
|
{ capture: true }
|
||||||
);
|
);
|
||||||
|
@@ -3,6 +3,8 @@ import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|||||||
export const mockTranslations = (hass: MockHomeAssistant) => {
|
export const mockTranslations = (hass: MockHomeAssistant) => {
|
||||||
hass.mockWS(
|
hass.mockWS(
|
||||||
"frontend/get_translations",
|
"frontend/get_translations",
|
||||||
(/* msg: {language: string, category: string} */) => ({ resources: {} })
|
(/* msg: {language: string, category: string} */) => {
|
||||||
|
return { resources: {} };
|
||||||
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
/* eslint-plugin-disable lit */
|
/* eslint-plugin-disable lit */
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import { load } from "js-yaml";
|
import { safeLoad } from "js-yaml";
|
||||||
import { createCardElement } from "../../../src/panels/lovelace/create-element/create-card-element";
|
import { createCardElement } from "../../../src/panels/lovelace/create-element/create-card-element";
|
||||||
|
|
||||||
class DemoCard extends PolymerElement {
|
class DemoCard extends PolymerElement {
|
||||||
@@ -15,10 +15,6 @@ class DemoCard extends PolymerElement {
|
|||||||
margin: 0 0 20px;
|
margin: 0 0 20px;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
h2 small {
|
|
||||||
font-size: 0.5em;
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
#card {
|
#card {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
@@ -38,12 +34,7 @@ class DemoCard extends PolymerElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<h2>
|
<h2>[[config.heading]]</h2>
|
||||||
[[config.heading]]
|
|
||||||
<template is="dom-if" if="[[_size]]">
|
|
||||||
<small>(size [[_size]])</small>
|
|
||||||
</template>
|
|
||||||
</h2>
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<div id="card"></div>
|
<div id="card"></div>
|
||||||
<template is="dom-if" if="[[showConfig]]">
|
<template is="dom-if" if="[[showConfig]]">
|
||||||
@@ -64,9 +55,6 @@ class DemoCard extends PolymerElement {
|
|||||||
observer: "_configChanged",
|
observer: "_configChanged",
|
||||||
},
|
},
|
||||||
showConfig: Boolean,
|
showConfig: Boolean,
|
||||||
_size: {
|
|
||||||
type: Number,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,19 +68,8 @@ class DemoCard extends PolymerElement {
|
|||||||
card.removeChild(card.lastChild);
|
card.removeChild(card.lastChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
const el = this._createCardElement(load(config.config)[0]);
|
const el = this._createCardElement(safeLoad(config.config)[0]);
|
||||||
card.appendChild(el);
|
card.appendChild(el);
|
||||||
this._getSize(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _getSize(el) {
|
|
||||||
await customElements.whenDefined(el.localName);
|
|
||||||
|
|
||||||
if (!("getCardSize" in el)) {
|
|
||||||
this._size = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._size = await el.getCardSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_createCardElement(cardConfig) {
|
_createCardElement(cardConfig) {
|
||||||
|
@@ -1,349 +0,0 @@
|
|||||||
import { DemoTrace } from "./types";
|
|
||||||
|
|
||||||
export const basicTrace: DemoTrace = {
|
|
||||||
trace: {
|
|
||||||
last_step: "action/2",
|
|
||||||
run_id: "0",
|
|
||||||
state: "stopped",
|
|
||||||
timestamp: {
|
|
||||||
start: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
finish: "2021-03-25T04:36:51.266132+00:00",
|
|
||||||
},
|
|
||||||
trigger: "state of input_boolean.toggle_1",
|
|
||||||
domain: "automation",
|
|
||||||
item_id: "1615419646544",
|
|
||||||
trace: {
|
|
||||||
"trigger/0": [
|
|
||||||
{
|
|
||||||
path: "trigger/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"condition/0": [
|
|
||||||
{
|
|
||||||
path: "condition/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.228243+00:00",
|
|
||||||
changed_variables: {
|
|
||||||
trigger: {
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
from_state: {
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
editable: true,
|
|
||||||
friendly_name: "Toggle 1",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-24T19:03:59.141440+00:00",
|
|
||||||
last_updated: "2021-03-24T19:03:59.141440+00:00",
|
|
||||||
context: {
|
|
||||||
id: "5d0918eb379214d07554bdab6a08bcff",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
to_state: {
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
state: "off",
|
|
||||||
attributes: {
|
|
||||||
editable: true,
|
|
||||||
friendly_name: "Toggle 1",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-25T04:36:51.220696+00:00",
|
|
||||||
last_updated: "2021-03-25T04:36:51.220696+00:00",
|
|
||||||
context: {
|
|
||||||
id: "664d6d261450a9ecea6738e97269a149",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: "d1b4e89da01445fa8bc98e39fac477ca",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
for: null,
|
|
||||||
attribute: null,
|
|
||||||
description: "state of input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/0": [
|
|
||||||
{
|
|
||||||
path: "action/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.243018+00:00",
|
|
||||||
changed_variables: {
|
|
||||||
trigger: {
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
from_state: {
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
editable: true,
|
|
||||||
friendly_name: "Toggle 1",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-24T19:03:59.141440+00:00",
|
|
||||||
last_updated: "2021-03-24T19:03:59.141440+00:00",
|
|
||||||
context: {
|
|
||||||
id: "5d0918eb379214d07554bdab6a08bcff",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
to_state: {
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
state: "off",
|
|
||||||
attributes: {
|
|
||||||
editable: true,
|
|
||||||
friendly_name: "Toggle 1",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-25T04:36:51.220696+00:00",
|
|
||||||
last_updated: "2021-03-25T04:36:51.220696+00:00",
|
|
||||||
context: {
|
|
||||||
id: "664d6d261450a9ecea6738e97269a149",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: "d1b4e89da01445fa8bc98e39fac477ca",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
for: null,
|
|
||||||
attribute: null,
|
|
||||||
description: "state of input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "6cfcae368e7b3686fad6c59e83ae76c9",
|
|
||||||
parent_id: "664d6d261450a9ecea6738e97269a149",
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
params: {
|
|
||||||
domain: "input_boolean",
|
|
||||||
service: "toggle",
|
|
||||||
service_data: {},
|
|
||||||
target: {
|
|
||||||
entity_id: ["input_boolean.toggle_4"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
running_script: false,
|
|
||||||
limit: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1": [
|
|
||||||
{
|
|
||||||
path: "action/1",
|
|
||||||
timestamp: "2021-03-25T04:36:51.252406+00:00",
|
|
||||||
result: {
|
|
||||||
choice: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1/choose/0": [
|
|
||||||
{
|
|
||||||
path: "action/1/choose/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.254569+00:00",
|
|
||||||
result: {
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1/choose/0/conditions/0": [
|
|
||||||
{
|
|
||||||
path: "action/1/choose/0/conditions/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.254697+00:00",
|
|
||||||
result: {
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1/choose/0/sequence/0": [
|
|
||||||
{
|
|
||||||
path: "action/1/choose/0/sequence/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.257360+00:00",
|
|
||||||
result: {
|
|
||||||
params: {
|
|
||||||
domain: "input_boolean",
|
|
||||||
service: "toggle",
|
|
||||||
service_data: {},
|
|
||||||
target: {
|
|
||||||
entity_id: ["input_boolean.toggle_2"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
running_script: false,
|
|
||||||
limit: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1/choose/0/sequence/1": [
|
|
||||||
{
|
|
||||||
path: "action/1/choose/0/sequence/1",
|
|
||||||
timestamp: "2021-03-25T04:36:51.260658+00:00",
|
|
||||||
result: {
|
|
||||||
params: {
|
|
||||||
domain: "input_boolean",
|
|
||||||
service: "toggle",
|
|
||||||
service_data: {},
|
|
||||||
target: {
|
|
||||||
entity_id: ["input_boolean.toggle_3"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
running_script: false,
|
|
||||||
limit: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/2": [
|
|
||||||
{
|
|
||||||
path: "action/2",
|
|
||||||
timestamp: "2021-03-25T04:36:51.264159+00:00",
|
|
||||||
result: {
|
|
||||||
params: {
|
|
||||||
domain: "input_boolean",
|
|
||||||
service: "toggle",
|
|
||||||
service_data: {},
|
|
||||||
target: {
|
|
||||||
entity_id: ["input_boolean.toggle_4"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
running_script: false,
|
|
||||||
limit: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
config: {
|
|
||||||
id: "1615419646544",
|
|
||||||
alias: "Ensure Party mode",
|
|
||||||
description: "",
|
|
||||||
trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
condition: [
|
|
||||||
{
|
|
||||||
condition: "template",
|
|
||||||
alias: "Test if Paulus is home",
|
|
||||||
value_template: "{{ true }}",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
action: [
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
choose: [
|
|
||||||
{
|
|
||||||
alias: "If toggle 3 is on",
|
|
||||||
conditions: [
|
|
||||||
{
|
|
||||||
condition: "template",
|
|
||||||
value_template:
|
|
||||||
"{{ is_state('input_boolean.toggle_3', 'on') }}",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
sequence: [
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
alias: "Toggle 2 while 3 is on",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
alias: "Toggle 3",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
default: [
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
alias: "Toggle 2",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
mode: "single",
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "6cfcae368e7b3686fad6c59e83ae76c9",
|
|
||||||
parent_id: "664d6d261450a9ecea6738e97269a149",
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
script_execution: "finished",
|
|
||||||
},
|
|
||||||
logbookEntries: [
|
|
||||||
{
|
|
||||||
name: "Ensure Party mode",
|
|
||||||
message: "has been triggered by state of input_boolean.toggle_1",
|
|
||||||
source: "state of input_boolean.toggle_1",
|
|
||||||
entity_id: "automation.toggle_toggles",
|
|
||||||
context_id: "6cfcae368e7b3686fad6c59e83ae76c9",
|
|
||||||
when: "2021-03-25T04:36:51.240832+00:00",
|
|
||||||
domain: "automation",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-25T04:36:51.249828+00:00",
|
|
||||||
name: "Toggle 4",
|
|
||||||
state: "on",
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
context_entity_id: "automation.toggle_toggles",
|
|
||||||
context_entity_id_name: "Ensure Party mode",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Ensure Party mode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-25T04:36:51.258947+00:00",
|
|
||||||
name: "Toggle 2",
|
|
||||||
state: "on",
|
|
||||||
entity_id: "input_boolean.toggle_2",
|
|
||||||
context_entity_id: "automation.toggle_toggles",
|
|
||||||
context_entity_id_name: "Ensure Party mode",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Ensure Party mode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-25T04:36:51.261806+00:00",
|
|
||||||
name: "Toggle 3",
|
|
||||||
state: "off",
|
|
||||||
entity_id: "input_boolean.toggle_3",
|
|
||||||
context_entity_id: "automation.toggle_toggles",
|
|
||||||
context_entity_id_name: "Ensure Party mode",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Ensure Party mode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-25T04:36:51.265246+00:00",
|
|
||||||
name: "Toggle 4",
|
|
||||||
state: "off",
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
context_entity_id: "automation.toggle_toggles",
|
|
||||||
context_entity_id_name: "Ensure Party mode",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Ensure Party mode",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
@@ -1,44 +0,0 @@
|
|||||||
import { LogbookEntry } from "../../../../src/data/logbook";
|
|
||||||
import { AutomationTraceExtended } from "../../../../src/data/trace";
|
|
||||||
import { DemoTrace } from "./types";
|
|
||||||
|
|
||||||
export const mockDemoTrace = (
|
|
||||||
tracePartial: Partial<AutomationTraceExtended>,
|
|
||||||
logbookEntries?: LogbookEntry[]
|
|
||||||
): DemoTrace => ({
|
|
||||||
trace: {
|
|
||||||
last_step: "",
|
|
||||||
run_id: "0",
|
|
||||||
state: "stopped",
|
|
||||||
timestamp: {
|
|
||||||
start: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
finish: "2021-03-25T04:36:51.266132+00:00",
|
|
||||||
},
|
|
||||||
trigger: "mocked trigger",
|
|
||||||
domain: "automation",
|
|
||||||
item_id: "1615419646544",
|
|
||||||
trace: {
|
|
||||||
"trigger/0": [
|
|
||||||
{
|
|
||||||
path: "trigger/0",
|
|
||||||
changed_variables: {
|
|
||||||
trigger: {
|
|
||||||
description: "mocked trigger",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
trigger: [],
|
|
||||||
action: [],
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "abcd",
|
|
||||||
},
|
|
||||||
script_execution: "finished",
|
|
||||||
...tracePartial,
|
|
||||||
},
|
|
||||||
logbookEntries: logbookEntries || [],
|
|
||||||
});
|
|
@@ -1,214 +0,0 @@
|
|||||||
import { DemoTrace } from "./types";
|
|
||||||
|
|
||||||
export const motionLightTrace: DemoTrace = {
|
|
||||||
trace: {
|
|
||||||
last_step: "action/3",
|
|
||||||
run_id: "1",
|
|
||||||
state: "stopped",
|
|
||||||
timestamp: {
|
|
||||||
start: "2021-03-14T06:07:01.768006+00:00",
|
|
||||||
finish: "2021-03-14T06:07:53.287525+00:00",
|
|
||||||
},
|
|
||||||
trigger: "state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
domain: "automation",
|
|
||||||
item_id: "1614732497392",
|
|
||||||
trace: {
|
|
||||||
"trigger/0": [
|
|
||||||
{
|
|
||||||
path: "trigger/0",
|
|
||||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/0": [
|
|
||||||
{
|
|
||||||
path: "action/0",
|
|
||||||
timestamp: "2021-03-14T06:07:01.771038+00:00",
|
|
||||||
changed_variables: {
|
|
||||||
trigger: {
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
from_state: {
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
state: "off",
|
|
||||||
attributes: {
|
|
||||||
friendly_name: "Paulus’s MacBook Pro Camera In Use",
|
|
||||||
icon: "mdi:camera-off",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-14T06:06:29.235325+00:00",
|
|
||||||
last_updated: "2021-03-14T06:06:29.235325+00:00",
|
|
||||||
context: {
|
|
||||||
id: "ad4864c5ce957c38a07b50378eeb245d",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
to_state: {
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
friendly_name: "Paulus’s MacBook Pro Camera In Use",
|
|
||||||
icon: "mdi:camera",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-14T06:07:01.762009+00:00",
|
|
||||||
last_updated: "2021-03-14T06:07:01.762009+00:00",
|
|
||||||
context: {
|
|
||||||
id: "e22ddfd5f11dc4aad9a52fc10dab613b",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
for: null,
|
|
||||||
attribute: null,
|
|
||||||
description:
|
|
||||||
"state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "43b6ee9293a551c5cc14e8eb60af54ba",
|
|
||||||
parent_id: "e22ddfd5f11dc4aad9a52fc10dab613b",
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/1": [
|
|
||||||
{ path: "action/1", timestamp: "2021-03-14T06:07:01.875316+00:00" },
|
|
||||||
],
|
|
||||||
"action/2": [
|
|
||||||
{
|
|
||||||
path: "action/2",
|
|
||||||
timestamp: "2021-03-14T06:07:53.195013+00:00",
|
|
||||||
changed_variables: {
|
|
||||||
wait: {
|
|
||||||
remaining: null,
|
|
||||||
trigger: {
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
from_state: {
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
state: "on",
|
|
||||||
attributes: {
|
|
||||||
friendly_name: "Paulus’s MacBook Pro Camera In Use",
|
|
||||||
icon: "mdi:camera",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-14T06:07:01.762009+00:00",
|
|
||||||
last_updated: "2021-03-14T06:07:01.762009+00:00",
|
|
||||||
context: {
|
|
||||||
id: "e22ddfd5f11dc4aad9a52fc10dab613b",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
to_state: {
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
state: "off",
|
|
||||||
attributes: {
|
|
||||||
friendly_name: "Paulus’s MacBook Pro Camera In Use",
|
|
||||||
icon: "mdi:camera-off",
|
|
||||||
},
|
|
||||||
last_changed: "2021-03-14T06:07:53.186755+00:00",
|
|
||||||
last_updated: "2021-03-14T06:07:53.186755+00:00",
|
|
||||||
context: {
|
|
||||||
id: "b2308cc91d509ea8e0c623331ab178d6",
|
|
||||||
parent_id: null,
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
for: null,
|
|
||||||
attribute: null,
|
|
||||||
description:
|
|
||||||
"state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"action/3": [
|
|
||||||
{
|
|
||||||
path: "action/3",
|
|
||||||
timestamp: "2021-03-14T06:07:53.196014+00:00",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
mode: "restart",
|
|
||||||
max_exceeded: "silent",
|
|
||||||
trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
from: "off",
|
|
||||||
to: "on",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
action: [
|
|
||||||
{
|
|
||||||
service: "light.turn_on",
|
|
||||||
target: {
|
|
||||||
entity_id: "light.elgato_key_light_air",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
wait_for_trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
from: "on",
|
|
||||||
to: "off",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
delay: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "light.turn_off",
|
|
||||||
target: {
|
|
||||||
entity_id: "light.elgato_key_light_air",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
id: "1614732497392",
|
|
||||||
alias: "Auto Elgato",
|
|
||||||
description: "",
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
id: "43b6ee9293a551c5cc14e8eb60af54ba",
|
|
||||||
parent_id: "e22ddfd5f11dc4aad9a52fc10dab613b",
|
|
||||||
user_id: null,
|
|
||||||
},
|
|
||||||
script_execution: "finished",
|
|
||||||
},
|
|
||||||
logbookEntries: [
|
|
||||||
{
|
|
||||||
name: "Auto Elgato",
|
|
||||||
message:
|
|
||||||
"has been triggered by state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
source: "state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
|
||||||
entity_id: "automation.auto_elgato",
|
|
||||||
when: "2021-03-14T06:07:01.768492+00:00",
|
|
||||||
domain: "automation",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-14T06:07:01.872187+00:00",
|
|
||||||
name: "Elgato Key Light Air",
|
|
||||||
state: "on",
|
|
||||||
entity_id: "light.elgato_key_light_air",
|
|
||||||
context_entity_id: "automation.auto_elgato",
|
|
||||||
context_entity_id_name: "Auto Elgato",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Auto Elgato",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
when: "2021-03-14T06:07:53.284505+00:00",
|
|
||||||
name: "Elgato Key Light Air",
|
|
||||||
state: "off",
|
|
||||||
entity_id: "light.elgato_key_light_air",
|
|
||||||
context_entity_id: "automation.auto_elgato",
|
|
||||||
context_entity_id_name: "Auto Elgato",
|
|
||||||
context_event_type: "automation_triggered",
|
|
||||||
context_domain: "automation",
|
|
||||||
context_name: "Auto Elgato",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
@@ -1,7 +0,0 @@
|
|||||||
import { AutomationTraceExtended } from "../../../../src/data/trace";
|
|
||||||
import { LogbookEntry } from "../../../../src/data/logbook";
|
|
||||||
|
|
||||||
export interface DemoTrace {
|
|
||||||
trace: AutomationTraceExtended;
|
|
||||||
logbookEntries: LogbookEntry[];
|
|
||||||
}
|
|
@@ -1,96 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeAction } from "../../../src/data/script_i18n";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
|
|
||||||
const actions = [
|
|
||||||
{ wait_template: "{{ true }}", alias: "Something with an alias" },
|
|
||||||
{ delay: "0:05" },
|
|
||||||
{ wait_template: "{{ true }}" },
|
|
||||||
{
|
|
||||||
condition: "template",
|
|
||||||
value_template: "{{ true }}",
|
|
||||||
},
|
|
||||||
{ event: "happy_event" },
|
|
||||||
{
|
|
||||||
device_id: "abcdefgh",
|
|
||||||
domain: "plex",
|
|
||||||
entity_id: "media_player.kitchen",
|
|
||||||
},
|
|
||||||
{ scene: "scene.kitchen_morning" },
|
|
||||||
{
|
|
||||||
wait_for_trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
variables: {
|
|
||||||
hello: "world",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-action")
|
|
||||||
export class DemoAutomationDescribeAction extends LitElement {
|
|
||||||
@property({ attribute: false }) hass!: HomeAssistant;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<ha-card header="Actions">
|
|
||||||
${actions.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="action">
|
|
||||||
<span>${describeAction(this.hass, conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.action {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-action": DemoAutomationDescribeAction;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,60 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeCondition } from "../../../src/data/automation_i18n";
|
|
||||||
|
|
||||||
const conditions = [
|
|
||||||
{ condition: "and" },
|
|
||||||
{ condition: "not" },
|
|
||||||
{ condition: "or" },
|
|
||||||
{ condition: "state" },
|
|
||||||
{ condition: "numeric_state" },
|
|
||||||
{ condition: "sun", after: "sunset" },
|
|
||||||
{ condition: "sun", after: "sunrise" },
|
|
||||||
{ condition: "zone" },
|
|
||||||
{ condition: "time" },
|
|
||||||
{ condition: "template" },
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-condition")
|
|
||||||
export class DemoAutomationDescribeCondition extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="Conditions">
|
|
||||||
${conditions.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="condition">
|
|
||||||
<span>${describeCondition(conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.condition {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-condition": DemoAutomationDescribeCondition;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,63 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeTrigger } from "../../../src/data/automation_i18n";
|
|
||||||
|
|
||||||
const triggers = [
|
|
||||||
{ platform: "state" },
|
|
||||||
{ platform: "mqtt" },
|
|
||||||
{ platform: "geo_location" },
|
|
||||||
{ platform: "homeassistant" },
|
|
||||||
{ platform: "numeric_state" },
|
|
||||||
{ platform: "sun" },
|
|
||||||
{ platform: "time_pattern" },
|
|
||||||
{ platform: "webhook" },
|
|
||||||
{ platform: "zone" },
|
|
||||||
{ platform: "tag" },
|
|
||||||
{ platform: "time" },
|
|
||||||
{ platform: "template" },
|
|
||||||
{ platform: "event" },
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-trigger")
|
|
||||||
export class DemoAutomationDescribeTrigger extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="Triggers">
|
|
||||||
${triggers.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="trigger">
|
|
||||||
<span>${describeTrigger(conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.trigger {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-trigger": DemoAutomationDescribeTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,81 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import "../../../src/components/trace/hat-script-graph";
|
|
||||||
import "../../../src/components/trace/hat-trace-timeline";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
import { mockDemoTrace } from "../data/traces/mock-demo-trace";
|
|
||||||
import { DemoTrace } from "../data/traces/types";
|
|
||||||
|
|
||||||
const traces: DemoTrace[] = [
|
|
||||||
mockDemoTrace({ state: "running" }),
|
|
||||||
mockDemoTrace({ state: "debugged" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "failed_conditions" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "failed_single" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "failed_max_runs" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "finished" }),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "aborted" }),
|
|
||||||
mockDemoTrace({
|
|
||||||
state: "stopped",
|
|
||||||
script_execution: "error",
|
|
||||||
error: 'Variable "beer" cannot be None',
|
|
||||||
}),
|
|
||||||
mockDemoTrace({ state: "stopped", script_execution: "cancelled" }),
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-trace-timeline")
|
|
||||||
export class DemoAutomationTraceTimeline extends LitElement {
|
|
||||||
@property({ attribute: false }) hass?: HomeAssistant;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
${traces.map(
|
|
||||||
(trace) => html`
|
|
||||||
<ha-card .header=${trace.trace.config.alias}>
|
|
||||||
<div class="card-content">
|
|
||||||
<hat-trace-timeline
|
|
||||||
.hass=${this.hass}
|
|
||||||
.trace=${trace.trace}
|
|
||||||
.logbookEntries=${trace.logbookEntries}
|
|
||||||
></hat-trace-timeline>
|
|
||||||
<button @click=${() => console.log(trace)}>Log trace</button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px;
|
|
||||||
}
|
|
||||||
.card-content {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-trace-timeline": DemoAutomationTraceTimeline;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,91 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import "../../../src/components/trace/hat-script-graph";
|
|
||||||
import "../../../src/components/trace/hat-trace-timeline";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
import { DemoTrace } from "../data/traces/types";
|
|
||||||
import { basicTrace } from "../data/traces/basic_trace";
|
|
||||||
import { motionLightTrace } from "../data/traces/motion-light-trace";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
|
|
||||||
const traces: DemoTrace[] = [basicTrace, motionLightTrace];
|
|
||||||
|
|
||||||
@customElement("demo-automation-trace")
|
|
||||||
export class DemoAutomationTrace extends LitElement {
|
|
||||||
@property({ attribute: false }) hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _selected = {};
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
${traces.map(
|
|
||||||
(trace, idx) => html`
|
|
||||||
<ha-card .header=${trace.trace.config.alias}>
|
|
||||||
<div class="card-content">
|
|
||||||
<hat-script-graph
|
|
||||||
.trace=${trace.trace}
|
|
||||||
.selected=${this._selected[idx]}
|
|
||||||
@graph-node-selected=${(ev) => {
|
|
||||||
this._selected = { ...this._selected, [idx]: ev.detail.path };
|
|
||||||
}}
|
|
||||||
></hat-script-graph>
|
|
||||||
<hat-trace-timeline
|
|
||||||
allowPick
|
|
||||||
.hass=${this.hass}
|
|
||||||
.trace=${trace.trace}
|
|
||||||
.logbookEntries=${trace.logbookEntries}
|
|
||||||
.selectedPath=${this._selected[idx]}
|
|
||||||
@value-changed=${(ev) => {
|
|
||||||
this._selected = {
|
|
||||||
...this._selected,
|
|
||||||
[idx]: ev.detail.value,
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
></hat-trace-timeline>
|
|
||||||
<button @click=${() => console.log(trace)}>Log trace</button>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px;
|
|
||||||
}
|
|
||||||
.card-content {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.card-content > * {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
.card-content > *:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-trace": DemoAutomationTrace;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -87,8 +93,4 @@ class DemoAlarmPanelEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-alarm-panel-card", DemoAlarmPanelEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-alarm-panel-card": DemoAlarmPanelEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -69,8 +75,4 @@ class DemoConditional extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-conditional-card", DemoConditional);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-conditional-card": DemoConditional;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -233,8 +239,4 @@ class DemoEntities extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-entities-card", DemoEntities);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-entities-card": DemoEntities;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -85,8 +91,4 @@ class DemoButtonEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-entity-button-card", DemoButtonEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-entity-button-card": DemoButtonEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -126,8 +132,4 @@ class DemoEntityFilter extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-entity-filter-card", DemoEntityFilter);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-entity-filter-card": DemoEntityFilter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -123,8 +129,4 @@ class DemoGaugeEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-gauge-card", DemoGaugeEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-gauge-card": DemoGaugeEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -226,8 +232,4 @@ class DemoGlanceEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-glance-card", DemoGlanceEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-glance-card": DemoGlanceEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { customElement, html, LitElement, TemplateResult } from "lit-element";
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
@@ -43,8 +42,4 @@ class DemoIframe extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-iframe-card", DemoIframe);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-iframe-card": DemoIframe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -79,8 +85,4 @@ class DemoLightEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-light-card", DemoLightEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-light-card": DemoLightEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -177,8 +183,4 @@ class DemoMap extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-map-card", DemoMap);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-map-card": DemoMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { mockTemplate } from "../../../demo/src/stubs/template";
|
import { mockTemplate } from "../../../demo/src/stubs/template";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -270,8 +276,4 @@ class DemoMarkdown extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-markdown-card", DemoMarkdown);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-markdown-card": DemoMarkdown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
import { createMediaPlayerEntities } from "../data/media_players";
|
import { createMediaPlayerEntities } from "../data/media_players";
|
||||||
@@ -174,8 +180,4 @@ class DemoHuiMediaControlCard extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-media-control-card", DemoHuiMediaControlCard);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-media-control-card": DemoHuiMediaControlCard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
import { createMediaPlayerEntities } from "../data/media_players";
|
import { createMediaPlayerEntities } from "../data/media_players";
|
||||||
@@ -71,8 +77,4 @@ class DemoHuiMediaPlayerRow extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-media-player-row", DemoHuiMediaPlayerRow);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-media-player-row": DemoHuiMediaPlayerRow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -141,8 +147,4 @@ class DemoPictureElements extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-picture-elements-card", DemoPictureElements);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-picture-elements-card": DemoPictureElements;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -96,8 +102,4 @@ class DemoPictureEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-picture-entity-card", DemoPictureEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-picture-entity-card": DemoPictureEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -137,8 +143,4 @@ class DemoPictureGlance extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-picture-glance-card", DemoPictureGlance);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-picture-glance-card": DemoPictureGlance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
import { createPlantEntities } from "../data/plants";
|
import { createPlantEntities } from "../data/plants";
|
||||||
@@ -46,8 +52,4 @@ export class DemoPlantEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-plant-card", DemoPlantEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-plant-card": DemoPlantEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
@@ -42,8 +48,4 @@ class DemoShoppingListEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-shopping-list-card", DemoShoppingListEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-shopping-list-card": DemoShoppingListEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { mockHistory } from "../../../demo/src/stubs/history";
|
import { mockHistory } from "../../../demo/src/stubs/history";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
@@ -43,110 +49,6 @@ const ENTITIES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
{
|
|
||||||
heading: "Default Grid",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_paulus
|
|
||||||
- type: sensor
|
|
||||||
entity: sensor.illumination
|
|
||||||
graph: line
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_anne_therese
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Non-square Grid with 2 columns",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 2
|
|
||||||
square: false
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_paulus
|
|
||||||
- type: sensor
|
|
||||||
entity: sensor.illumination
|
|
||||||
graph: line
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Default Grid with title",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
title: Kitchen
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_paulus
|
|
||||||
- type: sensor
|
|
||||||
entity: sensor.illumination
|
|
||||||
graph: line
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_anne_therese
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Columns 4",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 4
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
- type: entity
|
|
||||||
entity: device_tracker.demo_paulus
|
|
||||||
- type: sensor
|
|
||||||
entity: sensor.illumination
|
|
||||||
graph: line
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Columns 2",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 2
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
- type: entity
|
|
||||||
entity: light.bed_light
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Columns 1",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
columns: 1
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
heading: "Size for single card",
|
|
||||||
config: `
|
|
||||||
- type: grid
|
|
||||||
cards:
|
|
||||||
- type: entity
|
|
||||||
entity: light.kitchen_lights
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
heading: "Vertical Stack",
|
heading: "Vertical Stack",
|
||||||
config: `
|
config: `
|
||||||
@@ -197,9 +99,45 @@ const CONFIGS = [
|
|||||||
entity: light.bed_light
|
entity: light.bed_light
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
heading: "Default Grid",
|
||||||
|
config: `
|
||||||
|
- type: grid
|
||||||
|
cards:
|
||||||
|
- type: entity
|
||||||
|
entity: light.kitchen_lights
|
||||||
|
- type: entity
|
||||||
|
entity: light.bed_light
|
||||||
|
- type: entity
|
||||||
|
entity: device_tracker.demo_paulus
|
||||||
|
- type: sensor
|
||||||
|
entity: sensor.illumination
|
||||||
|
graph: line
|
||||||
|
- type: entity
|
||||||
|
entity: device_tracker.demo_anne_therese
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Non-square Grid with 2 columns",
|
||||||
|
config: `
|
||||||
|
- type: grid
|
||||||
|
columns: 2
|
||||||
|
square: false
|
||||||
|
cards:
|
||||||
|
- type: entity
|
||||||
|
entity: light.kitchen_lights
|
||||||
|
- type: entity
|
||||||
|
entity: light.bed_light
|
||||||
|
- type: entity
|
||||||
|
entity: device_tracker.demo_paulus
|
||||||
|
- type: sensor
|
||||||
|
entity: sensor.illumination
|
||||||
|
graph: line
|
||||||
|
`,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-hui-grid-and-stack-card")
|
@customElement("demo-hui-stack-card")
|
||||||
class DemoStack extends LitElement {
|
class DemoStack extends LitElement {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
@query("#demos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
@@ -217,8 +155,4 @@ class DemoStack extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-stack-card", DemoStack);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-grid-and-stack-card": DemoStack;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,11 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
@@ -90,8 +96,4 @@ class DemoThermostatEntity extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-hui-thermostat-card", DemoThermostatEntity);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-hui-thermostat-card": DemoThermostatEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,354 +0,0 @@
|
|||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import "../../../src/components/ha-formfield";
|
|
||||||
import "../../../src/components/ha-switch";
|
|
||||||
|
|
||||||
import { IntegrationManifest } from "../../../src/data/integration";
|
|
||||||
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
import "../../../src/panels/config/integrations/ha-integration-card";
|
|
||||||
import "../../../src/panels/config/integrations/ha-ignored-config-entry-card";
|
|
||||||
import "../../../src/panels/config/integrations/ha-config-flow-card";
|
|
||||||
import type {
|
|
||||||
ConfigEntryExtended,
|
|
||||||
DataEntryFlowProgressExtended,
|
|
||||||
} from "../../../src/panels/config/integrations/ha-config-integrations";
|
|
||||||
import { DeviceRegistryEntry } from "../../../src/data/device_registry";
|
|
||||||
import { EntityRegistryEntry } from "../../../src/data/entity_registry";
|
|
||||||
import { classMap } from "lit/directives/class-map";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
|
|
||||||
const createConfigEntry = (
|
|
||||||
title: string,
|
|
||||||
override: Partial<ConfigEntryExtended> = {}
|
|
||||||
): ConfigEntryExtended => ({
|
|
||||||
entry_id: title,
|
|
||||||
domain: "esphome",
|
|
||||||
localized_domain_name: "ESPHome",
|
|
||||||
title,
|
|
||||||
source: "zeroconf",
|
|
||||||
state: "loaded",
|
|
||||||
supports_options: false,
|
|
||||||
supports_unload: true,
|
|
||||||
disabled_by: null,
|
|
||||||
pref_disable_new_entities: false,
|
|
||||||
pref_disable_polling: false,
|
|
||||||
reason: null,
|
|
||||||
...override,
|
|
||||||
});
|
|
||||||
|
|
||||||
const createManifest = (
|
|
||||||
isCustom: boolean,
|
|
||||||
isCloud: boolean,
|
|
||||||
name = "ESPHome"
|
|
||||||
): IntegrationManifest => ({
|
|
||||||
name,
|
|
||||||
domain: "esphome",
|
|
||||||
is_built_in: !isCustom,
|
|
||||||
config_flow: false,
|
|
||||||
documentation: "https://www.home-assistant.io/integrations/esphome/",
|
|
||||||
iot_class: isCloud ? "cloud_polling" : "local_polling",
|
|
||||||
});
|
|
||||||
|
|
||||||
const loadedEntry = createConfigEntry("Loaded");
|
|
||||||
const nameAsDomainEntry = createConfigEntry("ESPHome");
|
|
||||||
const longNameEntry = createConfigEntry(
|
|
||||||
"Entry with a super long name that is going to the next line"
|
|
||||||
);
|
|
||||||
const longNonBreakingNameEntry = createConfigEntry(
|
|
||||||
"EntryWithASuperLongNameThatDoesNotBreak"
|
|
||||||
);
|
|
||||||
const configPanelEntry = createConfigEntry("Config Panel", {
|
|
||||||
domain: "mqtt",
|
|
||||||
localized_domain_name: "MQTT",
|
|
||||||
});
|
|
||||||
const optionsFlowEntry = createConfigEntry("Options Flow", {
|
|
||||||
supports_options: true,
|
|
||||||
});
|
|
||||||
const disabledPollingEntry = createConfigEntry("Disabled Polling", {
|
|
||||||
pref_disable_polling: true,
|
|
||||||
});
|
|
||||||
const setupErrorEntry = createConfigEntry("Setup Error", {
|
|
||||||
state: "setup_error",
|
|
||||||
});
|
|
||||||
const migrationErrorEntry = createConfigEntry("Migration Error", {
|
|
||||||
state: "migration_error",
|
|
||||||
});
|
|
||||||
const setupRetryEntry = createConfigEntry("Setup Retry", {
|
|
||||||
state: "setup_retry",
|
|
||||||
});
|
|
||||||
const setupRetryReasonEntry = createConfigEntry("Setup Retry", {
|
|
||||||
state: "setup_retry",
|
|
||||||
reason: "connection_error",
|
|
||||||
});
|
|
||||||
const setupRetryReasonMissingKeyEntry = createConfigEntry("Setup Retry", {
|
|
||||||
state: "setup_retry",
|
|
||||||
reason:
|
|
||||||
"HTTPSConnectionpool: Max retries exceeded with NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x9eedfc10>: Failed to establish a new connection: [Errno 113] Host is unreachable')",
|
|
||||||
});
|
|
||||||
const failedUnloadEntry = createConfigEntry("Failed Unload", {
|
|
||||||
state: "failed_unload",
|
|
||||||
});
|
|
||||||
const notLoadedEntry = createConfigEntry("Not Loaded", { state: "not_loaded" });
|
|
||||||
const disabledEntry = createConfigEntry("Disabled", {
|
|
||||||
state: "not_loaded",
|
|
||||||
disabled_by: "user",
|
|
||||||
});
|
|
||||||
const disabledFailedUnloadEntry = createConfigEntry(
|
|
||||||
"Disabled - Failed Unload",
|
|
||||||
{
|
|
||||||
state: "failed_unload",
|
|
||||||
disabled_by: "user",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const configFlows: DataEntryFlowProgressExtended[] = [
|
|
||||||
{
|
|
||||||
flow_id: "adbb401329d8439ebb78ef29837826a8",
|
|
||||||
handler: "roku",
|
|
||||||
context: {
|
|
||||||
source: "ssdp",
|
|
||||||
unique_id: "YF008D862864",
|
|
||||||
title_placeholders: {
|
|
||||||
name: "Living room Roku",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
step_id: "discovery_confirm",
|
|
||||||
localized_title: "Living room Roku",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
flow_id: "adbb401329d8439ebb78ef29837826a8",
|
|
||||||
handler: "hue",
|
|
||||||
context: {
|
|
||||||
source: "reauth",
|
|
||||||
unique_id: "YF008D862864",
|
|
||||||
title_placeholders: {
|
|
||||||
name: "Living room Roku",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
step_id: "discovery_confirm",
|
|
||||||
localized_title: "Philips Hue",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const configEntries: Array<{
|
|
||||||
items: ConfigEntryExtended[];
|
|
||||||
is_custom?: boolean;
|
|
||||||
disabled?: boolean;
|
|
||||||
highlight?: string;
|
|
||||||
}> = [
|
|
||||||
{ items: [loadedEntry] },
|
|
||||||
{ items: [configPanelEntry] },
|
|
||||||
{ items: [optionsFlowEntry] },
|
|
||||||
{ items: [disabledPollingEntry] },
|
|
||||||
{ items: [nameAsDomainEntry] },
|
|
||||||
{ items: [longNameEntry] },
|
|
||||||
{ items: [longNonBreakingNameEntry] },
|
|
||||||
{ items: [setupErrorEntry] },
|
|
||||||
{ items: [migrationErrorEntry] },
|
|
||||||
{ items: [setupRetryEntry] },
|
|
||||||
{ items: [setupRetryReasonEntry] },
|
|
||||||
{ items: [setupRetryReasonMissingKeyEntry] },
|
|
||||||
{ items: [failedUnloadEntry] },
|
|
||||||
{ items: [notLoadedEntry] },
|
|
||||||
{
|
|
||||||
items: [
|
|
||||||
loadedEntry,
|
|
||||||
setupErrorEntry,
|
|
||||||
migrationErrorEntry,
|
|
||||||
longNameEntry,
|
|
||||||
longNonBreakingNameEntry,
|
|
||||||
setupRetryEntry,
|
|
||||||
failedUnloadEntry,
|
|
||||||
notLoadedEntry,
|
|
||||||
disabledEntry,
|
|
||||||
nameAsDomainEntry,
|
|
||||||
configPanelEntry,
|
|
||||||
optionsFlowEntry,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{ disabled: true, items: [disabledEntry] },
|
|
||||||
{ disabled: true, items: [disabledFailedUnloadEntry] },
|
|
||||||
{
|
|
||||||
disabled: true,
|
|
||||||
items: [disabledEntry, disabledFailedUnloadEntry],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
items: [loadedEntry, configPanelEntry],
|
|
||||||
highlight: "Loaded",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const createEntityRegistryEntries = (
|
|
||||||
item: ConfigEntryExtended
|
|
||||||
): EntityRegistryEntry[] => [
|
|
||||||
{
|
|
||||||
config_entry_id: item.entry_id,
|
|
||||||
device_id: "mock-device-id",
|
|
||||||
area_id: null,
|
|
||||||
disabled_by: null,
|
|
||||||
entity_id: "binary_sensor.updater",
|
|
||||||
name: null,
|
|
||||||
icon: null,
|
|
||||||
platform: "updater",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const createDeviceRegistryEntries = (
|
|
||||||
item: ConfigEntryExtended
|
|
||||||
): DeviceRegistryEntry[] => [
|
|
||||||
{
|
|
||||||
entry_type: null,
|
|
||||||
config_entries: [item.entry_id],
|
|
||||||
connections: [],
|
|
||||||
manufacturer: "ESPHome",
|
|
||||||
model: "Mock Device",
|
|
||||||
name: "Tag Reader",
|
|
||||||
sw_version: null,
|
|
||||||
id: "mock-device-id",
|
|
||||||
identifiers: [],
|
|
||||||
via_device_id: null,
|
|
||||||
area_id: null,
|
|
||||||
name_by_user: null,
|
|
||||||
disabled_by: null,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-integration-card")
|
|
||||||
export class DemoIntegrationCard extends LitElement {
|
|
||||||
@property({ attribute: false }) hass?: HomeAssistant;
|
|
||||||
|
|
||||||
@state() isCustomIntegration = false;
|
|
||||||
|
|
||||||
@state() isCloud = false;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<div class="container">
|
|
||||||
<div class="filters">
|
|
||||||
<ha-formfield label="Custom Integration">
|
|
||||||
<ha-switch @change=${this._toggleCustomIntegration}></ha-switch>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield label="Relies on cloud">
|
|
||||||
<ha-switch @change=${this._toggleCloud}></ha-switch>
|
|
||||||
</ha-formfield>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ha-ignored-config-entry-card
|
|
||||||
.hass=${this.hass}
|
|
||||||
.entry=${createConfigEntry("Ignored Entry")}
|
|
||||||
.manifest=${createManifest(this.isCustomIntegration, this.isCloud)}
|
|
||||||
></ha-ignored-config-entry-card>
|
|
||||||
|
|
||||||
${configFlows.map(
|
|
||||||
(flow) => html`
|
|
||||||
<ha-config-flow-card
|
|
||||||
.hass=${this.hass}
|
|
||||||
.flow=${flow}
|
|
||||||
.manifest=${createManifest(
|
|
||||||
this.isCustomIntegration,
|
|
||||||
this.isCloud,
|
|
||||||
flow.handler === "roku" ? "Roku" : "Philips Hue"
|
|
||||||
)}
|
|
||||||
></ha-config-flow-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
${configEntries.map(
|
|
||||||
(info) => html`
|
|
||||||
<ha-integration-card
|
|
||||||
class=${classMap({
|
|
||||||
highlight: info.highlight !== undefined,
|
|
||||||
})}
|
|
||||||
.hass=${this.hass}
|
|
||||||
domain="esphome"
|
|
||||||
.items=${info.items}
|
|
||||||
.manifest=${createManifest(
|
|
||||||
this.isCustomIntegration,
|
|
||||||
this.isCloud
|
|
||||||
)}
|
|
||||||
.entityRegistryEntries=${createEntityRegistryEntries(
|
|
||||||
info.items[0]
|
|
||||||
)}
|
|
||||||
.deviceRegistryEntries=${createDeviceRegistryEntries(
|
|
||||||
info.items[0]
|
|
||||||
)}
|
|
||||||
?disabled=${info.disabled}
|
|
||||||
.selectedConfigEntryId=${info.highlight}
|
|
||||||
></ha-integration-card>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div class="container">
|
|
||||||
<!-- One that is standalone to see how it increases height if height
|
|
||||||
not defined by other cards. -->
|
|
||||||
<ha-integration-card
|
|
||||||
.hass=${this.hass}
|
|
||||||
domain="esphome"
|
|
||||||
.items=${[
|
|
||||||
loadedEntry,
|
|
||||||
setupErrorEntry,
|
|
||||||
migrationErrorEntry,
|
|
||||||
setupRetryEntry,
|
|
||||||
failedUnloadEntry,
|
|
||||||
]}
|
|
||||||
.manifest=${createManifest(this.isCustomIntegration, this.isCloud)}
|
|
||||||
.entityRegistryEntries=${createEntityRegistryEntries(loadedEntry)}
|
|
||||||
.deviceRegistryEntries=${createDeviceRegistryEntries(loadedEntry)}
|
|
||||||
></ha-integration-card>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("config", "en");
|
|
||||||
// Normally this string is loaded from backend
|
|
||||||
hass.addTranslations(
|
|
||||||
{
|
|
||||||
"component.esphome.config.error.connection_error":
|
|
||||||
"Can't connect to ESP. Please make sure your YAML file contains an 'api:' line.",
|
|
||||||
},
|
|
||||||
"en"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toggleCustomIntegration() {
|
|
||||||
this.isCustomIntegration = !this.isCustomIntegration;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toggleCloud() {
|
|
||||||
this.isCloud = !this.isCloud;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
.container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
||||||
grid-gap: 16px 16px;
|
|
||||||
padding: 8px 16px 16px;
|
|
||||||
margin-bottom: 64px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container > * {
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-formfield {
|
|
||||||
margin: 8px 0;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-integration-card": DemoIntegrationCard;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +1,21 @@
|
|||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, query } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
LightColorModes,
|
SUPPORT_BRIGHTNESS,
|
||||||
|
SUPPORT_COLOR,
|
||||||
|
SUPPORT_COLOR_TEMP,
|
||||||
SUPPORT_EFFECT,
|
SUPPORT_EFFECT,
|
||||||
SUPPORT_FLASH,
|
SUPPORT_FLASH,
|
||||||
SUPPORT_TRANSITION,
|
SUPPORT_TRANSITION,
|
||||||
|
SUPPORT_WHITE_VALUE,
|
||||||
} from "../../../src/data/light";
|
} from "../../../src/data/light";
|
||||||
import "../../../src/dialogs/more-info/more-info-content";
|
import "../../../src/dialogs/more-info/more-info-content";
|
||||||
import { getEntity } from "../../../src/fake_data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
@@ -22,8 +32,7 @@ const ENTITIES = [
|
|||||||
getEntity("light", "kitchen_light", "on", {
|
getEntity("light", "kitchen_light", "on", {
|
||||||
friendly_name: "Brightness Light",
|
friendly_name: "Brightness Light",
|
||||||
brightness: 200,
|
brightness: 200,
|
||||||
supported_color_modes: [LightColorModes.BRIGHTNESS],
|
supported_features: SUPPORT_BRIGHTNESS,
|
||||||
color_mode: LightColorModes.BRIGHTNESS,
|
|
||||||
}),
|
}),
|
||||||
getEntity("light", "color_temperature_light", "on", {
|
getEntity("light", "color_temperature_light", "on", {
|
||||||
friendly_name: "White Color Temperature Light",
|
friendly_name: "White Color Temperature Light",
|
||||||
@@ -31,96 +40,20 @@ const ENTITIES = [
|
|||||||
color_temp: 75,
|
color_temp: 75,
|
||||||
min_mireds: 30,
|
min_mireds: 30,
|
||||||
max_mireds: 150,
|
max_mireds: 150,
|
||||||
supported_color_modes: [
|
supported_features: SUPPORT_BRIGHTNESS + SUPPORT_COLOR_TEMP,
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.COLOR_TEMP,
|
|
||||||
}),
|
}),
|
||||||
getEntity("light", "color_hs_light", "on", {
|
getEntity("light", "color_effectslight", "on", {
|
||||||
friendly_name: "Color HS Light",
|
|
||||||
brightness: 255,
|
|
||||||
hs_color: [30, 100],
|
|
||||||
rgb_color: [30, 100, 255],
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.HS,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.HS,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_rgb_ct_light", "on", {
|
|
||||||
friendly_name: "Color RGB + CT Light",
|
|
||||||
brightness: 255,
|
|
||||||
color_temp: 75,
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.RGB,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.COLOR_TEMP,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_RGB_light", "on", {
|
|
||||||
friendly_name: "Color Effets Light",
|
friendly_name: "Color Effets Light",
|
||||||
brightness: 255,
|
brightness: 255,
|
||||||
rgb_color: [30, 100, 255],
|
hs_color: [30, 100],
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
white_value: 36,
|
||||||
supported_color_modes: [LightColorModes.BRIGHTNESS, LightColorModes.RGB],
|
supported_features:
|
||||||
color_mode: LightColorModes.RGB,
|
SUPPORT_BRIGHTNESS +
|
||||||
effect_list: ["random", "colorloop"],
|
SUPPORT_EFFECT +
|
||||||
}),
|
SUPPORT_FLASH +
|
||||||
getEntity("light", "color_rgbw_light", "on", {
|
SUPPORT_COLOR +
|
||||||
friendly_name: "Color RGBW Light",
|
SUPPORT_TRANSITION +
|
||||||
brightness: 255,
|
SUPPORT_WHITE_VALUE,
|
||||||
rgbw_color: [30, 100, 255, 125],
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.RGBW,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.RGBW,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_rgbww_light", "on", {
|
|
||||||
friendly_name: "Color RGBWW Light",
|
|
||||||
brightness: 255,
|
|
||||||
rgbww_color: [30, 100, 255, 125, 10],
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.RGBWW,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.RGBWW,
|
|
||||||
effect_list: ["random", "colorloop"],
|
|
||||||
}),
|
|
||||||
getEntity("light", "color_xy_light", "on", {
|
|
||||||
friendly_name: "Color XY Light",
|
|
||||||
brightness: 255,
|
|
||||||
xy_color: [30, 100],
|
|
||||||
rgb_color: [30, 100, 255],
|
|
||||||
min_mireds: 30,
|
|
||||||
max_mireds: 150,
|
|
||||||
supported_features: SUPPORT_EFFECT + SUPPORT_FLASH + SUPPORT_TRANSITION,
|
|
||||||
supported_color_modes: [
|
|
||||||
LightColorModes.BRIGHTNESS,
|
|
||||||
LightColorModes.COLOR_TEMP,
|
|
||||||
LightColorModes.XY,
|
|
||||||
],
|
|
||||||
color_mode: LightColorModes.XY,
|
|
||||||
effect_list: ["random", "colorloop"],
|
effect_list: ["random", "colorloop"],
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@@ -148,8 +81,4 @@ class DemoMoreInfoLight extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
customElements.define("demo-more-info-light", DemoMoreInfoLight);
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-more-info-light": DemoMoreInfoLight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { customElement, html, LitElement, TemplateResult } from "lit-element";
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
||||||
import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive";
|
import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive";
|
||||||
|
@@ -111,9 +111,29 @@ class HaGallery extends PolymerElement {
|
|||||||
</template>
|
</template>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
|
||||||
<ha-card header="Other Demos">
|
<ha-card header="More Info Demos">
|
||||||
<div class="card-content intro"></div>
|
<div class="card-content intro">
|
||||||
<template is="dom-repeat" items="[[_restDemos]]">
|
<p>
|
||||||
|
More info screens show up when an entity is clicked.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<template is="dom-repeat" items="[[_moreInfoDemos]]">
|
||||||
|
<a href="#[[item]]">
|
||||||
|
<paper-item>
|
||||||
|
<paper-item-body>{{ item }}</paper-item-body>
|
||||||
|
<ha-icon icon="hass:chevron-right"></ha-icon>
|
||||||
|
</paper-item>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</ha-card>
|
||||||
|
|
||||||
|
<ha-card header="Util Demos">
|
||||||
|
<div class="card-content intro">
|
||||||
|
<p>
|
||||||
|
Test pages for our utility functions.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<template is="dom-repeat" items="[[_utilDemos]]">
|
||||||
<a href="#[[item]]">
|
<a href="#[[item]]">
|
||||||
<paper-item>
|
<paper-item>
|
||||||
<paper-item-body>{{ item }}</paper-item-body>
|
<paper-item-body>{{ item }}</paper-item-body>
|
||||||
@@ -158,9 +178,13 @@ class HaGallery extends PolymerElement {
|
|||||||
type: Array,
|
type: Array,
|
||||||
computed: "_computeLovelace(_demos)",
|
computed: "_computeLovelace(_demos)",
|
||||||
},
|
},
|
||||||
_restDemos: {
|
_moreInfoDemos: {
|
||||||
type: Array,
|
type: Array,
|
||||||
computed: "_computeRest(_demos)",
|
computed: "_computeMoreInfos(_demos)",
|
||||||
|
},
|
||||||
|
_utilDemos: {
|
||||||
|
type: Array,
|
||||||
|
computed: "_computeUtil(_demos)",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -213,8 +237,12 @@ class HaGallery extends PolymerElement {
|
|||||||
return demos.filter((demo) => demo.includes("hui"));
|
return demos.filter((demo) => demo.includes("hui"));
|
||||||
}
|
}
|
||||||
|
|
||||||
_computeRest(demos) {
|
_computeMoreInfos(demos) {
|
||||||
return demos.filter((demo) => !demo.includes("hui"));
|
return demos.filter((demo) => demo.includes("more-info"));
|
||||||
|
}
|
||||||
|
|
||||||
|
_computeUtil(demos) {
|
||||||
|
return demos.filter((demo) => demo.includes("util"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js";
|
import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { property } from "lit/decorators";
|
css,
|
||||||
|
CSSResultArray,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import { navigate } from "../../../src/common/navigate";
|
import { navigate } from "../../../src/common/navigate";
|
||||||
@@ -9,7 +15,6 @@ import {
|
|||||||
HassioAddonInfo,
|
HassioAddonInfo,
|
||||||
HassioAddonRepository,
|
HassioAddonRepository,
|
||||||
} from "../../../src/data/hassio/addon";
|
} from "../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
import "../components/hassio-card-content";
|
import "../components/hassio-card-content";
|
||||||
import { filterAndSort } from "../components/hassio-filter-addons";
|
import { filterAndSort } from "../components/hassio-filter-addons";
|
||||||
@@ -18,8 +23,6 @@ import { hassioStyle } from "../resources/hassio-style";
|
|||||||
class HassioAddonRepositoryEl extends LitElement {
|
class HassioAddonRepositoryEl extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public repo!: HassioAddonRepository;
|
@property({ attribute: false }) public repo!: HassioAddonRepository;
|
||||||
|
|
||||||
@property({ attribute: false }) public addons!: HassioAddonInfo[];
|
@property({ attribute: false }) public addons!: HassioAddonInfo[];
|
||||||
@@ -41,7 +44,9 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
const repo = this.repo;
|
const repo = this.repo;
|
||||||
let _addons = this.addons;
|
let _addons = this.addons;
|
||||||
if (!this.hass.userData?.showAdvanced) {
|
if (!this.hass.userData?.showAdvanced) {
|
||||||
_addons = _addons.filter((addon) => !addon.advanced);
|
_addons = _addons.filter((addon) => {
|
||||||
|
return !addon.advanced;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const addons = this._getAddons(_addons, this.filter);
|
const addons = this._getAddons(_addons, this.filter);
|
||||||
|
|
||||||
@@ -49,18 +54,16 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p class="description">
|
<p class="description">
|
||||||
${this.supervisor.localize(
|
No results found in "${repo.name}."
|
||||||
"store.no_results_found",
|
|
||||||
"repository",
|
|
||||||
repo.name
|
|
||||||
)}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1>${repo.name}</h1>
|
<h1>
|
||||||
|
${repo.name}
|
||||||
|
</h1>
|
||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
${addons.map(
|
${addons.map(
|
||||||
(addon) => html`
|
(addon) => html`
|
||||||
@@ -80,13 +83,11 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
: mdiPuzzle}
|
: mdiPuzzle}
|
||||||
.iconTitle=${addon.installed
|
.iconTitle=${addon.installed
|
||||||
? addon.update_available
|
? addon.update_available
|
||||||
? this.supervisor.localize(
|
? "New version available"
|
||||||
"common.new_version_available"
|
: "Add-on is installed"
|
||||||
)
|
|
||||||
: this.supervisor.localize("addon.installed")
|
|
||||||
: addon.available
|
: addon.available
|
||||||
? this.supervisor.localize("addon.not_installed")
|
? "Add-on is not installed"
|
||||||
: this.supervisor.localize("addon.not_available")}
|
: "Add-on is not available on your system"}
|
||||||
.iconClass=${addon.installed
|
.iconClass=${addon.installed
|
||||||
? addon.update_available
|
? addon.update_available
|
||||||
? "update"
|
? "update"
|
||||||
@@ -120,10 +121,10 @@ class HassioAddonRepositoryEl extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _addonTapped(ev) {
|
private _addonTapped(ev) {
|
||||||
navigate(`/hassio/addon/${ev.currentTarget.addon.slug}`);
|
navigate(this, `/hassio/addon/${ev.currentTarget.addon.slug}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultArray {
|
||||||
return [
|
return [
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
css`
|
css`
|
||||||
|
@@ -4,27 +4,26 @@ import "@material/mwc-list/mwc-list-item";
|
|||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResult,
|
||||||
html,
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
} from "lit-element";
|
||||||
} from "lit";
|
import { html, TemplateResult } from "lit-html";
|
||||||
import { property, state } from "lit/decorators";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||||
import { navigate } from "../../../src/common/navigate";
|
|
||||||
import "../../../src/common/search/search-input";
|
import "../../../src/common/search/search-input";
|
||||||
import { extractSearchParam } from "../../../src/common/url/search-params";
|
|
||||||
import "../../../src/components/ha-button-menu";
|
import "../../../src/components/ha-button-menu";
|
||||||
import "../../../src/components/ha-svg-icon";
|
import "../../../src/components/ha-svg-icon";
|
||||||
import {
|
import {
|
||||||
|
fetchHassioAddonsInfo,
|
||||||
HassioAddonInfo,
|
HassioAddonInfo,
|
||||||
HassioAddonRepository,
|
HassioAddonRepository,
|
||||||
reloadHassioAddons,
|
reloadHassioAddons,
|
||||||
} from "../../../src/data/hassio/addon";
|
} from "../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
||||||
|
import { fetchHassioSupervisorInfo } from "../../../src/data/hassio/supervisor";
|
||||||
import "../../../src/layouts/hass-loading-screen";
|
import "../../../src/layouts/hass-loading-screen";
|
||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import { HomeAssistant, Route } from "../../../src/types";
|
import { HomeAssistant, Route } from "../../../src/types";
|
||||||
@@ -52,41 +51,58 @@ const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => {
|
|||||||
class HassioAddonStore extends LitElement {
|
class HassioAddonStore extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
@state() private _filter?: string;
|
@property({ attribute: false }) private _addons?: HassioAddonInfo[];
|
||||||
|
|
||||||
|
@property({ attribute: false }) private _repos?: HassioAddonRepository[];
|
||||||
|
|
||||||
|
@internalProperty() private _filter?: string;
|
||||||
|
|
||||||
public async refreshData() {
|
public async refreshData() {
|
||||||
|
this._repos = undefined;
|
||||||
|
this._addons = undefined;
|
||||||
|
this._filter = undefined;
|
||||||
await reloadHassioAddons(this.hass);
|
await reloadHassioAddons(this.hass);
|
||||||
await this._loadData();
|
await this._loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
let repos: TemplateResult[] = [];
|
const repos: TemplateResult[] = [];
|
||||||
|
|
||||||
if (this.supervisor.addon.repositories) {
|
if (this._repos) {
|
||||||
repos = this.addonRepositories(
|
for (const repo of this._repos) {
|
||||||
this.supervisor.addon.repositories,
|
const addons = this._addons!.filter(
|
||||||
this.supervisor.addon.addons,
|
(addon) => addon.repository === repo.slug
|
||||||
this._filter
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (addons.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
repos.push(html`
|
||||||
|
<hassio-addon-repository
|
||||||
|
.hass=${this.hass}
|
||||||
|
.repo=${repo}
|
||||||
|
.addons=${addons}
|
||||||
|
.filter=${this._filter!}
|
||||||
|
></hassio-addon-repository>
|
||||||
|
`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage
|
<hass-tabs-subpage
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.localizeFunc=${this.supervisor.localize}
|
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${supervisorTabs}
|
hassio
|
||||||
main-page
|
main-page
|
||||||
supervisor
|
.tabs=${supervisorTabs}
|
||||||
>
|
>
|
||||||
<span slot="header"> ${this.supervisor.localize("panel.store")} </span>
|
<span slot="header">Add-on Store</span>
|
||||||
<ha-button-menu
|
<ha-button-menu
|
||||||
corner="BOTTOM_START"
|
corner="BOTTOM_START"
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
@@ -96,15 +112,15 @@ class HassioAddonStore extends LitElement {
|
|||||||
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
||||||
</mwc-icon-button>
|
</mwc-icon-button>
|
||||||
<mwc-list-item>
|
<mwc-list-item>
|
||||||
${this.supervisor.localize("store.repositories")}
|
Repositories
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
<mwc-list-item>
|
<mwc-list-item>
|
||||||
${this.supervisor.localize("common.reload")}
|
Reload
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
${this.hass.userData?.showAdvanced &&
|
${this.hass.userData?.showAdvanced &&
|
||||||
atLeastVersion(this.hass.config.version, 0, 117)
|
atLeastVersion(this.hass.config.version, 0, 117)
|
||||||
? html`<mwc-list-item>
|
? html`<mwc-list-item>
|
||||||
${this.supervisor.localize("store.registries")}
|
Registries
|
||||||
</mwc-list-item>`
|
</mwc-list-item>`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
@@ -125,9 +141,11 @@ class HassioAddonStore extends LitElement {
|
|||||||
${!this.hass.userData?.showAdvanced
|
${!this.hass.userData?.showAdvanced
|
||||||
? html`
|
? html`
|
||||||
<div class="advanced">
|
<div class="advanced">
|
||||||
|
Missing add-ons? Enable advanced mode on
|
||||||
<a href="/profile" target="_top">
|
<a href="/profile" target="_top">
|
||||||
${this.supervisor.localize("store.missing_addons")}
|
your profile page
|
||||||
</a>
|
</a>
|
||||||
|
.
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@@ -137,45 +155,14 @@ class HassioAddonStore extends LitElement {
|
|||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
const repositoryUrl = extractSearchParam("repository_url");
|
|
||||||
navigate("/hassio/store", { replace: true });
|
|
||||||
if (repositoryUrl) {
|
|
||||||
this._manageRepositories(repositoryUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
|
||||||
this._loadData();
|
this._loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private addonRepositories = memoizeOne(
|
|
||||||
(
|
|
||||||
repositories: HassioAddonRepository[],
|
|
||||||
addons: HassioAddonInfo[],
|
|
||||||
filter?: string
|
|
||||||
) =>
|
|
||||||
repositories.sort(sortRepos).map((repo) => {
|
|
||||||
const filteredAddons = addons.filter(
|
|
||||||
(addon) => addon.repository === repo.slug
|
|
||||||
);
|
|
||||||
|
|
||||||
return filteredAddons.length !== 0
|
|
||||||
? html`
|
|
||||||
<hassio-addon-repository
|
|
||||||
.hass=${this.hass}
|
|
||||||
.repo=${repo}
|
|
||||||
.addons=${filteredAddons}
|
|
||||||
.filter=${filter!}
|
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-addon-repository>
|
|
||||||
`
|
|
||||||
: html``;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||||
switch (ev.detail.index) {
|
switch (ev.detail.index) {
|
||||||
case 0:
|
case 0:
|
||||||
this._manageRepositoriesClicked();
|
this._manageRepositories();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
this.refreshData();
|
this.refreshData();
|
||||||
@@ -192,33 +179,37 @@ class HassioAddonStore extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _manageRepositoriesClicked() {
|
private async _manageRepositories() {
|
||||||
this._manageRepositories();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _manageRepositories(url?: string) {
|
|
||||||
showRepositoriesDialog(this, {
|
showRepositoriesDialog(this, {
|
||||||
supervisor: this.supervisor,
|
repos: this._repos!,
|
||||||
url,
|
loadData: () => this._loadData(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _manageRegistries() {
|
private async _manageRegistries() {
|
||||||
showRegistriesDialog(this, { supervisor: this.supervisor });
|
showRegistriesDialog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _loadData() {
|
private async _loadData() {
|
||||||
fireEvent(this, "supervisor-collection-refresh", { collection: "addon" });
|
try {
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
const [addonsInfo, supervisor] = await Promise.all([
|
||||||
collection: "supervisor",
|
fetchHassioAddonsInfo(this.hass),
|
||||||
});
|
fetchHassioSupervisorInfo(this.hass),
|
||||||
|
]);
|
||||||
|
fireEvent(this, "supervisor-update", { supervisor });
|
||||||
|
this._repos = addonsInfo.repositories;
|
||||||
|
this._repos.sort(sortRepos);
|
||||||
|
this._addons = addonsInfo.addons;
|
||||||
|
} catch (err) {
|
||||||
|
alert(extractApiErrorMessage(err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _filterChanged(e) {
|
private async _filterChanged(e) {
|
||||||
this._filter = e.detail.value;
|
this._filter = e.detail.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
hassio-addon-repository {
|
hassio-addon-repository {
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
|
@@ -4,13 +4,15 @@ import "@polymer/paper-item/paper-item";
|
|||||||
import "@polymer/paper-listbox/paper-listbox";
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResult,
|
||||||
|
customElement,
|
||||||
html,
|
html,
|
||||||
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit-element";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import "web-animations-js/web-animations-next-lite.min";
|
import "web-animations-js/web-animations-next-lite.min";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
@@ -23,7 +25,6 @@ import {
|
|||||||
fetchHassioHardwareAudio,
|
fetchHassioHardwareAudio,
|
||||||
HassioHardwareAudioDevice,
|
HassioHardwareAudioDevice,
|
||||||
} from "../../../../src/data/hassio/hardware";
|
} from "../../../../src/data/hassio/hardware";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
|
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
|
||||||
@@ -33,32 +34,26 @@ import { hassioStyle } from "../../resources/hassio-style";
|
|||||||
class HassioAddonAudio extends LitElement {
|
class HassioAddonAudio extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _inputDevices?: HassioHardwareAudioDevice[];
|
@internalProperty() private _inputDevices?: HassioHardwareAudioDevice[];
|
||||||
|
|
||||||
@state() private _outputDevices?: HassioHardwareAudioDevice[];
|
@internalProperty() private _outputDevices?: HassioHardwareAudioDevice[];
|
||||||
|
|
||||||
@state() private _selectedInput!: null | string;
|
@internalProperty() private _selectedInput!: null | string;
|
||||||
|
|
||||||
@state() private _selectedOutput!: null | string;
|
@internalProperty() private _selectedOutput!: null | string;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card header="Audio">
|
||||||
.header=${this.supervisor.localize("addon.configuration.audio.header")}
|
|
||||||
>
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
|
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
.label=${this.supervisor.localize(
|
label="Input"
|
||||||
"addon.configuration.audio.input"
|
|
||||||
)}
|
|
||||||
@iron-select=${this._setInputDevice}
|
@iron-select=${this._setInputDevice}
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
@@ -67,19 +62,17 @@ class HassioAddonAudio extends LitElement {
|
|||||||
.selected=${this._selectedInput!}
|
.selected=${this._selectedInput!}
|
||||||
>
|
>
|
||||||
${this._inputDevices &&
|
${this._inputDevices &&
|
||||||
this._inputDevices.map(
|
this._inputDevices.map((item) => {
|
||||||
(item) => html`
|
return html`
|
||||||
<paper-item device=${item.device || ""}>
|
<paper-item device=${item.device || ""}
|
||||||
${item.name}
|
>${item.name}</paper-item
|
||||||
</paper-item>
|
>
|
||||||
`
|
`;
|
||||||
)}
|
})}
|
||||||
</paper-listbox>
|
</paper-listbox>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
.label=${this.supervisor.localize(
|
label="Output"
|
||||||
"addon.configuration.audio.output"
|
|
||||||
)}
|
|
||||||
@iron-select=${this._setOutputDevice}
|
@iron-select=${this._setOutputDevice}
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
@@ -88,26 +81,26 @@ class HassioAddonAudio extends LitElement {
|
|||||||
.selected=${this._selectedOutput!}
|
.selected=${this._selectedOutput!}
|
||||||
>
|
>
|
||||||
${this._outputDevices &&
|
${this._outputDevices &&
|
||||||
this._outputDevices.map(
|
this._outputDevices.map((item) => {
|
||||||
(item) => html`
|
return html`
|
||||||
<paper-item device=${item.device || ""}
|
<paper-item device=${item.device || ""}
|
||||||
>${item.name}</paper-item
|
>${item.name}</paper-item
|
||||||
>
|
>
|
||||||
`
|
`;
|
||||||
)}
|
})}
|
||||||
</paper-listbox>
|
</paper-listbox>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<ha-progress-button @click=${this._saveSettings}>
|
<ha-progress-button @click=${this._saveSettings}>
|
||||||
${this.supervisor.localize("common.save")}
|
Save
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -159,7 +152,7 @@ class HassioAddonAudio extends LitElement {
|
|||||||
|
|
||||||
const noDevice: HassioHardwareAudioDevice = {
|
const noDevice: HassioHardwareAudioDevice = {
|
||||||
device: "default",
|
device: "default",
|
||||||
name: this.supervisor.localize("addon.configuration.audio.default"),
|
name: "Default",
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -196,7 +189,7 @@ class HassioAddonAudio extends LitElement {
|
|||||||
try {
|
try {
|
||||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.addon);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
this._error = "Failed to set addon audio device";
|
this._error = "Failed to set addon audio device";
|
||||||
|
@@ -1,8 +1,14 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
@@ -14,28 +20,26 @@ import "./hassio-addon-network";
|
|||||||
class HassioAddonConfigDashboard extends LitElement {
|
class HassioAddonConfigDashboard extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress active></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
const hasConfiguration =
|
const hasOptions =
|
||||||
(this.addon.options && Object.keys(this.addon.options).length) ||
|
this.addon.options && Object.keys(this.addon.options).length;
|
||||||
(this.addon.schema && Object.keys(this.addon.schema).length);
|
const hasSchema =
|
||||||
|
this.addon.schema && Object.keys(this.addon.schema).length;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${hasConfiguration || this.addon.network || this.addon.audio
|
${hasOptions || hasSchema || this.addon.network || this.addon.audio
|
||||||
? html`
|
? html`
|
||||||
${hasConfiguration
|
${hasOptions || hasSchema
|
||||||
? html`
|
? html`
|
||||||
<hassio-addon-config
|
<hassio-addon-config
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-addon-config>
|
></hassio-addon-config>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@@ -44,7 +48,6 @@ class HassioAddonConfigDashboard extends LitElement {
|
|||||||
<hassio-addon-network
|
<hassio-addon-network
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-addon-network>
|
></hassio-addon-network>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@@ -53,17 +56,16 @@ class HassioAddonConfigDashboard extends LitElement {
|
|||||||
<hassio-addon-audio
|
<hassio-addon-audio
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
></hassio-addon-audio>
|
></hassio-addon-audio>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
`
|
`
|
||||||
: this.supervisor.localize("addon.configuration.no_configuration")}
|
: "This add-on does not expose configuration for you to mess with.... 👋"}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
|
@@ -3,35 +3,31 @@ import { ActionDetail } from "@material/mwc-list";
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
import "@polymer/iron-autogrow-textarea/iron-autogrow-textarea";
|
import "@polymer/iron-autogrow-textarea/iron-autogrow-textarea";
|
||||||
import { DEFAULT_SCHEMA, Type } from "js-yaml";
|
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResult,
|
||||||
|
customElement,
|
||||||
html,
|
html,
|
||||||
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
|
query,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit-element";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../../src/components/ha-button-menu";
|
import "../../../../src/components/ha-button-menu";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import "../../../../src/components/ha-form/ha-form";
|
import "../../../../src/components/ha-form/ha-form";
|
||||||
import type { HaFormSchema } from "../../../../src/components/ha-form/ha-form";
|
|
||||||
import "../../../../src/components/ha-formfield";
|
|
||||||
import "../../../../src/components/ha-switch";
|
|
||||||
import "../../../../src/components/ha-yaml-editor";
|
import "../../../../src/components/ha-yaml-editor";
|
||||||
import type { HaYamlEditor } from "../../../../src/components/ha-yaml-editor";
|
import type { HaYamlEditor } from "../../../../src/components/ha-yaml-editor";
|
||||||
import {
|
import {
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
HassioAddonSetOptionParams,
|
HassioAddonSetOptionParams,
|
||||||
setHassioAddonOption,
|
setHassioAddonOption,
|
||||||
validateHassioAddonOption,
|
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { showConfirmationDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
import { showConfirmationDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../src/types";
|
import type { HomeAssistant } from "../../../../src/types";
|
||||||
@@ -40,135 +36,70 @@ import { hassioStyle } from "../../resources/hassio-style";
|
|||||||
|
|
||||||
const SUPPORTED_UI_TYPES = ["string", "select", "boolean", "integer", "float"];
|
const SUPPORTED_UI_TYPES = ["string", "select", "boolean", "integer", "float"];
|
||||||
|
|
||||||
const ADDON_YAML_SCHEMA = DEFAULT_SCHEMA.extend([
|
|
||||||
new Type("!secret", {
|
|
||||||
kind: "scalar",
|
|
||||||
construct: (data) => `!secret ${data}`,
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
|
|
||||||
@customElement("hassio-addon-config")
|
@customElement("hassio-addon-config")
|
||||||
class HassioAddonConfig extends LitElement {
|
class HassioAddonConfig extends LitElement {
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) private _configHasChanged = false;
|
@property({ type: Boolean }) private _configHasChanged = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) private _valid = true;
|
@property({ type: Boolean }) private _valid = true;
|
||||||
|
|
||||||
@state() private _canShowSchema = false;
|
@internalProperty() private _canShowSchema = false;
|
||||||
|
|
||||||
@state() private _showOptional = false;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _options?: Record<string, unknown>;
|
||||||
|
|
||||||
@state() private _options?: Record<string, unknown>;
|
@internalProperty() private _yamlMode = false;
|
||||||
|
|
||||||
@state() private _yamlMode = false;
|
|
||||||
|
|
||||||
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
|
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
|
||||||
|
|
||||||
public computeLabel = (entry: HaFormSchema): string =>
|
|
||||||
this.addon.translations[this.hass.language]?.configuration?.[entry.name]
|
|
||||||
?.name ||
|
|
||||||
this.addon.translations.en?.configuration?.[entry.name].name ||
|
|
||||||
entry.name;
|
|
||||||
|
|
||||||
private _filteredShchema = memoizeOne(
|
|
||||||
(options: Record<string, unknown>, schema: HaFormSchema[]) =>
|
|
||||||
schema.filter((entry) => entry.name in options || entry.required)
|
|
||||||
);
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const showForm =
|
|
||||||
!this._yamlMode && this._canShowSchema && this.addon.schema;
|
|
||||||
const hasHiddenOptions =
|
|
||||||
showForm &&
|
|
||||||
JSON.stringify(this.addon.schema) !==
|
|
||||||
JSON.stringify(
|
|
||||||
this._filteredShchema(this.addon.options, this.addon.schema!)
|
|
||||||
);
|
|
||||||
return html`
|
return html`
|
||||||
<h1>${this.addon.name}</h1>
|
<h1>${this.addon.name}</h1>
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h2>
|
<h2>Configuration</h2>
|
||||||
${this.supervisor.localize("addon.configuration.options.header")}
|
|
||||||
</h2>
|
|
||||||
<div class="card-menu">
|
<div class="card-menu">
|
||||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||||
<mwc-icon-button slot="trigger">
|
<mwc-icon-button slot="trigger">
|
||||||
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
||||||
</mwc-icon-button>
|
</mwc-icon-button>
|
||||||
<mwc-list-item .disabled=${!this._canShowSchema}>
|
<mwc-list-item .disabled=${!this._canShowSchema}>
|
||||||
${this._yamlMode
|
${this._yamlMode ? "Edit in UI" : "Edit in YAML"}
|
||||||
? this.supervisor.localize(
|
|
||||||
"addon.configuration.options.edit_in_ui"
|
|
||||||
)
|
|
||||||
: this.supervisor.localize(
|
|
||||||
"addon.configuration.options.edit_in_yaml"
|
|
||||||
)}
|
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
<mwc-list-item class="warning">
|
<mwc-list-item class="warning">
|
||||||
${this.supervisor.localize("common.reset_defaults")}
|
Reset to defaults
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${showForm
|
${!this._yamlMode && this._canShowSchema && this.addon.schema
|
||||||
? html`<ha-form
|
? html`<ha-form
|
||||||
.data=${this._options!}
|
.data=${this._options!}
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
.computeLabel=${this.computeLabel}
|
.schema=${this.addon.schema}
|
||||||
.schema=${this._showOptional
|
|
||||||
? this.addon.schema!
|
|
||||||
: this._filteredShchema(
|
|
||||||
this.addon.options,
|
|
||||||
this.addon.schema!
|
|
||||||
)}
|
|
||||||
></ha-form>`
|
></ha-form>`
|
||||||
: html` <ha-yaml-editor
|
: html` <ha-yaml-editor
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
.schema=${ADDON_YAML_SCHEMA}
|
|
||||||
></ha-yaml-editor>`}
|
></ha-yaml-editor>`}
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
${!this._yamlMode ||
|
${!this._yamlMode ||
|
||||||
(this._canShowSchema && this.addon.schema) ||
|
(this._canShowSchema && this.addon.schema) ||
|
||||||
this._valid
|
this._valid
|
||||||
? ""
|
? ""
|
||||||
: html`
|
: html` <div class="errors">Invalid YAML</div> `}
|
||||||
<div class="errors">
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.configuration.options.invalid_yaml"
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
`}
|
<div class="card-actions">
|
||||||
</div>
|
|
||||||
${hasHiddenOptions
|
|
||||||
? html`<ha-formfield
|
|
||||||
class="show-additional"
|
|
||||||
.label=${this.supervisor.localize(
|
|
||||||
"addon.configuration.options.show_unused_optional"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<ha-switch
|
|
||||||
@change=${this._toggleOptional}
|
|
||||||
.checked=${this._showOptional}
|
|
||||||
>
|
|
||||||
</ha-switch>
|
|
||||||
</ha-formfield>`
|
|
||||||
: ""}
|
|
||||||
<div class="card-actions right">
|
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
@click=${this._saveTapped}
|
@click=${this._saveTapped}
|
||||||
.disabled=${!this._configHasChanged || !this._valid}
|
.disabled=${!this._configHasChanged || !this._valid}
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("common.save")}
|
Save
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
@@ -177,7 +108,7 @@ class HassioAddonConfig extends LitElement {
|
|||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
protected firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this._canShowSchema = !this.addon.schema!.find(
|
this._canShowSchema = !this.addon.schema.find(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
(entry) => !SUPPORTED_UI_TYPES.includes(entry.type) || entry.multiple
|
(entry) => !SUPPORTED_UI_TYPES.includes(entry.type) || entry.multiple
|
||||||
);
|
);
|
||||||
@@ -213,19 +144,17 @@ class HassioAddonConfig extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _toggleOptional() {
|
|
||||||
this._showOptional = !this._showOptional;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _configChanged(ev): void {
|
private _configChanged(ev): void {
|
||||||
if (this.addon.schema && this._canShowSchema && !this._yamlMode) {
|
if (this.addon.schema && this._canShowSchema && !this._yamlMode) {
|
||||||
this._valid = true;
|
this._valid = true;
|
||||||
this._configHasChanged = true;
|
this._configHasChanged = true;
|
||||||
this._options! = ev.detail.value;
|
|
||||||
} else {
|
} else {
|
||||||
this._configHasChanged = true;
|
this._configHasChanged = true;
|
||||||
this._valid = ev.detail.isValid;
|
this._valid = ev.detail.isValid;
|
||||||
}
|
}
|
||||||
|
if (this._valid) {
|
||||||
|
this._options! = ev.detail.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _resetTapped(ev: CustomEvent): Promise<void> {
|
private async _resetTapped(ev: CustomEvent): Promise<void> {
|
||||||
@@ -233,10 +162,10 @@ class HassioAddonConfig extends LitElement {
|
|||||||
button.progress = true;
|
button.progress = true;
|
||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
title: this.supervisor.localize("confirm.reset_options.title"),
|
title: this.addon.name,
|
||||||
text: this.supervisor.localize("confirm.reset_options.text"),
|
text: "Are you sure you want to reset all your options?",
|
||||||
confirmText: this.supervisor.localize("common.reset_options"),
|
confirmText: "reset options",
|
||||||
dismissText: this.supervisor.localize("common.cancel"),
|
dismissText: "no",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
@@ -258,56 +187,42 @@ class HassioAddonConfig extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to reset addon configuration, ${extractApiErrorMessage(
|
||||||
"addon.common.update_available",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _saveTapped(ev: CustomEvent): Promise<void> {
|
private async _saveTapped(ev: CustomEvent): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
const eventdata = {
|
|
||||||
success: true,
|
|
||||||
response: undefined,
|
|
||||||
path: "options",
|
|
||||||
};
|
|
||||||
button.progress = true;
|
button.progress = true;
|
||||||
|
|
||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const validation = await validateHassioAddonOption(
|
|
||||||
this.hass,
|
|
||||||
this.addon.slug,
|
|
||||||
this._editor?.value
|
|
||||||
);
|
|
||||||
if (!validation.valid) {
|
|
||||||
throw Error(validation.message);
|
|
||||||
}
|
|
||||||
await setHassioAddonOption(this.hass, this.addon.slug, {
|
await setHassioAddonOption(this.hass, this.addon.slug, {
|
||||||
options: this._yamlMode ? this._editor?.value : this._options,
|
options: this._options!,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._configHasChanged = false;
|
this._configHasChanged = false;
|
||||||
|
const eventdata = {
|
||||||
|
success: true,
|
||||||
|
response: undefined,
|
||||||
|
path: "options",
|
||||||
|
};
|
||||||
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to save addon configuration, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_save",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
eventdata.success = false;
|
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -356,13 +271,6 @@ class HassioAddonConfig extends LitElement {
|
|||||||
margin-block: 0px;
|
margin-block: 0px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
.card-actions.right {
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show-additional {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,15 @@
|
|||||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResult,
|
||||||
|
customElement,
|
||||||
html,
|
html,
|
||||||
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
|
property,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit-element";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
@@ -17,7 +19,6 @@ import {
|
|||||||
setHassioAddonOption,
|
setHassioAddonOption,
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
|
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
|
||||||
@@ -37,13 +38,11 @@ interface NetworkItemInput extends PaperInputElement {
|
|||||||
class HassioAddonNetwork extends LitElement {
|
class HassioAddonNetwork extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _config?: NetworkItem[];
|
@internalProperty() private _config?: NetworkItem[];
|
||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
@@ -56,57 +55,43 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card header="Network">
|
||||||
.header=${this.supervisor.localize(
|
|
||||||
"addon.configuration.network.header"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>Container</th>
|
||||||
${this.supervisor.localize(
|
<th>Host</th>
|
||||||
"addon.configuration.network.container"
|
<th>Description</th>
|
||||||
)}
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.configuration.network.host"
|
|
||||||
)}
|
|
||||||
</th>
|
|
||||||
<th>${this.supervisor.localize("common.description")}</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
${this._config!.map(
|
${this._config!.map((item) => {
|
||||||
(item) => html`
|
return html`
|
||||||
<tr>
|
<tr>
|
||||||
<td>${item.container}</td>
|
<td>${item.container}</td>
|
||||||
<td>
|
<td>
|
||||||
<paper-input
|
<paper-input
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
placeholder="${this.supervisor.localize(
|
placeholder="disabled"
|
||||||
"addon.configuration.network.disabled"
|
|
||||||
)}"
|
|
||||||
.value=${item.host ? String(item.host) : ""}
|
.value=${item.host ? String(item.host) : ""}
|
||||||
.container=${item.container}
|
.container=${item.container}
|
||||||
no-label-float
|
no-label-float
|
||||||
></paper-input>
|
></paper-input>
|
||||||
</td>
|
</td>
|
||||||
<td>${this._computeDescription(item)}</td>
|
<td>${item.description}</td>
|
||||||
</tr>
|
</tr>
|
||||||
`
|
`;
|
||||||
)}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<ha-progress-button class="warning" @click=${this._resetTapped}>
|
<ha-progress-button class="warning" @click=${this._resetTapped}>
|
||||||
${this.supervisor.localize("common.reset_defaults")}
|
Reset to defaults
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
<ha-progress-button @click=${this._saveTapped}>
|
<ha-progress-button @click=${this._saveTapped}>
|
||||||
${this.supervisor.localize("common.save")}
|
Save
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
@@ -120,20 +105,16 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeDescription = (item: NetworkItem): string =>
|
|
||||||
this.addon.translations[this.hass.language]?.network?.[item.container]
|
|
||||||
?.description ||
|
|
||||||
this.addon.translations.en?.network?.[item.container]?.description ||
|
|
||||||
item.description;
|
|
||||||
|
|
||||||
private _setNetworkConfig(): void {
|
private _setNetworkConfig(): void {
|
||||||
const network = this.addon.network || {};
|
const network = this.addon.network || {};
|
||||||
const description = this.addon.network_description || {};
|
const description = this.addon.network_description || {};
|
||||||
const items: NetworkItem[] = Object.keys(network).map((key) => ({
|
const items: NetworkItem[] = Object.keys(network).map((key) => {
|
||||||
|
return {
|
||||||
container: key,
|
container: key,
|
||||||
host: network[key],
|
host: network[key],
|
||||||
description: description[key],
|
description: description[key],
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
this._config = items.sort((a, b) => (a.container > b.container ? 1 : -1));
|
this._config = items.sort((a, b) => (a.container > b.container ? 1 : -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,14 +147,12 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to set addon network configuration, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_reset",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
@@ -202,19 +181,17 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to set addon network configuration, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_save",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
|
@@ -1,5 +1,13 @@
|
|||||||
import "../../../../src/components/ha-card";
|
import {
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import "../../../../src/components/ha-markdown";
|
import "../../../../src/components/ha-markdown";
|
||||||
import {
|
import {
|
||||||
@@ -11,20 +19,16 @@ import "../../../../src/layouts/hass-loading-screen";
|
|||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
|
|
||||||
@customElement("hassio-addon-documentation-tab")
|
@customElement("hassio-addon-documentation-tab")
|
||||||
class HassioAddonDocumentationDashboard extends LitElement {
|
class HassioAddonDocumentationDashboard extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _content?: string;
|
@internalProperty() private _content?: string;
|
||||||
|
|
||||||
public async connectedCallback(): Promise<void> {
|
public async connectedCallback(): Promise<void> {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
@@ -49,7 +53,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -77,11 +81,9 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
this.addon!.slug
|
this.addon!.slug
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to get addon documentation, ${extractApiErrorMessage(
|
||||||
"addon.documentation.get_logs",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,22 +4,21 @@ import {
|
|||||||
mdiInformationVariant,
|
mdiInformationVariant,
|
||||||
mdiMathLog,
|
mdiMathLog,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
|
||||||
import { navigate } from "../../../src/common/navigate";
|
|
||||||
import { extractSearchParam } from "../../../src/common/url/search-params";
|
|
||||||
import "../../../src/components/ha-circular-progress";
|
import "../../../src/components/ha-circular-progress";
|
||||||
import {
|
import {
|
||||||
fetchHassioAddonInfo,
|
fetchHassioAddonInfo,
|
||||||
fetchHassioAddonsInfo,
|
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
} from "../../../src/data/hassio/addon";
|
} from "../../../src/data/hassio/addon";
|
||||||
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
|
||||||
import "../../../src/layouts/hass-error-screen";
|
|
||||||
import "../../../src/layouts/hass-loading-screen";
|
|
||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import type { PageNavigation } from "../../../src/layouts/hass-tabs-subpage";
|
import type { PageNavigation } from "../../../src/layouts/hass-tabs-subpage";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
@@ -36,16 +35,12 @@ import "./log/hassio-addon-logs";
|
|||||||
class HassioAddonDashboard extends LitElement {
|
class HassioAddonDashboard extends LitElement {
|
||||||
@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({ attribute: false }) public addon?: HassioAddonDetails;
|
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@state() _error?: string;
|
|
||||||
|
|
||||||
private _computeTail = memoizeOne((route: Route) => {
|
private _computeTail = memoizeOne((route: Route) => {
|
||||||
const dividerPos = route.path.indexOf("/", 1);
|
const dividerPos = route.path.indexOf("/", 1);
|
||||||
return dividerPos === -1
|
return dividerPos === -1
|
||||||
@@ -60,19 +55,13 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (this._error) {
|
|
||||||
return html`<hass-error-screen
|
|
||||||
.error=${this._error}
|
|
||||||
></hass-error-screen>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
return html`<ha-circular-progress active></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const addonTabs: PageNavigation[] = [
|
const addonTabs: PageNavigation[] = [
|
||||||
{
|
{
|
||||||
translationKey: "addon.panel.info",
|
name: "Info",
|
||||||
path: `/hassio/addon/${this.addon.slug}/info`,
|
path: `/hassio/addon/${this.addon.slug}/info`,
|
||||||
iconPath: mdiInformationVariant,
|
iconPath: mdiInformationVariant,
|
||||||
},
|
},
|
||||||
@@ -80,7 +69,7 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
|
|
||||||
if (this.addon.documentation) {
|
if (this.addon.documentation) {
|
||||||
addonTabs.push({
|
addonTabs.push({
|
||||||
translationKey: "addon.panel.documentation",
|
name: "Documentation",
|
||||||
path: `/hassio/addon/${this.addon.slug}/documentation`,
|
path: `/hassio/addon/${this.addon.slug}/documentation`,
|
||||||
iconPath: mdiFileDocument,
|
iconPath: mdiFileDocument,
|
||||||
});
|
});
|
||||||
@@ -89,12 +78,12 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
if (this.addon.version) {
|
if (this.addon.version) {
|
||||||
addonTabs.push(
|
addonTabs.push(
|
||||||
{
|
{
|
||||||
translationKey: "addon.panel.configuration",
|
name: "Configuration",
|
||||||
path: `/hassio/addon/${this.addon.slug}/config`,
|
path: `/hassio/addon/${this.addon.slug}/config`,
|
||||||
iconPath: mdiCogs,
|
iconPath: mdiCogs,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
translationKey: "addon.panel.log",
|
name: "Log",
|
||||||
path: `/hassio/addon/${this.addon.slug}/logs`,
|
path: `/hassio/addon/${this.addon.slug}/logs`,
|
||||||
iconPath: mdiMathLog,
|
iconPath: mdiMathLog,
|
||||||
}
|
}
|
||||||
@@ -106,26 +95,24 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage
|
<hass-tabs-subpage
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.localizeFunc=${this.supervisor.localize}
|
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.backPath=${this.addon.version ? "/hassio/dashboard" : "/hassio/store"}
|
.backPath=${this.addon.version ? "/hassio/dashboard" : "/hassio/store"}
|
||||||
.route=${route}
|
.route=${route}
|
||||||
|
hassio
|
||||||
.tabs=${addonTabs}
|
.tabs=${addonTabs}
|
||||||
supervisor
|
|
||||||
>
|
>
|
||||||
<span slot="header">${this.addon.name}</span>
|
<span slot="header">${this.addon.name}</span>
|
||||||
<hassio-addon-router
|
<hassio-addon-router
|
||||||
.route=${route}
|
.route=${route}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
></hassio-addon-router>
|
></hassio-addon-router>
|
||||||
</hass-tabs-subpage>
|
</hass-tabs-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -165,65 +152,30 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async firstUpdated(): Promise<void> {
|
protected async firstUpdated(): Promise<void> {
|
||||||
if (this.route.path === "") {
|
await this._routeDataChanged(this.route);
|
||||||
const requestedAddon = extractSearchParam("addon");
|
|
||||||
if (requestedAddon) {
|
|
||||||
const addonsInfo = await fetchHassioAddonsInfo(this.hass);
|
|
||||||
const validAddon = addonsInfo.addons.some(
|
|
||||||
(addon) => addon.slug === requestedAddon
|
|
||||||
);
|
|
||||||
if (!validAddon) {
|
|
||||||
this._error = this.supervisor.localize("my.error_addon_not_found");
|
|
||||||
} else {
|
|
||||||
navigate(`/hassio/addon/${requestedAddon}`, { replace: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
|
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _apiCalled(ev): Promise<void> {
|
private async _apiCalled(ev): Promise<void> {
|
||||||
if (!ev.detail.success) {
|
const path: string = ev.detail.path;
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pathSplit: string[] = ev.detail.path?.split("/");
|
|
||||||
|
|
||||||
if (!pathSplit || pathSplit.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const path: string = pathSplit[pathSplit.length - 1];
|
|
||||||
|
|
||||||
if (["uninstall", "install", "update", "start", "stop"].includes(path)) {
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: "supervisor",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path === "uninstall") {
|
if (path === "uninstall") {
|
||||||
window.history.back();
|
history.back();
|
||||||
} else {
|
} else {
|
||||||
await this._routeDataChanged();
|
await this._routeDataChanged(this.route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProperties) {
|
private async _routeDataChanged(routeData: Route): Promise<void> {
|
||||||
if (changedProperties.has("route") && !this.addon) {
|
const addon = routeData.path.split("/")[1];
|
||||||
this._routeDataChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _routeDataChanged(): Promise<void> {
|
|
||||||
const addon = this.route.path.split("/")[1];
|
|
||||||
if (!addon) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const addoninfo = await fetchHassioAddonInfo(this.hass, addon);
|
const addoninfo = await fetchHassioAddonInfo(this.hass, addon);
|
||||||
this.addon = addoninfo;
|
this.addon = addoninfo;
|
||||||
} catch (err) {
|
} catch {
|
||||||
this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`;
|
|
||||||
this.addon = undefined;
|
this.addon = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit-element";
|
||||||
import { HassioAddonDetails } from "../../../src/data/hassio/addon";
|
import { HassioAddonDetails } from "../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
|
||||||
import {
|
import {
|
||||||
HassRouterPage,
|
HassRouterPage,
|
||||||
RouterOptions,
|
RouterOptions,
|
||||||
@@ -18,8 +17,6 @@ class HassioAddonRouter extends HassRouterPage {
|
|||||||
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
protected routerOptions: RouterOptions = {
|
protected routerOptions: RouterOptions = {
|
||||||
@@ -44,7 +41,6 @@ class HassioAddonRouter extends HassRouterPage {
|
|||||||
protected updatePageEl(el) {
|
protected updatePageEl(el) {
|
||||||
el.route = this.routeTail;
|
el.route = this.routeTail;
|
||||||
el.hass = this.hass;
|
el.hass = this.hass;
|
||||||
el.supervisor = this.supervisor;
|
|
||||||
el.addon = this.addon;
|
el.addon = this.addon;
|
||||||
el.narrow = this.narrow;
|
el.narrow = this.narrow;
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,14 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
@@ -14,8 +20,6 @@ class HassioAddonInfoDashboard extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@@ -28,14 +32,13 @@ class HassioAddonInfoDashboard extends LitElement {
|
|||||||
<hassio-addon-info
|
<hassio-addon-info
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
></hassio-addon-info>
|
></hassio-addon-info>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
|
@@ -14,10 +14,17 @@ import {
|
|||||||
mdiPound,
|
mdiPound,
|
||||||
mdiShield,
|
mdiShield,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
import { classMap } from "lit/directives/class-map";
|
CSSResult,
|
||||||
import memoizeOne from "memoize-one";
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import { navigate } from "../../../../src/common/navigate";
|
import { navigate } from "../../../../src/common/navigate";
|
||||||
@@ -36,13 +43,10 @@ import {
|
|||||||
HassioAddonSetOptionParams,
|
HassioAddonSetOptionParams,
|
||||||
HassioAddonSetSecurityParams,
|
HassioAddonSetSecurityParams,
|
||||||
installHassioAddon,
|
installHassioAddon,
|
||||||
restartHassioAddon,
|
|
||||||
setHassioAddonOption,
|
setHassioAddonOption,
|
||||||
setHassioAddonSecurity,
|
setHassioAddonSecurity,
|
||||||
startHassioAddon,
|
startHassioAddon,
|
||||||
stopHassioAddon,
|
|
||||||
uninstallHassioAddon,
|
uninstallHassioAddon,
|
||||||
updateHassioAddon,
|
|
||||||
validateHassioAddonOption,
|
validateHassioAddonOption,
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import {
|
import {
|
||||||
@@ -50,8 +54,6 @@ import {
|
|||||||
fetchHassioStats,
|
fetchHassioStats,
|
||||||
HassioStats,
|
HassioStats,
|
||||||
} from "../../../../src/data/hassio/common";
|
} from "../../../../src/data/hassio/common";
|
||||||
import { StoreAddon } from "../../../../src/data/supervisor/store";
|
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@@ -62,9 +64,7 @@ import { bytesToString } from "../../../../src/util/bytes-to-string";
|
|||||||
import "../../components/hassio-card-content";
|
import "../../components/hassio-card-content";
|
||||||
import "../../components/supervisor-metric";
|
import "../../components/supervisor-metric";
|
||||||
import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown";
|
import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown";
|
||||||
import { showDialogSupervisorUpdate } from "../../dialogs/update/show-dialog-update";
|
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
import { addonArchIsSupported } from "../../util/addon";
|
|
||||||
|
|
||||||
const STAGE_ICON = {
|
const STAGE_ICON = {
|
||||||
stable: mdiCheckCircle,
|
stable: mdiCheckCircle,
|
||||||
@@ -72,6 +72,63 @@ const STAGE_ICON = {
|
|||||||
deprecated: mdiExclamationThick,
|
deprecated: mdiExclamationThick,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PERMIS_DESC = {
|
||||||
|
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.`,
|
||||||
|
},
|
||||||
|
rating: {
|
||||||
|
title: "Add-on Security Rating",
|
||||||
|
description:
|
||||||
|
"Home Assistant provides a security rating to each of the add-ons, which indicates the risks involved when using this add-on. The more access an add-on requires on your system, the lower the score, thus raising the possible security risks.\n\nA score is on a scale from 1 to 6. Where 1 is the lowest score (considered the most insecure and highest risk) and a score of 6 is the highest score (considered the most secure and lowest risk).",
|
||||||
|
},
|
||||||
|
host_network: {
|
||||||
|
title: "Host Network",
|
||||||
|
description:
|
||||||
|
"Add-ons usually run in their own isolated network layer, which prevents them from accessing the network of the host operating system. In some cases, this network isolation can limit add-ons in providing their services and therefore, the isolation can be lifted by the add-on author, giving the add-on full access to the network capabilities of the host machine. This gives the add-on more networking capabilities but lowers the security, hence, the security rating of the add-on will be lowered when this option is used by the add-on.",
|
||||||
|
},
|
||||||
|
homeassistant_api: {
|
||||||
|
title: "Home Assistant API Access",
|
||||||
|
description:
|
||||||
|
"This add-on is allowed to access your running Home Assistant instance directly via the Home Assistant API. This mode handles authentication for the add-on as well, which enables an add-on to interact with Home Assistant without the need for additional authentication tokens.",
|
||||||
|
},
|
||||||
|
full_access: {
|
||||||
|
title: "Full Hardware Access",
|
||||||
|
description:
|
||||||
|
"This add-on is given full access to the hardware of your system, by request of the add-on author. Access is comparable to the privileged mode in Docker. Since this opens up possible security risks, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on.",
|
||||||
|
},
|
||||||
|
hassio_api: {
|
||||||
|
title: "Supervisor API Access",
|
||||||
|
description:
|
||||||
|
"The add-on was given access to the Supervisor API, by request of the add-on author. By default, the add-on can access general version information of your system. When the add-on requests 'manager' or 'admin' level access to the API, it will gain access to control multiple parts of your Home Assistant system. This permission is indicated by this badge and will impact the security score of the addon negatively.",
|
||||||
|
},
|
||||||
|
docker_api: {
|
||||||
|
title: "Full Docker Access",
|
||||||
|
description:
|
||||||
|
"The add-on author has requested the add-on to have management access to the Docker instance running on your system. This mode gives the add-on full access and control to your entire Home Assistant system, which adds security risks, and could damage your system when misused. Therefore, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on.",
|
||||||
|
},
|
||||||
|
host_pid: {
|
||||||
|
title: "Host Processes Namespace",
|
||||||
|
description:
|
||||||
|
"Usually, the processes the add-on runs, are isolated from all other system processes. The add-on author has requested the add-on to have access to the system processes running on the host system instance, and allow the add-on to spawn processes on the host system as well. This mode gives the add-on full access and control to your entire Home Assistant system, which adds security risks, and could damage your system when misused. Therefore, this feature impacts the add-on security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the add-on manually. Only disable the protection mode if you know, need AND trust the source of this add-on.",
|
||||||
|
},
|
||||||
|
apparmor: {
|
||||||
|
title: "AppArmor",
|
||||||
|
description:
|
||||||
|
"AppArmor ('Application Armor') is a Linux kernel security module that restricts add-ons capabilities like network access, raw socket access, and permission to read, write, or execute specific files.\n\nAdd-on authors can provide their security profiles, optimized for the add-on, or request it to be disabled. If AppArmor is disabled, it will raise security risks and therefore, has a negative impact on the security score of the add-on.",
|
||||||
|
},
|
||||||
|
auth_api: {
|
||||||
|
title: "Home Assistant Authentication",
|
||||||
|
description:
|
||||||
|
"An add-on can authenticate users against Home Assistant, allowing add-ons to give users the possibility to log into applications running inside add-ons, using their Home Assistant username/password. This badge indicates if the add-on author requests this capability.",
|
||||||
|
},
|
||||||
|
ingress: {
|
||||||
|
title: "Ingress",
|
||||||
|
description:
|
||||||
|
"This add-on is using Ingress to embed its interface securely into Home Assistant.",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
@customElement("hassio-addon-info")
|
@customElement("hassio-addon-info")
|
||||||
class HassioAddonInfo extends LitElement {
|
class HassioAddonInfo extends LitElement {
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
@@ -80,29 +137,18 @@ class HassioAddonInfo extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@internalProperty() private _metrics?: HassioStats;
|
||||||
|
|
||||||
@state() private _metrics?: HassioStats;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _error?: string;
|
|
||||||
|
|
||||||
private _addonStoreInfo = memoizeOne(
|
|
||||||
(slug: string, storeAddons: StoreAddon[]) =>
|
|
||||||
storeAddons.find((addon) => addon.slug === slug)
|
|
||||||
);
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const addonStoreInfo =
|
|
||||||
!this.addon.detached && !this.addon.available
|
|
||||||
? this._addonStoreInfo(this.addon.slug, this.supervisor.store.addons)
|
|
||||||
: undefined;
|
|
||||||
const metrics = [
|
const metrics = [
|
||||||
{
|
{
|
||||||
description: this.supervisor.localize("addon.dashboard.cpu_usage"),
|
description: "Add-on CPU Usage",
|
||||||
value: this._metrics?.cpu_percent,
|
value: this._metrics?.cpu_percent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: this.supervisor.localize("addon.dashboard.ram_usage"),
|
description: "Add-on RAM Usage",
|
||||||
value: this._metrics?.memory_percent,
|
value: this._metrics?.memory_percent,
|
||||||
tooltip: `${bytesToString(this._metrics?.memory_usage)}/${bytesToString(
|
tooltip: `${bytesToString(this._metrics?.memory_usage)}/${bytesToString(
|
||||||
this._metrics?.memory_limit
|
this._metrics?.memory_limit
|
||||||
@@ -112,67 +158,40 @@ class HassioAddonInfo extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
${this.addon.update_available
|
${this.addon.update_available
|
||||||
? html`
|
? html`
|
||||||
<ha-card
|
<ha-card header="Update available! 🎉">
|
||||||
.header="${this.supervisor.localize(
|
|
||||||
"common.update_available",
|
|
||||||
"count",
|
|
||||||
1
|
|
||||||
)}🎉"
|
|
||||||
>
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<hassio-card-content
|
<hassio-card-content
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.title="${this.supervisor.localize(
|
.title="${this.addon.name} ${this.addon
|
||||||
"addon.dashboard.new_update_available",
|
.version_latest} is available"
|
||||||
"name",
|
.description="You are currently running version ${this.addon
|
||||||
this.addon.name,
|
.version}"
|
||||||
"version",
|
|
||||||
this.addon.version_latest
|
|
||||||
)}"
|
|
||||||
.description="${this.supervisor.localize(
|
|
||||||
"common.running_version",
|
|
||||||
"version",
|
|
||||||
this.addon.version
|
|
||||||
)}"
|
|
||||||
icon=${mdiArrowUpBoldCircle}
|
icon=${mdiArrowUpBoldCircle}
|
||||||
iconClass="update"
|
iconClass="update"
|
||||||
></hassio-card-content>
|
></hassio-card-content>
|
||||||
${!this.addon.available && addonStoreInfo
|
${!this.addon.available
|
||||||
? !addonArchIsSupported(
|
|
||||||
this.supervisor.info.supported_arch,
|
|
||||||
this.addon.arch
|
|
||||||
)
|
|
||||||
? html`
|
? html`
|
||||||
<p class="warning">
|
<p>
|
||||||
${this.supervisor.localize(
|
This update is no longer compatible with your system.
|
||||||
"addon.dashboard.not_available_arch"
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<p class="warning">
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.not_available_arch",
|
|
||||||
"core_version_installed",
|
|
||||||
this.supervisor.core.version,
|
|
||||||
"core_version_needed",
|
|
||||||
addonStoreInfo.homeassistant
|
|
||||||
)}
|
|
||||||
</p>
|
</p>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
|
<ha-call-api-button
|
||||||
|
.hass=${this.hass}
|
||||||
|
.disabled=${!this.addon.available}
|
||||||
|
path="hassio/addons/${this.addon.slug}/update"
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</ha-call-api-button>
|
||||||
${this.addon.changelog
|
${this.addon.changelog
|
||||||
? html`
|
? html`
|
||||||
<mwc-button @click=${this._openChangelog}>
|
<mwc-button @click=${this._openChangelog}>
|
||||||
${this.supervisor.localize("addon.dashboard.changelog")}
|
Changelog
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
`
|
`
|
||||||
: html`<span></span>`}
|
: ""}
|
||||||
<mwc-button @click=${this._updateClicked}>
|
|
||||||
${this.supervisor.localize("common.update")}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`
|
`
|
||||||
@@ -180,19 +199,12 @@ class HassioAddonInfo extends LitElement {
|
|||||||
${!this.addon.protected
|
${!this.addon.protected
|
||||||
? html`
|
? html`
|
||||||
<ha-card class="warning">
|
<ha-card class="warning">
|
||||||
<h1 class="card-header">${this.supervisor.localize(
|
<h1 class="card-header">Warning: Protection mode is disabled!</h1>
|
||||||
"addon.dashboard.protection_mode.title"
|
|
||||||
)}
|
|
||||||
</h1>
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this.supervisor.localize("addon.dashboard.protection_mode.content")}
|
Protection mode on this add-on is disabled! This gives the add-on full access to the entire system, which adds security risks, and could damage your system when used incorrectly. Only disable the protection mode if you know, need AND trust the source of this add-on.
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions protection-enable">
|
<div class="card-actions protection-enable">
|
||||||
<mwc-button @click=${this._protectionToggled}>
|
<mwc-button @click=${this._protectionToggled}>Enable Protection mode</mwc-button>
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.protection_mode.enable"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
@@ -209,18 +221,14 @@ class HassioAddonInfo extends LitElement {
|
|||||||
${this._computeIsRunning
|
${this._computeIsRunning
|
||||||
? html`
|
? html`
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
.title=${this.supervisor.localize(
|
title="Add-on is running"
|
||||||
"dashboard.addon_running"
|
|
||||||
)}
|
|
||||||
class="running"
|
class="running"
|
||||||
.path=${mdiCircle}
|
.path=${mdiCircle}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
.title=${this.supervisor.localize(
|
title="Add-on is stopped"
|
||||||
"dashboard.addon_stopped"
|
|
||||||
)}
|
|
||||||
class="stopped"
|
class="stopped"
|
||||||
.path=${mdiCircle}
|
.path=${mdiCircle}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
@@ -234,29 +242,21 @@ class HassioAddonInfo extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
Current version: ${this.addon.version}
|
Current version: ${this.addon.version}
|
||||||
<div class="changelog" @click=${this._openChangelog}>
|
<div class="changelog" @click=${this._openChangelog}>
|
||||||
(<span class="changelog-link"
|
(<span class="changelog-link">changelog</span>)
|
||||||
>${this.supervisor.localize(
|
|
||||||
"addon.dashboard.changelog"
|
|
||||||
)}</span
|
|
||||||
>)
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: html`<span class="changelog-link" @click=${this._openChangelog}
|
: html`<span class="changelog-link" @click=${this._openChangelog}
|
||||||
>${this.supervisor.localize(
|
>Changelog</span
|
||||||
"addon.dashboard.changelog"
|
|
||||||
)}</span
|
|
||||||
>`}
|
>`}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="description light-color">
|
<div class="description light-color">
|
||||||
${this.addon.description}.<br />
|
${this.addon.description}.<br />
|
||||||
${this.supervisor.localize(
|
Visit
|
||||||
"addon.dashboard.visit_addon_page",
|
<a href="${this.addon.url!}" target="_blank" rel="noreferrer">
|
||||||
"name",
|
${this.addon.name} page</a
|
||||||
html`<a href="${this.addon.url!}" target="_blank" rel="noreferrer"
|
>
|
||||||
>${this.addon.name}</a
|
for details.
|
||||||
>`
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="addon-container">
|
<div class="addon-container">
|
||||||
<div>
|
<div>
|
||||||
@@ -277,9 +277,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
})}
|
})}
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="stage"
|
id="stage"
|
||||||
.label=${this.supervisor.localize(
|
label="stage"
|
||||||
"addon.dashboard.capability.label.stage"
|
|
||||||
)}
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
@@ -305,9 +303,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="host_network"
|
id="host_network"
|
||||||
.label=${this.supervisor.localize(
|
label="host"
|
||||||
"addon.dashboard.capability.label.host"
|
|
||||||
)}
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiNetwork}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiNetwork}></ha-svg-icon>
|
||||||
@@ -319,9 +315,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="full_access"
|
id="full_access"
|
||||||
.label=${this.supervisor.localize(
|
label="hardware"
|
||||||
"addon.dashboard.capability.label.hardware"
|
|
||||||
)}
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiChip}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiChip}></ha-svg-icon>
|
||||||
@@ -333,9 +327,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="homeassistant_api"
|
id="homeassistant_api"
|
||||||
.label=${this.supervisor.localize(
|
label="hass"
|
||||||
"addon.dashboard.capability.label.hass"
|
|
||||||
)}
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
||||||
@@ -347,12 +339,8 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="hassio_api"
|
id="hassio_api"
|
||||||
.label=${this.supervisor.localize(
|
label="hassio"
|
||||||
"addon.dashboard.capability.label.hassio"
|
.description=${this.addon.hassio_role}
|
||||||
)}
|
|
||||||
.description=${this.supervisor.localize(
|
|
||||||
`addon.dashboard.capability.role.${this.addon.hassio_role}`
|
|
||||||
) || this.addon.hassio_role}
|
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
||||||
</ha-label-badge>
|
</ha-label-badge>
|
||||||
@@ -363,9 +351,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="docker_api"
|
id="docker_api"
|
||||||
.label=".${this.supervisor.localize(
|
label="docker"
|
||||||
"addon.dashboard.capability.label.docker"
|
|
||||||
)}"
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiDocker}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDocker}></ha-svg-icon>
|
||||||
@@ -377,9 +363,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="host_pid"
|
id="host_pid"
|
||||||
.label=${this.supervisor.localize(
|
label="host pid"
|
||||||
"addon.dashboard.capability.label.host_pid"
|
|
||||||
)}
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiPound}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiPound}></ha-svg-icon>
|
||||||
@@ -392,9 +376,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
class=${this._computeApparmorClassName}
|
class=${this._computeApparmorClassName}
|
||||||
id="apparmor"
|
id="apparmor"
|
||||||
.label=${this.supervisor.localize(
|
label="apparmor"
|
||||||
"addon.dashboard.capability.label.apparmor"
|
|
||||||
)}
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiShield}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiShield}></ha-svg-icon>
|
||||||
@@ -406,9 +388,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="auth_api"
|
id="auth_api"
|
||||||
.label=${this.supervisor.localize(
|
label="auth"
|
||||||
"addon.dashboard.capability.label.auth"
|
|
||||||
)}
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiKey}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiKey}></ha-svg-icon>
|
||||||
@@ -420,9 +400,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="ingress"
|
id="ingress"
|
||||||
.label=${this.supervisor.localize(
|
label="ingress"
|
||||||
"addon.dashboard.capability.label.ingress"
|
|
||||||
)}
|
|
||||||
description=""
|
description=""
|
||||||
>
|
>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
@@ -443,14 +421,10 @@ class HassioAddonInfo extends LitElement {
|
|||||||
>
|
>
|
||||||
<ha-settings-row ?three-line=${this.narrow}>
|
<ha-settings-row ?three-line=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
${this.supervisor.localize(
|
Start on boot
|
||||||
"addon.dashboard.option.boot.title"
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.localize(
|
Make the add-on start during a system boot
|
||||||
"addon.dashboard.option.boot.description"
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<ha-switch
|
<ha-switch
|
||||||
@change=${this._startOnBootToggled}
|
@change=${this._startOnBootToggled}
|
||||||
@@ -463,14 +437,10 @@ class HassioAddonInfo extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<ha-settings-row ?three-line=${this.narrow}>
|
<ha-settings-row ?three-line=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
${this.supervisor.localize(
|
Watchdog
|
||||||
"addon.dashboard.option.watchdog.title"
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.localize(
|
This will start the add-on if it crashes
|
||||||
"addon.dashboard.option.watchdog.description"
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<ha-switch
|
<ha-switch
|
||||||
@change=${this._watchdogToggled}
|
@change=${this._watchdogToggled}
|
||||||
@@ -485,14 +455,11 @@ class HassioAddonInfo extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<ha-settings-row ?three-line=${this.narrow}>
|
<ha-settings-row ?three-line=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
${this.supervisor.localize(
|
Auto update
|
||||||
"addon.dashboard.option.auto_update.title"
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.localize(
|
Auto update the add-on when there is a new
|
||||||
"addon.dashboard.option.auto_update.description"
|
version available
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<ha-switch
|
<ha-switch
|
||||||
@change=${this._autoUpdateToggled}
|
@change=${this._autoUpdateToggled}
|
||||||
@@ -502,22 +469,21 @@ class HassioAddonInfo extends LitElement {
|
|||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${!this._computeCannotIngressSidebar && this.addon.ingress
|
${this.addon.ingress
|
||||||
? html`
|
? html`
|
||||||
<ha-settings-row ?three-line=${this.narrow}>
|
<ha-settings-row ?three-line=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
${this.supervisor.localize(
|
Show in sidebar
|
||||||
"addon.dashboard.option.ingress_panel.title"
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.localize(
|
${this._computeCannotIngressSidebar
|
||||||
"addon.dashboard.option.ingress_panel.description"
|
? "This option requires Home Assistant 0.92 or later."
|
||||||
)}
|
: "Add this add-on to your sidebar"}
|
||||||
</span>
|
</span>
|
||||||
<ha-switch
|
<ha-switch
|
||||||
@change=${this._panelToggled}
|
@change=${this._panelToggled}
|
||||||
.checked=${this.addon.ingress_panel}
|
.checked=${this.addon.ingress_panel}
|
||||||
|
.disabled=${this._computeCannotIngressSidebar}
|
||||||
haptic
|
haptic
|
||||||
></ha-switch>
|
></ha-switch>
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
@@ -527,14 +493,10 @@ class HassioAddonInfo extends LitElement {
|
|||||||
? html`
|
? html`
|
||||||
<ha-settings-row ?three-line=${this.narrow}>
|
<ha-settings-row ?three-line=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
${this.supervisor.localize(
|
Protection mode
|
||||||
"addon.dashboard.option.protected.title"
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.supervisor.localize(
|
Blocks elevated system access from the add-on
|
||||||
"addon.dashboard.option.protected.description"
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<ha-switch
|
<ha-switch
|
||||||
@change=${this._protectionToggled}
|
@change=${this._protectionToggled}
|
||||||
@@ -552,9 +514,11 @@ class HassioAddonInfo extends LitElement {
|
|||||||
${this.addon.state === "started"
|
${this.addon.state === "started"
|
||||||
? html`<ha-settings-row ?three-line=${this.narrow}>
|
? html`<ha-settings-row ?three-line=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
${this.supervisor.localize("addon.dashboard.hostname")}
|
Hostname
|
||||||
</span>
|
</span>
|
||||||
<code slot="description"> ${this.addon.hostname} </code>
|
<code slot="description">
|
||||||
|
${this.addon.hostname}
|
||||||
|
</code>
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
${metrics.map(
|
${metrics.map(
|
||||||
(metric) =>
|
(metric) =>
|
||||||
@@ -570,109 +534,87 @@ class HassioAddonInfo extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
||||||
${!this.addon.version && addonStoreInfo && !this.addon.available
|
|
||||||
? !addonArchIsSupported(
|
|
||||||
this.supervisor.info.supported_arch,
|
|
||||||
this.addon.arch
|
|
||||||
)
|
|
||||||
? html`
|
|
||||||
<p class="warning">
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.not_available_arch"
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<p class="warning">
|
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.not_available_version",
|
|
||||||
"core_version_installed",
|
|
||||||
this.supervisor.core.version,
|
|
||||||
"core_version_needed",
|
|
||||||
addonStoreInfo!.homeassistant
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<div>
|
|
||||||
${this.addon.version
|
${this.addon.version
|
||||||
? this._computeIsRunning
|
|
||||||
? html`
|
? html`
|
||||||
<ha-progress-button
|
${this._computeIsRunning
|
||||||
|
? html`
|
||||||
|
<ha-call-api-button
|
||||||
class="warning"
|
class="warning"
|
||||||
@click=${this._stopClicked}
|
.hass=${this.hass}
|
||||||
|
.path="hassio/addons/${this.addon.slug}/stop"
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("addon.dashboard.stop")}
|
Stop
|
||||||
</ha-progress-button>
|
</ha-call-api-button>
|
||||||
<ha-progress-button
|
<ha-call-api-button
|
||||||
class="warning"
|
class="warning"
|
||||||
@click=${this._restartClicked}
|
.hass=${this.hass}
|
||||||
|
.path="hassio/addons/${this.addon.slug}/restart"
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("addon.dashboard.restart")}
|
Restart
|
||||||
</ha-progress-button>
|
</ha-call-api-button>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<ha-progress-button @click=${this._startClicked}>
|
<ha-progress-button @click=${this._startClicked}>
|
||||||
${this.supervisor.localize("addon.dashboard.start")}
|
Start
|
||||||
</ha-progress-button>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<ha-progress-button
|
|
||||||
.disabled=${!this.addon.available}
|
|
||||||
@click=${this._installClicked}
|
|
||||||
>
|
|
||||||
${this.supervisor.localize("addon.dashboard.install")}
|
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
`}
|
`}
|
||||||
</div>
|
${this._computeShowWebUI
|
||||||
<div>
|
|
||||||
${this.addon.version
|
|
||||||
? html` ${this._computeShowWebUI
|
|
||||||
? html`
|
? html`
|
||||||
<a
|
<a
|
||||||
href=${this._pathWebui!}
|
href=${this._pathWebui!}
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
class="right"
|
||||||
rel="noopener"
|
rel="noopener"
|
||||||
>
|
>
|
||||||
<mwc-button>
|
<mwc-button>
|
||||||
${this.supervisor.localize(
|
Open web UI
|
||||||
"addon.dashboard.open_web_ui"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</a>
|
</a>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this._computeShowIngressUI
|
${this._computeShowIngressUI
|
||||||
? html`
|
? html`
|
||||||
<mwc-button @click=${this._openIngress}>
|
<mwc-button class="right" @click=${this._openIngress}>
|
||||||
${this.supervisor.localize(
|
Open web UI
|
||||||
"addon.dashboard.open_web_ui"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
class="warning"
|
class=" right warning"
|
||||||
@click=${this._uninstallClicked}
|
@click=${this._uninstallClicked}
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("addon.dashboard.uninstall")}
|
Uninstall
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
${this.addon.build
|
${this.addon.build
|
||||||
? html`
|
? html`
|
||||||
<ha-call-api-button
|
<ha-call-api-button
|
||||||
class="warning"
|
class="warning right"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.path="hassio/addons/${this.addon.slug}/rebuild"
|
.path="hassio/addons/${this.addon.slug}/rebuild"
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("addon.dashboard.rebuild")}
|
Rebuild
|
||||||
</ha-call-api-button>
|
</ha-call-api-button>
|
||||||
`
|
`
|
||||||
: ""}`
|
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
`
|
||||||
|
: html`
|
||||||
|
${!this.addon.available
|
||||||
|
? html`
|
||||||
|
<p class="warning">
|
||||||
|
This add-on is not available on your system.
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<ha-progress-button
|
||||||
|
.disabled=${!this.addon.available}
|
||||||
|
@click=${this._installClicked}
|
||||||
|
>
|
||||||
|
Install
|
||||||
|
</ha-progress-button>
|
||||||
|
`}
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
|
||||||
@@ -727,21 +669,8 @@ class HassioAddonInfo extends LitElement {
|
|||||||
private _showMoreInfo(ev): void {
|
private _showMoreInfo(ev): void {
|
||||||
const id = ev.currentTarget.id;
|
const id = ev.currentTarget.id;
|
||||||
showHassioMarkdownDialog(this, {
|
showHassioMarkdownDialog(this, {
|
||||||
title: this.supervisor.localize(`addon.dashboard.capability.${id}.title`),
|
title: PERMIS_DESC[id].title,
|
||||||
content:
|
content: PERMIS_DESC[id].description,
|
||||||
id === "stage"
|
|
||||||
? this.supervisor.localize(
|
|
||||||
`addon.dashboard.capability.${id}.description`,
|
|
||||||
"icon_stable",
|
|
||||||
`<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon>`,
|
|
||||||
"icon_experimental",
|
|
||||||
`<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon>`,
|
|
||||||
"icon_deprecated",
|
|
||||||
`<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon>`
|
|
||||||
)
|
|
||||||
: this.supervisor.localize(
|
|
||||||
`addon.dashboard.capability.${id}.description`
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,7 +690,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _openIngress(): void {
|
private _openIngress(): void {
|
||||||
navigate(`/hassio/ingress/${this.addon.slug}`);
|
navigate(this, `/hassio/ingress/${this.addon.slug}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _computeShowIngressUI(): boolean {
|
private get _computeShowIngressUI(): boolean {
|
||||||
@@ -794,11 +723,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to set addon option, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_save",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -816,11 +743,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to set addon option, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_save",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,11 +763,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to set addon option, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_save",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -860,11 +783,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to set addon security option, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_save",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -882,11 +803,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to set addon option, ${extractApiErrorMessage(
|
||||||
"addon.failed_to_save",
|
err
|
||||||
"error",
|
)}`;
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,14 +816,12 @@ class HassioAddonInfo extends LitElement {
|
|||||||
this.addon.slug
|
this.addon.slug
|
||||||
);
|
);
|
||||||
showHassioMarkdownDialog(this, {
|
showHassioMarkdownDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.changelog"),
|
title: "Changelog",
|
||||||
content,
|
content,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: "Failed to get addon changelog",
|
||||||
"addon.dashboard.action_error.get_changelog"
|
|
||||||
),
|
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -924,82 +841,13 @@ class HassioAddonInfo extends LitElement {
|
|||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.install"),
|
title: "Failed to install addon",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _stopClicked(ev: CustomEvent): Promise<void> {
|
|
||||||
const button = ev.currentTarget as any;
|
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await stopHassioAddon(this.hass, this.addon.slug);
|
|
||||||
const eventdata = {
|
|
||||||
success: true,
|
|
||||||
response: undefined,
|
|
||||||
path: "stop",
|
|
||||||
};
|
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
|
||||||
} catch (err) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.stop"),
|
|
||||||
text: extractApiErrorMessage(err),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
button.progress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _restartClicked(ev: CustomEvent): Promise<void> {
|
|
||||||
const button = ev.currentTarget as any;
|
|
||||||
button.progress = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await restartHassioAddon(this.hass, this.addon.slug);
|
|
||||||
const eventdata = {
|
|
||||||
success: true,
|
|
||||||
response: undefined,
|
|
||||||
path: "stop",
|
|
||||||
};
|
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
|
||||||
} catch (err) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.restart"),
|
|
||||||
text: extractApiErrorMessage(err),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
button.progress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _updateClicked(): Promise<void> {
|
|
||||||
showDialogSupervisorUpdate(this, {
|
|
||||||
supervisor: this.supervisor,
|
|
||||||
name: this.addon.name,
|
|
||||||
version: this.addon.version_latest,
|
|
||||||
snapshotParams: {
|
|
||||||
name: `addon_${this.addon.slug}_${this.addon.version}`,
|
|
||||||
addons: [this.addon.slug],
|
|
||||||
homeassistant: false,
|
|
||||||
},
|
|
||||||
updateHandler: async () => this._updateAddon(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _updateAddon(): Promise<void> {
|
|
||||||
await updateHassioAddon(this.hass, this.addon.slug);
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: "addon",
|
|
||||||
});
|
|
||||||
const eventdata = {
|
|
||||||
success: true,
|
|
||||||
response: undefined,
|
|
||||||
path: "update",
|
|
||||||
};
|
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _startClicked(ev: CustomEvent): Promise<void> {
|
private async _startClicked(ev: CustomEvent): Promise<void> {
|
||||||
const button = ev.currentTarget as any;
|
const button = ev.currentTarget as any;
|
||||||
button.progress = true;
|
button.progress = true;
|
||||||
@@ -1008,17 +856,13 @@ class HassioAddonInfo extends LitElement {
|
|||||||
this.hass,
|
this.hass,
|
||||||
this.addon.slug
|
this.addon.slug
|
||||||
);
|
);
|
||||||
if (!validate.valid) {
|
if (!validate.data.valid) {
|
||||||
await showConfirmationDialog(this, {
|
await showConfirmationDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: "Failed to start addon - configuration validation failed!",
|
||||||
"addon.dashboard.action_error.start_invalid_config"
|
text: validate.data.message.split(" Got ")[0],
|
||||||
),
|
|
||||||
text: validate.message.split(" Got ")[0],
|
|
||||||
confirm: () => this._openConfiguration(),
|
confirm: () => this._openConfiguration(),
|
||||||
confirmText: this.supervisor.localize(
|
confirmText: "Go to configuration",
|
||||||
"addon.dashboard.action_error.go_to_config"
|
dismissText: "Cancel",
|
||||||
),
|
|
||||||
dismissText: this.supervisor.localize("common.cancel"),
|
|
||||||
});
|
});
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
return;
|
return;
|
||||||
@@ -1035,15 +879,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
try {
|
try {
|
||||||
await startHassioAddon(this.hass, this.addon.slug);
|
await startHassioAddon(this.hass, this.addon.slug);
|
||||||
this.addon = await fetchHassioAddonInfo(this.hass, this.addon.slug);
|
this.addon = await fetchHassioAddonInfo(this.hass, this.addon.slug);
|
||||||
const eventdata = {
|
|
||||||
success: true,
|
|
||||||
response: undefined,
|
|
||||||
path: "start",
|
|
||||||
};
|
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.start"),
|
title: "Failed to start addon",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1051,7 +889,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _openConfiguration(): void {
|
private _openConfiguration(): void {
|
||||||
navigate(`/hassio/addon/${this.addon.slug}/config`);
|
navigate(this, `/hassio/addon/${this.addon.slug}/config`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _uninstallClicked(ev: CustomEvent): Promise<void> {
|
private async _uninstallClicked(ev: CustomEvent): Promise<void> {
|
||||||
@@ -1081,16 +919,14 @@ class HassioAddonInfo extends LitElement {
|
|||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: "Failed to uninstall addon",
|
||||||
"addon.dashboard.action_error.uninstall"
|
|
||||||
),
|
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -1158,6 +994,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
.right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
protection-enable mwc-button {
|
protection-enable mwc-button {
|
||||||
--mdc-theme-primary: white;
|
--mdc-theme-primary: white;
|
||||||
}
|
}
|
||||||
@@ -1180,8 +1019,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
.card-actions {
|
.card-actions {
|
||||||
justify-content: space-between;
|
display: flow-root;
|
||||||
display: flex;
|
|
||||||
}
|
}
|
||||||
.security h3 {
|
.security h3 {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
@@ -1217,16 +1055,18 @@ class HassioAddonInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.addon-options {
|
.addon-options {
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
|
.addon-options.started {
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.addon-container {
|
.addon-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
grid-template-columns: 60% 40%;
|
grid-template-columns: 1fr auto;
|
||||||
}
|
}
|
||||||
|
.addon-container div:last-of-type {
|
||||||
.addon-container > div:last-of-type {
|
|
||||||
align-self: end;
|
align-self: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,14 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
@@ -12,8 +18,6 @@ import "./hassio-addon-logs";
|
|||||||
class HassioAddonLogDashboard extends LitElement {
|
class HassioAddonLogDashboard extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
@property({ attribute: false }) public addon?: HassioAddonDetails;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@@ -24,14 +28,13 @@ class HassioAddonLogDashboard extends LitElement {
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<hassio-addon-logs
|
<hassio-addon-logs
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this.supervisor}
|
|
||||||
.addon=${this.addon}
|
.addon=${this.addon}
|
||||||
></hassio-addon-logs>
|
></hassio-addon-logs>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
|
@@ -1,13 +1,20 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
fetchHassioAddonLogs,
|
fetchHassioAddonLogs,
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import "../../components/hassio-ansi-to-html";
|
import "../../components/hassio-ansi-to-html";
|
||||||
@@ -17,13 +24,11 @@ import { hassioStyle } from "../../resources/hassio-style";
|
|||||||
class HassioAddonLogs extends LitElement {
|
class HassioAddonLogs extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||||
|
|
||||||
@state() private _error?: string;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _content?: string;
|
@internalProperty() private _content?: string;
|
||||||
|
|
||||||
public async connectedCallback(): Promise<void> {
|
public async connectedCallback(): Promise<void> {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
@@ -43,15 +48,13 @@ class HassioAddonLogs extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<mwc-button @click=${this._refresh}>
|
<mwc-button @click=${this._refresh}>Refresh</mwc-button>
|
||||||
${this.supervisor.localize("common.refresh")}
|
|
||||||
</mwc-button>
|
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -73,11 +76,7 @@ class HassioAddonLogs extends LitElement {
|
|||||||
try {
|
try {
|
||||||
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
|
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = `Failed to get addon logs, ${extractApiErrorMessage(err)}`;
|
||||||
"addon.logs.get_logs",
|
|
||||||
"error",
|
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
bold: boolean;
|
bold: boolean;
|
||||||
@@ -18,7 +25,7 @@ class HassioAnsiToHtml extends LitElement {
|
|||||||
return html`${this._parseTextToColoredPre(this.content)}`;
|
return html`${this._parseTextToColoredPre(this.content)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
pre {
|
pre {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
|
@@ -1,6 +1,13 @@
|
|||||||
import { mdiHelpCircle } from "@mdi/js";
|
import { mdiHelpCircle } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../src/components/ha-relative-time";
|
import "../../../src/components/ha-relative-time";
|
||||||
import "../../../src/components/ha-svg-icon";
|
import "../../../src/components/ha-svg-icon";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
@@ -37,7 +44,7 @@ class HassioCardContent extends LitElement {
|
|||||||
${this.iconImage
|
${this.iconImage
|
||||||
? html`
|
? html`
|
||||||
<div class="icon_image ${this.iconClass}">
|
<div class="icon_image ${this.iconClass}">
|
||||||
<img src="${this.iconImage}" .title=${this.iconTitle} />
|
<img src="${this.iconImage}" title="${this.iconTitle}" />
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@@ -49,13 +56,13 @@ class HassioCardContent extends LitElement {
|
|||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
`}
|
`}
|
||||||
<div>
|
<div>
|
||||||
<div class="title">${this.title}</div>
|
<div class="title">
|
||||||
|
${this.title}
|
||||||
|
</div>
|
||||||
<div class="addition">
|
<div class="addition">
|
||||||
${this.description}
|
${this.description}
|
||||||
${
|
${/* treat as available when undefined */
|
||||||
/* treat as available when undefined */
|
this.available === false ? " (Not available)" : ""}
|
||||||
this.available === false ? " (Not available)" : ""
|
|
||||||
}
|
|
||||||
${this.datetime
|
${this.datetime
|
||||||
? html`
|
? html`
|
||||||
<ha-relative-time
|
<ha-relative-time
|
||||||
@@ -70,7 +77,7 @@ class HassioCardContent extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
ha-svg-icon {
|
ha-svg-icon {
|
||||||
margin-right: 24px;
|
margin-right: 24px;
|
||||||
|
@@ -2,8 +2,13 @@ import "@material/mwc-icon-button/mwc-icon-button";
|
|||||||
import { mdiFolderUpload } from "@mdi/js";
|
import { mdiFolderUpload } from "@mdi/js";
|
||||||
import "@polymer/iron-input/iron-input";
|
import "@polymer/iron-input/iron-input";
|
||||||
import "@polymer/paper-input/paper-input-container";
|
import "@polymer/paper-input/paper-input-container";
|
||||||
import { html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, state } from "lit/decorators";
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||||
import "../../../src/components/ha-circular-progress";
|
import "../../../src/components/ha-circular-progress";
|
||||||
import "../../../src/components/ha-file-upload";
|
import "../../../src/components/ha-file-upload";
|
||||||
@@ -28,9 +33,9 @@ const MAX_FILE_SIZE = 1 * 1024 * 1024 * 1024; // 1GB
|
|||||||
export class HassioUploadSnapshot extends LitElement {
|
export class HassioUploadSnapshot extends LitElement {
|
||||||
public hass!: HomeAssistant;
|
public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() public value: string | null = null;
|
@internalProperty() public value: string | null = null;
|
||||||
|
|
||||||
@state() private _uploading = false;
|
@internalProperty() private _uploading = false;
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
|
@@ -1,55 +0,0 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-svg-icon";
|
|
||||||
|
|
||||||
@customElement("supervisor-formfield-label")
|
|
||||||
class SupervisorFormfieldLabel extends LitElement {
|
|
||||||
@property({ type: String }) public label!: string;
|
|
||||||
|
|
||||||
@property({ type: String }) public imageUrl?: string;
|
|
||||||
|
|
||||||
@property({ type: String }) public iconPath?: string;
|
|
||||||
|
|
||||||
@property({ type: String }) public version?: string;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
${this.imageUrl
|
|
||||||
? html`<img loading="lazy" .src=${this.imageUrl} class="icon" />`
|
|
||||||
: this.iconPath
|
|
||||||
? html`<ha-svg-icon .path=${this.iconPath} class="icon"></ha-svg-icon>`
|
|
||||||
: ""}
|
|
||||||
<span class="label">${this.label}</span>
|
|
||||||
${this.version
|
|
||||||
? html`<span class="version">(${this.version})</span>`
|
|
||||||
: ""}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return css`
|
|
||||||
:host {
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.label {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
.version {
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
max-height: 22px;
|
|
||||||
max-width: 22px;
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"supervisor-formfield-label": SupervisorFormfieldLabel;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +1,13 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
import { classMap } from "lit/directives/class-map";
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
import { classMap } from "lit-html/directives/class-map";
|
||||||
import "../../../src/components/ha-bar";
|
import "../../../src/components/ha-bar";
|
||||||
import "../../../src/components/ha-settings-row";
|
import "../../../src/components/ha-settings-row";
|
||||||
import { roundWithOneDecimal } from "../../../src/util/calculate";
|
import { roundWithOneDecimal } from "../../../src/util/calculate";
|
||||||
@@ -16,9 +23,13 @@ class SupervisorMetric extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const roundedValue = roundWithOneDecimal(this.value);
|
const roundedValue = roundWithOneDecimal(this.value);
|
||||||
return html`<ha-settings-row>
|
return html`<ha-settings-row>
|
||||||
<span slot="heading"> ${this.description} </span>
|
<span slot="heading">
|
||||||
<div slot="description" .title=${this.tooltip ?? ""}>
|
${this.description}
|
||||||
<span class="value"> ${roundedValue} % </span>
|
</span>
|
||||||
|
<div slot="description" title="${this.tooltip ?? ""}">
|
||||||
|
<span class="value">
|
||||||
|
${roundedValue}%
|
||||||
|
</span>
|
||||||
<ha-bar
|
<ha-bar
|
||||||
class="${classMap({
|
class="${classMap({
|
||||||
"target-warning": roundedValue > 50,
|
"target-warning": roundedValue > 50,
|
||||||
@@ -30,7 +41,7 @@ class SupervisorMetric extends LitElement {
|
|||||||
</ha-settings-row>`;
|
</ha-settings-row>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
ha-settings-row {
|
ha-settings-row {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -62,9 +73,8 @@ class SupervisorMetric extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
.value {
|
.value {
|
||||||
width: 48px;
|
width: 42px;
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@@ -1,418 +0,0 @@
|
|||||||
import { mdiFolder, mdiHomeAssistant, mdiPuzzle } from "@mdi/js";
|
|
||||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
|
||||||
import { formatDate } from "../../../src/common/datetime/format_date";
|
|
||||||
import { formatDateTime } from "../../../src/common/datetime/format_date_time";
|
|
||||||
import "../../../src/components/ha-checkbox";
|
|
||||||
import "../../../src/components/ha-formfield";
|
|
||||||
import "../../../src/components/ha-radio";
|
|
||||||
import type { HaRadio } from "../../../src/components/ha-radio";
|
|
||||||
import {
|
|
||||||
HassioFullSnapshotCreateParams,
|
|
||||||
HassioPartialSnapshotCreateParams,
|
|
||||||
HassioSnapshotDetail,
|
|
||||||
} from "../../../src/data/hassio/snapshot";
|
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
|
||||||
import { PolymerChangedEvent } from "../../../src/polymer-types";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
import "./supervisor-formfield-label";
|
|
||||||
|
|
||||||
interface CheckboxItem {
|
|
||||||
slug: string;
|
|
||||||
checked: boolean;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AddonCheckboxItem extends CheckboxItem {
|
|
||||||
version: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const _computeFolders = (folders): CheckboxItem[] => {
|
|
||||||
const list: CheckboxItem[] = [];
|
|
||||||
if (folders.includes("homeassistant")) {
|
|
||||||
list.push({
|
|
||||||
slug: "homeassistant",
|
|
||||||
name: "Home Assistant configuration",
|
|
||||||
checked: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (folders.includes("ssl")) {
|
|
||||||
list.push({ slug: "ssl", name: "SSL", checked: false });
|
|
||||||
}
|
|
||||||
if (folders.includes("share")) {
|
|
||||||
list.push({ slug: "share", name: "Share", checked: false });
|
|
||||||
}
|
|
||||||
if (folders.includes("addons/local")) {
|
|
||||||
list.push({ slug: "addons/local", name: "Local add-ons", checked: false });
|
|
||||||
}
|
|
||||||
return list.sort((a, b) => (a.name > b.name ? 1 : -1));
|
|
||||||
};
|
|
||||||
|
|
||||||
const _computeAddons = (addons): AddonCheckboxItem[] =>
|
|
||||||
addons
|
|
||||||
.map((addon) => ({
|
|
||||||
slug: addon.slug,
|
|
||||||
name: addon.name,
|
|
||||||
version: addon.version,
|
|
||||||
checked: false,
|
|
||||||
}))
|
|
||||||
.sort((a, b) => (a.name > b.name ? 1 : -1));
|
|
||||||
|
|
||||||
@customElement("supervisor-snapshot-content")
|
|
||||||
export class SupervisorSnapshotContent extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor?: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public snapshot?: HassioSnapshotDetail;
|
|
||||||
|
|
||||||
@property() public snapshotType: HassioSnapshotDetail["type"] = "full";
|
|
||||||
|
|
||||||
@property({ attribute: false }) public folders?: CheckboxItem[];
|
|
||||||
|
|
||||||
@property({ attribute: false }) public addons?: AddonCheckboxItem[];
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public homeAssistant = false;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public snapshotHasPassword = false;
|
|
||||||
|
|
||||||
@property() public snapshotName = "";
|
|
||||||
|
|
||||||
@property() public snapshotPassword = "";
|
|
||||||
|
|
||||||
public willUpdate(changedProps) {
|
|
||||||
super.willUpdate(changedProps);
|
|
||||||
if (!this.hasUpdated) {
|
|
||||||
this.folders = _computeFolders(
|
|
||||||
this.snapshot
|
|
||||||
? this.snapshot.folders
|
|
||||||
: ["homeassistant", "ssl", "share", "media", "addons/local"]
|
|
||||||
);
|
|
||||||
this.addons = _computeAddons(
|
|
||||||
this.snapshot
|
|
||||||
? this.snapshot.addons
|
|
||||||
: this.supervisor?.supervisor.addons
|
|
||||||
);
|
|
||||||
this.snapshotType = this.snapshot?.type || "full";
|
|
||||||
this.snapshotName = this.snapshot?.name || "";
|
|
||||||
this.snapshotHasPassword = this.snapshot?.protected || false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.supervisor) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
const foldersSection =
|
|
||||||
this.snapshotType === "partial" ? this._getSection("folders") : undefined;
|
|
||||||
const addonsSection =
|
|
||||||
this.snapshotType === "partial" ? this._getSection("addons") : undefined;
|
|
||||||
|
|
||||||
return html`
|
|
||||||
${this.snapshot
|
|
||||||
? html`<div class="details">
|
|
||||||
${this.snapshot.type === "full"
|
|
||||||
? this.supervisor.localize("snapshot.full_snapshot")
|
|
||||||
: this.supervisor.localize("snapshot.partial_snapshot")}
|
|
||||||
(${Math.ceil(this.snapshot.size * 10) / 10 + " MB"})<br />
|
|
||||||
${formatDateTime(new Date(this.snapshot.date), this.hass.locale)}
|
|
||||||
</div>`
|
|
||||||
: html`<paper-input
|
|
||||||
name="snapshotName"
|
|
||||||
.label=${this.supervisor.localize("snapshot.name")}
|
|
||||||
.value=${this.snapshotName}
|
|
||||||
@value-changed=${this._handleTextValueChanged}
|
|
||||||
>
|
|
||||||
</paper-input>`}
|
|
||||||
${!this.snapshot || this.snapshot.type === "full"
|
|
||||||
? html`<div class="sub-header">
|
|
||||||
${!this.snapshot
|
|
||||||
? this.supervisor.localize("snapshot.type")
|
|
||||||
: this.supervisor.localize("snapshot.select_type")}
|
|
||||||
</div>
|
|
||||||
<div class="snapshot-types">
|
|
||||||
<ha-formfield
|
|
||||||
.label=${this.supervisor.localize("snapshot.full_snapshot")}
|
|
||||||
>
|
|
||||||
<ha-radio
|
|
||||||
@change=${this._handleRadioValueChanged}
|
|
||||||
value="full"
|
|
||||||
name="snapshotType"
|
|
||||||
.checked=${this.snapshotType === "full"}
|
|
||||||
>
|
|
||||||
</ha-radio>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield
|
|
||||||
.label=${this.supervisor!.localize("snapshot.partial_snapshot")}
|
|
||||||
>
|
|
||||||
<ha-radio
|
|
||||||
@change=${this._handleRadioValueChanged}
|
|
||||||
value="partial"
|
|
||||||
name="snapshotType"
|
|
||||||
.checked=${this.snapshotType === "partial"}
|
|
||||||
>
|
|
||||||
</ha-radio>
|
|
||||||
</ha-formfield>
|
|
||||||
</div>`
|
|
||||||
: ""}
|
|
||||||
${this.snapshot && this.snapshotType === "partial"
|
|
||||||
? html`
|
|
||||||
${this.snapshot.homeassistant
|
|
||||||
? html`
|
|
||||||
<ha-formfield
|
|
||||||
.label=${html`<supervisor-formfield-label
|
|
||||||
label="Home Assistant"
|
|
||||||
.iconPath=${mdiHomeAssistant}
|
|
||||||
.version=${this.snapshot.homeassistant}
|
|
||||||
>
|
|
||||||
</supervisor-formfield-label>`}
|
|
||||||
>
|
|
||||||
<ha-checkbox
|
|
||||||
.checked=${this.homeAssistant}
|
|
||||||
@click=${() => {
|
|
||||||
this.homeAssistant = !this.homeAssistant;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
</ha-checkbox>
|
|
||||||
</ha-formfield>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${this.snapshotType === "partial"
|
|
||||||
? html`
|
|
||||||
${foldersSection?.templates.length
|
|
||||||
? html`
|
|
||||||
<ha-formfield
|
|
||||||
.label=${html`<supervisor-formfield-label
|
|
||||||
.label=${this.supervisor.localize("snapshot.folders")}
|
|
||||||
.iconPath=${mdiFolder}
|
|
||||||
>
|
|
||||||
</supervisor-formfield-label>`}
|
|
||||||
>
|
|
||||||
<ha-checkbox
|
|
||||||
@change=${this._toggleSection}
|
|
||||||
.checked=${foldersSection.checked}
|
|
||||||
.indeterminate=${foldersSection.indeterminate}
|
|
||||||
.section=${"folders"}
|
|
||||||
>
|
|
||||||
</ha-checkbox>
|
|
||||||
</ha-formfield>
|
|
||||||
<div class="section-content">${foldersSection.templates}</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${addonsSection?.templates.length
|
|
||||||
? html`
|
|
||||||
<ha-formfield
|
|
||||||
.label=${html`<supervisor-formfield-label
|
|
||||||
.label=${this.supervisor.localize("snapshot.addons")}
|
|
||||||
.iconPath=${mdiPuzzle}
|
|
||||||
>
|
|
||||||
</supervisor-formfield-label>`}
|
|
||||||
>
|
|
||||||
<ha-checkbox
|
|
||||||
@change=${this._toggleSection}
|
|
||||||
.checked=${addonsSection.checked}
|
|
||||||
.indeterminate=${addonsSection.indeterminate}
|
|
||||||
.section=${"addons"}
|
|
||||||
>
|
|
||||||
</ha-checkbox>
|
|
||||||
</ha-formfield>
|
|
||||||
<div class="section-content">${addonsSection.templates}</div>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
${!this.snapshot
|
|
||||||
? html`<ha-formfield
|
|
||||||
.label=${this.supervisor.localize("snapshot.password_protection")}
|
|
||||||
>
|
|
||||||
<ha-checkbox
|
|
||||||
.checked=${this.snapshotHasPassword}
|
|
||||||
@change=${this._toggleHasPassword}
|
|
||||||
>
|
|
||||||
</ha-checkbox
|
|
||||||
></ha-formfield>`
|
|
||||||
: ""}
|
|
||||||
${this.snapshotHasPassword
|
|
||||||
? html`
|
|
||||||
<paper-input
|
|
||||||
.label=${this.supervisor.localize("snapshot.password")}
|
|
||||||
type="password"
|
|
||||||
name="snapshotPassword"
|
|
||||||
.value=${this.snapshotPassword}
|
|
||||||
@value-changed=${this._handleTextValueChanged}
|
|
||||||
>
|
|
||||||
</paper-input>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return css`
|
|
||||||
ha-checkbox {
|
|
||||||
--mdc-checkbox-touch-target-size: 16px;
|
|
||||||
display: block;
|
|
||||||
margin: 4px 12px 8px 0;
|
|
||||||
}
|
|
||||||
ha-formfield {
|
|
||||||
display: contents;
|
|
||||||
}
|
|
||||||
supervisor-formfield-label {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
paper-input[type="password"] {
|
|
||||||
display: block;
|
|
||||||
margin: 4px 0 4px 16px;
|
|
||||||
}
|
|
||||||
.details {
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
.section-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-left: 16px;
|
|
||||||
}
|
|
||||||
.security {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.snapshot-types {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.sub-header {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public snapshotDetails():
|
|
||||||
| HassioPartialSnapshotCreateParams
|
|
||||||
| HassioFullSnapshotCreateParams {
|
|
||||||
const data: any = {};
|
|
||||||
|
|
||||||
if (!this.snapshot) {
|
|
||||||
data.name = this.snapshotName || formatDate(new Date(), this.hass.locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.snapshotHasPassword) {
|
|
||||||
data.password = this.snapshotPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.snapshotType === "full") {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const addons = this.addons
|
|
||||||
?.filter((addon) => addon.checked)
|
|
||||||
.map((addon) => addon.slug);
|
|
||||||
const folders = this.folders
|
|
||||||
?.filter((folder) => folder.checked)
|
|
||||||
.map((folder) => folder.slug);
|
|
||||||
|
|
||||||
if (addons?.length) {
|
|
||||||
data.addons = addons;
|
|
||||||
}
|
|
||||||
if (folders?.length) {
|
|
||||||
data.folders = folders;
|
|
||||||
}
|
|
||||||
if (this.homeAssistant) {
|
|
||||||
data.homeassistant = this.homeAssistant;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getSection(section: string) {
|
|
||||||
const templates: TemplateResult[] = [];
|
|
||||||
const addons =
|
|
||||||
section === "addons"
|
|
||||||
? new Map(
|
|
||||||
this.supervisor!.addon.addons.map((item) => [item.slug, item])
|
|
||||||
)
|
|
||||||
: undefined;
|
|
||||||
let checkedItems = 0;
|
|
||||||
this[section].forEach((item) => {
|
|
||||||
templates.push(html`<ha-formfield
|
|
||||||
.label=${html`<supervisor-formfield-label
|
|
||||||
.label=${item.name}
|
|
||||||
.iconPath=${section === "addons" ? mdiPuzzle : mdiFolder}
|
|
||||||
.imageUrl=${section === "addons" &&
|
|
||||||
atLeastVersion(this.hass.config.version, 0, 105) &&
|
|
||||||
addons?.get(item.slug)?.icon
|
|
||||||
? `/api/hassio/addons/${item.slug}/icon`
|
|
||||||
: undefined}
|
|
||||||
.version=${item.version}
|
|
||||||
>
|
|
||||||
</supervisor-formfield-label>`}
|
|
||||||
>
|
|
||||||
<ha-checkbox
|
|
||||||
.item=${item}
|
|
||||||
.checked=${item.checked}
|
|
||||||
.section=${section}
|
|
||||||
@change=${this._updateSectionEntry}
|
|
||||||
>
|
|
||||||
</ha-checkbox>
|
|
||||||
</ha-formfield>`);
|
|
||||||
|
|
||||||
if (item.checked) {
|
|
||||||
checkedItems++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const checked = checkedItems === this[section].length;
|
|
||||||
|
|
||||||
return {
|
|
||||||
templates,
|
|
||||||
checked,
|
|
||||||
indeterminate: !checked && checkedItems !== 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleRadioValueChanged(ev: CustomEvent) {
|
|
||||||
const input = ev.currentTarget as HaRadio;
|
|
||||||
this[input.name] = input.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleTextValueChanged(ev: PolymerChangedEvent<string>) {
|
|
||||||
const input = ev.currentTarget as PaperInputElement;
|
|
||||||
this[input.name!] = ev.detail.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toggleHasPassword(): void {
|
|
||||||
this.snapshotHasPassword = !this.snapshotHasPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toggleSection(ev): void {
|
|
||||||
const section = ev.currentTarget.section;
|
|
||||||
|
|
||||||
this[section] = (section === "addons" ? this.addons : this.folders)!.map(
|
|
||||||
(item) => ({
|
|
||||||
...item,
|
|
||||||
checked: ev.currentTarget.checked,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateSectionEntry(ev): void {
|
|
||||||
const item = ev.currentTarget.item;
|
|
||||||
const section = ev.currentTarget.section;
|
|
||||||
this[section] = this[section].map((entry) =>
|
|
||||||
entry.slug === item.slug
|
|
||||||
? {
|
|
||||||
...entry,
|
|
||||||
checked: ev.currentTarget.checked,
|
|
||||||
}
|
|
||||||
: entry
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"supervisor-snapshot-content": SupervisorSnapshotContent;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +1,13 @@
|
|||||||
import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js";
|
import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import { navigate } from "../../../src/common/navigate";
|
import { navigate } from "../../../src/common/navigate";
|
||||||
import { compare } from "../../../src/common/string/compare";
|
import { compare } from "../../../src/common/string/compare";
|
||||||
@@ -20,15 +27,17 @@ class HassioAddons extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1>${this.supervisor.localize("dashboard.addons")}</h1>
|
<h1>Add-ons</h1>
|
||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
${!this.supervisor.supervisor.addons?.length
|
${!this.supervisor.supervisor.addons?.length
|
||||||
? html`
|
? html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
|
You don't have any add-ons installed yet. Head over to
|
||||||
<button class="link" @click=${this._openStore}>
|
<button class="link" @click=${this._openStore}>
|
||||||
${this.supervisor.localize("dashboard.no_addons")}
|
the add-on store
|
||||||
</button>
|
</button>
|
||||||
|
to get started!
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`
|
`
|
||||||
@@ -49,16 +58,10 @@ class HassioAddons extends LitElement {
|
|||||||
? mdiArrowUpBoldCircle
|
? mdiArrowUpBoldCircle
|
||||||
: mdiPuzzle}
|
: mdiPuzzle}
|
||||||
.iconTitle=${addon.state !== "started"
|
.iconTitle=${addon.state !== "started"
|
||||||
? this.supervisor.localize(
|
? "Add-on is stopped"
|
||||||
"dashboard.addon_stopped"
|
|
||||||
)
|
|
||||||
: addon.update_available!
|
: addon.update_available!
|
||||||
? this.supervisor.localize(
|
? "New version available"
|
||||||
"dashboard.addon_new_version"
|
: "Add-on is running"}
|
||||||
)
|
|
||||||
: this.supervisor.localize(
|
|
||||||
"dashboard.addon_running"
|
|
||||||
)}
|
|
||||||
.iconClass=${addon.update_available
|
.iconClass=${addon.update_available
|
||||||
? addon.state === "started"
|
? addon.state === "started"
|
||||||
? "update"
|
? "update"
|
||||||
@@ -83,7 +86,7 @@ class HassioAddons extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -96,11 +99,11 @@ class HassioAddons extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _addonTapped(ev: any): void {
|
private _addonTapped(ev: any): void {
|
||||||
navigate(`/hassio/addon/${ev.currentTarget.addon.slug}/info`);
|
navigate(this, `/hassio/addon/${ev.currentTarget.addon.slug}/info`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _openStore(): void {
|
private _openStore(): void {
|
||||||
navigate("/hassio/store");
|
navigate(this, "/hassio/store");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import "../../../src/layouts/hass-tabs-subpage";
|
import "../../../src/layouts/hass-tabs-subpage";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
@@ -22,16 +29,13 @@ class HassioDashboard extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage
|
<hass-tabs-subpage
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.localizeFunc=${this.supervisor.localize}
|
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
|
hassio
|
||||||
|
main-page
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${supervisorTabs}
|
.tabs=${supervisorTabs}
|
||||||
main-page
|
|
||||||
supervisor
|
|
||||||
>
|
>
|
||||||
<span slot="header">
|
<span slot="header">Dashboard</span>
|
||||||
${this.supervisor.localize("panel.dashboard")}
|
|
||||||
</span>
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<hassio-update
|
<hassio-update
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@@ -46,7 +50,7 @@ class HassioDashboard extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
|
@@ -1,53 +1,48 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { mdiHomeAssistant } from "@mdi/js";
|
import { mdiHomeAssistant } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
|
||||||
import "../../../src/components/buttons/ha-progress-button";
|
import "../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/ha-settings-row";
|
|
||||||
import "../../../src/components/ha-svg-icon";
|
import "../../../src/components/ha-svg-icon";
|
||||||
import {
|
import {
|
||||||
extractApiErrorMessage,
|
extractApiErrorMessage,
|
||||||
HassioResponse,
|
HassioResponse,
|
||||||
ignoreSupervisorError,
|
ignoredStatusCodes,
|
||||||
} from "../../../src/data/hassio/common";
|
} from "../../../src/data/hassio/common";
|
||||||
import { HassioHassOSInfo } from "../../../src/data/hassio/host";
|
import { HassioHassOSInfo } from "../../../src/data/hassio/host";
|
||||||
import {
|
import {
|
||||||
HassioHomeAssistantInfo,
|
HassioHomeAssistantInfo,
|
||||||
HassioSupervisorInfo,
|
HassioSupervisorInfo,
|
||||||
} from "../../../src/data/hassio/supervisor";
|
} from "../../../src/data/hassio/supervisor";
|
||||||
import { updateCore } from "../../../src/data/supervisor/core";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import {
|
|
||||||
Supervisor,
|
|
||||||
supervisorApiWsRequest,
|
|
||||||
} from "../../../src/data/supervisor/supervisor";
|
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
} from "../../../src/dialogs/generic/show-dialog-box";
|
} from "../../../src/dialogs/generic/show-dialog-box";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../src/types";
|
import { HomeAssistant } from "../../../src/types";
|
||||||
import { showDialogSupervisorUpdate } from "../dialogs/update/show-dialog-update";
|
|
||||||
import { hassioStyle } from "../resources/hassio-style";
|
import { hassioStyle } from "../resources/hassio-style";
|
||||||
|
|
||||||
const computeVersion = (key: string, version: string): string =>
|
|
||||||
key === "os" ? version : `${key}-${version}`;
|
|
||||||
|
|
||||||
@customElement("hassio-update")
|
@customElement("hassio-update")
|
||||||
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 supervisor!: Supervisor;
|
||||||
|
|
||||||
private _pendingUpdates = memoizeOne(
|
private _pendingUpdates = memoizeOne((supervisor: Supervisor): number => {
|
||||||
(supervisor: Supervisor): number =>
|
return Object.keys(supervisor).filter(
|
||||||
Object.keys(supervisor).filter(
|
|
||||||
(value) => supervisor[value].update_available
|
(value) => supervisor[value].update_available
|
||||||
).length
|
).length;
|
||||||
);
|
});
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.supervisor) {
|
if (!this.supervisor) {
|
||||||
@@ -62,17 +57,13 @@ export class HassioUpdate extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1>
|
<h1>
|
||||||
${this.supervisor.localize(
|
${updatesAvailable > 1
|
||||||
"common.update_available",
|
? "Updates Available 🎉"
|
||||||
"count",
|
: "Update Available 🎉"}
|
||||||
updatesAvailable
|
|
||||||
)}
|
|
||||||
🎉
|
|
||||||
</h1>
|
</h1>
|
||||||
<div class="card-group">
|
<div class="card-group">
|
||||||
${this._renderUpdateCard(
|
${this._renderUpdateCard(
|
||||||
"Home Assistant Core",
|
"Home Assistant Core",
|
||||||
"core",
|
|
||||||
this.supervisor.core,
|
this.supervisor.core,
|
||||||
"hassio/homeassistant/update",
|
"hassio/homeassistant/update",
|
||||||
`https://${
|
`https://${
|
||||||
@@ -81,7 +72,6 @@ export class HassioUpdate extends LitElement {
|
|||||||
)}
|
)}
|
||||||
${this._renderUpdateCard(
|
${this._renderUpdateCard(
|
||||||
"Supervisor",
|
"Supervisor",
|
||||||
"supervisor",
|
|
||||||
this.supervisor.supervisor,
|
this.supervisor.supervisor,
|
||||||
"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.supervisor.supervisor.version_latest}`
|
||||||
@@ -89,7 +79,6 @@ export class HassioUpdate extends LitElement {
|
|||||||
${this.supervisor.host.features.includes("hassos")
|
${this.supervisor.host.features.includes("hassos")
|
||||||
? this._renderUpdateCard(
|
? this._renderUpdateCard(
|
||||||
"Operating System",
|
"Operating System",
|
||||||
"os",
|
|
||||||
this.supervisor.os,
|
this.supervisor.os,
|
||||||
"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.supervisor.os.version_latest}`
|
||||||
@@ -102,7 +91,6 @@ export class HassioUpdate extends LitElement {
|
|||||||
|
|
||||||
private _renderUpdateCard(
|
private _renderUpdateCard(
|
||||||
name: string,
|
name: string,
|
||||||
key: string,
|
|
||||||
object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo,
|
object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo,
|
||||||
apiPath: string,
|
apiPath: string,
|
||||||
releaseNotesUrl: string
|
releaseNotesUrl: string
|
||||||
@@ -116,39 +104,22 @@ export class HassioUpdate extends LitElement {
|
|||||||
<div class="icon">
|
<div class="icon">
|
||||||
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="update-heading">${name}</div>
|
<div class="update-heading">${name} ${object.version_latest}</div>
|
||||||
<ha-settings-row two-line>
|
<div class="warning">
|
||||||
<span slot="heading">
|
You are currently running version ${object.version}
|
||||||
${this.supervisor.localize("common.version")}
|
</div>
|
||||||
</span>
|
|
||||||
<span slot="description">
|
|
||||||
${computeVersion(key, object.version!)}
|
|
||||||
</span>
|
|
||||||
</ha-settings-row>
|
|
||||||
|
|
||||||
<ha-settings-row two-line>
|
|
||||||
<span slot="heading">
|
|
||||||
${this.supervisor.localize("common.newest_version")}
|
|
||||||
</span>
|
|
||||||
<span slot="description">
|
|
||||||
${computeVersion(key, object.version_latest!)}
|
|
||||||
</span>
|
|
||||||
</ha-settings-row>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<a href="${releaseNotesUrl}" target="_blank" rel="noreferrer">
|
<a href="${releaseNotesUrl}" target="_blank" rel="noreferrer">
|
||||||
<mwc-button>
|
<mwc-button>Release notes</mwc-button>
|
||||||
${this.supervisor.localize("common.release_notes")}
|
|
||||||
</mwc-button>
|
|
||||||
</a>
|
</a>
|
||||||
<ha-progress-button
|
<ha-progress-button
|
||||||
.apiPath=${apiPath}
|
.apiPath=${apiPath}
|
||||||
.name=${name}
|
.name=${name}
|
||||||
.key=${key}
|
|
||||||
.version=${object.version_latest}
|
.version=${object.version_latest}
|
||||||
@click=${this._confirmUpdate}
|
@click=${this._confirmUpdate}
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("common.update")}
|
Update
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
@@ -157,36 +128,12 @@ export class HassioUpdate extends LitElement {
|
|||||||
|
|
||||||
private async _confirmUpdate(ev): Promise<void> {
|
private async _confirmUpdate(ev): Promise<void> {
|
||||||
const item = ev.currentTarget;
|
const item = ev.currentTarget;
|
||||||
if (item.key === "core") {
|
|
||||||
showDialogSupervisorUpdate(this, {
|
|
||||||
supervisor: this.supervisor,
|
|
||||||
name: "Home Assistant Core",
|
|
||||||
version: this.supervisor.core.version_latest,
|
|
||||||
snapshotParams: {
|
|
||||||
name: `core_${this.supervisor.core.version}`,
|
|
||||||
folders: ["homeassistant"],
|
|
||||||
homeassistant: true,
|
|
||||||
},
|
|
||||||
updateHandler: async () => this._updateCore(),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
item.progress = true;
|
item.progress = true;
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
const confirmed = await showConfirmationDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: `Update ${item.name}`,
|
||||||
"confirm.update.title",
|
text: `Are you sure you want to update ${item.name} to version ${item.version}?`,
|
||||||
"name",
|
confirmText: "update",
|
||||||
item.name
|
dismissText: "cancel",
|
||||||
),
|
|
||||||
text: this.supervisor.localize(
|
|
||||||
"confirm.update.text",
|
|
||||||
"name",
|
|
||||||
item.name,
|
|
||||||
"version",
|
|
||||||
computeVersion(item.key, item.version)
|
|
||||||
),
|
|
||||||
confirmText: this.supervisor.localize("common.update"),
|
|
||||||
dismissText: this.supervisor.localize("common.cancel"),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
@@ -194,24 +141,13 @@ export class HassioUpdate extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
|
|
||||||
await supervisorApiWsRequest(this.hass.connection, {
|
|
||||||
method: "post",
|
|
||||||
endpoint: item.apiPath.replace("hassio", ""),
|
|
||||||
timeout: null,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await this.hass.callApi<HassioResponse<void>>("POST", item.apiPath);
|
await this.hass.callApi<HassioResponse<void>>("POST", item.apiPath);
|
||||||
}
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: item.key,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Only show an error if the status code was not expected (user behind proxy)
|
// Only show an error if the status code was not expected (user behind proxy)
|
||||||
// or no status at all(connection terminated)
|
// or no status at all(connection terminated)
|
||||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
if (err.status_code && !ignoredStatusCodes.has(err.status_code)) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("common.error.update_failed"),
|
title: "Update failed",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -219,14 +155,7 @@ export class HassioUpdate extends LitElement {
|
|||||||
item.progress = false;
|
item.progress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _updateCore(): Promise<void> {
|
static get styles(): CSSResult[] {
|
||||||
await updateCore(this.hass);
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", {
|
|
||||||
collection: "core",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
@@ -243,6 +172,9 @@ export class HassioUpdate extends LitElement {
|
|||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
|
.warning {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
.card-content {
|
.card-content {
|
||||||
height: calc(100% - 47px);
|
height: calc(100% - 47px);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -250,13 +182,13 @@ export class HassioUpdate extends LitElement {
|
|||||||
.card-actions {
|
.card-actions {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
.errors {
|
||||||
|
color: var(--error-color);
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
ha-settings-row {
|
|
||||||
padding: 0;
|
|
||||||
--paper-item-body-two-line-min-height: 32px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,13 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
||||||
import "../../../../src/components/ha-markdown";
|
import "../../../../src/components/ha-markdown";
|
||||||
import { haStyleDialog } from "../../../../src/resources/styles";
|
import { haStyleDialog } from "../../../../src/resources/styles";
|
||||||
@@ -15,7 +23,7 @@ class HassioMarkdownDialog extends LitElement {
|
|||||||
|
|
||||||
@property() public content!: string;
|
@property() public content!: string;
|
||||||
|
|
||||||
@state() private _opened = false;
|
@internalProperty() private _opened = false;
|
||||||
|
|
||||||
public showDialog(params: HassioMarkdownDialogParams) {
|
public showDialog(params: HassioMarkdownDialogParams) {
|
||||||
this.title = params.title;
|
this.title = params.title;
|
||||||
@@ -42,7 +50,7 @@ class HassioMarkdownDialog extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
hassioStyle,
|
hassioStyle,
|
||||||
|
@@ -6,10 +6,19 @@ import "@material/mwc-tab";
|
|||||||
import "@material/mwc-tab-bar";
|
import "@material/mwc-tab-bar";
|
||||||
import { mdiClose } from "@mdi/js";
|
import { mdiClose } from "@mdi/js";
|
||||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
import { cache } from "lit/directives/cache";
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
|
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-expansion-panel";
|
||||||
@@ -26,7 +35,6 @@ import {
|
|||||||
updateNetworkInterface,
|
updateNetworkInterface,
|
||||||
WifiConfiguration,
|
WifiConfiguration,
|
||||||
} from "../../../../src/data/hassio/network";
|
} from "../../../../src/data/hassio/network";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@@ -39,39 +47,35 @@ import { HassioNetworkDialogParams } from "./show-dialog-network";
|
|||||||
const IP_VERSIONS = ["ipv4", "ipv6"];
|
const IP_VERSIONS = ["ipv4", "ipv6"];
|
||||||
|
|
||||||
@customElement("dialog-hassio-network")
|
@customElement("dialog-hassio-network")
|
||||||
export class DialogHassioNetwork
|
export class DialogHassioNetwork extends LitElement
|
||||||
extends LitElement
|
|
||||||
implements HassDialog<HassioNetworkDialogParams> {
|
implements HassDialog<HassioNetworkDialogParams> {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
@internalProperty() private _accessPoints?: AccessPoints;
|
||||||
|
|
||||||
@state() private _accessPoints?: AccessPoints;
|
@internalProperty() private _curTabIndex = 0;
|
||||||
|
|
||||||
@state() private _curTabIndex = 0;
|
@internalProperty() private _dirty = false;
|
||||||
|
|
||||||
@state() private _dirty = false;
|
@internalProperty() private _interface?: NetworkInterface;
|
||||||
|
|
||||||
@state() private _interface?: NetworkInterface;
|
@internalProperty() private _interfaces!: NetworkInterface[];
|
||||||
|
|
||||||
@state() private _interfaces!: NetworkInterface[];
|
@internalProperty() private _params?: HassioNetworkDialogParams;
|
||||||
|
|
||||||
@state() private _params?: HassioNetworkDialogParams;
|
@internalProperty() private _processing = false;
|
||||||
|
|
||||||
@state() private _processing = false;
|
@internalProperty() private _scanning = false;
|
||||||
|
|
||||||
@state() private _scanning = false;
|
@internalProperty() private _wifiConfiguration?: WifiConfiguration;
|
||||||
|
|
||||||
@state() private _wifiConfiguration?: WifiConfiguration;
|
|
||||||
|
|
||||||
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.supervisor = params.supervisor;
|
this._interfaces = params.network.interfaces.sort((a, b) => {
|
||||||
this._interfaces = params.supervisor.network.interfaces.sort((a, b) =>
|
return a.primary > b.primary ? -1 : 1;
|
||||||
a.primary > b.primary ? -1 : 1
|
});
|
||||||
);
|
|
||||||
this._interface = { ...this._interfaces[this._curTabIndex] };
|
this._interface = { ...this._interfaces[this._curTabIndex] };
|
||||||
|
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
@@ -100,7 +104,7 @@ export class DialogHassioNetwork
|
|||||||
<div slot="heading">
|
<div slot="heading">
|
||||||
<ha-header-bar>
|
<ha-header-bar>
|
||||||
<span slot="title">
|
<span slot="title">
|
||||||
${this.supervisor.localize("dialog.network.title")}
|
Network settings
|
||||||
</span>
|
</span>
|
||||||
<mwc-icon-button slot="actionItems" dialogAction="cancel">
|
<mwc-icon-button slot="actionItems" dialogAction="cancel">
|
||||||
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
||||||
@@ -135,13 +139,7 @@ export class DialogHassioNetwork
|
|||||||
? html`
|
? html`
|
||||||
<ha-expansion-panel header="Wi-Fi" outlined>
|
<ha-expansion-panel header="Wi-Fi" outlined>
|
||||||
${this._interface?.wifi?.ssid
|
${this._interface?.wifi?.ssid
|
||||||
? html`<p>
|
? html`<p>Connected to: ${this._interface?.wifi?.ssid}</p>`
|
||||||
${this.supervisor.localize(
|
|
||||||
"dialog.network.connected_to",
|
|
||||||
"ssid",
|
|
||||||
this._interface?.wifi?.ssid
|
|
||||||
)}
|
|
||||||
</p>`
|
|
||||||
: ""}
|
: ""}
|
||||||
<mwc-button
|
<mwc-button
|
||||||
class="scan"
|
class="scan"
|
||||||
@@ -151,7 +149,7 @@ export class DialogHassioNetwork
|
|||||||
${this._scanning
|
${this._scanning
|
||||||
? html`<ha-circular-progress active size="small">
|
? html`<ha-circular-progress active size="small">
|
||||||
</ha-circular-progress>`
|
</ha-circular-progress>`
|
||||||
: this.supervisor.localize("dialog.network.scan_ap")}
|
: "Scan for accesspoints"}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
${this._accessPoints &&
|
${this._accessPoints &&
|
||||||
this._accessPoints.accesspoints &&
|
this._accessPoints.accesspoints &&
|
||||||
@@ -183,11 +181,7 @@ export class DialogHassioNetwork
|
|||||||
${this._wifiConfiguration
|
${this._wifiConfiguration
|
||||||
? html`
|
? html`
|
||||||
<div class="radio-row">
|
<div class="radio-row">
|
||||||
<ha-formfield
|
<ha-formfield label="open">
|
||||||
.label=${this.supervisor.localize(
|
|
||||||
"dialog.network.open"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<ha-radio
|
<ha-radio
|
||||||
@change=${this._handleRadioValueChangedAp}
|
@change=${this._handleRadioValueChangedAp}
|
||||||
.ap=${this._wifiConfiguration}
|
.ap=${this._wifiConfiguration}
|
||||||
@@ -199,11 +193,7 @@ export class DialogHassioNetwork
|
|||||||
>
|
>
|
||||||
</ha-radio>
|
</ha-radio>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
<ha-formfield
|
<ha-formfield label="wep">
|
||||||
.label=${this.supervisor.localize(
|
|
||||||
"dialog.network.wep"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<ha-radio
|
<ha-radio
|
||||||
@change=${this._handleRadioValueChangedAp}
|
@change=${this._handleRadioValueChangedAp}
|
||||||
.ap=${this._wifiConfiguration}
|
.ap=${this._wifiConfiguration}
|
||||||
@@ -213,11 +203,7 @@ export class DialogHassioNetwork
|
|||||||
>
|
>
|
||||||
</ha-radio>
|
</ha-radio>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
<ha-formfield
|
<ha-formfield label="wpa-psk">
|
||||||
.label=${this.supervisor.localize(
|
|
||||||
"dialog.network.wpa"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<ha-radio
|
<ha-radio
|
||||||
@change=${this._handleRadioValueChangedAp}
|
@change=${this._handleRadioValueChangedAp}
|
||||||
.ap=${this._wifiConfiguration}
|
.ap=${this._wifiConfiguration}
|
||||||
@@ -251,21 +237,18 @@ export class DialogHassioNetwork
|
|||||||
: ""}
|
: ""}
|
||||||
${this._dirty
|
${this._dirty
|
||||||
? html`<div class="warning">
|
? html`<div class="warning">
|
||||||
${this.supervisor.localize("dialog.network.warning")}
|
If you are changing the Wi-Fi, IP or gateway addresses, you might
|
||||||
|
lose the connection!
|
||||||
</div>`
|
</div>`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<mwc-button
|
<mwc-button label="close" @click=${this.closeDialog}> </mwc-button>
|
||||||
.label=${this.supervisor.localize("common.cancel")}
|
|
||||||
@click=${this.closeDialog}
|
|
||||||
>
|
|
||||||
</mwc-button>
|
|
||||||
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
|
||||||
${this._processing
|
${this._processing
|
||||||
? html`<ha-circular-progress active size="small">
|
? html`<ha-circular-progress active size="small">
|
||||||
</ha-circular-progress>`
|
</ha-circular-progress>`
|
||||||
: this.supervisor.localize("common.save")}
|
: "Save"}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
@@ -302,9 +285,7 @@ export class DialogHassioNetwork
|
|||||||
outlined
|
outlined
|
||||||
>
|
>
|
||||||
<div class="radio-row">
|
<div class="radio-row">
|
||||||
<ha-formfield
|
<ha-formfield label="DHCP">
|
||||||
.label=${this.supervisor.localize("dialog.network.dhcp")}
|
|
||||||
>
|
|
||||||
<ha-radio
|
<ha-radio
|
||||||
@change=${this._handleRadioValueChanged}
|
@change=${this._handleRadioValueChanged}
|
||||||
.version=${version}
|
.version=${version}
|
||||||
@@ -314,9 +295,7 @@ export class DialogHassioNetwork
|
|||||||
>
|
>
|
||||||
</ha-radio>
|
</ha-radio>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
<ha-formfield
|
<ha-formfield label="Static">
|
||||||
.label=${this.supervisor.localize("dialog.network.static")}
|
|
||||||
>
|
|
||||||
<ha-radio
|
<ha-radio
|
||||||
@change=${this._handleRadioValueChanged}
|
@change=${this._handleRadioValueChanged}
|
||||||
.version=${version}
|
.version=${version}
|
||||||
@@ -326,10 +305,7 @@ export class DialogHassioNetwork
|
|||||||
>
|
>
|
||||||
</ha-radio>
|
</ha-radio>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
<ha-formfield
|
<ha-formfield label="Disabled" class="warning">
|
||||||
.label=${this.supervisor.localize("dialog.network.disabled")}
|
|
||||||
class="warning"
|
|
||||||
>
|
|
||||||
<ha-radio
|
<ha-radio
|
||||||
@change=${this._handleRadioValueChanged}
|
@change=${this._handleRadioValueChanged}
|
||||||
.version=${version}
|
.version=${version}
|
||||||
@@ -345,7 +321,7 @@ export class DialogHassioNetwork
|
|||||||
<paper-input
|
<paper-input
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
id="address"
|
id="address"
|
||||||
.label=${this.supervisor.localize("dialog.network.ip_netmask")}
|
label="IP address/Netmask"
|
||||||
.version=${version}
|
.version=${version}
|
||||||
.value=${this._toString(this._interface![version].address)}
|
.value=${this._toString(this._interface![version].address)}
|
||||||
@value-changed=${this._handleInputValueChanged}
|
@value-changed=${this._handleInputValueChanged}
|
||||||
@@ -354,7 +330,7 @@ export class DialogHassioNetwork
|
|||||||
<paper-input
|
<paper-input
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
id="gateway"
|
id="gateway"
|
||||||
.label=${this.supervisor.localize("dialog.network.gateway")}
|
label="Gateway address"
|
||||||
.version=${version}
|
.version=${version}
|
||||||
.value=${this._interface![version].gateway}
|
.value=${this._interface![version].gateway}
|
||||||
@value-changed=${this._handleInputValueChanged}
|
@value-changed=${this._handleInputValueChanged}
|
||||||
@@ -363,7 +339,7 @@ export class DialogHassioNetwork
|
|||||||
<paper-input
|
<paper-input
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
id="nameservers"
|
id="nameservers"
|
||||||
.label=${this.supervisor.localize("dialog.network.dns_servers")}
|
label="DNS servers"
|
||||||
.version=${version}
|
.version=${version}
|
||||||
.value=${this._toString(this._interface![version].nameservers)}
|
.value=${this._toString(this._interface![version].nameservers)}
|
||||||
@value-changed=${this._handleInputValueChanged}
|
@value-changed=${this._handleInputValueChanged}
|
||||||
@@ -448,7 +424,7 @@ export class DialogHassioNetwork
|
|||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("dialog.network.failed_to_change"),
|
title: "Failed to change network settings",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
this._processing = false;
|
this._processing = false;
|
||||||
@@ -461,9 +437,10 @@ export class DialogHassioNetwork
|
|||||||
private async _handleTabActivated(ev: CustomEvent): Promise<void> {
|
private async _handleTabActivated(ev: CustomEvent): Promise<void> {
|
||||||
if (this._dirty) {
|
if (this._dirty) {
|
||||||
const confirm = await showConfirmationDialog(this, {
|
const confirm = await showConfirmationDialog(this, {
|
||||||
text: this.supervisor.localize("dialog.network.unsaved"),
|
text:
|
||||||
confirmText: this.supervisor.localize("common.yes"),
|
"You have unsaved changes, these will get lost if you change tabs, do you want to continue?",
|
||||||
dismissText: this.supervisor.localize("common.no"),
|
confirmText: "yes",
|
||||||
|
dismissText: "no",
|
||||||
});
|
});
|
||||||
if (!confirm) {
|
if (!confirm) {
|
||||||
this.requestUpdate("_interface");
|
this.requestUpdate("_interface");
|
||||||
@@ -535,7 +512,7 @@ export class DialogHassioNetwork
|
|||||||
this._wifiConfiguration![id] = value;
|
this._wifiConfiguration![id] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
css`
|
css`
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
import { NetworkInfo } from "../../../../src/data/hassio/network";
|
||||||
import "./dialog-hassio-network";
|
import "./dialog-hassio-network";
|
||||||
|
|
||||||
export interface HassioNetworkDialogParams {
|
export interface HassioNetworkDialogParams {
|
||||||
supervisor: Supervisor;
|
network: NetworkInfo;
|
||||||
loadData: () => Promise<void>;
|
loadData: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,8 +3,16 @@ import "@material/mwc-icon-button/mwc-icon-button";
|
|||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDelete } from "@mdi/js";
|
import { mdiDelete } from "@mdi/js";
|
||||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
import "../../../../src/components/ha-svg-icon";
|
||||||
@@ -14,45 +22,41 @@ import {
|
|||||||
fetchHassioDockerRegistries,
|
fetchHassioDockerRegistries,
|
||||||
removeHassioDockerRegistry,
|
removeHassioDockerRegistry,
|
||||||
} from "../../../../src/data/hassio/docker";
|
} from "../../../../src/data/hassio/docker";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
||||||
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../src/types";
|
import type { HomeAssistant } from "../../../../src/types";
|
||||||
import { RegistriesDialogParams } from "./show-dialog-registries";
|
|
||||||
|
|
||||||
@customElement("dialog-hassio-registries")
|
@customElement("dialog-hassio-registries")
|
||||||
class HassioRegistriesDialog extends LitElement {
|
class HassioRegistriesDialog extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
|
||||||
|
|
||||||
@property({ attribute: false }) private _registries?: {
|
@property({ attribute: false }) private _registries?: {
|
||||||
registry: string;
|
registry: string;
|
||||||
username: string;
|
username: string;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
@state() private _registry?: string;
|
@internalProperty() private _registry?: string;
|
||||||
|
|
||||||
@state() private _username?: string;
|
@internalProperty() private _username?: string;
|
||||||
|
|
||||||
@state() private _password?: string;
|
@internalProperty() private _password?: string;
|
||||||
|
|
||||||
@state() private _opened = false;
|
@internalProperty() private _opened = false;
|
||||||
|
|
||||||
@state() private _addingRegistry = false;
|
@internalProperty() private _addingRegistry = false;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
.open=${this._opened}
|
.open=${this._opened}
|
||||||
@closed=${this.closeDialog}
|
@closing=${this.closeDialog}
|
||||||
scrimClickAction
|
scrimClickAction
|
||||||
escapeKeyAction
|
escapeKeyAction
|
||||||
.heading=${createCloseHeading(
|
.heading=${createCloseHeading(
|
||||||
this.hass,
|
this.hass,
|
||||||
this._addingRegistry
|
this._addingRegistry
|
||||||
? this.supervisor.localize("dialog.registries.title_add")
|
? "Add New Docker Registry"
|
||||||
: this.supervisor.localize("dialog.registries.title_manage")
|
: "Manage Docker Registries"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div class="form">
|
<div class="form">
|
||||||
@@ -62,9 +66,7 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
@value-changed=${this._inputChanged}
|
@value-changed=${this._inputChanged}
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
name="registry"
|
name="registry"
|
||||||
.label=${this.supervisor.localize(
|
label="Registry"
|
||||||
"dialog.registries.registry"
|
|
||||||
)}
|
|
||||||
required
|
required
|
||||||
auto-validate
|
auto-validate
|
||||||
></paper-input>
|
></paper-input>
|
||||||
@@ -72,9 +74,7 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
@value-changed=${this._inputChanged}
|
@value-changed=${this._inputChanged}
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
name="username"
|
name="username"
|
||||||
.label=${this.supervisor.localize(
|
label="Username"
|
||||||
"dialog.registries.username"
|
|
||||||
)}
|
|
||||||
required
|
required
|
||||||
auto-validate
|
auto-validate
|
||||||
></paper-input>
|
></paper-input>
|
||||||
@@ -82,9 +82,7 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
@value-changed=${this._inputChanged}
|
@value-changed=${this._inputChanged}
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
name="password"
|
name="password"
|
||||||
.label=${this.supervisor.localize(
|
label="Password"
|
||||||
"dialog.registries.password"
|
|
||||||
)}
|
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
auto-validate
|
auto-validate
|
||||||
@@ -96,46 +94,35 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
)}
|
)}
|
||||||
@click=${this._addNewRegistry}
|
@click=${this._addNewRegistry}
|
||||||
>
|
>
|
||||||
${this.supervisor.localize("dialog.registries.add_registry")}
|
Add registry
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
`
|
`
|
||||||
: html`${this._registries?.length
|
: html`${this._registries?.length
|
||||||
? this._registries.map(
|
? this._registries.map((entry) => {
|
||||||
(entry) => html`
|
return html`
|
||||||
<mwc-list-item class="option" hasMeta twoline>
|
<mwc-list-item class="option" hasMeta twoline>
|
||||||
<span>${entry.registry}</span>
|
<span>${entry.registry}</span>
|
||||||
<span slot="secondary"
|
<span slot="secondary"
|
||||||
>${this.supervisor.localize(
|
>Username: ${entry.username}</span
|
||||||
"dialog.registries.username"
|
|
||||||
)}:
|
|
||||||
${entry.username}</span
|
|
||||||
>
|
>
|
||||||
<mwc-icon-button
|
<mwc-icon-button
|
||||||
.entry=${entry}
|
.entry=${entry}
|
||||||
.title=${this.supervisor.localize(
|
title="Remove"
|
||||||
"dialog.registries.remove"
|
|
||||||
)}
|
|
||||||
slot="meta"
|
slot="meta"
|
||||||
@click=${this._removeRegistry}
|
@click=${this._removeRegistry}
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
|
||||||
</mwc-icon-button>
|
</mwc-icon-button>
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
`
|
`;
|
||||||
)
|
})
|
||||||
: html`
|
: html`
|
||||||
<mwc-list-item>
|
<mwc-list-item>
|
||||||
<span
|
<span>No registries configured</span>
|
||||||
>${this.supervisor.localize(
|
|
||||||
"dialog.registries.no_registries"
|
|
||||||
)}</span
|
|
||||||
>
|
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
`}
|
`}
|
||||||
<mwc-button @click=${this._addRegistry}>
|
<mwc-button @click=${this._addRegistry}>
|
||||||
${this.supervisor.localize(
|
Add new registry
|
||||||
"dialog.registries.add_new_registry"
|
|
||||||
)}
|
|
||||||
</mwc-button> `}
|
</mwc-button> `}
|
||||||
</div>
|
</div>
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
@@ -147,9 +134,8 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
this[`_${target.name}`] = target.value;
|
this[`_${target.name}`] = target.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async showDialog(dialogParams: RegistriesDialogParams): Promise<void> {
|
public async showDialog(_dialogParams: any): Promise<void> {
|
||||||
this._opened = true;
|
this._opened = true;
|
||||||
this.supervisor = dialogParams.supervisor;
|
|
||||||
await this._loadRegistries();
|
await this._loadRegistries();
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
}
|
}
|
||||||
@@ -192,7 +178,7 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
this._addingRegistry = false;
|
this._addingRegistry = false;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("dialog.registries.failed_to_add"),
|
title: "Failed to add registry",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -206,13 +192,13 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
await this._loadRegistries();
|
await this._loadRegistries();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("dialog.registries.failed_to_remove"),
|
title: "Failed to remove registry",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
@@ -244,6 +230,9 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
mwc-list-item span[slot="secondary"] {
|
mwc-list-item span[slot="secondary"] {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
ha-paper-dropdown-menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,10 @@
|
|||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
|
||||||
import "./dialog-hassio-registries";
|
import "./dialog-hassio-registries";
|
||||||
|
|
||||||
export interface RegistriesDialogParams {
|
export const showRegistriesDialog = (element: HTMLElement): void => {
|
||||||
supervisor: Supervisor;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const showRegistriesDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
dialogParams: RegistriesDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
fireEvent(element, "show-dialog", {
|
||||||
dialogTag: "dialog-hassio-registries",
|
dialogTag: "dialog-hassio-registries",
|
||||||
dialogImport: () => import("./dialog-hassio-registries"),
|
dialogImport: () => import("./dialog-hassio-registries"),
|
||||||
dialogParams,
|
dialogParams: {},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -5,12 +5,20 @@ import "@polymer/paper-input/paper-input";
|
|||||||
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
|
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
query,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
import "../../../../src/components/ha-dialog";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
import "../../../../src/components/ha-svg-icon";
|
||||||
import {
|
import {
|
||||||
fetchHassioAddonsInfo,
|
fetchHassioAddonsInfo,
|
||||||
@@ -26,29 +34,27 @@ import { HassioRepositoryDialogParams } from "./show-dialog-repositories";
|
|||||||
class HassioRepositoriesDialog extends LitElement {
|
class HassioRepositoriesDialog extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) private _repos: HassioAddonRepository[] = [];
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
private _dialogParams?: HassioRepositoryDialogParams;
|
||||||
|
|
||||||
@query("#repository_input", true) private _optionInput?: PaperInputElement;
|
@query("#repository_input", true) private _optionInput?: PaperInputElement;
|
||||||
|
|
||||||
@state() private _repositories?: HassioAddonRepository[];
|
@internalProperty() private _opened = false;
|
||||||
|
|
||||||
@state() private _dialogParams?: HassioRepositoryDialogParams;
|
@internalProperty() private _prosessing = false;
|
||||||
|
|
||||||
@state() private _opened = false;
|
@internalProperty() private _error?: string;
|
||||||
|
|
||||||
@state() private _processing = false;
|
public async showDialog(_dialogParams: any): Promise<void> {
|
||||||
|
this._dialogParams = _dialogParams;
|
||||||
@state() private _error?: string;
|
this._repos = _dialogParams.repos;
|
||||||
|
|
||||||
public async showDialog(
|
|
||||||
dialogParams: HassioRepositoryDialogParams
|
|
||||||
): Promise<void> {
|
|
||||||
this._dialogParams = dialogParams;
|
|
||||||
this._opened = true;
|
this._opened = true;
|
||||||
await this._loadData();
|
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeDialog(): void {
|
public closeDialog(): void {
|
||||||
this._dialogParams = undefined;
|
|
||||||
this._opened = false;
|
this._opened = false;
|
||||||
this._error = "";
|
this._error = "";
|
||||||
}
|
}
|
||||||
@@ -60,26 +66,20 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._dialogParams?.supervisor || this._repositories === undefined) {
|
const repositories = this._filteredRepositories(this._repos);
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
const repositories = this._filteredRepositories(this._repositories);
|
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
.open=${this._opened}
|
.open=${this._opened}
|
||||||
@closed=${this.closeDialog}
|
@closing=${this.closeDialog}
|
||||||
scrimClickAction
|
scrimClickAction
|
||||||
escapeKeyAction
|
escapeKeyAction
|
||||||
.heading=${createCloseHeading(
|
heading="Manage add-on repositories"
|
||||||
this.hass,
|
|
||||||
this._dialogParams!.supervisor.localize("dialog.repositories.title")
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
${this._error ? html`<div class="error">${this._error}</div>` : ""}
|
${this._error ? html`<div class="error">${this._error}</div>` : ""}
|
||||||
<div class="form">
|
<div class="form">
|
||||||
${repositories.length
|
${repositories.length
|
||||||
? repositories.map(
|
? repositories.map((repo) => {
|
||||||
(repo) => html`
|
return html`
|
||||||
<paper-item class="option">
|
<paper-item class="option">
|
||||||
<paper-item-body three-line>
|
<paper-item-body three-line>
|
||||||
<div>${repo.name}</div>
|
<div>${repo.name}</div>
|
||||||
@@ -88,47 +88,41 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
</paper-item-body>
|
</paper-item-body>
|
||||||
<mwc-icon-button
|
<mwc-icon-button
|
||||||
.slug=${repo.slug}
|
.slug=${repo.slug}
|
||||||
.title=${this._dialogParams!.supervisor.localize(
|
title="Remove"
|
||||||
"dialog.repositories.remove"
|
|
||||||
)}
|
|
||||||
@click=${this._removeRepository}
|
@click=${this._removeRepository}
|
||||||
>
|
>
|
||||||
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
|
||||||
</mwc-icon-button>
|
</mwc-icon-button>
|
||||||
</paper-item>
|
</paper-item>
|
||||||
`
|
`;
|
||||||
)
|
})
|
||||||
: html` <paper-item> No repositories </paper-item> `}
|
: html`
|
||||||
|
<paper-item>
|
||||||
|
No repositories
|
||||||
|
</paper-item>
|
||||||
|
`}
|
||||||
<div class="layout horizontal bottom">
|
<div class="layout horizontal bottom">
|
||||||
<paper-input
|
<paper-input
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
id="repository_input"
|
id="repository_input"
|
||||||
.value=${this._dialogParams!.url || ""}
|
label="Add repository"
|
||||||
.label=${this._dialogParams!.supervisor.localize(
|
|
||||||
"dialog.repositories.add"
|
|
||||||
)}
|
|
||||||
@keydown=${this._handleKeyAdd}
|
@keydown=${this._handleKeyAdd}
|
||||||
></paper-input>
|
></paper-input>
|
||||||
<mwc-button @click=${this._addRepository}>
|
<mwc-button @click=${this._addRepository}>
|
||||||
${this._processing
|
${this._prosessing
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress active></ha-circular-progress>`
|
||||||
active
|
: "Add"}
|
||||||
size="small"
|
|
||||||
></ha-circular-progress>`
|
|
||||||
: this._dialogParams!.supervisor.localize(
|
|
||||||
"dialog.repositories.add"
|
|
||||||
)}
|
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<mwc-button slot="primaryAction" @click=${this.closeDialog}>
|
<mwc-button slot="primaryAction" @click="${this.closeDialog}">
|
||||||
${this._dialogParams?.supervisor.localize("common.close")}
|
Close
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
@@ -150,10 +144,8 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
mwc-button {
|
mwc-button {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
ha-circular-progress {
|
ha-paper-dropdown-menu {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 32px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
@@ -175,57 +167,61 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
this._addRepository();
|
this._addRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _loadData(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const addonsinfo = await fetchHassioAddonsInfo(this.hass);
|
|
||||||
|
|
||||||
this._repositories = addonsinfo.repositories;
|
|
||||||
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", { collection: "addon" });
|
|
||||||
} catch (err) {
|
|
||||||
this._error = extractApiErrorMessage(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _addRepository() {
|
private async _addRepository() {
|
||||||
const input = this._optionInput;
|
const input = this._optionInput;
|
||||||
if (!input || !input.value) {
|
if (!input || !input.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._processing = true;
|
this._prosessing = true;
|
||||||
const repositories = this._filteredRepositories(this._repositories!);
|
const repositories = this._filteredRepositories(this._repos);
|
||||||
const newRepositories = repositories.map((repo) => repo.source);
|
const newRepositories = repositories.map((repo) => {
|
||||||
|
return repo.source;
|
||||||
|
});
|
||||||
newRepositories.push(input.value);
|
newRepositories.push(input.value);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await setSupervisorOption(this.hass, {
|
await setSupervisorOption(this.hass, {
|
||||||
addons_repositories: newRepositories,
|
addons_repositories: newRepositories,
|
||||||
});
|
});
|
||||||
await this._loadData();
|
|
||||||
|
const addonsInfo = await fetchHassioAddonsInfo(this.hass);
|
||||||
|
this._repos = addonsInfo.repositories;
|
||||||
|
|
||||||
|
await this._dialogParams!.loadData();
|
||||||
|
|
||||||
input.value = "";
|
input.value = "";
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
}
|
}
|
||||||
this._processing = false;
|
this._prosessing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _removeRepository(ev: Event) {
|
private async _removeRepository(ev: Event) {
|
||||||
const slug = (ev.currentTarget as any).slug;
|
const slug = (ev.currentTarget as any).slug;
|
||||||
const repositories = this._filteredRepositories(this._repositories!);
|
const repositories = this._filteredRepositories(this._repos);
|
||||||
const repository = repositories.find((repo) => repo.slug === slug);
|
const repository = repositories.find((repo) => {
|
||||||
|
return repo.slug === slug;
|
||||||
|
});
|
||||||
if (!repository) {
|
if (!repository) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newRepositories = repositories
|
const newRepositories = repositories
|
||||||
.map((repo) => repo.source)
|
.map((repo) => {
|
||||||
.filter((repo) => repo !== repository.source);
|
return repo.source;
|
||||||
|
})
|
||||||
|
.filter((repo) => {
|
||||||
|
return repo !== repository.source;
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await setSupervisorOption(this.hass, {
|
await setSupervisorOption(this.hass, {
|
||||||
addons_repositories: newRepositories,
|
addons_repositories: newRepositories,
|
||||||
});
|
});
|
||||||
await this._loadData();
|
|
||||||
|
const addonsInfo = await fetchHassioAddonsInfo(this.hass);
|
||||||
|
this._repos = addonsInfo.repositories;
|
||||||
|
|
||||||
|
await this._dialogParams!.loadData();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
import { HassioAddonRepository } from "../../../../src/data/hassio/addon";
|
||||||
import "./dialog-hassio-repositories";
|
import "./dialog-hassio-repositories";
|
||||||
|
|
||||||
export interface HassioRepositoryDialogParams {
|
export interface HassioRepositoryDialogParams {
|
||||||
supervisor: Supervisor;
|
repos: HassioAddonRepository[];
|
||||||
url?: string;
|
loadData: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const showRepositoriesDialog = (
|
export const showRepositoriesDialog = (
|
||||||
|
@@ -1,142 +0,0 @@
|
|||||||
import "@material/mwc-button";
|
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
|
||||||
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
|
||||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
|
||||||
import {
|
|
||||||
createHassioFullSnapshot,
|
|
||||||
createHassioPartialSnapshot,
|
|
||||||
} from "../../../../src/data/hassio/snapshot";
|
|
||||||
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
|
||||||
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
|
||||||
import "../../components/supervisor-snapshot-content";
|
|
||||||
import type { SupervisorSnapshotContent } from "../../components/supervisor-snapshot-content";
|
|
||||||
import { HassioCreateSnapshotDialogParams } from "./show-dialog-hassio-create-snapshot";
|
|
||||||
|
|
||||||
@customElement("dialog-hassio-create-snapshot")
|
|
||||||
class HassioCreateSnapshotDialog extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _dialogParams?: HassioCreateSnapshotDialogParams;
|
|
||||||
|
|
||||||
@state() private _error?: string;
|
|
||||||
|
|
||||||
@state() private _creatingSnapshot = false;
|
|
||||||
|
|
||||||
@query("supervisor-snapshot-content")
|
|
||||||
private _snapshotContent!: SupervisorSnapshotContent;
|
|
||||||
|
|
||||||
public showDialog(params: HassioCreateSnapshotDialogParams) {
|
|
||||||
this._dialogParams = params;
|
|
||||||
this._creatingSnapshot = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeDialog() {
|
|
||||||
this._dialogParams = undefined;
|
|
||||||
this._creatingSnapshot = false;
|
|
||||||
this._error = undefined;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this._dialogParams) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<ha-dialog
|
|
||||||
open
|
|
||||||
scrimClickAction
|
|
||||||
@closed=${this.closeDialog}
|
|
||||||
.heading=${createCloseHeading(
|
|
||||||
this.hass,
|
|
||||||
this._dialogParams.supervisor.localize("snapshot.create_snapshot")
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
${this._creatingSnapshot
|
|
||||||
? html` <ha-circular-progress active></ha-circular-progress>`
|
|
||||||
: html`<supervisor-snapshot-content
|
|
||||||
.hass=${this.hass}
|
|
||||||
.supervisor=${this._dialogParams.supervisor}
|
|
||||||
>
|
|
||||||
</supervisor-snapshot-content>`}
|
|
||||||
${this._error ? html`<p class="error">Error: ${this._error}</p>` : ""}
|
|
||||||
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
|
|
||||||
${this._dialogParams.supervisor.localize("common.close")}
|
|
||||||
</mwc-button>
|
|
||||||
<mwc-button
|
|
||||||
.disabled=${this._creatingSnapshot}
|
|
||||||
slot="primaryAction"
|
|
||||||
@click=${this._createSnapshot}
|
|
||||||
>
|
|
||||||
${this._dialogParams.supervisor.localize("snapshot.create")}
|
|
||||||
</mwc-button>
|
|
||||||
</ha-dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _createSnapshot(): Promise<void> {
|
|
||||||
if (this._dialogParams!.supervisor.info.state !== "running") {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: this._dialogParams!.supervisor.localize(
|
|
||||||
"snapshot.could_not_create"
|
|
||||||
),
|
|
||||||
text: this._dialogParams!.supervisor.localize(
|
|
||||||
"snapshot.create_blocked_not_running",
|
|
||||||
"state",
|
|
||||||
this._dialogParams!.supervisor.info.state
|
|
||||||
),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const snapshotDetails = this._snapshotContent.snapshotDetails();
|
|
||||||
this._creatingSnapshot = true;
|
|
||||||
|
|
||||||
this._error = "";
|
|
||||||
if (
|
|
||||||
this._snapshotContent.snapshotHasPassword &&
|
|
||||||
!this._snapshotContent.snapshotPassword.length
|
|
||||||
) {
|
|
||||||
this._error = this._dialogParams!.supervisor.localize(
|
|
||||||
"snapshot.enter_password"
|
|
||||||
);
|
|
||||||
this._creatingSnapshot = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (this._snapshotContent.snapshotType === "full") {
|
|
||||||
await createHassioFullSnapshot(this.hass, snapshotDetails);
|
|
||||||
} else {
|
|
||||||
await createHassioPartialSnapshot(this.hass, snapshotDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._dialogParams!.onCreate();
|
|
||||||
this.closeDialog();
|
|
||||||
} catch (err) {
|
|
||||||
this._error = extractApiErrorMessage(err);
|
|
||||||
}
|
|
||||||
this._creatingSnapshot = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
|
||||||
return [
|
|
||||||
haStyle,
|
|
||||||
haStyleDialog,
|
|
||||||
css`
|
|
||||||
ha-circular-progress {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"dialog-hassio-create-snapshot": HassioCreateSnapshotDialog;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +1,14 @@
|
|||||||
import { mdiClose } from "@mdi/js";
|
import { mdiClose } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
internalProperty,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/components/ha-header-bar";
|
import "../../../../src/components/ha-header-bar";
|
||||||
import { HassDialog } from "../../../../src/dialogs/make-dialog-manager";
|
import { HassDialog } from "../../../../src/dialogs/make-dialog-manager";
|
||||||
@@ -10,12 +18,11 @@ import "../../components/hassio-upload-snapshot";
|
|||||||
import { HassioSnapshotUploadDialogParams } from "./show-dialog-snapshot-upload";
|
import { HassioSnapshotUploadDialogParams } from "./show-dialog-snapshot-upload";
|
||||||
|
|
||||||
@customElement("dialog-hassio-snapshot-upload")
|
@customElement("dialog-hassio-snapshot-upload")
|
||||||
export class DialogHassioSnapshotUpload
|
export class DialogHassioSnapshotUpload extends LitElement
|
||||||
extends LitElement
|
|
||||||
implements HassDialog<HassioSnapshotUploadDialogParams> {
|
implements HassDialog<HassioSnapshotUploadDialogParams> {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@state() private _params?: HassioSnapshotUploadDialogParams;
|
@internalProperty() private _params?: HassioSnapshotUploadDialogParams;
|
||||||
|
|
||||||
public async showDialog(
|
public async showDialog(
|
||||||
params: HassioSnapshotUploadDialogParams
|
params: HassioSnapshotUploadDialogParams
|
||||||
@@ -50,7 +57,9 @@ export class DialogHassioSnapshotUpload
|
|||||||
>
|
>
|
||||||
<div slot="heading">
|
<div slot="heading">
|
||||||
<ha-header-bar>
|
<ha-header-bar>
|
||||||
<span slot="title"> Upload snapshot </span>
|
<span slot="title">
|
||||||
|
Upload snapshot
|
||||||
|
</span>
|
||||||
<mwc-icon-button slot="actionItems" dialogAction="cancel">
|
<mwc-icon-button slot="actionItems" dialogAction="cancel">
|
||||||
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
||||||
</mwc-icon-button>
|
</mwc-icon-button>
|
||||||
@@ -70,7 +79,7 @@ export class DialogHassioSnapshotUpload
|
|||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
css`
|
css`
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user