mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-13 19:29:27 +00:00
Compare commits
125 Commits
20210813.0
...
data-disk-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2c440976aa | ||
![]() |
abbfe7200a | ||
![]() |
419942112b | ||
![]() |
597d4a0426 | ||
![]() |
e023d60be7 | ||
![]() |
41a7b42037 | ||
![]() |
2936865c55 | ||
![]() |
ff2bf1f3c1 | ||
![]() |
1bccbd4173 | ||
![]() |
d7f00df391 | ||
![]() |
22f88c59c7 | ||
![]() |
8721776839 | ||
![]() |
a89da0dac0 | ||
![]() |
e4b4dc4ae9 | ||
![]() |
b26c44b2b9 | ||
![]() |
68095417b9 | ||
![]() |
b6344eb6e8 | ||
![]() |
224302cfef | ||
![]() |
abc4816888 | ||
![]() |
21e14bd644 | ||
![]() |
a89caccd32 | ||
![]() |
03dc3e52b7 | ||
![]() |
f04be8efa6 | ||
![]() |
2c32f6bcb3 | ||
![]() |
a3a08ff5c7 | ||
![]() |
ea51186767 | ||
![]() |
49494c572b | ||
![]() |
fcac3fa164 | ||
![]() |
9c1153ef37 | ||
![]() |
0adc4b33ef | ||
![]() |
c0f3215340 | ||
![]() |
bab1e6a95f | ||
![]() |
53b26a43c0 | ||
![]() |
2240d019f5 | ||
![]() |
cb11c6b3ea | ||
![]() |
5893559951 | ||
![]() |
8408d25cef | ||
![]() |
1ac2ffcf02 | ||
![]() |
6b6c38c2c8 | ||
![]() |
e55df73a91 | ||
![]() |
360c2cbfa3 | ||
![]() |
aba96674f3 | ||
![]() |
5c3d85fc90 | ||
![]() |
6486b7fd4c | ||
![]() |
5f3e980de0 | ||
![]() |
d0edbec5fb | ||
![]() |
5d46963e8a | ||
![]() |
321f441b63 | ||
![]() |
d55bade070 | ||
![]() |
6ba6b821f5 | ||
![]() |
b3dedae115 | ||
![]() |
5a1070c30f | ||
![]() |
40664997e1 | ||
![]() |
c6e83cb7c0 | ||
![]() |
e7e27e794c | ||
![]() |
1073dbe6ab | ||
![]() |
2bd9b5a015 | ||
![]() |
bc09febd2c | ||
![]() |
b2a87c90a2 | ||
![]() |
d6dbbcb0de | ||
![]() |
9ccb5360b3 | ||
![]() |
0187c4faff | ||
![]() |
605172a0bc | ||
![]() |
8565a0d911 | ||
![]() |
61c8d23a7e | ||
![]() |
5e3487ed59 | ||
![]() |
d5a161769c | ||
![]() |
1692f9c2dd | ||
![]() |
0cbac8bb44 | ||
![]() |
35a81e7f11 | ||
![]() |
ac64d293e7 | ||
![]() |
708b8787c5 | ||
![]() |
2bddd151eb | ||
![]() |
43a585187c | ||
![]() |
324658a36b | ||
![]() |
dd9a9b34d1 | ||
![]() |
2ab0e40952 | ||
![]() |
dfea80ae96 | ||
![]() |
6e38f5accf | ||
![]() |
7c952d92bf | ||
![]() |
2fae0d2d95 | ||
![]() |
67ab63f00e | ||
![]() |
719f9c28af | ||
![]() |
035d621109 | ||
![]() |
791f3b896d | ||
![]() |
fe2172a660 | ||
![]() |
640fbd616b | ||
![]() |
900efe8a36 | ||
![]() |
5bd92d04d9 | ||
![]() |
b15684bcbd | ||
![]() |
a93222dbb2 | ||
![]() |
20744e90a0 | ||
![]() |
32777b4259 | ||
![]() |
271120999c | ||
![]() |
68fe13a67d | ||
![]() |
f3606014c6 | ||
![]() |
efbf4482b2 | ||
![]() |
21a3b4f8e2 | ||
![]() |
de23b2d046 | ||
![]() |
bd8f436c1d | ||
![]() |
e963735dba | ||
![]() |
46c981103d | ||
![]() |
f6d02d8fc6 | ||
![]() |
e08f691510 | ||
![]() |
af9199aaff | ||
![]() |
8576b13f74 | ||
![]() |
2270d8a795 | ||
![]() |
f4dcce6d6c | ||
![]() |
b802a410b9 | ||
![]() |
9e3d339ec5 | ||
![]() |
fb97a98b97 | ||
![]() |
72773f3bc8 | ||
![]() |
b0fd93e0c3 | ||
![]() |
7aa2ec78f2 | ||
![]() |
047e856a61 | ||
![]() |
dbe209e3f2 | ||
![]() |
e0d23ee6cf | ||
![]() |
7a35f46370 | ||
![]() |
4a4465efb6 | ||
![]() |
3a112531cc | ||
![]() |
456209dded | ||
![]() |
2556b0d157 | ||
![]() |
1e8903fd76 | ||
![]() |
ad9f18c231 | ||
![]() |
63e3de00cb |
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
|
"airbnb-base",
|
||||||
"airbnb-typescript/base",
|
"airbnb-typescript/base",
|
||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
"plugin:wc/recommended",
|
"plugin:wc/recommended",
|
||||||
"plugin:lit/recommended",
|
"plugin:lit/all",
|
||||||
"prettier"
|
"prettier"
|
||||||
],
|
],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
@@ -109,7 +110,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"unused-imports/no-unused-imports": "error",
|
"unused-imports/no-unused-imports": "error",
|
||||||
"lit/attribute-value-entities": "off"
|
"lit/attribute-value-entities": "off",
|
||||||
|
"lit/no-template-map": "off",
|
||||||
|
"lit/no-template-arrow": "warn"
|
||||||
},
|
},
|
||||||
"plugins": ["disable", "unused-imports"],
|
"plugins": ["disable", "unused-imports"],
|
||||||
"processor": "disable/disable"
|
"processor": "disable/disable"
|
||||||
|
6
.github/workflows/ci.yaml
vendored
6
.github/workflows/ci.yaml
vendored
@@ -12,7 +12,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 14
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
@@ -53,8 +53,8 @@ jobs:
|
|||||||
run: yarn install
|
run: yarn install
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
- name: Run Mocha
|
- name: Run Tests
|
||||||
run: yarn run mocha
|
run: yarn run test
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
|
2
.github/workflows/demo.yaml
vendored
2
.github/workflows/demo.yaml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 14
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
|
5
.github/workflows/release.yaml
vendored
5
.github/workflows/release.yaml
vendored
@@ -8,7 +8,7 @@ on:
|
|||||||
env:
|
env:
|
||||||
PYTHON_VERSION: 3.8
|
PYTHON_VERSION: 3.8
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 14
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
@@ -73,8 +73,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
arch: ["aarch64", "armhf", "armv7", "amd64", "i386"]
|
arch: ["aarch64", "armhf", "armv7", "amd64", "i386"]
|
||||||
tag:
|
tag:
|
||||||
- "3.8-alpine3.12"
|
- "3.9-alpine3.14"
|
||||||
- "3.9-alpine3.13"
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download requirements.txt
|
- name: Download requirements.txt
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
|
@@ -1,4 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
require: "test-mocha/testconf.js",
|
|
||||||
timeout: 10000,
|
|
||||||
};
|
|
55
.yarn/releases/yarn-2.4.2.cjs
vendored
55
.yarn/releases/yarn-2.4.2.cjs
vendored
File diff suppressed because one or more lines are too long
631
.yarn/releases/yarn-3.0.2.cjs
vendored
Executable file
631
.yarn/releases/yarn-3.0.2.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
@@ -6,4 +6,4 @@ plugins:
|
|||||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||||
spec: "@yarnpkg/plugin-interactive-tools"
|
spec: "@yarnpkg/plugin-interactive-tools"
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-2.4.2.cjs
|
yarnPath: .yarn/releases/yarn-3.0.2.cjs
|
||||||
|
@@ -82,6 +82,7 @@ module.exports.babelOptions = ({ latestBuild }) => ({
|
|||||||
// Only support the syntax, Webpack will handle it.
|
// Only support the syntax, Webpack will handle it.
|
||||||
"@babel/plugin-syntax-import-meta",
|
"@babel/plugin-syntax-import-meta",
|
||||||
"@babel/plugin-syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
|
"@babel/plugin-syntax-top-level-await",
|
||||||
"@babel/plugin-proposal-optional-chaining",
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
|
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
|
||||||
|
@@ -5,32 +5,32 @@ require("./translations");
|
|||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean",
|
"clean",
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
gulp.parallel("clean-translations", () =>
|
||||||
return del([paths.app_output_root, paths.build_dir]);
|
del([paths.app_output_root, paths.build_dir])
|
||||||
})
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-demo",
|
"clean-demo",
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
gulp.parallel("clean-translations", () =>
|
||||||
return del([paths.demo_output_root, paths.build_dir]);
|
del([paths.demo_output_root, paths.build_dir])
|
||||||
})
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-cast",
|
"clean-cast",
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
gulp.parallel("clean-translations", () =>
|
||||||
return del([paths.cast_output_root, paths.build_dir]);
|
del([paths.cast_output_root, paths.build_dir])
|
||||||
})
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("clean-hassio", function cleanOutputAndBuildDir() {
|
gulp.task("clean-hassio", () =>
|
||||||
return del([paths.hassio_output_root, paths.build_dir]);
|
del([paths.hassio_output_root, paths.build_dir])
|
||||||
});
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-gallery",
|
"clean-gallery",
|
||||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
gulp.parallel("clean-translations", () =>
|
||||||
return del([paths.gallery_output_root, paths.build_dir]);
|
del([paths.gallery_output_root, paths.build_dir])
|
||||||
})
|
)
|
||||||
);
|
);
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
|
||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
const del = require("del");
|
const del = require("del");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
@@ -26,13 +28,6 @@ gulp.task("translations-enable-merge-backend", (done) => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
String.prototype.rsplit = function (sep, maxsplit) {
|
|
||||||
var split = this.split(sep);
|
|
||||||
return maxsplit
|
|
||||||
? [split.slice(0, -maxsplit).join(sep)].concat(split.slice(-maxsplit))
|
|
||||||
: split;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Panel translations which should be split from the core translations.
|
// Panel translations which should be split from the core translations.
|
||||||
const TRANSLATION_FRAGMENTS = Object.keys(
|
const TRANSLATION_FRAGMENTS = Object.keys(
|
||||||
require("../../src/translations/en.json").ui.panel
|
require("../../src/translations/en.json").ui.panel
|
||||||
@@ -40,7 +35,7 @@ const TRANSLATION_FRAGMENTS = Object.keys(
|
|||||||
|
|
||||||
function recursiveFlatten(prefix, data) {
|
function recursiveFlatten(prefix, data) {
|
||||||
let output = {};
|
let output = {};
|
||||||
Object.keys(data).forEach(function (key) {
|
Object.keys(data).forEach((key) => {
|
||||||
if (typeof data[key] === "object") {
|
if (typeof data[key] === "object") {
|
||||||
output = {
|
output = {
|
||||||
...output,
|
...output,
|
||||||
@@ -101,15 +96,19 @@ function lokaliseTransform(data, original, file) {
|
|||||||
if (value instanceof Object) {
|
if (value instanceof Object) {
|
||||||
output[key] = lokaliseTransform(value, original, file);
|
output[key] = lokaliseTransform(value, original, file);
|
||||||
} else {
|
} else {
|
||||||
output[key] = value.replace(re_key_reference, (match, key) => {
|
output[key] = value.replace(re_key_reference, (_match, lokalise_key) => {
|
||||||
const replace = key.split("::").reduce((tr, k) => {
|
const replace = lokalise_key.split("::").reduce((tr, k) => {
|
||||||
if (!tr) {
|
if (!tr) {
|
||||||
throw Error(`Invalid key placeholder ${key} in ${file.path}`);
|
throw Error(
|
||||||
|
`Invalid key placeholder ${lokalise_key} in ${file.path}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return tr[k];
|
return tr[k];
|
||||||
}, original);
|
}, original);
|
||||||
if (typeof replace !== "string") {
|
if (typeof replace !== "string") {
|
||||||
throw Error(`Invalid key placeholder ${key} in ${file.path}`);
|
throw Error(
|
||||||
|
`Invalid key placeholder ${lokalise_key} in ${file.path}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return replace;
|
return replace;
|
||||||
});
|
});
|
||||||
@@ -118,9 +117,7 @@ function lokaliseTransform(data, original, file) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task("clean-translations", function () {
|
gulp.task("clean-translations", () => del([workDir]));
|
||||||
return del([workDir]);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("ensure-translations-build-dir", (done) => {
|
gulp.task("ensure-translations-build-dir", (done) => {
|
||||||
if (!fs.existsSync(workDir)) {
|
if (!fs.existsSync(workDir)) {
|
||||||
@@ -129,7 +126,7 @@ gulp.task("ensure-translations-build-dir", (done) => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("create-test-metadata", function (cb) {
|
gulp.task("create-test-metadata", (cb) => {
|
||||||
fs.writeFile(
|
fs.writeFile(
|
||||||
workDir + "/testMetadata.json",
|
workDir + "/testMetadata.json",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -143,17 +140,13 @@ gulp.task("create-test-metadata", function (cb) {
|
|||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"create-test-translation",
|
"create-test-translation",
|
||||||
gulp.series("create-test-metadata", function createTestTranslation() {
|
gulp.series("create-test-metadata", () =>
|
||||||
return gulp
|
gulp
|
||||||
.src(path.join(paths.translations_src, "en.json"))
|
.src(path.join(paths.translations_src, "en.json"))
|
||||||
.pipe(
|
.pipe(transform((data, _file) => recursiveEmpty(data)))
|
||||||
transform(function (data, file) {
|
|
||||||
return recursiveEmpty(data);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(rename("test.json"))
|
.pipe(rename("test.json"))
|
||||||
.pipe(gulp.dest(workDir));
|
.pipe(gulp.dest(workDir))
|
||||||
})
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,7 +158,7 @@ gulp.task(
|
|||||||
* project is buildable immediately after merging new translation keys, since
|
* project is buildable immediately after merging new translation keys, since
|
||||||
* the Lokalise update to translations/en.json will not happen immediately.
|
* the Lokalise update to translations/en.json will not happen immediately.
|
||||||
*/
|
*/
|
||||||
gulp.task("build-master-translation", function () {
|
gulp.task("build-master-translation", () => {
|
||||||
const src = [path.join(paths.translations_src, "en.json")];
|
const src = [path.join(paths.translations_src, "en.json")];
|
||||||
|
|
||||||
if (mergeBackend) {
|
if (mergeBackend) {
|
||||||
@@ -174,11 +167,7 @@ gulp.task("build-master-translation", function () {
|
|||||||
|
|
||||||
return gulp
|
return gulp
|
||||||
.src(src)
|
.src(src)
|
||||||
.pipe(
|
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
||||||
transform(function (data, file) {
|
|
||||||
return lokaliseTransform(data, data, file);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(
|
.pipe(
|
||||||
merge({
|
merge({
|
||||||
fileName: "translationMaster.json",
|
fileName: "translationMaster.json",
|
||||||
@@ -187,18 +176,14 @@ gulp.task("build-master-translation", function () {
|
|||||||
.pipe(gulp.dest(workDir));
|
.pipe(gulp.dest(workDir));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("build-merged-translations", function () {
|
gulp.task("build-merged-translations", () =>
|
||||||
return gulp
|
gulp
|
||||||
.src([inFrontendDir + "/*.json", workDir + "/test.json"], {
|
.src([inFrontendDir + "/*.json", workDir + "/test.json"], {
|
||||||
allowEmpty: true,
|
allowEmpty: true,
|
||||||
})
|
})
|
||||||
|
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
||||||
.pipe(
|
.pipe(
|
||||||
transform(function (data, file) {
|
foreach((stream, file) => {
|
||||||
return lokaliseTransform(data, data, file);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(
|
|
||||||
foreach(function (stream, file) {
|
|
||||||
// For each language generate a merged json file. It begins with the master
|
// For each language generate a merged json file. It begins with the master
|
||||||
// translation as a failsafe for untranslated strings, and merges all parent
|
// translation as a failsafe for untranslated strings, and merges all parent
|
||||||
// tags into one file for each specific subtag
|
// tags into one file for each specific subtag
|
||||||
@@ -230,17 +215,17 @@ gulp.task("build-merged-translations", function () {
|
|||||||
)
|
)
|
||||||
.pipe(gulp.dest(fullDir));
|
.pipe(gulp.dest(fullDir));
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
});
|
);
|
||||||
|
|
||||||
var taskName;
|
let taskName;
|
||||||
|
|
||||||
const splitTasks = [];
|
const splitTasks = [];
|
||||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||||
taskName = "build-translation-fragment-" + fragment;
|
taskName = "build-translation-fragment-" + fragment;
|
||||||
gulp.task(taskName, function () {
|
gulp.task(taskName, () =>
|
||||||
// Return only the translations for this fragment.
|
// Return only the translations for this fragment.
|
||||||
return gulp
|
gulp
|
||||||
.src(fullDir + "/*.json")
|
.src(fullDir + "/*.json")
|
||||||
.pipe(
|
.pipe(
|
||||||
transform((data) => ({
|
transform((data) => ({
|
||||||
@@ -251,18 +236,18 @@ TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(workDir + "/" + fragment));
|
.pipe(gulp.dest(workDir + "/" + fragment))
|
||||||
});
|
);
|
||||||
splitTasks.push(taskName);
|
splitTasks.push(taskName);
|
||||||
});
|
});
|
||||||
|
|
||||||
taskName = "build-translation-core";
|
taskName = "build-translation-core";
|
||||||
gulp.task(taskName, function () {
|
gulp.task(taskName, () =>
|
||||||
// Remove the fragment translations from the core translation.
|
// Remove the fragment translations from the core translation.
|
||||||
return gulp
|
gulp
|
||||||
.src(fullDir + "/*.json")
|
.src(fullDir + "/*.json")
|
||||||
.pipe(
|
.pipe(
|
||||||
transform((data, file) => {
|
transform((data, _file) => {
|
||||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||||
delete data.ui.panel[fragment];
|
delete data.ui.panel[fragment];
|
||||||
});
|
});
|
||||||
@@ -270,14 +255,14 @@ gulp.task(taskName, function () {
|
|||||||
return data;
|
return data;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(coreDir));
|
.pipe(gulp.dest(coreDir))
|
||||||
});
|
);
|
||||||
|
|
||||||
splitTasks.push(taskName);
|
splitTasks.push(taskName);
|
||||||
|
|
||||||
gulp.task("build-flattened-translations", function () {
|
gulp.task("build-flattened-translations", () =>
|
||||||
// Flatten the split versions of our translations, and move them into outDir
|
// Flatten the split versions of our translations, and move them into outDir
|
||||||
return gulp
|
gulp
|
||||||
.src(
|
.src(
|
||||||
TRANSLATION_FRAGMENTS.map(
|
TRANSLATION_FRAGMENTS.map(
|
||||||
(fragment) => workDir + "/" + fragment + "/*.json"
|
(fragment) => workDir + "/" + fragment + "/*.json"
|
||||||
@@ -285,41 +270,45 @@ gulp.task("build-flattened-translations", function () {
|
|||||||
{ base: workDir }
|
{ base: workDir }
|
||||||
)
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
transform(function (data) {
|
transform((data) =>
|
||||||
// Polymer.AppLocalizeBehavior requires flattened json
|
// Polymer.AppLocalizeBehavior requires flattened json
|
||||||
return flatten(data);
|
flatten(data)
|
||||||
})
|
)
|
||||||
)
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
rename((filePath) => {
|
rename((filePath) => {
|
||||||
if (filePath.dirname === "core") {
|
if (filePath.dirname === "core") {
|
||||||
filePath.dirname = "";
|
filePath.dirname = "";
|
||||||
}
|
}
|
||||||
|
// In dev we create the file with the fake hash in the filename
|
||||||
|
if (!env.isProdBuild()) {
|
||||||
|
filePath.basename += "-dev";
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(outDir));
|
.pipe(gulp.dest(outDir))
|
||||||
});
|
);
|
||||||
|
|
||||||
const fingerprints = {};
|
const fingerprints = {};
|
||||||
|
|
||||||
gulp.task(
|
gulp.task("build-translation-fingerprints", () => {
|
||||||
"build-translation-fingerprints",
|
// Fingerprint full file of each language
|
||||||
function fingerprintTranslationFiles() {
|
const files = fs.readdirSync(fullDir);
|
||||||
// Fingerprint full file of each language
|
|
||||||
const files = fs.readdirSync(fullDir);
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
fingerprints[files[i].split(".")[0]] = {
|
fingerprints[files[i].split(".")[0]] = {
|
||||||
// In dev we create fake hashes
|
// In dev we create fake hashes
|
||||||
hash: env.isProdBuild()
|
hash: env.isProdBuild()
|
||||||
? crypto
|
? crypto
|
||||||
.createHash("md5")
|
.createHash("md5")
|
||||||
.update(fs.readFileSync(path.join(fullDir, files[i]), "utf-8"))
|
.update(fs.readFileSync(path.join(fullDir, files[i]), "utf-8"))
|
||||||
.digest("hex")
|
.digest("hex")
|
||||||
: "dev",
|
: "dev",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In dev we create the file with the fake hash in the filename
|
||||||
|
if (env.isProdBuild()) {
|
||||||
mapFiles(outDir, ".json", (filename) => {
|
mapFiles(outDir, ".json", (filename) => {
|
||||||
const parsed = path.parse(filename);
|
const parsed = path.parse(filename);
|
||||||
|
|
||||||
@@ -335,35 +324,43 @@ gulp.task(
|
|||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const stream = source("translationFingerprints.json");
|
|
||||||
stream.write(JSON.stringify(fingerprints));
|
|
||||||
process.nextTick(() => stream.end());
|
|
||||||
return stream.pipe(vinylBuffer()).pipe(gulp.dest(workDir));
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
gulp.task("build-translation-fragment-supervisor", function () {
|
const stream = source("translationFingerprints.json");
|
||||||
return gulp
|
stream.write(JSON.stringify(fingerprints));
|
||||||
|
process.nextTick(() => stream.end());
|
||||||
|
return stream.pipe(vinylBuffer()).pipe(gulp.dest(workDir));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("build-translation-fragment-supervisor", () =>
|
||||||
|
gulp
|
||||||
.src(fullDir + "/*.json")
|
.src(fullDir + "/*.json")
|
||||||
.pipe(transform((data) => data.supervisor))
|
.pipe(transform((data) => data.supervisor))
|
||||||
.pipe(gulp.dest(workDir + "/supervisor"));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("build-translation-flatten-supervisor", function () {
|
|
||||||
return gulp
|
|
||||||
.src(workDir + "/supervisor/*.json")
|
|
||||||
.pipe(
|
.pipe(
|
||||||
transform(function (data) {
|
rename((filePath) => {
|
||||||
// Polymer.AppLocalizeBehavior requires flattened json
|
// In dev we create the file with the fake hash in the filename
|
||||||
return flatten(data);
|
if (!env.isProdBuild()) {
|
||||||
|
filePath.basename += "-dev";
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(outDir));
|
.pipe(gulp.dest(workDir + "/supervisor"))
|
||||||
});
|
);
|
||||||
|
|
||||||
gulp.task("build-translation-write-metadata", function writeMetadata() {
|
gulp.task("build-translation-flatten-supervisor", () =>
|
||||||
return gulp
|
gulp
|
||||||
|
.src(workDir + "/supervisor/*.json")
|
||||||
|
.pipe(
|
||||||
|
transform((data) =>
|
||||||
|
// Polymer.AppLocalizeBehavior requires flattened json
|
||||||
|
flatten(data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.pipe(gulp.dest(outDir))
|
||||||
|
);
|
||||||
|
|
||||||
|
gulp.task("build-translation-write-metadata", () =>
|
||||||
|
gulp
|
||||||
.src(
|
.src(
|
||||||
[
|
[
|
||||||
path.join(paths.translations_src, "translationMetadata.json"),
|
path.join(paths.translations_src, "translationMetadata.json"),
|
||||||
@@ -374,13 +371,14 @@ gulp.task("build-translation-write-metadata", function writeMetadata() {
|
|||||||
)
|
)
|
||||||
.pipe(merge({}))
|
.pipe(merge({}))
|
||||||
.pipe(
|
.pipe(
|
||||||
transform(function (data) {
|
transform((data) => {
|
||||||
const newData = {};
|
const newData = {};
|
||||||
Object.entries(data).forEach(([key, value]) => {
|
Object.entries(data).forEach(([key, value]) => {
|
||||||
// Filter out translations without native name.
|
// Filter out translations without native name.
|
||||||
if (value.nativeName) {
|
if (value.nativeName) {
|
||||||
newData[key] = value;
|
newData[key] = value;
|
||||||
} else {
|
} else {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.warn(
|
console.warn(
|
||||||
`Skipping language ${key}. Native name was not translated.`
|
`Skipping language ${key}. Native name was not translated.`
|
||||||
);
|
);
|
||||||
@@ -396,19 +394,26 @@ 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(
|
||||||
|
"create-translations",
|
||||||
|
gulp.series(
|
||||||
|
env.isProdBuild() ? (done) => done() : "create-test-translation",
|
||||||
|
"build-master-translation",
|
||||||
|
"build-merged-translations",
|
||||||
|
gulp.parallel(...splitTasks),
|
||||||
|
"build-flattened-translations"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"build-translations",
|
"build-translations",
|
||||||
gulp.series(
|
gulp.series(
|
||||||
"clean-translations",
|
"clean-translations",
|
||||||
"ensure-translations-build-dir",
|
"ensure-translations-build-dir",
|
||||||
env.isProdBuild() ? (done) => done() : "create-test-translation",
|
"create-translations",
|
||||||
"build-master-translation",
|
|
||||||
"build-merged-translations",
|
|
||||||
gulp.parallel(...splitTasks),
|
|
||||||
"build-flattened-translations",
|
|
||||||
"build-translation-fingerprints",
|
"build-translation-fingerprints",
|
||||||
"build-translation-write-metadata"
|
"build-translation-write-metadata"
|
||||||
)
|
)
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
// Tasks to run webpack.
|
// Tasks to run webpack.
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
@@ -44,7 +45,7 @@ const runDevServer = ({
|
|||||||
open: true,
|
open: true,
|
||||||
watchContentBase: true,
|
watchContentBase: true,
|
||||||
contentBase,
|
contentBase,
|
||||||
}).listen(port, listenHost, function (err) {
|
}).listen(port, listenHost, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@@ -65,6 +66,7 @@ const doneHandler = (done) => (err, stats) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stats.hasErrors() || stats.hasWarnings()) {
|
if (stats.hasErrors() || stats.hasWarnings()) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(stats.toString("minimal"));
|
console.log(stats.toString("minimal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,16 +92,10 @@ gulp.task("webpack-watch-app", () => {
|
|||||||
process.env.ES5
|
process.env.ES5
|
||||||
? bothBuilds(createAppConfig, { isProdBuild: false })
|
? bothBuilds(createAppConfig, { isProdBuild: false })
|
||||||
: createAppConfig({ isProdBuild: false, latestBuild: true })
|
: createAppConfig({ isProdBuild: false, latestBuild: true })
|
||||||
).watch(
|
).watch({ poll: isWsl }, doneHandler());
|
||||||
{
|
|
||||||
ignored: /build-translations/,
|
|
||||||
poll: isWsl,
|
|
||||||
},
|
|
||||||
doneHandler()
|
|
||||||
);
|
|
||||||
gulp.watch(
|
gulp.watch(
|
||||||
path.join(paths.translations_src, "en.json"),
|
path.join(paths.translations_src, "en.json"),
|
||||||
gulp.series("build-translations", "copy-translations-app")
|
gulp.series("create-translations", "copy-translations-app")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -6,6 +6,7 @@ const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
|
|||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
const bundle = require("./bundle.js");
|
const bundle = require("./bundle.js");
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
|
const WebpackBar = require("webpackbar");
|
||||||
|
|
||||||
class LogStartCompilePlugin {
|
class LogStartCompilePlugin {
|
||||||
ignoredFirst = false;
|
ignoredFirst = false;
|
||||||
@@ -74,6 +75,7 @@ const createWebpackConfig = ({
|
|||||||
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new WebpackBar({ fancy: !isProdBuild }),
|
||||||
new WebpackManifestPlugin({
|
new WebpackManifestPlugin({
|
||||||
// Only include the JS of entrypoints
|
// Only include the JS of entrypoints
|
||||||
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
||||||
@@ -125,6 +127,13 @@ const createWebpackConfig = ({
|
|||||||
alias: {
|
alias: {
|
||||||
"lit/decorators$": "lit/decorators.js",
|
"lit/decorators$": "lit/decorators.js",
|
||||||
"lit/directive$": "lit/directive.js",
|
"lit/directive$": "lit/directive.js",
|
||||||
|
"lit/directives/until$": "lit/directives/until.js",
|
||||||
|
"lit/directives/class-map$": "lit/directives/class-map.js",
|
||||||
|
"lit/directives/style-map$": "lit/directives/style-map.js",
|
||||||
|
"lit/directives/if-defined$": "lit/directives/if-defined.js",
|
||||||
|
"lit/directives/guard$": "lit/directives/guard.js",
|
||||||
|
"lit/directives/cache$": "lit/directives/cache.js",
|
||||||
|
"lit/directives/repeat$": "lit/directives/repeat.js",
|
||||||
"lit/polyfill-support$": "lit/polyfill-support.js",
|
"lit/polyfill-support$": "lit/polyfill-support.js",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -142,6 +151,9 @@ const createWebpackConfig = ({
|
|||||||
// To silence warning in worker plugin
|
// To silence warning in worker plugin
|
||||||
globalObject: "self",
|
globalObject: "self",
|
||||||
},
|
},
|
||||||
|
experiments: {
|
||||||
|
topLevelAwait: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -191,7 +191,7 @@ class HcCast extends LitElement {
|
|||||||
}
|
}
|
||||||
this.connection.close();
|
this.connection.close();
|
||||||
location.reload();
|
location.reload();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
alert("Unable to log out!");
|
alert("Unable to log out!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -212,7 +212,7 @@ export class HcConnect extends LitElement {
|
|||||||
let url: URL;
|
let url: URL;
|
||||||
try {
|
try {
|
||||||
url = new URL(value);
|
url = new URL(value);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this.error = "Invalid URL";
|
this.error = "Invalid URL";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -240,7 +240,7 @@ export class HcConnect extends LitElement {
|
|||||||
try {
|
try {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
auth = await getAuth(options);
|
auth = await getAuth(options);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (init === "saved-tokens" && err === ERR_CANNOT_CONNECT) {
|
if (init === "saved-tokens" && err === ERR_CANNOT_CONNECT) {
|
||||||
this.cannotConnect = true;
|
this.cannotConnect = true;
|
||||||
return;
|
return;
|
||||||
@@ -259,7 +259,7 @@ export class HcConnect extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
conn = await createConnection({ auth });
|
conn = await createConnection({ auth });
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// In case of saved tokens, silently solve problems.
|
// In case of saved tokens, silently solve problems.
|
||||||
if (init === "saved-tokens") {
|
if (init === "saved-tokens") {
|
||||||
if (err === ERR_CANNOT_CONNECT) {
|
if (err === ERR_CANNOT_CONNECT) {
|
||||||
@@ -285,7 +285,7 @@ export class HcConnect extends LitElement {
|
|||||||
try {
|
try {
|
||||||
saveTokens(null);
|
saveTokens(null);
|
||||||
location.reload();
|
location.reload();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
alert("Unable to log out!");
|
alert("Unable to log out!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -148,14 +148,14 @@ export class HcMain extends HassElement {
|
|||||||
expires_in: 0,
|
expires_in: 0,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this._getErrorMessage(err);
|
this._error = this._getErrorMessage(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let connection;
|
let connection;
|
||||||
try {
|
try {
|
||||||
connection = await createConnection({ auth });
|
connection = await createConnection({ auth });
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this._getErrorMessage(err);
|
this._error = this._getErrorMessage(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ export class HcMain extends HassElement {
|
|||||||
this._unsubLovelace = llColl.subscribe((lovelaceConfig) =>
|
this._unsubLovelace = llColl.subscribe((lovelaceConfig) =>
|
||||||
this._handleNewLovelaceConfig(lovelaceConfig)
|
this._handleNewLovelaceConfig(lovelaceConfig)
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
console.log("Error fetching Lovelace configuration", err, msg);
|
console.log("Error fetching Lovelace configuration", err, msg);
|
||||||
// Generate a Lovelace config.
|
// Generate a Lovelace config.
|
||||||
|
@@ -44,7 +44,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
(conf) => html`
|
(conf) => html`
|
||||||
${conf.name}
|
${conf.name}
|
||||||
<small>
|
<small>
|
||||||
<a target="_blank" href="${conf.authorUrl}">
|
<a target="_blank" href=${conf.authorUrl}>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.page-demo.cards.demo.demo_by",
|
"ui.panel.page-demo.cards.demo.demo_by",
|
||||||
"name",
|
"name",
|
||||||
@@ -94,7 +94,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
this._switching = true;
|
this._switching = true;
|
||||||
try {
|
try {
|
||||||
await setDemoConfig(this.hass, this.lovelace!, index);
|
await setDemoConfig(this.hass, this.lovelace!, index);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
alert("Failed to switch config :-(");
|
alert("Failed to switch config :-(");
|
||||||
} finally {
|
} finally {
|
||||||
this._switching = false;
|
this._switching = false;
|
||||||
|
@@ -23,7 +23,6 @@ import { mockTranslations } from "./stubs/translations";
|
|||||||
import { mockEnergy } from "./stubs/energy";
|
import { mockEnergy } from "./stubs/energy";
|
||||||
import { mockConfig } from "./stubs/config";
|
import { mockConfig } from "./stubs/config";
|
||||||
import { energyEntities } from "./stubs/entities";
|
import { energyEntities } from "./stubs/entities";
|
||||||
import { mockForecastSolar } from "./stubs/forecast_solar";
|
|
||||||
|
|
||||||
class HaDemo extends HomeAssistantAppEl {
|
class HaDemo extends HomeAssistantAppEl {
|
||||||
protected async _initializeHass() {
|
protected async _initializeHass() {
|
||||||
@@ -52,7 +51,6 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
mockMediaPlayer(hass);
|
mockMediaPlayer(hass);
|
||||||
mockFrontend(hass);
|
mockFrontend(hass);
|
||||||
mockEnergy(hass);
|
mockEnergy(hass);
|
||||||
mockForecastSolar(hass);
|
|
||||||
mockConfig(hass);
|
mockConfig(hass);
|
||||||
mockPersistentNotification(hass);
|
mockPersistentNotification(hass);
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import { format, startOfToday, startOfTomorrow } from "date-fns";
|
||||||
|
import { EnergySolarForecasts } from "../../../src/data/energy";
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
export const mockEnergy = (hass: MockHomeAssistant) => {
|
export const mockEnergy = (hass: MockHomeAssistant) => {
|
||||||
@@ -44,11 +46,11 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
|
|||||||
stat_energy_from: "sensor.solar_production",
|
stat_energy_from: "sensor.solar_production",
|
||||||
config_entry_solar_forecast: ["solar_forecast"],
|
config_entry_solar_forecast: ["solar_forecast"],
|
||||||
},
|
},
|
||||||
{
|
/* {
|
||||||
type: "battery",
|
type: "battery",
|
||||||
stat_energy_from: "sensor.battery_output",
|
stat_energy_from: "sensor.battery_output",
|
||||||
stat_energy_to: "sensor.battery_input",
|
stat_energy_to: "sensor.battery_input",
|
||||||
},
|
}, */
|
||||||
{
|
{
|
||||||
type: "gas",
|
type: "gas",
|
||||||
stat_energy_from: "sensor.energy_gas",
|
stat_energy_from: "sensor.energy_gas",
|
||||||
@@ -80,4 +82,53 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
|
|||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
hass.mockWS("energy/info", () => ({ cost_sensors: [] }));
|
hass.mockWS("energy/info", () => ({ cost_sensors: [] }));
|
||||||
|
const todayString = format(startOfToday(), "yyyy-MM-dd");
|
||||||
|
const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd");
|
||||||
|
hass.mockWS(
|
||||||
|
"energy/solar_forecast",
|
||||||
|
(): EnergySolarForecasts => ({
|
||||||
|
solar_forecast: {
|
||||||
|
wh_hours: {
|
||||||
|
[`${todayString}T06:00:00`]: 0,
|
||||||
|
[`${todayString}T06:23:00`]: 6,
|
||||||
|
[`${todayString}T06:45:00`]: 39,
|
||||||
|
[`${todayString}T07:00:00`]: 28,
|
||||||
|
[`${todayString}T08:00:00`]: 208,
|
||||||
|
[`${todayString}T09:00:00`]: 352,
|
||||||
|
[`${todayString}T10:00:00`]: 544,
|
||||||
|
[`${todayString}T11:00:00`]: 748,
|
||||||
|
[`${todayString}T12:00:00`]: 1259,
|
||||||
|
[`${todayString}T13:00:00`]: 1361,
|
||||||
|
[`${todayString}T14:00:00`]: 1373,
|
||||||
|
[`${todayString}T15:00:00`]: 1370,
|
||||||
|
[`${todayString}T16:00:00`]: 1186,
|
||||||
|
[`${todayString}T17:00:00`]: 937,
|
||||||
|
[`${todayString}T18:00:00`]: 652,
|
||||||
|
[`${todayString}T19:00:00`]: 370,
|
||||||
|
[`${todayString}T20:00:00`]: 155,
|
||||||
|
[`${todayString}T21:48:00`]: 24,
|
||||||
|
[`${todayString}T22:36:00`]: 0,
|
||||||
|
[`${tomorrowString}T06:01:00`]: 0,
|
||||||
|
[`${tomorrowString}T06:23:00`]: 9,
|
||||||
|
[`${tomorrowString}T06:45:00`]: 47,
|
||||||
|
[`${tomorrowString}T07:00:00`]: 48,
|
||||||
|
[`${tomorrowString}T08:00:00`]: 473,
|
||||||
|
[`${tomorrowString}T09:00:00`]: 827,
|
||||||
|
[`${tomorrowString}T10:00:00`]: 1153,
|
||||||
|
[`${tomorrowString}T11:00:00`]: 1413,
|
||||||
|
[`${tomorrowString}T12:00:00`]: 1590,
|
||||||
|
[`${tomorrowString}T13:00:00`]: 1652,
|
||||||
|
[`${tomorrowString}T14:00:00`]: 1612,
|
||||||
|
[`${tomorrowString}T15:00:00`]: 1438,
|
||||||
|
[`${tomorrowString}T16:00:00`]: 1149,
|
||||||
|
[`${tomorrowString}T17:00:00`]: 830,
|
||||||
|
[`${tomorrowString}T18:00:00`]: 542,
|
||||||
|
[`${tomorrowString}T19:00:00`]: 311,
|
||||||
|
[`${tomorrowString}T20:00:00`]: 140,
|
||||||
|
[`${tomorrowString}T21:47:00`]: 22,
|
||||||
|
[`${tomorrowString}T22:34:00`]: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,55 +0,0 @@
|
|||||||
import { format, startOfToday, startOfTomorrow } from "date-fns";
|
|
||||||
import { ForecastSolarForecast } from "../../../src/data/forecast_solar";
|
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
export const mockForecastSolar = (hass: MockHomeAssistant) => {
|
|
||||||
const todayString = format(startOfToday(), "yyyy-MM-dd");
|
|
||||||
const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd");
|
|
||||||
hass.mockWS(
|
|
||||||
"forecast_solar/forecasts",
|
|
||||||
(): Record<string, ForecastSolarForecast> => ({
|
|
||||||
solar_forecast: {
|
|
||||||
wh_hours: {
|
|
||||||
[`${todayString}T06:00:00`]: 0,
|
|
||||||
[`${todayString}T06:23:00`]: 6,
|
|
||||||
[`${todayString}T06:45:00`]: 39,
|
|
||||||
[`${todayString}T07:00:00`]: 28,
|
|
||||||
[`${todayString}T08:00:00`]: 208,
|
|
||||||
[`${todayString}T09:00:00`]: 352,
|
|
||||||
[`${todayString}T10:00:00`]: 544,
|
|
||||||
[`${todayString}T11:00:00`]: 748,
|
|
||||||
[`${todayString}T12:00:00`]: 1259,
|
|
||||||
[`${todayString}T13:00:00`]: 1361,
|
|
||||||
[`${todayString}T14:00:00`]: 1373,
|
|
||||||
[`${todayString}T15:00:00`]: 1370,
|
|
||||||
[`${todayString}T16:00:00`]: 1186,
|
|
||||||
[`${todayString}T17:00:00`]: 937,
|
|
||||||
[`${todayString}T18:00:00`]: 652,
|
|
||||||
[`${todayString}T19:00:00`]: 370,
|
|
||||||
[`${todayString}T20:00:00`]: 155,
|
|
||||||
[`${todayString}T21:48:00`]: 24,
|
|
||||||
[`${todayString}T22:36:00`]: 0,
|
|
||||||
[`${tomorrowString}T06:01:00`]: 0,
|
|
||||||
[`${tomorrowString}T06:23:00`]: 9,
|
|
||||||
[`${tomorrowString}T06:45:00`]: 47,
|
|
||||||
[`${tomorrowString}T07:00:00`]: 48,
|
|
||||||
[`${tomorrowString}T08:00:00`]: 473,
|
|
||||||
[`${tomorrowString}T09:00:00`]: 827,
|
|
||||||
[`${tomorrowString}T10:00:00`]: 1153,
|
|
||||||
[`${tomorrowString}T11:00:00`]: 1413,
|
|
||||||
[`${tomorrowString}T12:00:00`]: 1590,
|
|
||||||
[`${tomorrowString}T13:00:00`]: 1652,
|
|
||||||
[`${tomorrowString}T14:00:00`]: 1612,
|
|
||||||
[`${tomorrowString}T15:00:00`]: 1438,
|
|
||||||
[`${tomorrowString}T16:00:00`]: 1149,
|
|
||||||
[`${tomorrowString}T17:00:00`]: 830,
|
|
||||||
[`${tomorrowString}T18:00:00`]: 542,
|
|
||||||
[`${tomorrowString}T19:00:00`]: 311,
|
|
||||||
[`${tomorrowString}T20:00:00`]: 140,
|
|
||||||
[`${tomorrowString}T21:47:00`]: 22,
|
|
||||||
[`${tomorrowString}T22:34:00`]: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
@@ -23,9 +23,9 @@ customElements.whenDefined("hui-view").then(() => {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const HUIView = customElements.get("hui-view");
|
const HUIView = customElements.get("hui-view");
|
||||||
// Patch HUI-VIEW to make the lovelace object available to the demo card
|
// Patch HUI-VIEW to make the lovelace object available to the demo card
|
||||||
const oldCreateCard = HUIView.prototype.createCardElement;
|
const oldCreateCard = HUIView!.prototype.createCardElement;
|
||||||
|
|
||||||
HUIView.prototype.createCardElement = function (config) {
|
HUIView!.prototype.createCardElement = function (config) {
|
||||||
const el = oldCreateCard.call(this, config);
|
const el = oldCreateCard.call(this, config);
|
||||||
if (el.tagName === "HA-DEMO-CARD") {
|
if (el.tagName === "HA-DEMO-CARD") {
|
||||||
(el as HADemoCard).lovelace = this.lovelace;
|
(el as HADemoCard).lovelace = this.lovelace;
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable lit/no-template-arrow */
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable lit/no-template-arrow */
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/trace/hat-script-graph";
|
import "../../../src/components/trace/hat-script-graph";
|
||||||
|
150
gallery/src/demos/demo-ha-alert.ts
Normal file
150
gallery/src/demos/demo-ha-alert.ts
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import "../../../src/components/ha-alert";
|
||||||
|
import "../../../src/components/ha-card";
|
||||||
|
|
||||||
|
const alerts: {
|
||||||
|
title?: string;
|
||||||
|
description: string | TemplateResult;
|
||||||
|
type: "info" | "warning" | "error" | "success";
|
||||||
|
dismissable?: boolean;
|
||||||
|
action?: string;
|
||||||
|
rtl?: boolean;
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
title: "Test info alert",
|
||||||
|
description: "This is a test info alert with a title and description",
|
||||||
|
type: "info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Test warning alert",
|
||||||
|
description: "This is a test warning alert with a title and description",
|
||||||
|
type: "warning",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Test error alert",
|
||||||
|
description: "This is a test error alert with a title and description",
|
||||||
|
type: "error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Test warning with long string",
|
||||||
|
description:
|
||||||
|
"sensor.lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum_lorem_ipsum",
|
||||||
|
type: "warning",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Test success alert",
|
||||||
|
description: "This is a test success alert with a title and description",
|
||||||
|
type: "success",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "This is a test info alert with description only",
|
||||||
|
type: "info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
"This is a test warning alert with a rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really rally really really long description only",
|
||||||
|
type: "warning",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Error with description and list",
|
||||||
|
description: html`<p>
|
||||||
|
This is a test error alert with a title, description and a list
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>List item #1</li>
|
||||||
|
<li>List item #2</li>
|
||||||
|
<li>List item #3</li>
|
||||||
|
</ul>`,
|
||||||
|
type: "error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Test dismissable alert",
|
||||||
|
description: "This is a test success alert that can be dismissable",
|
||||||
|
type: "success",
|
||||||
|
dismissable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Dismissable information",
|
||||||
|
type: "info",
|
||||||
|
dismissable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Error with action",
|
||||||
|
description: "This is a test error alert with action",
|
||||||
|
type: "error",
|
||||||
|
action: "restart",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Unsaved data",
|
||||||
|
description: "You have unsaved data",
|
||||||
|
type: "warning",
|
||||||
|
action: "save",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Dismissable information (RTL)",
|
||||||
|
type: "info",
|
||||||
|
dismissable: true,
|
||||||
|
rtl: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Error with action",
|
||||||
|
description: "This is a test error alert with action (RTL)",
|
||||||
|
type: "error",
|
||||||
|
action: "restart",
|
||||||
|
rtl: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Test success alert (RTL)",
|
||||||
|
description: "This is a test success alert with a title and description",
|
||||||
|
type: "success",
|
||||||
|
rtl: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("demo-ha-alert")
|
||||||
|
export class DemoHaAlert extends LitElement {
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<ha-card header="ha-alert demo">
|
||||||
|
${alerts.map(
|
||||||
|
(alert) => html`
|
||||||
|
<ha-alert
|
||||||
|
.title=${alert.title || ""}
|
||||||
|
.alertType=${alert.type}
|
||||||
|
.dismissable=${alert.dismissable || false}
|
||||||
|
.actionText=${alert.action || ""}
|
||||||
|
.rtl=${alert.rtl || false}
|
||||||
|
>
|
||||||
|
${alert.description}
|
||||||
|
</ha-alert>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-card {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 24px auto;
|
||||||
|
}
|
||||||
|
.condition {
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-ha-alert": DemoHaAlert;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement } from "lit/decorators";
|
import { customElement } from "lit/decorators";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
||||||
@@ -9,7 +9,6 @@ import { actionHandler } from "../../../src/panels/lovelace/common/directives/ac
|
|||||||
export class DemoUtilLongPress extends LitElement {
|
export class DemoUtilLongPress extends LitElement {
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
${this.renderStyle()}
|
|
||||||
${[1, 2, 3].map(
|
${[1, 2, 3].map(
|
||||||
() => html`
|
() => html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
@@ -41,26 +40,22 @@ export class DemoUtilLongPress extends LitElement {
|
|||||||
area.scrollTop = area.scrollHeight;
|
area.scrollTop = area.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderStyle() {
|
static styles = css`
|
||||||
return html`
|
ha-card {
|
||||||
<style>
|
width: 200px;
|
||||||
ha-card {
|
margin: calc(42vh - 140px) auto;
|
||||||
width: 200px;
|
padding: 8px;
|
||||||
margin: calc(42vh - 140px) auto;
|
text-align: center;
|
||||||
padding: 8px;
|
}
|
||||||
text-align: center;
|
ha-card:first-of-type {
|
||||||
}
|
margin-top: 16px;
|
||||||
ha-card:first-of-type {
|
}
|
||||||
margin-top: 16px;
|
ha-card:last-of-type {
|
||||||
}
|
margin-bottom: 16px;
|
||||||
ha-card:last-of-type {
|
}
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
</style>
|
`;
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -172,6 +172,14 @@ class HaGallery extends PolymerElement {
|
|||||||
this.$.notifications.showDialog({ message: ev.detail.message })
|
this.$.notifications.showDialog({ message: ev.detail.message })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.addEventListener("alert-dismissed-clicked", () =>
|
||||||
|
this.$.notifications.showDialog({ message: "Alert dismissed clicked" })
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addEventListener("alert-action-clicked", () =>
|
||||||
|
this.$.notifications.showDialog({ message: "Alert action clicked" })
|
||||||
|
);
|
||||||
|
|
||||||
this.addEventListener("hass-more-info", (ev) => {
|
this.addEventListener("hass-more-info", (ev) => {
|
||||||
if (ev.detail.entityId) {
|
if (ev.detail.entityId) {
|
||||||
this.$.notifications.showDialog({
|
this.$.notifications.showDialog({
|
||||||
|
@@ -13,6 +13,7 @@ import {
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import "web-animations-js/web-animations-next-lite.min";
|
import "web-animations-js/web-animations-next-lite.min";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
@@ -53,7 +54,9 @@ class HassioAddonAudio extends LitElement {
|
|||||||
.header=${this.supervisor.localize("addon.configuration.audio.header")}
|
.header=${this.supervisor.localize("addon.configuration.audio.header")}
|
||||||
>
|
>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
|
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
.label=${this.supervisor.localize(
|
.label=${this.supervisor.localize(
|
||||||
@@ -117,10 +120,6 @@ class HassioAddonAudio extends LitElement {
|
|||||||
paper-dropdown-menu {
|
paper-dropdown-menu {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.errors {
|
|
||||||
color: var(--error-color);
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
paper-item {
|
paper-item {
|
||||||
width: 450px;
|
width: 450px;
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../../src/components/ha-button-menu";
|
import "../../../../src/components/ha-button-menu";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-form/ha-form";
|
import "../../../../src/components/ha-form/ha-form";
|
||||||
import type { HaFormSchema } from "../../../../src/components/ha-form/ha-form";
|
import type { HaFormSchema } from "../../../../src/components/ha-form/ha-form";
|
||||||
import "../../../../src/components/ha-formfield";
|
import "../../../../src/components/ha-formfield";
|
||||||
@@ -135,17 +136,19 @@ class HassioAddonConfig extends LitElement {
|
|||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
.yamlSchema=${ADDON_YAML_SCHEMA}
|
.yamlSchema=${ADDON_YAML_SCHEMA}
|
||||||
></ha-yaml-editor>`}
|
></ha-yaml-editor>`}
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
${!this._yamlMode ||
|
${!this._yamlMode ||
|
||||||
(this._canShowSchema && this.addon.schema) ||
|
(this._canShowSchema && this.addon.schema) ||
|
||||||
this._valid
|
this._valid
|
||||||
? ""
|
? ""
|
||||||
: html`
|
: html`
|
||||||
<div class="errors">
|
<ha-alert alert-type="error">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.configuration.options.invalid_yaml"
|
"addon.configuration.options.invalid_yaml"
|
||||||
)}
|
)}
|
||||||
</div>
|
</ha-alert>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
${hasHiddenOptions
|
${hasHiddenOptions
|
||||||
@@ -256,7 +259,7 @@ class HassioAddonConfig extends LitElement {
|
|||||||
path: "options",
|
path: "options",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.common.update_available",
|
"addon.common.update_available",
|
||||||
"error",
|
"error",
|
||||||
@@ -297,7 +300,7 @@ class HassioAddonConfig extends LitElement {
|
|||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -324,13 +327,7 @@ class HassioAddonConfig extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
.errors {
|
|
||||||
color: var(--error-color);
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
.syntaxerror {
|
|
||||||
color: var(--error-color);
|
|
||||||
}
|
|
||||||
.card-menu {
|
.card-menu {
|
||||||
float: right;
|
float: right;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
|
@@ -10,6 +10,7 @@ import {
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
@@ -62,7 +63,9 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -86,9 +89,9 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
<td>
|
<td>
|
||||||
<paper-input
|
<paper-input
|
||||||
@value-changed=${this._configChanged}
|
@value-changed=${this._configChanged}
|
||||||
placeholder="${this.supervisor.localize(
|
placeholder=${this.supervisor.localize(
|
||||||
"addon.configuration.network.disabled"
|
"addon.configuration.network.disabled"
|
||||||
)}"
|
)}
|
||||||
.value=${item.host ? String(item.host) : ""}
|
.value=${item.host ? String(item.host) : ""}
|
||||||
.container=${item.container}
|
.container=${item.container}
|
||||||
no-label-float
|
no-label-float
|
||||||
@@ -168,7 +171,7 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_reset",
|
"addon.failed_to_reset",
|
||||||
"error",
|
"error",
|
||||||
@@ -204,7 +207,7 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
if (this.addon?.state === "started") {
|
if (this.addon?.state === "started") {
|
||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -225,10 +228,6 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
ha-card {
|
ha-card {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.errors {
|
|
||||||
color: var(--error-color);
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
.card-actions {
|
.card-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-circular-progress";
|
import "../../../../src/components/ha-circular-progress";
|
||||||
import "../../../../src/components/ha-markdown";
|
import "../../../../src/components/ha-markdown";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
@@ -38,7 +39,9 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._content
|
${this._content
|
||||||
? html`<ha-markdown .content=${this._content}></ha-markdown>`
|
? html`<ha-markdown .content=${this._content}></ha-markdown>`
|
||||||
@@ -76,7 +79,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
this.hass,
|
this.hass,
|
||||||
this.addon!.slug
|
this.addon!.slug
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.documentation.get_logs",
|
"addon.documentation.get_logs",
|
||||||
"error",
|
"error",
|
||||||
|
@@ -222,7 +222,7 @@ class HassioAddonDashboard extends LitElement {
|
|||||||
try {
|
try {
|
||||||
const addoninfo = await fetchHassioAddonInfo(this.hass, addon);
|
const addoninfo = await fetchHassioAddonInfo(this.hass, addon);
|
||||||
this.addon = addoninfo;
|
this.addon = addoninfo;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`;
|
this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`;
|
||||||
this.addon = undefined;
|
this.addon = undefined;
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@ import { fireEvent } from "../../../../src/common/dom/fire_event";
|
|||||||
import { navigate } from "../../../../src/common/navigate";
|
import { navigate } from "../../../../src/common/navigate";
|
||||||
import "../../../../src/components/buttons/ha-call-api-button";
|
import "../../../../src/components/buttons/ha-call-api-button";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import "../../../../src/components/ha-label-badge";
|
import "../../../../src/components/ha-label-badge";
|
||||||
import "../../../../src/components/ha-markdown";
|
import "../../../../src/components/ha-markdown";
|
||||||
@@ -122,18 +123,18 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<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.supervisor.localize(
|
||||||
"addon.dashboard.new_update_available",
|
"addon.dashboard.new_update_available",
|
||||||
"name",
|
"name",
|
||||||
this.addon.name,
|
this.addon.name,
|
||||||
"version",
|
"version",
|
||||||
this.addon.version_latest
|
this.addon.version_latest
|
||||||
)}"
|
)}
|
||||||
.description="${this.supervisor.localize(
|
.description=${this.supervisor.localize(
|
||||||
"common.running_version",
|
"common.running_version",
|
||||||
"version",
|
"version",
|
||||||
this.addon.version
|
this.addon.version
|
||||||
)}"
|
)}
|
||||||
icon=${mdiArrowUpBoldCircle}
|
icon=${mdiArrowUpBoldCircle}
|
||||||
iconClass="update"
|
iconClass="update"
|
||||||
></hassio-card-content>
|
></hassio-card-content>
|
||||||
@@ -143,14 +144,14 @@ class HassioAddonInfo extends LitElement {
|
|||||||
this.addon.arch
|
this.addon.arch
|
||||||
)
|
)
|
||||||
? html`
|
? html`
|
||||||
<p class="warning">
|
<ha-alert alert-type="warning">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.not_available_arch"
|
"addon.dashboard.not_available_arch"
|
||||||
)}
|
)}
|
||||||
</p>
|
</ha-alert>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<p class="warning">
|
<ha-alert alert-type="warning">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.not_available_arch",
|
"addon.dashboard.not_available_arch",
|
||||||
"core_version_installed",
|
"core_version_installed",
|
||||||
@@ -158,7 +159,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
"core_version_needed",
|
"core_version_needed",
|
||||||
addonStoreInfo.homeassistant
|
addonStoreInfo.homeassistant
|
||||||
)}
|
)}
|
||||||
</p>
|
</ha-alert>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
@@ -253,7 +254,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.visit_addon_page",
|
"addon.dashboard.visit_addon_page",
|
||||||
"name",
|
"name",
|
||||||
html`<a href="${this.addon.url!}" target="_blank" rel="noreferrer"
|
html`<a href=${this.addon.url!} target="_blank" rel="noreferrer"
|
||||||
>${this.addon.name}</a
|
>${this.addon.name}</a
|
||||||
>`
|
>`
|
||||||
)}
|
)}
|
||||||
@@ -436,10 +437,10 @@ class HassioAddonInfo extends LitElement {
|
|||||||
${this.addon.version
|
${this.addon.version
|
||||||
? html`
|
? html`
|
||||||
<div
|
<div
|
||||||
class="${classMap({
|
class=${classMap({
|
||||||
"addon-options": true,
|
"addon-options": true,
|
||||||
started: this.addon.state === "started",
|
started: this.addon.state === "started",
|
||||||
})}"
|
})}
|
||||||
>
|
>
|
||||||
<ha-settings-row ?three-line=${this.narrow}>
|
<ha-settings-row ?three-line=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
@@ -569,21 +570,23 @@ class HassioAddonInfo extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
${!this.addon.version && addonStoreInfo && !this.addon.available
|
${!this.addon.version && addonStoreInfo && !this.addon.available
|
||||||
? !addonArchIsSupported(
|
? !addonArchIsSupported(
|
||||||
this.supervisor.info.supported_arch,
|
this.supervisor.info.supported_arch,
|
||||||
this.addon.arch
|
this.addon.arch
|
||||||
)
|
)
|
||||||
? html`
|
? html`
|
||||||
<p class="warning">
|
<ha-alert alert-type="warning">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.not_available_arch"
|
"addon.dashboard.not_available_arch"
|
||||||
)}
|
)}
|
||||||
</p>
|
</ha-alert>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<p class="warning">
|
<ha-alert alert-type="warning">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.not_available_version",
|
"addon.dashboard.not_available_version",
|
||||||
"core_version_installed",
|
"core_version_installed",
|
||||||
@@ -591,7 +594,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
"core_version_needed",
|
"core_version_needed",
|
||||||
addonStoreInfo!.homeassistant
|
addonStoreInfo!.homeassistant
|
||||||
)}
|
)}
|
||||||
</p>
|
</ha-alert>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
@@ -793,7 +796,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -815,7 +818,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -837,7 +840,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -859,7 +862,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "security",
|
path: "security",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -881,7 +884,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "option",
|
path: "option",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.failed_to_save",
|
"addon.failed_to_save",
|
||||||
"error",
|
"error",
|
||||||
@@ -909,7 +912,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
title: this.supervisor.localize("addon.dashboard.changelog"),
|
title: this.supervisor.localize("addon.dashboard.changelog"),
|
||||||
content,
|
content,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"addon.dashboard.action_error.get_changelog"
|
"addon.dashboard.action_error.get_changelog"
|
||||||
@@ -931,7 +934,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "install",
|
path: "install",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.install"),
|
title: this.supervisor.localize("addon.dashboard.action_error.install"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -952,7 +955,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "stop",
|
path: "stop",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.stop"),
|
title: this.supervisor.localize("addon.dashboard.action_error.stop"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -973,7 +976,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "stop",
|
path: "stop",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.restart"),
|
title: this.supervisor.localize("addon.dashboard.action_error.restart"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -1032,7 +1035,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
button.progress = false;
|
button.progress = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to validate addon configuration",
|
title: "Failed to validate addon configuration",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -1050,7 +1053,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "start",
|
path: "start",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("addon.dashboard.action_error.start"),
|
title: this.supervisor.localize("addon.dashboard.action_error.start"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -1088,7 +1091,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
path: "uninstall",
|
path: "uninstall",
|
||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"addon.dashboard.action_error.uninstall"
|
"addon.dashboard.action_error.uninstall"
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import {
|
import {
|
||||||
fetchHassioAddonLogs,
|
fetchHassioAddonLogs,
|
||||||
@@ -34,7 +35,9 @@ class HassioAddonLogs extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<h1>${this.addon.name}</h1>
|
<h1>${this.addon.name}</h1>
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._content
|
${this._content
|
||||||
? html`<hassio-ansi-to-html
|
? html`<hassio-ansi-to-html
|
||||||
@@ -60,10 +63,6 @@ class HassioAddonLogs extends LitElement {
|
|||||||
ha-card {
|
ha-card {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.errors {
|
|
||||||
color: var(--error-color);
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -72,7 +71,7 @@ class HassioAddonLogs extends LitElement {
|
|||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
try {
|
try {
|
||||||
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
|
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.logs.get_logs",
|
"addon.logs.get_logs",
|
||||||
"error",
|
"error",
|
||||||
|
@@ -14,7 +14,7 @@ import { customElement, property, query, state } from "lit/decorators";
|
|||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
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 relativeTime from "../../../src/common/datetime/relative_time";
|
import { relativeTime } from "../../../src/common/datetime/relative_time";
|
||||||
import { HASSDomEvent } from "../../../src/common/dom/fire_event";
|
import { HASSDomEvent } from "../../../src/common/dom/fire_event";
|
||||||
import {
|
import {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
@@ -133,7 +133,7 @@ export class HassioBackups extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (entry: string) =>
|
template: (entry: string) =>
|
||||||
relativeTime(new Date(entry), this.hass.localize),
|
relativeTime(new Date(entry), this.hass.locale),
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
title: "",
|
title: "",
|
||||||
@@ -294,7 +294,7 @@ export class HassioBackups extends LitElement {
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
this._selectedBackups.map((slug) => removeBackup(this.hass, slug))
|
this._selectedBackups.map((slug) => removeBackup(this.hass, slug))
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("backup.failed_to_delete"),
|
title: this.supervisor.localize("backup.failed_to_delete"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
|
@@ -37,7 +37,7 @@ class HassioCardContent extends LitElement {
|
|||||||
${this.iconImage
|
${this.iconImage
|
||||||
? html`
|
? html`
|
||||||
<div class="icon_image ${this.iconClass}">
|
<div class="icon_image ${this.iconClass}">
|
||||||
<img src="${this.iconImage}" .title=${this.iconTitle} />
|
<img src=${this.iconImage} .title=${this.iconTitle} />
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
@@ -70,7 +70,7 @@ export class HassioUploadBackup extends LitElement {
|
|||||||
try {
|
try {
|
||||||
const backup = await uploadBackup(this.hass, file);
|
const backup = await uploadBackup(this.hass, file);
|
||||||
fireEvent(this, "backup-uploaded", { backup: backup.data });
|
fireEvent(this, "backup-uploaded", { backup: backup.data });
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Upload failed",
|
title: "Upload failed",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
|
@@ -181,9 +181,7 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
>
|
>
|
||||||
<ha-checkbox
|
<ha-checkbox
|
||||||
.checked=${this.homeAssistant}
|
.checked=${this.homeAssistant}
|
||||||
@click=${() => {
|
@click=${this.toggleHomeAssistant}
|
||||||
this.homeAssistant = !this.homeAssistant;
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
</ha-checkbox>
|
</ha-checkbox>
|
||||||
</ha-formfield>
|
</ha-formfield>
|
||||||
@@ -272,6 +270,10 @@ export class SupervisorBackupContent extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toggleHomeAssistant() {
|
||||||
|
this.homeAssistant = !this.homeAssistant;
|
||||||
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
.partial-picker ha-formfield {
|
.partial-picker ha-formfield {
|
||||||
|
@@ -20,10 +20,10 @@ class SupervisorMetric extends LitElement {
|
|||||||
<div slot="description" .title=${this.tooltip ?? ""}>
|
<div slot="description" .title=${this.tooltip ?? ""}>
|
||||||
<span class="value"> ${roundedValue} % </span>
|
<span class="value"> ${roundedValue} % </span>
|
||||||
<ha-bar
|
<ha-bar
|
||||||
class="${classMap({
|
class=${classMap({
|
||||||
"target-warning": roundedValue > 50,
|
"target-warning": roundedValue > 50,
|
||||||
"target-critical": roundedValue > 85,
|
"target-critical": roundedValue > 85,
|
||||||
})}"
|
})}
|
||||||
.value=${this.value}
|
.value=${this.value}
|
||||||
></ha-bar>
|
></ha-bar>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -3,7 +3,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import { navigate } from "../../../src/common/navigate";
|
import { navigate } from "../../../src/common/navigate";
|
||||||
import { compare } from "../../../src/common/string/compare";
|
import { stringCompare } from "../../../src/common/string/compare";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||||
import { haStyle } from "../../../src/resources/styles";
|
import { haStyle } from "../../../src/resources/styles";
|
||||||
@@ -33,7 +33,7 @@ class HassioAddons extends LitElement {
|
|||||||
</ha-card>
|
</ha-card>
|
||||||
`
|
`
|
||||||
: this.supervisor.supervisor.addons
|
: this.supervisor.supervisor.addons
|
||||||
.sort((a, b) => compare(a.name, b.name))
|
.sort((a, b) => stringCompare(a.name, b.name))
|
||||||
.map(
|
.map(
|
||||||
(addon) => html`
|
(addon) => html`
|
||||||
<ha-card .addon=${addon} @click=${this._addonTapped}>
|
<ha-card .addon=${addon} @click=${this._addonTapped}>
|
||||||
|
@@ -136,7 +136,7 @@ export class HassioUpdate extends LitElement {
|
|||||||
</ha-settings-row>
|
</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>
|
||||||
${this.supervisor.localize("common.release_notes")}
|
${this.supervisor.localize("common.release_notes")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
@@ -206,7 +206,7 @@ export class HassioUpdate extends LitElement {
|
|||||||
fireEvent(this, "supervisor-collection-refresh", {
|
fireEvent(this, "supervisor-collection-refresh", {
|
||||||
collection: item.key,
|
collection: item.key,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// 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 (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||||
|
@@ -6,6 +6,7 @@ import { customElement, property, query, state } from "lit/decorators";
|
|||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import { slugify } from "../../../../src/common/string/slugify";
|
import { slugify } from "../../../../src/common/string/slugify";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-button-menu";
|
import "../../../../src/components/ha-button-menu";
|
||||||
import "../../../../src/components/ha-header-bar";
|
import "../../../../src/components/ha-header-bar";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
import "../../../../src/components/ha-svg-icon";
|
||||||
@@ -27,6 +28,7 @@ import "../../components/supervisor-backup-content";
|
|||||||
import type { SupervisorBackupContent } from "../../components/supervisor-backup-content";
|
import type { SupervisorBackupContent } from "../../components/supervisor-backup-content";
|
||||||
import { HassioBackupDialogParams } from "./show-dialog-hassio-backup";
|
import { HassioBackupDialogParams } from "./show-dialog-hassio-backup";
|
||||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||||
|
import { stopPropagation } from "../../../../src/common/dom/stop_propagation";
|
||||||
|
|
||||||
@customElement("dialog-hassio-backup")
|
@customElement("dialog-hassio-backup")
|
||||||
class HassioBackupDialog
|
class HassioBackupDialog
|
||||||
@@ -89,7 +91,9 @@ class HassioBackupDialog
|
|||||||
.localize=${this._dialogParams.localize}
|
.localize=${this._dialogParams.localize}
|
||||||
>
|
>
|
||||||
</supervisor-backup-content>`}
|
</supervisor-backup-content>`}
|
||||||
${this._error ? html`<p class="error">Error: ${this._error}</p>` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
|
|
||||||
<mwc-button
|
<mwc-button
|
||||||
.disabled=${this._restoringBackup}
|
.disabled=${this._restoringBackup}
|
||||||
@@ -104,7 +108,7 @@ class HassioBackupDialog
|
|||||||
fixed
|
fixed
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
@action=${this._handleMenuAction}
|
@action=${this._handleMenuAction}
|
||||||
@closed=${(ev: Event) => ev.stopPropagation()}
|
@closed=${stopPropagation}
|
||||||
>
|
>
|
||||||
<mwc-icon-button slot="trigger" alt="menu">
|
<mwc-icon-button slot="trigger" alt="menu">
|
||||||
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
|
||||||
@@ -280,9 +284,9 @@ class HassioBackupDialog
|
|||||||
atLeastVersion(this.hass.config.version, 2021, 9) ? "DELETE" : "POST",
|
atLeastVersion(this.hass.config.version, 2021, 9) ? "DELETE" : "POST",
|
||||||
`hassio/${
|
`hassio/${
|
||||||
atLeastVersion(this.hass.config.version, 2021, 9)
|
atLeastVersion(this.hass.config.version, 2021, 9)
|
||||||
? "backups"
|
? `backups/${this._backup!.slug}`
|
||||||
: "snapshots"
|
: `snapshots/${this._backup!.slug}/remove`
|
||||||
}/${this._backup!.slug}/remove`
|
}`
|
||||||
)
|
)
|
||||||
.then(
|
.then(
|
||||||
() => {
|
() => {
|
||||||
@@ -308,7 +312,7 @@ class HassioBackupDialog
|
|||||||
: "snapshots"
|
: "snapshots"
|
||||||
}/${this._backup!.slug}/download`
|
}/${this._backup!.slug}/download`
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
});
|
});
|
||||||
|
@@ -2,6 +2,7 @@ import "@material/mwc-button";
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
||||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||||
@@ -62,7 +63,9 @@ class HassioCreateBackupDialog extends LitElement {
|
|||||||
.supervisor=${this._dialogParams.supervisor}
|
.supervisor=${this._dialogParams.supervisor}
|
||||||
>
|
>
|
||||||
</supervisor-backup-content>`}
|
</supervisor-backup-content>`}
|
||||||
${this._error ? html`<p class="error">Error: ${this._error}</p>` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
|
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
|
||||||
${this._dialogParams.supervisor.localize("common.close")}
|
${this._dialogParams.supervisor.localize("common.close")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
@@ -124,7 +127,7 @@ class HassioCreateBackupDialog extends LitElement {
|
|||||||
|
|
||||||
this._dialogParams!.onCreate();
|
this._dialogParams!.onCreate();
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
}
|
}
|
||||||
this._creatingBackup = false;
|
this._creatingBackup = false;
|
||||||
|
193
hassio/src/dialogs/datadisk/dialog-hassio-datadisk.ts
Normal file
193
hassio/src/dialogs/datadisk/dialog-hassio-datadisk.ts
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
|
import "../../../../src/components/ha-circular-progress";
|
||||||
|
import "../../../../src/components/ha-markdown";
|
||||||
|
import {
|
||||||
|
extractApiErrorMessage,
|
||||||
|
ignoreSupervisorError,
|
||||||
|
} from "../../../../src/data/hassio/common";
|
||||||
|
import {
|
||||||
|
DatadiskList,
|
||||||
|
listDatadisks,
|
||||||
|
moveDatadisk,
|
||||||
|
} from "../../../../src/data/hassio/host";
|
||||||
|
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||||
|
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
|
||||||
|
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
import { HassioDatatiskDialogParams } from "./show-dialog-hassio-datadisk";
|
||||||
|
|
||||||
|
const calculateMoveTime = memoizeOne((supervisor: Supervisor): number => {
|
||||||
|
const speed = supervisor.host.disk_life_time !== "" ? 30 : 10;
|
||||||
|
const moveTime = (supervisor.host.disk_used * 1000) / 60 / speed;
|
||||||
|
const rebootTime = (supervisor.host.startup_time * 4) / 60;
|
||||||
|
return Math.ceil((moveTime + rebootTime) / 10) * 10;
|
||||||
|
});
|
||||||
|
|
||||||
|
@customElement("dialog-hassio-datadisk")
|
||||||
|
class HassioDatadiskDialog extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private dialogParams?: HassioDatatiskDialogParams;
|
||||||
|
|
||||||
|
@state() private selectedDevice?: string;
|
||||||
|
|
||||||
|
@state() private devices?: DatadiskList["devices"];
|
||||||
|
|
||||||
|
@state() private moving = false;
|
||||||
|
|
||||||
|
public showDialog(params: HassioDatatiskDialogParams) {
|
||||||
|
this.dialogParams = params;
|
||||||
|
listDatadisks(this.hass).then((data) => {
|
||||||
|
this.devices = data.devices;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog(): void {
|
||||||
|
this.dialogParams = undefined;
|
||||||
|
this.selectedDevice = undefined;
|
||||||
|
this.devices = undefined;
|
||||||
|
this.moving = false;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.dialogParams) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
let heading: string;
|
||||||
|
let content: TemplateResult;
|
||||||
|
|
||||||
|
if (this.moving) {
|
||||||
|
heading = this.dialogParams.supervisor.localize(
|
||||||
|
"dialog.datadisk_move.moving"
|
||||||
|
);
|
||||||
|
content = html`
|
||||||
|
<ha-circular-progress alt="Moving" size="large" active>
|
||||||
|
</ha-circular-progress>
|
||||||
|
<p class="progress-text">
|
||||||
|
${this.dialogParams.supervisor.localize(
|
||||||
|
"dialog.datadisk_move.moving_desc"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
heading = this.dialogParams.supervisor.localize(
|
||||||
|
"dialog.datadisk_move.title"
|
||||||
|
);
|
||||||
|
content = html`
|
||||||
|
${this.devices?.length
|
||||||
|
? html`
|
||||||
|
${this.dialogParams.supervisor.localize(
|
||||||
|
"dialog.datadisk_move.description",
|
||||||
|
{
|
||||||
|
current_path: this.dialogParams.supervisor.os.data_disk,
|
||||||
|
time: calculateMoveTime(this.dialogParams.supervisor),
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
<paper-dropdown-menu
|
||||||
|
.label=${this.dialogParams.supervisor.localize(
|
||||||
|
"dialog.datadisk_move.select_device"
|
||||||
|
)}
|
||||||
|
@value-changed=${this._select_device}
|
||||||
|
>
|
||||||
|
<paper-listbox slot="dropdown-content">
|
||||||
|
${this.devices.map(
|
||||||
|
(device) => html`<paper-item>${device}</paper-item>`
|
||||||
|
)}
|
||||||
|
</paper-listbox>
|
||||||
|
</paper-dropdown-menu>
|
||||||
|
`
|
||||||
|
: this.devices === undefined
|
||||||
|
? this.dialogParams.supervisor.localize(
|
||||||
|
"dialog.datadisk_move.loading_devices"
|
||||||
|
)
|
||||||
|
: this.dialogParams.supervisor.localize(
|
||||||
|
"dialog.datadisk_move.no_devices"
|
||||||
|
)}
|
||||||
|
|
||||||
|
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
|
||||||
|
${this.dialogParams.supervisor.localize(
|
||||||
|
"dialog.datadisk_move.cancel"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
|
||||||
|
<mwc-button
|
||||||
|
.disabled=${!this.selectedDevice}
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${this._moveDatadisk}
|
||||||
|
>
|
||||||
|
${this.dialogParams.supervisor.localize("dialog.datadisk_move.move")}
|
||||||
|
</mwc-button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
scrimClickAction
|
||||||
|
escapeKeyAction
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
?hideActions=${this.moving}
|
||||||
|
.heading=${heading}
|
||||||
|
>
|
||||||
|
${content}
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _select_device(event) {
|
||||||
|
this.selectedDevice = event.detail.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _moveDatadisk() {
|
||||||
|
this.moving = true;
|
||||||
|
try {
|
||||||
|
await moveDatadisk(this.hass, this.selectedDevice!);
|
||||||
|
} catch (err: any) {
|
||||||
|
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||||
|
showAlertDialog(this, {
|
||||||
|
title: this.dialogParams!.supervisor.localize(
|
||||||
|
"system.host.failed_to_move"
|
||||||
|
),
|
||||||
|
text: extractApiErrorMessage(err),
|
||||||
|
});
|
||||||
|
this.closeDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyle,
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
paper-dropdown-menu {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
ha-circular-progress {
|
||||||
|
display: block;
|
||||||
|
margin: 32px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-hassio-datadisk": HassioDatadiskDialog;
|
||||||
|
}
|
||||||
|
}
|
17
hassio/src/dialogs/datadisk/show-dialog-hassio-datadisk.ts
Normal file
17
hassio/src/dialogs/datadisk/show-dialog-hassio-datadisk.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
|
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||||
|
|
||||||
|
export interface HassioDatatiskDialogParams {
|
||||||
|
supervisor: Supervisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showHassioDatadiskDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
dialogParams: HassioDatatiskDialogParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-hassio-datadisk",
|
||||||
|
dialogImport: () => import("./dialog-hassio-datadisk"),
|
||||||
|
dialogParams,
|
||||||
|
});
|
||||||
|
};
|
@@ -4,7 +4,7 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import "../../../../src/common/search/search-input";
|
import "../../../../src/common/search/search-input";
|
||||||
import { compare } from "../../../../src/common/string/compare";
|
import { stringCompare } from "../../../../src/common/string/compare";
|
||||||
import "../../../../src/components/ha-dialog";
|
import "../../../../src/components/ha-dialog";
|
||||||
import "../../../../src/components/ha-expansion-panel";
|
import "../../../../src/components/ha-expansion-panel";
|
||||||
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
|
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
|
||||||
@@ -27,7 +27,7 @@ const _filterDevices = memoizeOne(
|
|||||||
.toLocaleLowerCase()
|
.toLocaleLowerCase()
|
||||||
.includes(filter))
|
.includes(filter))
|
||||||
)
|
)
|
||||||
.sort((a, b) => compare(a.name, b.name))
|
.sort((a, b) => stringCompare(a.name, b.name))
|
||||||
);
|
);
|
||||||
|
|
||||||
@customElement("dialog-hassio-hardware")
|
@customElement("dialog-hassio-hardware")
|
||||||
|
@@ -10,6 +10,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { cache } from "lit/directives/cache";
|
import { cache } from "lit/directives/cache";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
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";
|
||||||
@@ -251,9 +252,9 @@ export class DialogHassioNetwork
|
|||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this._dirty
|
${this._dirty
|
||||||
? html`<div class="warning">
|
? html`<ha-alert alert-type="warning">
|
||||||
${this.supervisor.localize("dialog.network.warning")}
|
${this.supervisor.localize("dialog.network.warning")}
|
||||||
</div>`
|
</ha-alert>`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
@@ -286,7 +287,7 @@ export class DialogHassioNetwork
|
|||||||
this.hass,
|
this.hass,
|
||||||
this._interface.interface
|
this._interface.interface
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: "Failed to scan for accesspoints",
|
title: "Failed to scan for accesspoints",
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -447,7 +448,7 @@ export class DialogHassioNetwork
|
|||||||
this._interface!.interface,
|
this._interface!.interface,
|
||||||
interfaceOptions
|
interfaceOptions
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("dialog.network.failed_to_change"),
|
title: this.supervisor.localize("dialog.network.failed_to_change"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
|
@@ -190,7 +190,7 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
await addHassioDockerRegistry(this.hass, data);
|
await addHassioDockerRegistry(this.hass, data);
|
||||||
await this._loadRegistries();
|
await this._loadRegistries();
|
||||||
this._addingRegistry = false;
|
this._addingRegistry = false;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("dialog.registries.failed_to_add"),
|
title: this.supervisor.localize("dialog.registries.failed_to_add"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -204,7 +204,7 @@ class HassioRegistriesDialog extends LitElement {
|
|||||||
try {
|
try {
|
||||||
await removeHassioDockerRegistry(this.hass, entry.registry);
|
await removeHassioDockerRegistry(this.hass, entry.registry);
|
||||||
await this._loadRegistries();
|
await this._loadRegistries();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("dialog.registries.failed_to_remove"),
|
title: this.supervisor.localize("dialog.registries.failed_to_remove"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
|
@@ -9,6 +9,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
|||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
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";
|
||||||
@@ -75,7 +76,9 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
this._dialogParams!.supervisor.localize("dialog.repositories.title")
|
this._dialogParams!.supervisor.localize("dialog.repositories.title")
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
${this._error ? html`<div class="error">${this._error}</div>` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
<div class="form">
|
<div class="form">
|
||||||
${repositories.length
|
${repositories.length
|
||||||
? repositories.map(
|
? repositories.map(
|
||||||
@@ -182,7 +185,7 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
this._repositories = addonsinfo.repositories;
|
this._repositories = addonsinfo.repositories;
|
||||||
|
|
||||||
fireEvent(this, "supervisor-collection-refresh", { collection: "addon" });
|
fireEvent(this, "supervisor-collection-refresh", { collection: "addon" });
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,7 +207,7 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
await this._loadData();
|
await this._loadData();
|
||||||
|
|
||||||
input.value = "";
|
input.value = "";
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
}
|
}
|
||||||
this._processing = false;
|
this._processing = false;
|
||||||
@@ -226,7 +229,7 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
addons_repositories: newRepositories,
|
addons_repositories: newRepositories,
|
||||||
});
|
});
|
||||||
await this._loadData();
|
await this._loadData();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ export const suggestAddonRestart = async (
|
|||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
try {
|
try {
|
||||||
await restartHassioAddon(hass, addon.slug);
|
await restartHassioAddon(hass, addon.slug);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(element, {
|
showAlertDialog(element, {
|
||||||
title: supervisor.localize(
|
title: supervisor.localize(
|
||||||
"common.failed_to_restart_name",
|
"common.failed_to_restart_name",
|
||||||
|
@@ -2,6 +2,7 @@ import "@material/mwc-button/mwc-button";
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, state } from "lit/decorators";
|
import { customElement, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
|
import "../../../../src/components/ha-alert";
|
||||||
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-settings-row";
|
import "../../../../src/components/ha-settings-row";
|
||||||
@@ -128,7 +129,9 @@ class DialogSupervisorUpdate extends LitElement {
|
|||||||
this._dialogParams.name
|
this._dialogParams.name
|
||||||
)}
|
)}
|
||||||
</p>`}
|
</p>`}
|
||||||
${this._error ? html`<p class="error">${this._error}</p>` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -145,7 +148,7 @@ class DialogSupervisorUpdate extends LitElement {
|
|||||||
this.hass,
|
this.hass,
|
||||||
this._dialogParams!.backupParams
|
this._dialogParams!.backupParams
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
this._action = null;
|
this._action = null;
|
||||||
return;
|
return;
|
||||||
@@ -155,7 +158,7 @@ class DialogSupervisorUpdate extends LitElement {
|
|||||||
this._action = "update";
|
this._action = "update";
|
||||||
try {
|
try {
|
||||||
await this._dialogParams!.updateHandler!();
|
await this._dialogParams!.updateHandler!();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||||
this._error = extractApiErrorMessage(err);
|
this._error = extractApiErrorMessage(err);
|
||||||
this._action = null;
|
this._action = null;
|
||||||
|
@@ -87,7 +87,7 @@ class HassioMyRedirect extends LitElement {
|
|||||||
let url: string;
|
let url: string;
|
||||||
try {
|
try {
|
||||||
url = this._createRedirectUrl(redirect);
|
url = this._createRedirectUrl(redirect);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize("my.error");
|
this._error = this.supervisor.localize("my.error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -91,7 +91,7 @@ class HassioIngressView extends LitElement {
|
|||||||
if (requestedAddon) {
|
if (requestedAddon) {
|
||||||
try {
|
try {
|
||||||
addonInfo = await fetchHassioAddonInfo(this.hass, requestedAddon);
|
addonInfo = await fetchHassioAddonInfo(this.hass, requestedAddon);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
title: requestedAddon,
|
title: requestedAddon,
|
||||||
@@ -145,7 +145,7 @@ class HassioIngressView extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
addon = await fetchHassioAddonInfo(this.hass, addonSlug);
|
addon = await fetchHassioAddonInfo(this.hass, addonSlug);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
text: "Unable to fetch add-on info to start Ingress",
|
text: "Unable to fetch add-on info to start Ingress",
|
||||||
title: "Supervisor",
|
title: "Supervisor",
|
||||||
@@ -179,7 +179,7 @@ class HassioIngressView extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
session = await createSessionPromise;
|
session = await createSessionPromise;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
text: "Unable to create an Ingress session",
|
text: "Unable to create an Ingress session",
|
||||||
title: addon.name,
|
title: addon.name,
|
||||||
@@ -195,7 +195,7 @@ class HassioIngressView extends LitElement {
|
|||||||
this._sessionKeepAlive = window.setInterval(async () => {
|
this._sessionKeepAlive = window.setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
await validateHassioSession(this.hass, session);
|
await validateHassioSession(this.hass, session);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
session = await createHassioSession(this.hass);
|
session = await createHassioSession(this.hass);
|
||||||
}
|
}
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
@@ -144,7 +144,7 @@ class HassioCoreInfo extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await restartCore(this.hass);
|
await restartCore(this.hass);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (this.hass.connection.connected) {
|
if (this.hass.connection.connected) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical } from "@mdi/js";
|
import { mdiDotsVertical } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
@@ -40,8 +39,9 @@ import {
|
|||||||
roundWithOneDecimal,
|
roundWithOneDecimal,
|
||||||
} from "../../../src/util/calculate";
|
} from "../../../src/util/calculate";
|
||||||
import "../components/supervisor-metric";
|
import "../components/supervisor-metric";
|
||||||
import { showNetworkDialog } from "../dialogs/network/show-dialog-network";
|
import { showHassioDatadiskDialog } from "../dialogs/datadisk/show-dialog-hassio-datadisk";
|
||||||
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
|
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
|
||||||
|
import { showNetworkDialog } from "../dialogs/network/show-dialog-network";
|
||||||
import { hassioStyle } from "../resources/hassio-style";
|
import { hassioStyle } from "../resources/hassio-style";
|
||||||
|
|
||||||
@customElement("hassio-host-info")
|
@customElement("hassio-host-info")
|
||||||
@@ -180,20 +180,38 @@ class HassioHostInfo extends LitElement {
|
|||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
|
||||||
<ha-button-menu
|
<ha-button-menu corner="BOTTOM_START">
|
||||||
corner="BOTTOM_START"
|
|
||||||
@action=${this._handleMenuAction}
|
|
||||||
>
|
|
||||||
<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>
|
<mwc-list-item
|
||||||
|
.action=${"hardware"}
|
||||||
|
@click=${this._handleMenuAction}
|
||||||
|
>
|
||||||
${this.supervisor.localize("system.host.hardware")}
|
${this.supervisor.localize("system.host.hardware")}
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
${this.supervisor.host.features.includes("haos")
|
${this.supervisor.host.features.includes("haos")
|
||||||
? html`<mwc-list-item>
|
? html`
|
||||||
${this.supervisor.localize("system.host.import_from_usb")}
|
<mwc-list-item
|
||||||
</mwc-list-item>`
|
.action=${"import_from_usb"}
|
||||||
|
@click=${this._handleMenuAction}
|
||||||
|
>
|
||||||
|
${this.supervisor.localize("system.host.import_from_usb")}
|
||||||
|
</mwc-list-item>
|
||||||
|
${this.supervisor.host.features.includes("os_agent") &&
|
||||||
|
atLeastVersion(this.supervisor.host.agent_version, 1, 2, 0)
|
||||||
|
? html`
|
||||||
|
<mwc-list-item
|
||||||
|
.action=${"move_datadisk"}
|
||||||
|
@click=${this._handleMenuAction}
|
||||||
|
>
|
||||||
|
${this.supervisor.localize(
|
||||||
|
"system.host.move_datadisk"
|
||||||
|
)}
|
||||||
|
</mwc-list-item>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-button-menu>
|
</ha-button-menu>
|
||||||
</div>
|
</div>
|
||||||
@@ -216,22 +234,31 @@ class HassioHostInfo extends LitElement {
|
|||||||
return network_info.interfaces.find((a) => a.primary)?.ipv4?.address![0];
|
return network_info.interfaces.find((a) => a.primary)?.ipv4?.address![0];
|
||||||
});
|
});
|
||||||
|
|
||||||
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
private async _handleMenuAction(ev) {
|
||||||
switch (ev.detail.index) {
|
switch ((ev.target as any).action) {
|
||||||
case 0:
|
case "hardware":
|
||||||
await this._showHardware();
|
await this._showHardware();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case "import_from_usb":
|
||||||
await this._importFromUSB();
|
await this._importFromUSB();
|
||||||
break;
|
break;
|
||||||
|
case "move_datadisk":
|
||||||
|
await this._moveDatadisk();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _moveDatadisk(): void {
|
||||||
|
showHassioDatadiskDialog(this, {
|
||||||
|
supervisor: this.supervisor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private async _showHardware(): Promise<void> {
|
private async _showHardware(): Promise<void> {
|
||||||
let hardware;
|
let hardware;
|
||||||
try {
|
try {
|
||||||
hardware = await fetchHassioHardwareInfo(this.hass);
|
hardware = await fetchHassioHardwareInfo(this.hass);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"system.host.failed_to_get_hardware_list"
|
"system.host.failed_to_get_hardware_list"
|
||||||
@@ -261,7 +288,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await rebootHost(this.hass);
|
await rebootHost(this.hass);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// Ignore connection errors, these are all expected
|
// Ignore connection errors, these are all expected
|
||||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
@@ -291,7 +318,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await shutdownHost(this.hass);
|
await shutdownHost(this.hass);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// Ignore connection errors, these are all expected
|
// Ignore connection errors, these are all expected
|
||||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
@@ -332,7 +359,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
try {
|
try {
|
||||||
await updateOS(this.hass);
|
await updateOS(this.hass);
|
||||||
fireEvent(this, "supervisor-collection-refresh", { collection: "os" });
|
fireEvent(this, "supervisor-collection-refresh", { collection: "os" });
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (this.hass.connection.connected) {
|
if (this.hass.connection.connected) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
@@ -370,7 +397,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
fireEvent(this, "supervisor-collection-refresh", {
|
fireEvent(this, "supervisor-collection-refresh", {
|
||||||
collection: "host",
|
collection: "host",
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("system.host.failed_to_set_hostname"),
|
title: this.supervisor.localize("system.host.failed_to_set_hostname"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -385,7 +412,7 @@ class HassioHostInfo extends LitElement {
|
|||||||
fireEvent(this, "supervisor-collection-refresh", {
|
fireEvent(this, "supervisor-collection-refresh", {
|
||||||
collection: "host",
|
collection: "host",
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"system.host.failed_to_import_from_usb"
|
"system.host.failed_to_import_from_usb"
|
||||||
|
@@ -3,6 +3,7 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
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 "../../../src/components/buttons/ha-progress-button";
|
import "../../../src/components/buttons/ha-progress-button";
|
||||||
|
import "../../../src/components/ha-alert";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/ha-settings-row";
|
import "../../../src/components/ha-settings-row";
|
||||||
import "../../../src/components/ha-switch";
|
import "../../../src/components/ha-switch";
|
||||||
@@ -33,16 +34,18 @@ import { hassioStyle } from "../resources/hassio-style";
|
|||||||
const UNSUPPORTED_REASON_URL = {
|
const UNSUPPORTED_REASON_URL = {
|
||||||
apparmor: "/more-info/unsupported/apparmor",
|
apparmor: "/more-info/unsupported/apparmor",
|
||||||
container: "/more-info/unsupported/container",
|
container: "/more-info/unsupported/container",
|
||||||
|
content_trust: "/more-info/unsupported/content_trust",
|
||||||
dbus: "/more-info/unsupported/dbus",
|
dbus: "/more-info/unsupported/dbus",
|
||||||
docker_configuration: "/more-info/unsupported/docker_configuration",
|
docker_configuration: "/more-info/unsupported/docker_configuration",
|
||||||
docker_version: "/more-info/unsupported/docker_version",
|
docker_version: "/more-info/unsupported/docker_version",
|
||||||
job_conditions: "/more-info/unsupported/job_conditions",
|
job_conditions: "/more-info/unsupported/job_conditions",
|
||||||
lxc: "/more-info/unsupported/lxc",
|
lxc: "/more-info/unsupported/lxc",
|
||||||
network_manager: "/more-info/unsupported/network_manager",
|
network_manager: "/more-info/unsupported/network_manager",
|
||||||
|
os_agent: "/more-info/unsupported/os_agent",
|
||||||
os: "/more-info/unsupported/os",
|
os: "/more-info/unsupported/os",
|
||||||
privileged: "/more-info/unsupported/privileged",
|
privileged: "/more-info/unsupported/privileged",
|
||||||
|
source_mods: "/more-info/unsupported/source_mods",
|
||||||
systemd: "/more-info/unsupported/systemd",
|
systemd: "/more-info/unsupported/systemd",
|
||||||
content_trust: "/more-info/unsupported/content_trust",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const UNHEALTHY_REASON_URL = {
|
const UNHEALTHY_REASON_URL = {
|
||||||
@@ -170,31 +173,25 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
></ha-switch>
|
></ha-switch>
|
||||||
</ha-settings-row>`
|
</ha-settings-row>`
|
||||||
: ""
|
: ""
|
||||||
: html`<div class="error">
|
: html`<ha-alert
|
||||||
|
alert-type="warning"
|
||||||
|
.actionText=${this.supervisor.localize("common.learn_more")}
|
||||||
|
@alert-action-clicked=${this._unsupportedDialog}
|
||||||
|
>
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"system.supervisor.unsupported_title"
|
"system.supervisor.unsupported_title"
|
||||||
)}
|
)}
|
||||||
<button
|
</ha-alert>`}
|
||||||
class="link"
|
|
||||||
.title=${this.supervisor.localize("common.learn_more")}
|
|
||||||
@click=${this._unsupportedDialog}
|
|
||||||
>
|
|
||||||
Learn more
|
|
||||||
</button>
|
|
||||||
</div>`}
|
|
||||||
${!this.supervisor.supervisor.healthy
|
${!this.supervisor.supervisor.healthy
|
||||||
? html`<div class="error">
|
? html`<ha-alert
|
||||||
|
alert-type="error"
|
||||||
|
.actionText=${this.supervisor.localize("common.learn_more")}
|
||||||
|
@alert-action-clicked=${this._unhealthyDialog}
|
||||||
|
>
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"system.supervisor.unhealthy_title"
|
"system.supervisor.unhealthy_title"
|
||||||
)}
|
)}
|
||||||
<button
|
</ha-alert>`
|
||||||
class="link"
|
|
||||||
.title=${this.supervisor.localize("common.learn_more")}
|
|
||||||
@click=${this._unhealthyDialog}
|
|
||||||
>
|
|
||||||
Learn more
|
|
||||||
</button>
|
|
||||||
</div>`
|
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="metrics-block">
|
<div class="metrics-block">
|
||||||
@@ -285,7 +282,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
await setSupervisorOption(this.hass, data);
|
await setSupervisorOption(this.hass, data);
|
||||||
await this._reloadSupervisor();
|
await this._reloadSupervisor();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"system.supervisor.failed_to_set_option"
|
"system.supervisor.failed_to_set_option"
|
||||||
@@ -303,7 +300,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this._reloadSupervisor();
|
await this._reloadSupervisor();
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize("system.supervisor.failed_to_reload"),
|
title: this.supervisor.localize("system.supervisor.failed_to_reload"),
|
||||||
text: extractApiErrorMessage(err),
|
text: extractApiErrorMessage(err),
|
||||||
@@ -346,7 +343,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await restartSupervisor(this.hass);
|
await restartSupervisor(this.hass);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"common.failed_to_restart_name",
|
"common.failed_to_restart_name",
|
||||||
@@ -391,7 +388,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
fireEvent(this, "supervisor-collection-refresh", {
|
fireEvent(this, "supervisor-collection-refresh", {
|
||||||
collection: "supervisor",
|
collection: "supervisor",
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"common.failed_to_update_name",
|
"common.failed_to_update_name",
|
||||||
@@ -430,10 +427,10 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
<li>
|
<li>
|
||||||
${UNSUPPORTED_REASON_URL[reason]
|
${UNSUPPORTED_REASON_URL[reason]
|
||||||
? html`<a
|
? html`<a
|
||||||
href="${documentationUrl(
|
href=${documentationUrl(
|
||||||
this.hass,
|
this.hass,
|
||||||
UNSUPPORTED_REASON_URL[reason]
|
UNSUPPORTED_REASON_URL[reason]
|
||||||
)}"
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
@@ -461,10 +458,10 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
<li>
|
<li>
|
||||||
${UNHEALTHY_REASON_URL[reason]
|
${UNHEALTHY_REASON_URL[reason]
|
||||||
? html`<a
|
? html`<a
|
||||||
href="${documentationUrl(
|
href=${documentationUrl(
|
||||||
this.hass,
|
this.hass,
|
||||||
UNHEALTHY_REASON_URL[reason]
|
UNHEALTHY_REASON_URL[reason]
|
||||||
)}"
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
@@ -486,7 +483,7 @@ class HassioSupervisorInfo extends LitElement {
|
|||||||
diagnostics: !this.supervisor.supervisor?.diagnostics,
|
diagnostics: !this.supervisor.supervisor?.diagnostics,
|
||||||
};
|
};
|
||||||
await setSupervisorOption(this.hass, data);
|
await setSupervisorOption(this.hass, data);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor.localize(
|
title: this.supervisor.localize(
|
||||||
"system.supervisor.failed_to_set_option"
|
"system.supervisor.failed_to_set_option"
|
||||||
|
@@ -5,6 +5,7 @@ import "@polymer/paper-listbox/paper-listbox";
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import "../../../src/components/buttons/ha-progress-button";
|
import "../../../src/components/buttons/ha-progress-button";
|
||||||
|
import "../../../src/components/ha-alert";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
|
||||||
import { fetchHassioLogs } from "../../../src/data/hassio/supervisor";
|
import { fetchHassioLogs } from "../../../src/data/hassio/supervisor";
|
||||||
@@ -67,7 +68,9 @@ class HassioSupervisorLog extends LitElement {
|
|||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
return html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
|
${this._error
|
||||||
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
|
: ""}
|
||||||
${this.hass.userData?.showAdvanced
|
${this.hass.userData?.showAdvanced
|
||||||
? html`
|
? html`
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
@@ -127,7 +130,7 @@ class HassioSupervisorLog extends LitElement {
|
|||||||
this.hass,
|
this.hass,
|
||||||
this._selectedLogProvider
|
this._selectedLogProvider
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"system.log.get_logs",
|
"system.log.get_logs",
|
||||||
"provider",
|
"provider",
|
||||||
@@ -154,10 +157,6 @@ class HassioSupervisorLog extends LitElement {
|
|||||||
padding: 0 2%;
|
padding: 0 2%;
|
||||||
width: 96%;
|
width: 96%;
|
||||||
}
|
}
|
||||||
.errors {
|
|
||||||
color: var(--error-color);
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
[build.environment]
|
[build.environment]
|
||||||
YARN_VERSION = "1.22.11"
|
YARN_VERSION = "1.22.11"
|
||||||
NODE_OPTIONS = "--max_old_space_size=4096"
|
NODE_OPTIONS = "--max_old_space_size=6144"
|
||||||
|
182
package.json
182
package.json
@@ -16,53 +16,56 @@
|
|||||||
"lint:lit": "lit-analyzer \"**/src/**/*.ts\" --format markdown --outFile result.md",
|
"lint:lit": "lit-analyzer \"**/src/**/*.ts\" --format markdown --outFile result.md",
|
||||||
"lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types",
|
"lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types",
|
||||||
"format": "yarn run format:eslint && yarn run format:prettier",
|
"format": "yarn run format:eslint && yarn run format:prettier",
|
||||||
"mocha": "ts-mocha -p test-mocha/tsconfig.test.json \"test-mocha/**/*.ts\"",
|
"test": "instant-mocha --webpack-config ./test/webpack.config.js --require ./test/setup.js \"test/**/*.ts\""
|
||||||
"test": "yarn run mocha"
|
|
||||||
},
|
},
|
||||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braintree/sanitize-url": "^5.0.1",
|
"@braintree/sanitize-url": "^5.0.2",
|
||||||
"@codemirror/commands": "^0.18.0",
|
"@codemirror/commands": "^0.19.2",
|
||||||
"@codemirror/gutter": "^0.18.0",
|
"@codemirror/gutter": "^0.19.1",
|
||||||
"@codemirror/highlight": "^0.18.0",
|
"@codemirror/highlight": "^0.19.2",
|
||||||
"@codemirror/history": "^0.18.0",
|
"@codemirror/history": "^0.19.0",
|
||||||
"@codemirror/legacy-modes": "^0.18.0",
|
"@codemirror/legacy-modes": "^0.19.0",
|
||||||
"@codemirror/rectangular-selection": "^0.18.0",
|
"@codemirror/rectangular-selection": "^0.19.0",
|
||||||
"@codemirror/search": "^0.18.0",
|
"@codemirror/search": "^0.19.0",
|
||||||
"@codemirror/state": "^0.18.0",
|
"@codemirror/state": "^0.19.1",
|
||||||
"@codemirror/stream-parser": "^0.18.0",
|
"@codemirror/stream-parser": "^0.19.1",
|
||||||
"@codemirror/text": "^0.18.0",
|
"@codemirror/text": "^0.19.2",
|
||||||
"@codemirror/view": "^0.18.0",
|
"@codemirror/view": "^0.19.4",
|
||||||
"@formatjs/intl-getcanonicallocales": "^1.5.10",
|
"@formatjs/intl-datetimeformat": "^4.2.4",
|
||||||
"@formatjs/intl-locale": "^2.4.28",
|
"@formatjs/intl-getcanonicallocales": "^1.7.3",
|
||||||
"@formatjs/intl-pluralrules": "^4.0.22",
|
"@formatjs/intl-locale": "^2.4.38",
|
||||||
"@fullcalendar/common": "5.1.0",
|
"@formatjs/intl-numberformat": "^7.2.4",
|
||||||
"@fullcalendar/core": "5.1.0",
|
"@formatjs/intl-pluralrules": "^4.1.4",
|
||||||
"@fullcalendar/daygrid": "5.1.0",
|
"@formatjs/intl-relativetimeformat": "^9.3.1",
|
||||||
"@fullcalendar/interaction": "5.1.0",
|
"@formatjs/intl-utils": "^3.8.4",
|
||||||
"@fullcalendar/list": "5.1.0",
|
"@fullcalendar/common": "5.9.0",
|
||||||
|
"@fullcalendar/core": "5.9.0",
|
||||||
|
"@fullcalendar/daygrid": "5.9.0",
|
||||||
|
"@fullcalendar/interaction": "5.9.0",
|
||||||
|
"@fullcalendar/list": "5.9.0",
|
||||||
"@lit-labs/virtualizer": "patch:@lit-labs/virtualizer@0.6.0#./.yarn/patches/@lit-labs/virtualizer/0.7.0.patch",
|
"@lit-labs/virtualizer": "patch:@lit-labs/virtualizer@0.6.0#./.yarn/patches/@lit-labs/virtualizer/0.7.0.patch",
|
||||||
"@material/chips": "12.0.0-canary.22d29cbb4.0",
|
"@material/chips": "13.0.0-canary.65125b3a6.0",
|
||||||
"@material/data-table": "12.0.0-canary.22d29cbb4.0",
|
"@material/data-table": "13.0.0-canary.65125b3a6.0",
|
||||||
"@material/mwc-button": "0.22.1",
|
"@material/mwc-button": "0.25.1",
|
||||||
"@material/mwc-checkbox": "0.22.1",
|
"@material/mwc-checkbox": "0.25.1",
|
||||||
"@material/mwc-circular-progress": "0.22.1",
|
"@material/mwc-circular-progress": "0.25.1",
|
||||||
"@material/mwc-dialog": "0.22.1",
|
"@material/mwc-dialog": "0.25.1",
|
||||||
"@material/mwc-fab": "0.22.1",
|
"@material/mwc-fab": "0.25.1",
|
||||||
"@material/mwc-formfield": "0.22.1",
|
"@material/mwc-formfield": "0.25.1",
|
||||||
"@material/mwc-icon-button": "0.22.1",
|
"@material/mwc-icon-button": "0.25.1",
|
||||||
"@material/mwc-linear-progress": "0.22.1",
|
"@material/mwc-linear-progress": "0.25.1",
|
||||||
"@material/mwc-list": "0.22.1",
|
"@material/mwc-list": "0.25.1",
|
||||||
"@material/mwc-menu": "0.22.1",
|
"@material/mwc-menu": "0.25.1",
|
||||||
"@material/mwc-radio": "0.22.1",
|
"@material/mwc-radio": "0.25.1",
|
||||||
"@material/mwc-ripple": "0.22.1",
|
"@material/mwc-ripple": "0.25.1",
|
||||||
"@material/mwc-switch": "0.22.1",
|
"@material/mwc-switch": "0.25.1",
|
||||||
"@material/mwc-tab": "0.22.1",
|
"@material/mwc-tab": "0.25.1",
|
||||||
"@material/mwc-tab-bar": "0.22.1",
|
"@material/mwc-tab-bar": "0.25.1",
|
||||||
"@material/top-app-bar": "12.0.0-canary.22d29cbb4.0",
|
"@material/top-app-bar": "13.0.0-canary.65125b3a6.0",
|
||||||
"@mdi/js": "5.9.55",
|
"@mdi/js": "6.1.95",
|
||||||
"@mdi/svg": "5.9.55",
|
"@mdi/svg": "6.1.95",
|
||||||
"@polymer/app-layout": "^3.1.0",
|
"@polymer/app-layout": "^3.1.0",
|
||||||
"@polymer/iron-flex-layout": "^3.0.1",
|
"@polymer/iron-flex-layout": "^3.0.1",
|
||||||
"@polymer/iron-icon": "^3.0.1",
|
"@polymer/iron-icon": "^3.0.1",
|
||||||
@@ -88,9 +91,9 @@
|
|||||||
"@polymer/paper-toast": "^3.0.1",
|
"@polymer/paper-toast": "^3.0.1",
|
||||||
"@polymer/paper-tooltip": "^3.0.1",
|
"@polymer/paper-tooltip": "^3.0.1",
|
||||||
"@polymer/polymer": "3.4.1",
|
"@polymer/polymer": "3.4.1",
|
||||||
"@thomasloven/round-slider": "0.5.2",
|
"@thomasloven/round-slider": "0.5.4",
|
||||||
"@vaadin/vaadin-combo-box": "^20.0.1",
|
"@vaadin/vaadin-combo-box": "^21.0.2",
|
||||||
"@vaadin/vaadin-date-picker": "^20.0.1",
|
"@vaadin/vaadin-date-picker": "^21.0.2",
|
||||||
"@vibrant/color": "^3.2.1-alpha.1",
|
"@vibrant/color": "^3.2.1-alpha.1",
|
||||||
"@vibrant/core": "^3.2.1-alpha.1",
|
"@vibrant/core": "^3.2.1-alpha.1",
|
||||||
"@vibrant/quantizer-mmcq": "^3.2.1-alpha.1",
|
"@vibrant/quantizer-mmcq": "^3.2.1-alpha.1",
|
||||||
@@ -99,36 +102,34 @@
|
|||||||
"chart.js": "^3.3.2",
|
"chart.js": "^3.3.2",
|
||||||
"comlink": "^4.3.1",
|
"comlink": "^4.3.1",
|
||||||
"core-js": "^3.15.2",
|
"core-js": "^3.15.2",
|
||||||
"cropperjs": "^1.5.11",
|
"cropperjs": "^1.5.12",
|
||||||
"date-fns": "^2.22.1",
|
"date-fns": "^2.23.0",
|
||||||
"deep-clone-simple": "^1.1.1",
|
"deep-clone-simple": "^1.1.1",
|
||||||
"deep-freeze": "^0.0.1",
|
"deep-freeze": "^0.0.1",
|
||||||
"fecha": "^4.2.0",
|
|
||||||
"fuse.js": "^6.0.0",
|
"fuse.js": "^6.0.0",
|
||||||
"google-timezones-json": "^1.0.2",
|
"google-timezones-json": "^1.0.2",
|
||||||
"hls.js": "^1.0.7",
|
"hls.js": "^1.0.10",
|
||||||
"home-assistant-js-websocket": "^5.11.1",
|
"home-assistant-js-websocket": "^5.11.1",
|
||||||
"idb-keyval": "^5.0.5",
|
"idb-keyval": "^5.1.3",
|
||||||
"intl-messageformat": "^9.6.16",
|
"intl-messageformat": "^9.9.1",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
"leaflet-draw": "^1.0.4",
|
"leaflet-draw": "^1.0.4",
|
||||||
"lit": "^2.0.0-rc.2",
|
"lit": "^2.0.0",
|
||||||
"lit-vaadin-helpers": "^0.1.3",
|
"lit-vaadin-helpers": "^0.2.1",
|
||||||
"marked": "^2.0.5",
|
"marked": "^3.0.2",
|
||||||
"mdn-polyfills": "^5.16.0",
|
|
||||||
"memoize-one": "^5.2.1",
|
"memoize-one": "^5.2.1",
|
||||||
"node-vibrant": "3.2.1-alpha.1",
|
"node-vibrant": "3.2.1-alpha.1",
|
||||||
"proxy-polyfill": "^0.3.1",
|
"proxy-polyfill": "^0.3.2",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
"qrcode": "^1.4.4",
|
"qrcode": "^1.4.4",
|
||||||
"regenerator-runtime": "^0.13.8",
|
"regenerator-runtime": "^0.13.8",
|
||||||
"resize-observer-polyfill": "^1.5.1",
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
"roboto-fontface": "^0.10.0",
|
"roboto-fontface": "^0.10.0",
|
||||||
"sortablejs": "^1.10.2",
|
"sortablejs": "^1.14.0",
|
||||||
"superstruct": "^0.15.2",
|
"superstruct": "^0.15.2",
|
||||||
"tinykeys": "^1.1.3",
|
"tinykeys": "^1.1.3",
|
||||||
"tsparticles": "^1.19.2",
|
"tsparticles": "^1.34.0",
|
||||||
"unfetch": "^4.1.0",
|
"unfetch": "^4.1.0",
|
||||||
"vis-data": "^7.1.2",
|
"vis-data": "^7.1.2",
|
||||||
"vis-network": "^8.5.4",
|
"vis-network": "^8.5.4",
|
||||||
@@ -144,17 +145,18 @@
|
|||||||
"xss": "^1.0.9"
|
"xss": "^1.0.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.14.6",
|
"@babel/core": "^7.15.5",
|
||||||
"@babel/plugin-external-helpers": "^7.14.5",
|
"@babel/plugin-external-helpers": "^7.14.5",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||||
"@babel/plugin-proposal-decorators": "^7.14.5",
|
"@babel/plugin-proposal-decorators": "^7.15.4",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.14.7",
|
"@babel/plugin-proposal-object-rest-spread": "^7.15.6",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
||||||
"@babel/preset-env": "^7.14.7",
|
"@babel/plugin-syntax-top-level-await": "^7.14.5",
|
||||||
"@babel/preset-typescript": "^7.14.5",
|
"@babel/preset-env": "^7.15.6",
|
||||||
|
"@babel/preset-typescript": "^7.15.0",
|
||||||
"@koa/cors": "^3.1.0",
|
"@koa/cors": "^3.1.0",
|
||||||
"@open-wc/dev-server-hmr": "^0.0.2",
|
"@open-wc/dev-server-hmr": "^0.0.2",
|
||||||
"@rollup/plugin-babel": "^5.2.1",
|
"@rollup/plugin-babel": "^5.2.1",
|
||||||
@@ -164,30 +166,31 @@
|
|||||||
"@rollup/plugin-replace": "^2.3.2",
|
"@rollup/plugin-replace": "^2.3.2",
|
||||||
"@types/chromecast-caf-receiver": "5.0.12",
|
"@types/chromecast-caf-receiver": "5.0.12",
|
||||||
"@types/chromecast-caf-sender": "^1.0.3",
|
"@types/chromecast-caf-sender": "^1.0.3",
|
||||||
"@types/js-yaml": "^4.0.1",
|
"@types/js-yaml": "^4",
|
||||||
"@types/leaflet": "^1.7.0",
|
"@types/leaflet": "^1",
|
||||||
"@types/leaflet-draw": "^1.0.3",
|
"@types/leaflet-draw": "^1",
|
||||||
"@types/marked": "^2.0.3",
|
"@types/marked": "^2",
|
||||||
"@types/mocha": "^8.2.2",
|
"@types/mocha": "^8",
|
||||||
"@types/sortablejs": "^1.10.6",
|
"@types/sortablejs": "^1",
|
||||||
"@types/webspeechapi": "^0.0.29",
|
"@types/webspeechapi": "^0.0.29",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.28.3",
|
"@typescript-eslint/eslint-plugin": "^4.32.0",
|
||||||
"@typescript-eslint/parser": "^4.28.3",
|
"@typescript-eslint/parser": "^4.32.0",
|
||||||
"@web/dev-server": "^0.0.24",
|
"@web/dev-server": "^0.0.24",
|
||||||
"@web/dev-server-rollup": "^0.2.11",
|
"@web/dev-server-rollup": "^0.2.11",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
"del": "^4.0.0",
|
"del": "^4.0.0",
|
||||||
"eslint": "^7.30.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-airbnb-typescript": "^12.3.1",
|
"eslint-config-airbnb-base": "^14.2.1",
|
||||||
|
"eslint-config-airbnb-typescript": "^14.0.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-import-resolver-webpack": "^0.13.1",
|
"eslint-import-resolver-webpack": "^0.13.1",
|
||||||
"eslint-plugin-disable": "^2.0.1",
|
"eslint-plugin-disable": "^2.0.1",
|
||||||
"eslint-plugin-import": "^2.23.4",
|
"eslint-plugin-import": "^2.24.2",
|
||||||
"eslint-plugin-lit": "^1.5.1",
|
"eslint-plugin-lit": "^1.5.1",
|
||||||
"eslint-plugin-prettier": "^3.4.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-unused-imports": "^1.1.2",
|
"eslint-plugin-unused-imports": "^1.1.5",
|
||||||
"eslint-plugin-wc": "^1.3.0",
|
"eslint-plugin-wc": "^1.3.2",
|
||||||
"fancy-log": "^1.3.3",
|
"fancy-log": "^1.3.3",
|
||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
@@ -198,7 +201,8 @@
|
|||||||
"gulp-zopfli-green": "^3.0.1",
|
"gulp-zopfli-green": "^3.0.1",
|
||||||
"html-minifier": "^4.0.0",
|
"html-minifier": "^4.0.0",
|
||||||
"husky": "^1.3.1",
|
"husky": "^1.3.1",
|
||||||
"lint-staged": "^11.0.1",
|
"instant-mocha": "^1.3.1",
|
||||||
|
"lint-staged": "^11.1.2",
|
||||||
"lit-analyzer": "^1.2.1",
|
"lit-analyzer": "^1.2.1",
|
||||||
"lodash.template": "^4.5.0",
|
"lodash.template": "^4.5.0",
|
||||||
"magic-string": "^0.25.7",
|
"magic-string": "^0.25.7",
|
||||||
@@ -207,7 +211,7 @@
|
|||||||
"mocha": "^8.4.0",
|
"mocha": "^8.4.0",
|
||||||
"object-hash": "^2.0.3",
|
"object-hash": "^2.0.3",
|
||||||
"open": "^7.0.4",
|
"open": "^7.0.4",
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.4.1",
|
||||||
"require-dir": "^1.2.0",
|
"require-dir": "^1.2.0",
|
||||||
"rollup": "^2.8.2",
|
"rollup": "^2.8.2",
|
||||||
"rollup-plugin-string": "^3.0.0",
|
"rollup-plugin-string": "^3.0.0",
|
||||||
@@ -217,24 +221,26 @@
|
|||||||
"sinon": "^11.0.0",
|
"sinon": "^11.0.0",
|
||||||
"source-map-url": "^0.4.0",
|
"source-map-url": "^0.4.0",
|
||||||
"systemjs": "^6.3.2",
|
"systemjs": "^6.3.2",
|
||||||
"terser-webpack-plugin": "^5.1.4",
|
"terser-webpack-plugin": "^5.2.4",
|
||||||
"ts-lit-plugin": "^1.2.1",
|
"ts-lit-plugin": "^1.2.1",
|
||||||
"ts-mocha": "^8.0.0",
|
"typescript": "^4.4.3",
|
||||||
"typescript": "^4.3.5",
|
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
"vinyl-source-stream": "^2.0.0",
|
"vinyl-source-stream": "^2.0.0",
|
||||||
"webpack": "^5.43.0",
|
"webpack": "^5.55.1",
|
||||||
"webpack-cli": "^4.7.2",
|
"webpack-cli": "^4.8.0",
|
||||||
"webpack-dev-server": "^3.11.2",
|
"webpack-dev-server": "^4.3.0",
|
||||||
"webpack-manifest-plugin": "^3.1.1",
|
"webpack-manifest-plugin": "^4.0.2",
|
||||||
|
"webpackbar": "^5.0.0-3",
|
||||||
"workbox-build": "^6.1.5"
|
"workbox-build": "^6.1.5"
|
||||||
},
|
},
|
||||||
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
|
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@polymer/polymer": "patch:@polymer/polymer@3.4.1#./.yarn/patches/@polymer/polymer/pr-5569.patch",
|
"@polymer/polymer": "patch:@polymer/polymer@3.4.1#./.yarn/patches/@polymer/polymer/pr-5569.patch",
|
||||||
"@webcomponents/webcomponentsjs": "^2.2.10",
|
"@webcomponents/webcomponentsjs": "^2.2.10",
|
||||||
"lit-html": "2.0.0-rc.3",
|
"lit": "^2.0.0",
|
||||||
"lit-element": "3.0.0-rc.2"
|
"lit-html": "2.0.0",
|
||||||
|
"lit-element": "3.0.0",
|
||||||
|
"@lit/reactive-element": "1.0.0"
|
||||||
},
|
},
|
||||||
"main": "src/home-assistant.js",
|
"main": "src/home-assistant.js",
|
||||||
"husky": {
|
"husky": {
|
||||||
|
2
setup.py
2
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20210813.0",
|
version="20210930.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/frontend",
|
url="https://github.com/home-assistant/frontend",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@@ -194,7 +194,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
|||||||
this._state = "error";
|
this._state = "error";
|
||||||
this._errorMessage = data.message;
|
this._errorMessage = data.message;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error("Error starting auth flow", err);
|
console.error("Error starting auth flow", err);
|
||||||
this._state = "error";
|
this._state = "error";
|
||||||
@@ -317,7 +317,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this._updateStep(newStep);
|
await this._updateStep(newStep);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error("Error submitting step", err);
|
console.error("Error submitting step", err);
|
||||||
this._state = "error";
|
this._state = "error";
|
||||||
|
@@ -8,10 +8,6 @@ import {
|
|||||||
AuthUrlSearchParams,
|
AuthUrlSearchParams,
|
||||||
fetchAuthProviders,
|
fetchAuthProviders,
|
||||||
} from "../data/auth";
|
} from "../data/auth";
|
||||||
import {
|
|
||||||
DiscoveryInformation,
|
|
||||||
fetchDiscoveryInformation,
|
|
||||||
} from "../data/discovery";
|
|
||||||
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
|
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
|
||||||
import { registerServiceWorker } from "../util/register-service-worker";
|
import { registerServiceWorker } from "../util/register-service-worker";
|
||||||
import "./ha-auth-flow";
|
import "./ha-auth-flow";
|
||||||
@@ -29,8 +25,6 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _authProviders?: AuthProvider[];
|
@state() private _authProviders?: AuthProvider[];
|
||||||
|
|
||||||
@state() private _discovery?: DiscoveryInformation;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.translationFragment = "page-authorize";
|
this.translationFragment = "page-authorize";
|
||||||
@@ -58,17 +52,14 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
|||||||
// the name with a bold tag.
|
// the name with a bold tag.
|
||||||
const loggingInWith = document.createElement("div");
|
const loggingInWith = document.createElement("div");
|
||||||
loggingInWith.innerText = this.localize(
|
loggingInWith.innerText = this.localize(
|
||||||
this._discovery?.location_name
|
"ui.panel.page-authorize.logging_in_with",
|
||||||
? "ui.panel.page-authorize.logging_in_to_with"
|
|
||||||
: "ui.panel.page-authorize.logging_in_with",
|
|
||||||
"locationName",
|
|
||||||
"LOCATION",
|
|
||||||
"authProviderName",
|
"authProviderName",
|
||||||
"NAME"
|
"NAME"
|
||||||
);
|
);
|
||||||
loggingInWith.innerHTML = loggingInWith.innerHTML
|
loggingInWith.innerHTML = loggingInWith.innerHTML.replace(
|
||||||
.replace("**LOCATION**", `<b>${this._discovery?.location_name}</b>`)
|
"**NAME**",
|
||||||
.replace("**NAME**", `<b>${this._authProvider!.name}</b>`);
|
`<b>${this._authProvider!.name}</b>`
|
||||||
|
);
|
||||||
|
|
||||||
const inactiveProviders = this._authProviders.filter(
|
const inactiveProviders = this._authProviders.filter(
|
||||||
(prv) => prv !== this._authProvider
|
(prv) => prv !== this._authProvider
|
||||||
@@ -85,20 +76,20 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
|||||||
${loggingInWith}
|
${loggingInWith}
|
||||||
|
|
||||||
<ha-auth-flow
|
<ha-auth-flow
|
||||||
.resources="${this.resources}"
|
.resources=${this.resources}
|
||||||
.clientId="${this.clientId}"
|
.clientId=${this.clientId}
|
||||||
.redirectUri="${this.redirectUri}"
|
.redirectUri=${this.redirectUri}
|
||||||
.oauth2State="${this.oauth2State}"
|
.oauth2State=${this.oauth2State}
|
||||||
.authProvider="${this._authProvider}"
|
.authProvider=${this._authProvider}
|
||||||
></ha-auth-flow>
|
></ha-auth-flow>
|
||||||
|
|
||||||
${inactiveProviders.length > 0
|
${inactiveProviders.length > 0
|
||||||
? html`
|
? html`
|
||||||
<ha-pick-auth-provider
|
<ha-pick-auth-provider
|
||||||
.resources="${this.resources}"
|
.resources=${this.resources}
|
||||||
.clientId="${this.clientId}"
|
.clientId=${this.clientId}
|
||||||
.authProviders="${inactiveProviders}"
|
.authProviders=${inactiveProviders}
|
||||||
@pick-auth-provider="${this._handleAuthProviderPick}"
|
@pick-auth-provider=${this._handleAuthProviderPick}
|
||||||
></ha-pick-auth-provider>
|
></ha-pick-auth-provider>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
@@ -108,7 +99,6 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
|||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this._fetchAuthProviders();
|
this._fetchAuthProviders();
|
||||||
this._fetchDiscoveryInfo();
|
|
||||||
|
|
||||||
if (matchMedia("(prefers-color-scheme: dark)").matches) {
|
if (matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||||
applyThemesOnElement(
|
applyThemesOnElement(
|
||||||
@@ -144,10 +134,6 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchDiscoveryInfo() {
|
|
||||||
this._discovery = await fetchDiscoveryInformation();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _fetchAuthProviders() {
|
private async _fetchAuthProviders() {
|
||||||
// Fetch auth providers
|
// Fetch auth providers
|
||||||
try {
|
try {
|
||||||
@@ -172,7 +158,7 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
|||||||
|
|
||||||
this._authProviders = authProviders;
|
this._authProviders = authProviders;
|
||||||
this._authProvider = authProviders[0];
|
this._authProvider = authProviders[0];
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
console.error("Error loading auth providers", err);
|
console.error("Error loading auth providers", err);
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable lit/prefer-static-styles */
|
||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
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 { html, LitElement } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { property } from "lit/decorators";
|
import { property } from "lit/decorators";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import "../components/ha-icon-next";
|
import "../components/ha-icon-next";
|
||||||
@@ -18,14 +18,6 @@ class HaPickAuthProvider extends litLocalizeLiteMixin(LitElement) {
|
|||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
|
||||||
paper-item {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<p>${this.localize("ui.panel.page-authorize.pick_auth_provider")}:</p>
|
<p>${this.localize("ui.panel.page-authorize.pick_auth_provider")}:</p>
|
||||||
${this.authProviders.map(
|
${this.authProviders.map(
|
||||||
(provider) => html`
|
(provider) => html`
|
||||||
@@ -41,5 +33,14 @@ class HaPickAuthProvider extends litLocalizeLiteMixin(LitElement) {
|
|||||||
private _handlePick(ev) {
|
private _handlePick(ev) {
|
||||||
fireEvent(this, "pick-auth-provider", ev.currentTarget.auth_provider);
|
fireEvent(this, "pick-auth-provider", ev.currentTarget.auth_provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
paper-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
customElements.define("ha-pick-auth-provider", HaPickAuthProvider);
|
customElements.define("ha-pick-auth-provider", HaPickAuthProvider);
|
||||||
|
@@ -33,7 +33,7 @@ export function saveTokens(tokens: AuthData | null) {
|
|||||||
if (tokenCache.writeEnabled) {
|
if (tokenCache.writeEnabled) {
|
||||||
try {
|
try {
|
||||||
storage.hassTokens = JSON.stringify(tokens);
|
storage.hassTokens = JSON.stringify(tokens);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// write failed, ignore it. Happens if storage is full or private mode.
|
// write failed, ignore it. Happens if storage is full or private mode.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ export function loadTokens() {
|
|||||||
} else {
|
} else {
|
||||||
tokenCache.tokens = null;
|
tokenCache.tokens = null;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
tokenCache.tokens = null;
|
tokenCache.tokens = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
export const COLORS = [
|
export const COLORS = [
|
||||||
"#377eb8",
|
"#44739e",
|
||||||
"#984ea3",
|
"#984ea3",
|
||||||
"#00d2d5",
|
"#00d2d5",
|
||||||
"#ff7f00",
|
"#ff7f00",
|
||||||
|
@@ -56,19 +56,31 @@ export const FIXED_DOMAIN_ICONS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const FIXED_DEVICE_CLASS_ICONS = {
|
export const FIXED_DEVICE_CLASS_ICONS = {
|
||||||
|
aqi: "hass:air-filter",
|
||||||
current: "hass:current-ac",
|
current: "hass:current-ac",
|
||||||
carbon_dioxide: "mdi:molecule-co2",
|
carbon_dioxide: "mdi:molecule-co2",
|
||||||
carbon_monoxide: "mdi:molecule-co",
|
carbon_monoxide: "mdi:molecule-co",
|
||||||
|
date: "hass:calendar",
|
||||||
energy: "hass:lightning-bolt",
|
energy: "hass:lightning-bolt",
|
||||||
|
gas: "hass:gas-cylinder",
|
||||||
humidity: "hass:water-percent",
|
humidity: "hass:water-percent",
|
||||||
illuminance: "hass:brightness-5",
|
illuminance: "hass:brightness-5",
|
||||||
|
nitrogen_dioxide: "mdi:molecule",
|
||||||
|
nitrogen_monoxide: "mdi:molecule",
|
||||||
|
nitrous_oxide: "mdi:molecule",
|
||||||
|
ozone: "mdi:molecule",
|
||||||
temperature: "hass:thermometer",
|
temperature: "hass:thermometer",
|
||||||
monetary: "mdi:cash",
|
monetary: "mdi:cash",
|
||||||
|
pm25: "mdi:molecule",
|
||||||
|
pm1: "mdi:molecule",
|
||||||
|
pm10: "mdi:molecule",
|
||||||
pressure: "hass:gauge",
|
pressure: "hass:gauge",
|
||||||
power: "hass:flash",
|
power: "hass:flash",
|
||||||
power_factor: "hass:angle-acute",
|
power_factor: "hass:angle-acute",
|
||||||
signal_strength: "hass:wifi",
|
signal_strength: "hass:wifi",
|
||||||
|
sulphur_dioxide: "mdi:molecule",
|
||||||
timestamp: "hass:clock",
|
timestamp: "hass:clock",
|
||||||
|
volatile_organic_compounds: "mdi:molecule",
|
||||||
voltage: "hass:sine-wave",
|
voltage: "hass:sine-wave",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -157,66 +169,3 @@ export const UNIT_F = "°F";
|
|||||||
|
|
||||||
/** Entity ID of the default view. */
|
/** Entity ID of the default view. */
|
||||||
export const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
|
export const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
|
||||||
|
|
||||||
/** HA Color Pallete. */
|
|
||||||
export const HA_COLOR_PALETTE = [
|
|
||||||
"ff0029",
|
|
||||||
"66a61e",
|
|
||||||
"377eb8",
|
|
||||||
"984ea3",
|
|
||||||
"00d2d5",
|
|
||||||
"ff7f00",
|
|
||||||
"af8d00",
|
|
||||||
"7f80cd",
|
|
||||||
"b3e900",
|
|
||||||
"c42e60",
|
|
||||||
"a65628",
|
|
||||||
"f781bf",
|
|
||||||
"8dd3c7",
|
|
||||||
"bebada",
|
|
||||||
"fb8072",
|
|
||||||
"80b1d3",
|
|
||||||
"fdb462",
|
|
||||||
"fccde5",
|
|
||||||
"bc80bd",
|
|
||||||
"ffed6f",
|
|
||||||
"c4eaff",
|
|
||||||
"cf8c00",
|
|
||||||
"1b9e77",
|
|
||||||
"d95f02",
|
|
||||||
"e7298a",
|
|
||||||
"e6ab02",
|
|
||||||
"a6761d",
|
|
||||||
"0097ff",
|
|
||||||
"00d067",
|
|
||||||
"f43600",
|
|
||||||
"4ba93b",
|
|
||||||
"5779bb",
|
|
||||||
"927acc",
|
|
||||||
"97ee3f",
|
|
||||||
"bf3947",
|
|
||||||
"9f5b00",
|
|
||||||
"f48758",
|
|
||||||
"8caed6",
|
|
||||||
"f2b94f",
|
|
||||||
"eff26e",
|
|
||||||
"e43872",
|
|
||||||
"d9b100",
|
|
||||||
"9d7a00",
|
|
||||||
"698cff",
|
|
||||||
"d9d9d9",
|
|
||||||
"00d27e",
|
|
||||||
"d06800",
|
|
||||||
"009f82",
|
|
||||||
"c49200",
|
|
||||||
"cbe8ff",
|
|
||||||
"fecddf",
|
|
||||||
"c27eb6",
|
|
||||||
"8cd2ce",
|
|
||||||
"c4b8d9",
|
|
||||||
"f883b0",
|
|
||||||
"a49100",
|
|
||||||
"f48800",
|
|
||||||
"27d0df",
|
|
||||||
"a04a9b",
|
|
||||||
];
|
|
||||||
|
@@ -1,34 +0,0 @@
|
|||||||
// Check for support of native locale string options
|
|
||||||
function checkToLocaleDateStringSupportsOptions() {
|
|
||||||
try {
|
|
||||||
new Date().toLocaleDateString("i");
|
|
||||||
} catch (e) {
|
|
||||||
return e.name === "RangeError";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkToLocaleTimeStringSupportsOptions() {
|
|
||||||
try {
|
|
||||||
new Date().toLocaleTimeString("i");
|
|
||||||
} catch (e) {
|
|
||||||
return e.name === "RangeError";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkToLocaleStringSupportsOptions() {
|
|
||||||
try {
|
|
||||||
new Date().toLocaleString("i");
|
|
||||||
} catch (e) {
|
|
||||||
return e.name === "RangeError";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const toLocaleDateStringSupportsOptions =
|
|
||||||
checkToLocaleDateStringSupportsOptions();
|
|
||||||
export const toLocaleTimeStringSupportsOptions =
|
|
||||||
checkToLocaleTimeStringSupportsOptions();
|
|
||||||
export const toLocaleStringSupportsOptions =
|
|
||||||
checkToLocaleStringSupportsOptions();
|
|
@@ -1,13 +1,15 @@
|
|||||||
import { format } from "fecha";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { FrontendLocaleData } from "../../data/translation";
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
import { toLocaleDateStringSupportsOptions } from "./check_options_support";
|
import { polyfillsLoaded } from "../translations/localize";
|
||||||
|
|
||||||
|
if (__BUILD__ === "latest" && polyfillsLoaded) {
|
||||||
|
await polyfillsLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
// Tuesday, August 10
|
// Tuesday, August 10
|
||||||
export const formatDateWeekday = toLocaleDateStringSupportsOptions
|
export const formatDateWeekday = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateWeekdayMem(locale).format(dateObj);
|
||||||
formatDateWeekdayMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "dddd, MMMM D");
|
|
||||||
const formatDateWeekdayMem = memoizeOne(
|
const formatDateWeekdayMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
@@ -18,10 +20,9 @@ const formatDateWeekdayMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// August 10, 2021
|
// August 10, 2021
|
||||||
export const formatDate = toLocaleDateStringSupportsOptions
|
export const formatDate = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateMem(locale).format(dateObj);
|
||||||
formatDateMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "MMMM D, YYYY");
|
|
||||||
const formatDateMem = memoizeOne(
|
const formatDateMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
@@ -32,10 +33,9 @@ const formatDateMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 10/08/2021
|
// 10/08/2021
|
||||||
export const formatDateNumeric = toLocaleDateStringSupportsOptions
|
export const formatDateNumeric = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateNumericMem(locale).format(dateObj);
|
||||||
formatDateNumericMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "M/D/YYYY");
|
|
||||||
const formatDateNumericMem = memoizeOne(
|
const formatDateNumericMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
@@ -46,10 +46,9 @@ const formatDateNumericMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Aug 10
|
// Aug 10
|
||||||
export const formatDateShort = toLocaleDateStringSupportsOptions
|
export const formatDateShort = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateShortMem(locale).format(dateObj);
|
||||||
formatDateShortMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "MMM D");
|
|
||||||
const formatDateShortMem = memoizeOne(
|
const formatDateShortMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
@@ -59,10 +58,11 @@ const formatDateShortMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// August 2021
|
// August 2021
|
||||||
export const formatDateMonthYear = toLocaleDateStringSupportsOptions
|
export const formatDateMonthYear = (
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
dateObj: Date,
|
||||||
formatDateMonthYearMem(locale).format(dateObj)
|
locale: FrontendLocaleData
|
||||||
: (dateObj: Date) => format(dateObj, "MMMM YYYY");
|
) => formatDateMonthYearMem(locale).format(dateObj);
|
||||||
|
|
||||||
const formatDateMonthYearMem = memoizeOne(
|
const formatDateMonthYearMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
@@ -72,10 +72,9 @@ const formatDateMonthYearMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// August
|
// August
|
||||||
export const formatDateMonth = toLocaleDateStringSupportsOptions
|
export const formatDateMonth = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateMonthMem(locale).format(dateObj);
|
||||||
formatDateMonthMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "MMMM");
|
|
||||||
const formatDateMonthMem = memoizeOne(
|
const formatDateMonthMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
@@ -84,10 +83,9 @@ const formatDateMonthMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 2021
|
// 2021
|
||||||
export const formatDateYear = toLocaleDateStringSupportsOptions
|
export const formatDateYear = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateYearMem(locale).format(dateObj);
|
||||||
formatDateYearMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "YYYY");
|
|
||||||
const formatDateYearMem = memoizeOne(
|
const formatDateYearMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@@ -1,40 +1,41 @@
|
|||||||
import { format } from "fecha";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { FrontendLocaleData } from "../../data/translation";
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
import { toLocaleStringSupportsOptions } from "./check_options_support";
|
|
||||||
import { useAmPm } from "./use_am_pm";
|
import { useAmPm } from "./use_am_pm";
|
||||||
|
import { polyfillsLoaded } from "../translations/localize";
|
||||||
|
|
||||||
|
if (__BUILD__ === "latest" && polyfillsLoaded) {
|
||||||
|
await polyfillsLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
// August 9, 2021, 8:23 AM
|
// August 9, 2021, 8:23 AM
|
||||||
export const formatDateTime = toLocaleStringSupportsOptions
|
export const formatDateTime = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateTimeMem(locale).format(dateObj);
|
||||||
formatDateTimeMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
|
||||||
format(dateObj, "MMMM D, YYYY, HH:mm" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatDateTimeMem = memoizeOne(
|
const formatDateTimeMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
hour: "numeric",
|
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
hour12: useAmPm(locale),
|
hour12: useAmPm(locale),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// August 9, 2021, 8:23:15 AM
|
// August 9, 2021, 8:23:15 AM
|
||||||
export const formatDateTimeWithSeconds = toLocaleStringSupportsOptions
|
export const formatDateTimeWithSeconds = (
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
dateObj: Date,
|
||||||
formatDateTimeWithSecondsMem(locale).format(dateObj)
|
locale: FrontendLocaleData
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
) => formatDateTimeWithSecondsMem(locale).format(dateObj);
|
||||||
format(dateObj, "MMMM D, YYYY, HH:mm:ss" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatDateTimeWithSecondsMem = memoizeOne(
|
const formatDateTimeWithSecondsMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
hour: "numeric",
|
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
second: "2-digit",
|
second: "2-digit",
|
||||||
hour12: useAmPm(locale),
|
hour12: useAmPm(locale),
|
||||||
@@ -42,11 +43,11 @@ const formatDateTimeWithSecondsMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 9/8/2021, 8:23 AM
|
// 9/8/2021, 8:23 AM
|
||||||
export const formatDateTimeNumeric = toLocaleStringSupportsOptions
|
export const formatDateTimeNumeric = (
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
dateObj: Date,
|
||||||
formatDateTimeNumericMem(locale).format(dateObj)
|
locale: FrontendLocaleData
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
) => formatDateTimeNumericMem(locale).format(dateObj);
|
||||||
format(dateObj, "M/D/YYYY, HH:mm" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatDateTimeNumericMem = memoizeOne(
|
const formatDateTimeNumericMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@@ -1,15 +1,16 @@
|
|||||||
import { format } from "fecha";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { FrontendLocaleData } from "../../data/translation";
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
import { toLocaleTimeStringSupportsOptions } from "./check_options_support";
|
|
||||||
import { useAmPm } from "./use_am_pm";
|
import { useAmPm } from "./use_am_pm";
|
||||||
|
import { polyfillsLoaded } from "../translations/localize";
|
||||||
|
|
||||||
|
if (__BUILD__ === "latest" && polyfillsLoaded) {
|
||||||
|
await polyfillsLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
// 9:15 PM || 21:15
|
// 9:15 PM || 21:15
|
||||||
export const formatTime = toLocaleTimeStringSupportsOptions
|
export const formatTime = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatTimeMem(locale).format(dateObj);
|
||||||
formatTimeMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
|
||||||
format(dateObj, "shortTime" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatTimeMem = memoizeOne(
|
const formatTimeMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
@@ -20,15 +21,15 @@ const formatTimeMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 9:15:24 PM || 21:15:24
|
// 9:15:24 PM || 21:15:24
|
||||||
export const formatTimeWithSeconds = toLocaleTimeStringSupportsOptions
|
export const formatTimeWithSeconds = (
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
dateObj: Date,
|
||||||
formatTimeWithSecondsMem(locale).format(dateObj)
|
locale: FrontendLocaleData
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
) => formatTimeWithSecondsMem(locale).format(dateObj);
|
||||||
format(dateObj, "mediumTime" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatTimeWithSecondsMem = memoizeOne(
|
const formatTimeWithSecondsMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
hour: "numeric",
|
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
second: "2-digit",
|
second: "2-digit",
|
||||||
hour12: useAmPm(locale),
|
hour12: useAmPm(locale),
|
||||||
@@ -36,17 +37,15 @@ const formatTimeWithSecondsMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Tuesday 7:00 PM || Tuesday 19:00
|
// Tuesday 7:00 PM || Tuesday 19:00
|
||||||
export const formatTimeWeekday = toLocaleTimeStringSupportsOptions
|
export const formatTimeWeekday = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatTimeWeekdayMem(locale).format(dateObj);
|
||||||
formatTimeWeekdayMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
|
||||||
format(dateObj, "dddd, HH:mm" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatTimeWeekdayMem = memoizeOne(
|
const formatTimeWeekdayMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
weekday: "long",
|
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||||
hour: "numeric",
|
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
hour12: useAmPm(locale),
|
hour12: useAmPm(locale),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@@ -1,48 +1,32 @@
|
|||||||
import { LocalizeFunc } from "../translations/localize";
|
import { selectUnit } from "@formatjs/intl-utils";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
|
import { polyfillsLoaded } from "../translations/localize";
|
||||||
|
|
||||||
/**
|
if (__BUILD__ === "latest" && polyfillsLoaded) {
|
||||||
* Calculate a string representing a date object as relative time from now.
|
await polyfillsLoaded;
|
||||||
*
|
|
||||||
* Example output: 5 minutes ago, in 3 days.
|
|
||||||
*/
|
|
||||||
const tests = [60, 60, 24, 7];
|
|
||||||
const langKey = ["second", "minute", "hour", "day"];
|
|
||||||
|
|
||||||
export default function relativeTime(
|
|
||||||
dateObj: Date,
|
|
||||||
localize: LocalizeFunc,
|
|
||||||
options: {
|
|
||||||
compareTime?: Date;
|
|
||||||
includeTense?: boolean;
|
|
||||||
} = {}
|
|
||||||
): string {
|
|
||||||
const compareTime = options.compareTime || new Date();
|
|
||||||
let delta = (compareTime.getTime() - dateObj.getTime()) / 1000;
|
|
||||||
const tense = delta >= 0 ? "past" : "future";
|
|
||||||
delta = Math.abs(delta);
|
|
||||||
let roundedDelta = Math.round(delta);
|
|
||||||
|
|
||||||
if (roundedDelta === 0) {
|
|
||||||
return localize("ui.components.relative_time.just_now");
|
|
||||||
}
|
|
||||||
|
|
||||||
let unit = "week";
|
|
||||||
|
|
||||||
for (let i = 0; i < tests.length; i++) {
|
|
||||||
if (roundedDelta < tests[i]) {
|
|
||||||
unit = langKey[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
delta /= tests[i];
|
|
||||||
roundedDelta = Math.round(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
return localize(
|
|
||||||
options.includeTense === false
|
|
||||||
? `ui.components.relative_time.duration.${unit}`
|
|
||||||
: `ui.components.relative_time.${tense}_duration.${unit}`,
|
|
||||||
"count",
|
|
||||||
roundedDelta
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formatRelTimeMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData) =>
|
||||||
|
// @ts-expect-error
|
||||||
|
new Intl.RelativeTimeFormat(locale.language, { numeric: "auto" })
|
||||||
|
);
|
||||||
|
|
||||||
|
export const relativeTime = (
|
||||||
|
from: Date,
|
||||||
|
locale: FrontendLocaleData,
|
||||||
|
to?: Date,
|
||||||
|
includeTense = true
|
||||||
|
): string => {
|
||||||
|
const diff = selectUnit(from, to);
|
||||||
|
if (includeTense) {
|
||||||
|
return formatRelTimeMem(locale).format(diff.value, diff.unit);
|
||||||
|
}
|
||||||
|
return Intl.NumberFormat(locale.language, {
|
||||||
|
style: "unit",
|
||||||
|
// @ts-expect-error
|
||||||
|
unit: diff.unit,
|
||||||
|
unitDisplay: "long",
|
||||||
|
}).format(Math.abs(diff.value));
|
||||||
|
};
|
||||||
|
@@ -74,7 +74,7 @@ class Storage {
|
|||||||
this._storage[storageKey] = value;
|
this._storage[storageKey] = value;
|
||||||
try {
|
try {
|
||||||
window.localStorage.setItem(storageKey, JSON.stringify(value));
|
window.localStorage.setItem(storageKey, JSON.stringify(value));
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// Safari in private mode doesn't allow localstorage
|
// Safari in private mode doesn't allow localstorage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -167,7 +167,7 @@ const processTheme = (
|
|||||||
const prefixedRgbKey = `--${rgbKey}`;
|
const prefixedRgbKey = `--${rgbKey}`;
|
||||||
styles[prefixedRgbKey] = rgbValue;
|
styles[prefixedRgbKey] = rgbValue;
|
||||||
keys[prefixedRgbKey] = "";
|
keys[prefixedRgbKey] = "";
|
||||||
} catch (e) {
|
} catch (err: any) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,4 +5,4 @@ export const mainWindow =
|
|||||||
? window
|
? window
|
||||||
: parent.name === MAIN_WINDOW_NAME
|
: parent.name === MAIN_WINDOW_NAME
|
||||||
? parent
|
? parent
|
||||||
: top;
|
: top!;
|
||||||
|
24
src/common/entity/alarm_panel_icon.ts
Normal file
24
src/common/entity/alarm_panel_icon.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/** Return an icon representing a alarm panel state. */
|
||||||
|
|
||||||
|
export const alarmPanelIcon = (state?: string) => {
|
||||||
|
switch (state) {
|
||||||
|
case "armed_away":
|
||||||
|
return "hass:shield-lock";
|
||||||
|
case "armed_vacation":
|
||||||
|
return "hass:shield-airplane";
|
||||||
|
case "armed_home":
|
||||||
|
return "hass:shield-home";
|
||||||
|
case "armed_night":
|
||||||
|
return "hass:shield-moon";
|
||||||
|
case "armed_custom_bypass":
|
||||||
|
return "hass:security";
|
||||||
|
case "pending":
|
||||||
|
return "hass:shield-outline";
|
||||||
|
case "triggered":
|
||||||
|
return "hass:bell-ring";
|
||||||
|
case "disarmed":
|
||||||
|
return "hass:shield-off";
|
||||||
|
default:
|
||||||
|
return "hass:shield";
|
||||||
|
}
|
||||||
|
};
|
@@ -22,8 +22,9 @@ export const binarySensorIcon = (state?: string, stateObj?: HassEntity) => {
|
|||||||
case "gas":
|
case "gas":
|
||||||
case "problem":
|
case "problem":
|
||||||
case "safety":
|
case "safety":
|
||||||
case "smoke":
|
|
||||||
return is_off ? "hass:check-circle" : "hass:alert-circle";
|
return is_off ? "hass:check-circle" : "hass:alert-circle";
|
||||||
|
case "smoke":
|
||||||
|
return is_off ? "hass:check-circle" : "hass:smoke";
|
||||||
case "heat":
|
case "heat":
|
||||||
return is_off ? "hass:thermometer" : "hass:fire";
|
return is_off ? "hass:thermometer" : "hass:fire";
|
||||||
case "light":
|
case "light":
|
||||||
@@ -44,6 +45,8 @@ export const binarySensorIcon = (state?: string, stateObj?: HassEntity) => {
|
|||||||
return is_off ? "hass:home-outline" : "hass:home";
|
return is_off ? "hass:home-outline" : "hass:home";
|
||||||
case "sound":
|
case "sound":
|
||||||
return is_off ? "hass:music-note-off" : "hass:music-note";
|
return is_off ? "hass:music-note-off" : "hass:music-note";
|
||||||
|
case "update":
|
||||||
|
return is_off ? "mdi:package" : "mdi:package-up";
|
||||||
case "vibration":
|
case "vibration":
|
||||||
return is_off ? "hass:crop-portrait" : "hass:vibrate";
|
return is_off ? "hass:crop-portrait" : "hass:vibrate";
|
||||||
case "window":
|
case "window":
|
||||||
|
@@ -4,7 +4,7 @@ import { FrontendLocaleData } from "../../data/translation";
|
|||||||
import { formatDate } from "../datetime/format_date";
|
import { formatDate } from "../datetime/format_date";
|
||||||
import { formatDateTime } from "../datetime/format_date_time";
|
import { formatDateTime } from "../datetime/format_date_time";
|
||||||
import { formatTime } from "../datetime/format_time";
|
import { formatTime } from "../datetime/format_time";
|
||||||
import { formatNumber } from "../string/format_number";
|
import { formatNumber } from "../number/format_number";
|
||||||
import { LocalizeFunc } from "../translations/localize";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
import { computeStateDomain } from "./compute_state_domain";
|
import { computeStateDomain } from "./compute_state_domain";
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@ import { HassEntity } from "home-assistant-js-websocket";
|
|||||||
* Optionally pass in a state to influence the domain icon.
|
* Optionally pass in a state to influence the domain icon.
|
||||||
*/
|
*/
|
||||||
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../const";
|
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../const";
|
||||||
|
import { alarmPanelIcon } from "./alarm_panel_icon";
|
||||||
import { binarySensorIcon } from "./binary_sensor_icon";
|
import { binarySensorIcon } from "./binary_sensor_icon";
|
||||||
import { coverIcon } from "./cover_icon";
|
import { coverIcon } from "./cover_icon";
|
||||||
import { sensorIcon } from "./sensor_icon";
|
import { sensorIcon } from "./sensor_icon";
|
||||||
@@ -18,18 +19,7 @@ export const domainIcon = (
|
|||||||
|
|
||||||
switch (domain) {
|
switch (domain) {
|
||||||
case "alarm_control_panel":
|
case "alarm_control_panel":
|
||||||
switch (compareState) {
|
return alarmPanelIcon(compareState);
|
||||||
case "armed_home":
|
|
||||||
return "hass:bell-plus";
|
|
||||||
case "armed_night":
|
|
||||||
return "hass:bell-sleep";
|
|
||||||
case "disarmed":
|
|
||||||
return "hass:bell-outline";
|
|
||||||
case "triggered":
|
|
||||||
return "hass:bell-ring";
|
|
||||||
default:
|
|
||||||
return "hass:bell";
|
|
||||||
}
|
|
||||||
|
|
||||||
case "binary_sensor":
|
case "binary_sensor":
|
||||||
return binarySensorIcon(compareState, stateObj);
|
return binarySensorIcon(compareState, stateObj);
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { FIXED_DEVICE_CLASS_ICONS, UNIT_C, UNIT_F } from "../const";
|
import { FIXED_DEVICE_CLASS_ICONS, UNIT_C, UNIT_F } from "../const";
|
||||||
import { batteryIcon } from "./battery_icon";
|
import { batteryIcon } from "./battery_icon";
|
||||||
|
import { SENSOR_DEVICE_CLASS_BATTERY } from "../../data/sensor";
|
||||||
|
|
||||||
export const sensorIcon = (stateObj?: HassEntity): string | undefined => {
|
export const sensorIcon = (stateObj?: HassEntity): string | undefined => {
|
||||||
const dclass = stateObj?.attributes.device_class;
|
const dclass = stateObj?.attributes.device_class;
|
||||||
@@ -10,7 +11,7 @@ export const sensorIcon = (stateObj?: HassEntity): string | undefined => {
|
|||||||
return FIXED_DEVICE_CLASS_ICONS[dclass];
|
return FIXED_DEVICE_CLASS_ICONS[dclass];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dclass === "battery") {
|
if (dclass === SENSOR_DEVICE_CLASS_BATTERY) {
|
||||||
return stateObj ? batteryIcon(stateObj) : "hass:battery";
|
return stateObj ? batteryIcon(stateObj) : "hass:battery";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { FrontendLocaleData, NumberFormat } from "../../data/translation";
|
import { FrontendLocaleData, NumberFormat } from "../../data/translation";
|
||||||
import { round } from "../number/round";
|
import { round } from "./round";
|
||||||
|
|
||||||
export const numberFormatToLocale = (
|
export const numberFormatToLocale = (
|
||||||
localeOptions: FrontendLocaleData
|
localeOptions: FrontendLocaleData
|
||||||
@@ -51,10 +51,10 @@ export const formatNumber = (
|
|||||||
locale,
|
locale,
|
||||||
getDefaultFormatOptions(num, options)
|
getDefaultFormatOptions(num, options)
|
||||||
).format(Number(num));
|
).format(Number(num));
|
||||||
} catch (error) {
|
} catch (err: any) {
|
||||||
// Don't fail when using "TEST" language
|
// Don't fail when using "TEST" language
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(error);
|
console.error(err);
|
||||||
return new Intl.NumberFormat(
|
return new Intl.NumberFormat(
|
||||||
undefined,
|
undefined,
|
||||||
getDefaultFormatOptions(num, options)
|
getDefaultFormatOptions(num, options)
|
@@ -1,4 +1,4 @@
|
|||||||
export const compare = (a: string, b: string) => {
|
export const stringCompare = (a: string, b: string) => {
|
||||||
if (a < b) {
|
if (a < b) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -9,5 +9,5 @@ export const compare = (a: string, b: string) => {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const caseInsensitiveCompare = (a: string, b: string) =>
|
export const caseInsensitiveStringCompare = (a: string, b: string) =>
|
||||||
compare(a.toLowerCase(), b.toLowerCase());
|
stringCompare(a.toLowerCase(), b.toLowerCase());
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { refine, string } from "superstruct";
|
import { refine, string } from "superstruct";
|
||||||
|
|
||||||
const isCustomType = (value: string) => value.startsWith("custom:");
|
export const isCustomType = (value: string) => value.startsWith("custom:");
|
||||||
|
|
||||||
export const customType = () =>
|
export const customType = () =>
|
||||||
refine(string(), "custom element type", isCustomType);
|
refine(string(), "custom element type", isCustomType);
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
import { shouldPolyfill } from "@formatjs/intl-pluralrules/lib/should-polyfill";
|
import { shouldPolyfill as shouldPolyfillLocale } from "@formatjs/intl-locale/lib/should-polyfill";
|
||||||
|
import { shouldPolyfill as shouldPolyfillPluralRules } from "@formatjs/intl-pluralrules/lib/should-polyfill";
|
||||||
|
import { shouldPolyfill as shouldPolyfillRelativeTime } from "@formatjs/intl-relativetimeformat/lib/should-polyfill";
|
||||||
|
import { shouldPolyfill as shouldPolyfillDateTime } from "@formatjs/intl-datetimeformat/lib/should-polyfill";
|
||||||
import IntlMessageFormat from "intl-messageformat";
|
import IntlMessageFormat from "intl-messageformat";
|
||||||
import { Resources } from "../../types";
|
import { Resources } from "../../types";
|
||||||
|
|
||||||
@@ -12,17 +15,34 @@ export interface FormatsType {
|
|||||||
time: FormatType;
|
time: FormatType;
|
||||||
}
|
}
|
||||||
|
|
||||||
let loadedPolyfillLocale: Set<string> | undefined;
|
const polyfillPluralRules = shouldPolyfillPluralRules();
|
||||||
|
const polyfillRelativeTime = shouldPolyfillRelativeTime();
|
||||||
|
const polyfillDateTime = shouldPolyfillDateTime();
|
||||||
|
|
||||||
let polyfillLoaded = !shouldPolyfill();
|
const polyfills: Promise<any>[] = [];
|
||||||
const polyfillProm = polyfillLoaded
|
if (__BUILD__ === "latest") {
|
||||||
|
if (shouldPolyfillLocale()) {
|
||||||
|
polyfills.push(import("@formatjs/intl-locale/polyfill"));
|
||||||
|
}
|
||||||
|
if (polyfillPluralRules) {
|
||||||
|
polyfills.push(import("@formatjs/intl-pluralrules/polyfill"));
|
||||||
|
}
|
||||||
|
if (polyfillRelativeTime) {
|
||||||
|
polyfills.push(import("@formatjs/intl-relativetimeformat/polyfill"));
|
||||||
|
}
|
||||||
|
if (polyfillDateTime) {
|
||||||
|
polyfills.push(import("@formatjs/intl-datetimeformat/polyfill"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let polyfillLoaded = polyfills.length === 0;
|
||||||
|
export const polyfillsLoaded = polyfillLoaded
|
||||||
? undefined
|
? undefined
|
||||||
: import("@formatjs/intl-locale/polyfill")
|
: Promise.all(polyfills).then(() => {
|
||||||
.then(() => import("@formatjs/intl-pluralrules/polyfill"))
|
polyfillLoaded = true;
|
||||||
.then(() => {
|
// Load English so it becomes the default
|
||||||
loadedPolyfillLocale = new Set();
|
return loadPolyfillLocales("en");
|
||||||
polyfillLoaded = true;
|
});
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapted from Polymer app-localize-behavior.
|
* Adapted from Polymer app-localize-behavior.
|
||||||
@@ -52,17 +72,10 @@ export const computeLocalize = async (
|
|||||||
formats?: FormatsType
|
formats?: FormatsType
|
||||||
): Promise<LocalizeFunc> => {
|
): Promise<LocalizeFunc> => {
|
||||||
if (!polyfillLoaded) {
|
if (!polyfillLoaded) {
|
||||||
await polyfillProm;
|
await polyfillsLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadedPolyfillLocale && !loadedPolyfillLocale.has(language)) {
|
loadPolyfillLocales(language);
|
||||||
try {
|
|
||||||
loadedPolyfillLocale.add(language);
|
|
||||||
await import("@formatjs/intl-pluralrules/locale-data/en");
|
|
||||||
} catch (_e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everytime any of the parameters change, invalidate the strings cache.
|
// Everytime any of the parameters change, invalidate the strings cache.
|
||||||
cache._localizationCache = {};
|
cache._localizationCache = {};
|
||||||
@@ -92,7 +105,7 @@ export const computeLocalize = async (
|
|||||||
language,
|
language,
|
||||||
formats
|
formats
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
return "Translation error: " + err.message;
|
return "Translation error: " + err.message;
|
||||||
}
|
}
|
||||||
cache._localizationCache[messageKey] = translatedMessage;
|
cache._localizationCache[messageKey] = translatedMessage;
|
||||||
@@ -109,8 +122,37 @@ export const computeLocalize = async (
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return translatedMessage.format<string>(argObject) as string;
|
return translatedMessage.format<string>(argObject) as string;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
return "Translation " + err;
|
return "Translation " + err;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const loadPolyfillLocales = async (language: string) => {
|
||||||
|
if (!polyfillsLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await polyfillsLoaded;
|
||||||
|
try {
|
||||||
|
if (polyfillPluralRules) {
|
||||||
|
await import(
|
||||||
|
/* webpackExclude: /.+-.+\.js$/ */
|
||||||
|
`@formatjs/intl-pluralrules/locale-data/${language}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (polyfillRelativeTime) {
|
||||||
|
await import(
|
||||||
|
/* webpackExclude: /.+-.+\.js$/ */
|
||||||
|
`@formatjs/intl-relativetimeformat/locale-data/${language}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (polyfillDateTime) {
|
||||||
|
await import(
|
||||||
|
/* webpackExclude: /.+-.+\.js$/ */
|
||||||
|
`@formatjs/intl-datetimeformat/locale-data/${language}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (_e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
};
|
||||||
|
15
src/common/util/group-by.ts
Normal file
15
src/common/util/group-by.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
export const groupBy = <T>(
|
||||||
|
list: T[],
|
||||||
|
keySelector: (item: T) => string
|
||||||
|
): { [key: string]: T[] } => {
|
||||||
|
const result = {};
|
||||||
|
for (const item of list) {
|
||||||
|
const key = keySelector(item);
|
||||||
|
if (key in result) {
|
||||||
|
result[key].push(item);
|
||||||
|
} else {
|
||||||
|
result[key] = [item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
@@ -25,7 +25,7 @@ export default function parseAspectRatio(input: string) {
|
|||||||
return arr.length === 1
|
return arr.length === 1
|
||||||
? { w: parseOrThrow(arr[0]), h: 1 }
|
? { w: parseOrThrow(arr[0]), h: 1 }
|
||||||
: { w: parseOrThrow(arr[0]), h: parseOrThrow(arr[1]) };
|
: { w: parseOrThrow(arr[0]), h: parseOrThrow(arr[1]) };
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// Ignore the error
|
// Ignore the error
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@@ -50,7 +50,7 @@ class HaCallApiButton extends LitElement {
|
|||||||
this._progressButton.actionSuccess();
|
this._progressButton.actionSuccess();
|
||||||
eventData.success = true;
|
eventData.success = true;
|
||||||
eventData.response = resp;
|
eventData.response = resp;
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
this.progress = false;
|
this.progress = false;
|
||||||
this._progressButton.actionError();
|
this._progressButton.actionError();
|
||||||
eventData.success = false;
|
eventData.success = false;
|
||||||
|
@@ -61,6 +61,11 @@ export default class HaChartBase extends LitElement {
|
|||||||
this.chart.config.type = this.chartType;
|
this.chart.config.type = this.chartType;
|
||||||
}
|
}
|
||||||
if (changedProps.has("data")) {
|
if (changedProps.has("data")) {
|
||||||
|
if (this._hiddenDatasets.size) {
|
||||||
|
this.data.datasets.forEach((dataset, index) => {
|
||||||
|
dataset.hidden = this._hiddenDatasets.has(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
this.chart.data = this.data;
|
this.chart.data = this.data;
|
||||||
}
|
}
|
||||||
if (changedProps.has("options")) {
|
if (changedProps.has("options")) {
|
||||||
@@ -238,9 +243,19 @@ export default class HaChartBase extends LitElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateChart = (): void => {
|
public updateChart = (
|
||||||
|
mode:
|
||||||
|
| "resize"
|
||||||
|
| "reset"
|
||||||
|
| "none"
|
||||||
|
| "hide"
|
||||||
|
| "show"
|
||||||
|
| "normal"
|
||||||
|
| "active"
|
||||||
|
| undefined
|
||||||
|
): void => {
|
||||||
if (this.chart) {
|
if (this.chart) {
|
||||||
this.chart.update();
|
this.chart.update(mode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@ import { getColorByIndex } from "../../common/color/colors";
|
|||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../common/string/format_number";
|
} from "../../common/number/format_number";
|
||||||
import { LineChartEntity, LineChartState } from "../../data/history";
|
import { LineChartEntity, LineChartState } from "../../data/history";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import "./ha-chart-base";
|
import "./ha-chart-base";
|
||||||
|
@@ -5,7 +5,7 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import { getColorByIndex } from "../../common/color/colors";
|
import { getColorByIndex } from "../../common/color/colors";
|
||||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
import { numberFormatToLocale } from "../../common/string/format_number";
|
import { numberFormatToLocale } from "../../common/number/format_number";
|
||||||
import { computeRTL } from "../../common/util/compute_rtl";
|
import { computeRTL } from "../../common/util/compute_rtl";
|
||||||
import { TimelineEntity } from "../../data/history";
|
import { TimelineEntity } from "../../data/history";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
|
@@ -19,7 +19,7 @@ import { computeStateName } from "../../common/entity/compute_state_name";
|
|||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../common/string/format_number";
|
} from "../../common/number/format_number";
|
||||||
import {
|
import {
|
||||||
getStatisticIds,
|
getStatisticIds,
|
||||||
Statistics,
|
Statistics,
|
||||||
|
@@ -25,6 +25,7 @@ export const createCurrencyListEl = () => {
|
|||||||
"BSD",
|
"BSD",
|
||||||
"BTN",
|
"BTN",
|
||||||
"BWP",
|
"BWP",
|
||||||
|
"BYN",
|
||||||
"BYR",
|
"BYR",
|
||||||
"BZD",
|
"BZD",
|
||||||
"CAD",
|
"CAD",
|
||||||
|
@@ -62,6 +62,7 @@ export interface DataTableSortColumnData {
|
|||||||
sortable?: boolean;
|
sortable?: boolean;
|
||||||
filterable?: boolean;
|
filterable?: boolean;
|
||||||
filterKey?: string;
|
filterKey?: string;
|
||||||
|
valueColumn?: string;
|
||||||
direction?: SortingDirection;
|
direction?: SortingDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ export interface DataTableColumnData extends DataTableSortColumnData {
|
|||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClonedDataTableColumnData = Omit<DataTableColumnData, "title"> & {
|
export type ClonedDataTableColumnData = Omit<DataTableColumnData, "title"> & {
|
||||||
title?: TemplateResult | string;
|
title?: TemplateResult | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -455,7 +456,7 @@ export class HaDataTable extends LitElement {
|
|||||||
const prom = this._sortColumn
|
const prom = this._sortColumn
|
||||||
? sortData(
|
? sortData(
|
||||||
filteredData,
|
filteredData,
|
||||||
this._sortColumns,
|
this._sortColumns[this._sortColumn],
|
||||||
this._sortDirection,
|
this._sortDirection,
|
||||||
this._sortColumn
|
this._sortColumn
|
||||||
)
|
)
|
||||||
@@ -549,7 +550,7 @@ export class HaDataTable extends LitElement {
|
|||||||
|
|
||||||
private _handleRowClick(ev: Event) {
|
private _handleRowClick(ev: Event) {
|
||||||
const target = ev.target as HTMLElement;
|
const target = ev.target as HTMLElement;
|
||||||
if (target.tagName === "HA-CHECKBOX") {
|
if (["HA-CHECKBOX", "MWC-BUTTON"].includes(target.tagName)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rowId = (ev.currentTarget as any).rowId;
|
const rowId = (ev.currentTarget as any).rowId;
|
||||||
|
@@ -2,8 +2,8 @@
|
|||||||
import { expose } from "comlink";
|
import { expose } from "comlink";
|
||||||
import "proxy-polyfill";
|
import "proxy-polyfill";
|
||||||
import type {
|
import type {
|
||||||
|
ClonedDataTableColumnData,
|
||||||
DataTableRowData,
|
DataTableRowData,
|
||||||
DataTableSortColumnData,
|
|
||||||
SortableColumnContainer,
|
SortableColumnContainer,
|
||||||
SortingDirection,
|
SortingDirection,
|
||||||
} from "./ha-data-table";
|
} from "./ha-data-table";
|
||||||
@@ -19,7 +19,11 @@ const filterData = (
|
|||||||
const [key, column] = columnEntry;
|
const [key, column] = columnEntry;
|
||||||
if (column.filterable) {
|
if (column.filterable) {
|
||||||
if (
|
if (
|
||||||
String(column.filterKey ? row[key][column.filterKey] : row[key])
|
String(
|
||||||
|
column.filterKey
|
||||||
|
? row[column.valueColumn || key][column.filterKey]
|
||||||
|
: row[column.valueColumn || key]
|
||||||
|
)
|
||||||
.toUpperCase()
|
.toUpperCase()
|
||||||
.includes(filter)
|
.includes(filter)
|
||||||
) {
|
) {
|
||||||
@@ -33,7 +37,7 @@ const filterData = (
|
|||||||
|
|
||||||
const sortData = (
|
const sortData = (
|
||||||
data: DataTableRowData[],
|
data: DataTableRowData[],
|
||||||
column: DataTableSortColumnData,
|
column: ClonedDataTableColumnData,
|
||||||
direction: SortingDirection,
|
direction: SortingDirection,
|
||||||
sortColumn: string
|
sortColumn: string
|
||||||
) =>
|
) =>
|
||||||
@@ -44,12 +48,12 @@ const sortData = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
let valA = column.filterKey
|
let valA = column.filterKey
|
||||||
? a[sortColumn][column.filterKey]
|
? a[column.valueColumn || sortColumn][column.filterKey]
|
||||||
: a[sortColumn];
|
: a[column.valueColumn || sortColumn];
|
||||||
|
|
||||||
let valB = column.filterKey
|
let valB = column.filterKey
|
||||||
? b[sortColumn][column.filterKey]
|
? b[column.valueColumn || sortColumn][column.filterKey]
|
||||||
: b[sortColumn];
|
: b[column.valueColumn || sortColumn];
|
||||||
|
|
||||||
if (typeof valA === "string") {
|
if (typeof valA === "string") {
|
||||||
valA = valA.toUpperCase();
|
valA = valA.toUpperCase();
|
||||||
|
@@ -20,7 +20,7 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
import { compare } from "../../common/string/compare";
|
import { stringCompare } from "../../common/string/compare";
|
||||||
import {
|
import {
|
||||||
AreaRegistryEntry,
|
AreaRegistryEntry,
|
||||||
subscribeAreaRegistry,
|
subscribeAreaRegistry,
|
||||||
@@ -50,6 +50,7 @@ interface AreaDevices {
|
|||||||
devices: string[];
|
devices: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line lit/prefer-static-styles
|
||||||
const rowRenderer: ComboBoxLitRenderer<AreaDevices> = (item) => html`<style>
|
const rowRenderer: ComboBoxLitRenderer<AreaDevices> = (item) => html`<style>
|
||||||
paper-item {
|
paper-item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -226,7 +227,10 @@ export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
const sorted = Object.keys(devicesByArea)
|
const sorted = Object.keys(devicesByArea)
|
||||||
.sort((a, b) =>
|
.sort((a, b) =>
|
||||||
compare(devicesByArea[a].name || "", devicesByArea[b].name || "")
|
stringCompare(
|
||||||
|
devicesByArea[a].name || "",
|
||||||
|
devicesByArea[b].name || ""
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.map((key) => devicesByArea[key]);
|
.map((key) => devicesByArea[key]);
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ import { ComboBoxLitRenderer } from "lit-vaadin-helpers";
|
|||||||
import { mdiCheck } from "@mdi/js";
|
import { mdiCheck } from "@mdi/js";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
import { compare } from "../../common/string/compare";
|
import { stringCompare } from "../../common/string/compare";
|
||||||
import {
|
import {
|
||||||
AreaRegistryEntry,
|
AreaRegistryEntry,
|
||||||
subscribeAreaRegistry,
|
subscribeAreaRegistry,
|
||||||
@@ -46,6 +46,7 @@ export type HaDevicePickerDeviceFilterFunc = (
|
|||||||
device: DeviceRegistryEntry
|
device: DeviceRegistryEntry
|
||||||
) => boolean;
|
) => boolean;
|
||||||
|
|
||||||
|
// eslint-disable-next-line lit/prefer-static-styles
|
||||||
const rowRenderer: ComboBoxLitRenderer<Device> = (item) => html`<style>
|
const rowRenderer: ComboBoxLitRenderer<Device> = (item) => html`<style>
|
||||||
paper-item {
|
paper-item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -242,7 +243,9 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
|
|||||||
if (outputDevices.length === 1) {
|
if (outputDevices.length === 1) {
|
||||||
return outputDevices;
|
return outputDevices;
|
||||||
}
|
}
|
||||||
return outputDevices.sort((a, b) => compare(a.name || "", b.name || ""));
|
return outputDevices.sort((a, b) =>
|
||||||
|
stringCompare(a.name || "", b.name || "")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ const haTabFixBehaviorImpl = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// paper-dialog that uses the haTabFixBehaviorImpl behvaior
|
// paper-dialog that uses the haTabFixBehaviorImpl behavior
|
||||||
// export class HaPaperDialog extends paperDialogClass {}
|
// export class HaPaperDialog extends paperDialogClass {}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export class HaPaperDialog
|
export class HaPaperDialog
|
||||||
|
@@ -23,6 +23,7 @@ import "./state-badge";
|
|||||||
|
|
||||||
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
|
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
|
||||||
|
|
||||||
|
// eslint-disable-next-line lit/prefer-static-styles
|
||||||
const rowRenderer: ComboBoxLitRenderer<string> = (item) => html`<style>
|
const rowRenderer: ComboBoxLitRenderer<string> = (item) => html`<style>
|
||||||
paper-item {
|
paper-item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@@ -26,6 +26,7 @@ import "./state-badge";
|
|||||||
|
|
||||||
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
|
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
|
||||||
|
|
||||||
|
// eslint-disable-next-line lit/prefer-static-styles
|
||||||
const rowRenderer: ComboBoxLitRenderer<HassEntity> = (item) => html`<style>
|
const rowRenderer: ComboBoxLitRenderer<HassEntity> = (item) => html`<style>
|
||||||
paper-icon-item {
|
paper-icon-item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@@ -13,10 +13,9 @@ import secondsToDuration from "../../common/datetime/seconds_to_duration";
|
|||||||
import { computeStateDisplay } from "../../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../../common/entity/compute_state_display";
|
||||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||||
import { domainIcon } from "../../common/entity/domain_icon";
|
|
||||||
import { stateIcon } from "../../common/entity/state_icon";
|
import { stateIcon } from "../../common/entity/state_icon";
|
||||||
import { timerTimeRemaining } from "../../data/timer";
|
import { timerTimeRemaining } from "../../data/timer";
|
||||||
import { formatNumber } from "../../common/string/format_number";
|
import { formatNumber } from "../../common/number/format_number";
|
||||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import "../ha-label-badge";
|
import "../ha-label-badge";
|
||||||
@@ -58,11 +57,11 @@ export class HaStateLabelBadge extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
class="warning"
|
class="warning"
|
||||||
label="${this.hass!.localize("state_badge.default.error")}"
|
label=${this.hass!.localize("state_badge.default.error")}
|
||||||
icon="hass:alert"
|
icon="hass:alert"
|
||||||
description="${this.hass!.localize(
|
description=${this.hass!.localize(
|
||||||
"state_badge.default.entity_not_found"
|
"state_badge.default.entity_not_found"
|
||||||
)}"
|
)}
|
||||||
></ha-label-badge>
|
></ha-label-badge>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -71,27 +70,25 @@ export class HaStateLabelBadge extends LitElement {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-label-badge
|
<ha-label-badge
|
||||||
class="${classMap({
|
class=${classMap({
|
||||||
[domain]: true,
|
[domain]: true,
|
||||||
"has-unit_of_measurement":
|
"has-unit_of_measurement":
|
||||||
"unit_of_measurement" in entityState.attributes,
|
"unit_of_measurement" in entityState.attributes,
|
||||||
})}"
|
})}
|
||||||
.value="${this._computeValue(domain, entityState)}"
|
.value=${this._computeValue(domain, entityState)}
|
||||||
.icon="${this.icon
|
.icon=${this.icon ? this.icon : this._computeIcon(domain, entityState)}
|
||||||
? this.icon
|
.image=${this.icon
|
||||||
: this._computeIcon(domain, entityState)}"
|
|
||||||
.image="${this.icon
|
|
||||||
? ""
|
? ""
|
||||||
: this.image
|
: this.image
|
||||||
? this.image
|
? this.image
|
||||||
: entityState.attributes.entity_picture_local ||
|
: entityState.attributes.entity_picture_local ||
|
||||||
entityState.attributes.entity_picture}"
|
entityState.attributes.entity_picture}
|
||||||
.label="${this._computeLabel(
|
.label=${this._computeLabel(
|
||||||
domain,
|
domain,
|
||||||
entityState,
|
entityState,
|
||||||
this._timerTimeRemaining
|
this._timerTimeRemaining
|
||||||
)}"
|
)}
|
||||||
.description="${this.name ? this.name : computeStateName(entityState)}"
|
.description=${this.name ? this.name : computeStateName(entityState)}
|
||||||
></ha-label-badge>
|
></ha-label-badge>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -106,19 +103,24 @@ export class HaStateLabelBadge extends LitElement {
|
|||||||
|
|
||||||
private _computeValue(domain: string, entityState: HassEntity) {
|
private _computeValue(domain: string, entityState: HassEntity) {
|
||||||
switch (domain) {
|
switch (domain) {
|
||||||
|
case "alarm_control_panel":
|
||||||
case "binary_sensor":
|
case "binary_sensor":
|
||||||
case "device_tracker":
|
case "device_tracker":
|
||||||
case "person":
|
case "person":
|
||||||
case "updater":
|
case "scene":
|
||||||
case "sun":
|
case "sun":
|
||||||
case "alarm_control_panel":
|
|
||||||
case "timer":
|
case "timer":
|
||||||
|
case "updater":
|
||||||
return null;
|
return null;
|
||||||
|
// @ts-expect-error we don't break and go to default
|
||||||
case "sensor":
|
case "sensor":
|
||||||
|
if (entityState.attributes.device_class === "moon__phase") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line: disable=no-fallthrough
|
||||||
default:
|
default:
|
||||||
return entityState.attributes.device_class === "moon__phase"
|
return entityState.state === UNKNOWN ||
|
||||||
? null
|
entityState.state === UNAVAILABLE
|
||||||
: entityState.state === UNKNOWN
|
|
||||||
? "-"
|
? "-"
|
||||||
: entityState.attributes.unit_of_measurement
|
: entityState.attributes.unit_of_measurement
|
||||||
? formatNumber(entityState.state, this.hass!.locale)
|
? formatNumber(entityState.state, this.hass!.locale)
|
||||||
@@ -136,40 +138,23 @@ export class HaStateLabelBadge extends LitElement {
|
|||||||
}
|
}
|
||||||
switch (domain) {
|
switch (domain) {
|
||||||
case "alarm_control_panel":
|
case "alarm_control_panel":
|
||||||
if (entityState.state === "pending") {
|
|
||||||
return "hass:clock-fast";
|
|
||||||
}
|
|
||||||
if (entityState.state === "armed_away") {
|
|
||||||
return "hass:nature";
|
|
||||||
}
|
|
||||||
if (entityState.state === "armed_home") {
|
|
||||||
return "hass:home-variant";
|
|
||||||
}
|
|
||||||
if (entityState.state === "armed_night") {
|
|
||||||
return "hass:weather-night";
|
|
||||||
}
|
|
||||||
if (entityState.state === "armed_custom_bypass") {
|
|
||||||
return "hass:shield-home";
|
|
||||||
}
|
|
||||||
if (entityState.state === "triggered") {
|
|
||||||
return "hass:alert-circle";
|
|
||||||
}
|
|
||||||
// state == 'disarmed'
|
|
||||||
return domainIcon(domain, entityState);
|
|
||||||
case "binary_sensor":
|
case "binary_sensor":
|
||||||
case "device_tracker":
|
case "device_tracker":
|
||||||
case "updater":
|
case "updater":
|
||||||
case "person":
|
case "person":
|
||||||
|
case "scene":
|
||||||
case "sun":
|
case "sun":
|
||||||
return stateIcon(entityState);
|
return stateIcon(entityState);
|
||||||
case "timer":
|
case "timer":
|
||||||
return entityState.state === "active"
|
return entityState.state === "active"
|
||||||
? "hass:timer-outline"
|
? "hass:timer-outline"
|
||||||
: "hass:timer-off-outline";
|
: "hass:timer-off-outline";
|
||||||
default:
|
case "sensor":
|
||||||
return entityState?.attributes.device_class === "moon__phase"
|
return entityState.attributes.device_class === "moon__phase"
|
||||||
? stateIcon(entityState)
|
? stateIcon(entityState)
|
||||||
: null;
|
: null;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user