Compare commits

..

1 Commits

Author SHA1 Message Date
Ludeeus
d1605ba196 Add move data disk 2021-09-16 15:15:57 +00:00
467 changed files with 6160 additions and 8459 deletions

View File

@@ -1,10 +1,9 @@
{ {
"extends": [ "extends": [
"airbnb-base",
"airbnb-typescript/base", "airbnb-typescript/base",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"plugin:wc/recommended", "plugin:wc/recommended",
"plugin:lit/all", "plugin:lit/recommended",
"prettier" "prettier"
], ],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
@@ -29,7 +28,6 @@
"__BUILD__": false, "__BUILD__": false,
"__VERSION__": false, "__VERSION__": false,
"__STATIC_PATH__": false, "__STATIC_PATH__": false,
"__SUPERVISOR__": false,
"Polymer": true "Polymer": true
}, },
"env": { "env": {
@@ -111,8 +109,7 @@
} }
], ],
"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"
}, },
"plugins": ["disable", "unused-imports"], "plugins": ["disable", "unused-imports"],
"processor": "disable/disable" "processor": "disable/disable"

View File

@@ -12,7 +12,7 @@ on:
env: env:
NODE_VERSION: 14 NODE_VERSION: 14
NODE_OPTIONS: --max_old_space_size=6144 NODE_OPTIONS: --max_old_space_size=4096
jobs: jobs:
lint: lint:
@@ -30,7 +30,7 @@ jobs:
env: env:
CI: true CI: true
- name: Build resources - name: Build resources
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-demos run: ./node_modules/.bin/gulp gen-icons-json build-translations gather-gallery-demos
- name: Run eslint - name: Run eslint
run: yarn run lint:eslint run: yarn run lint:eslint
- name: Run tsc - name: Run tsc
@@ -53,10 +53,8 @@ jobs:
run: yarn install run: yarn install
env: env:
CI: true CI: true
- name: Build resources - name: Run Mocha
run: ./node_modules/.bin/gulp build-translations build-locale-data run: yarn run mocha
- name: Run Tests
run: yarn run test
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [lint, test] needs: [lint, test]

View File

@@ -7,7 +7,7 @@ on:
env: env:
NODE_VERSION: 14 NODE_VERSION: 14
NODE_OPTIONS: --max_old_space_size=6144 NODE_OPTIONS: --max_old_space_size=4096
jobs: jobs:
deploy: deploy:

View File

@@ -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=6144 NODE_OPTIONS: --max_old_space_size=4096
jobs: jobs:
release: release:

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
# build # build
build build
build-translations/*
hass_frontend/* hass_frontend/*
dist dist

4
.mocharc.cjs Normal file
View File

@@ -0,0 +1,4 @@
module.exports = {
require: "test-mocha/testconf.js",
timeout: 10000,
};

View File

@@ -1,4 +1,5 @@
build build
build-translations/*
translations/* translations/*
node_modules/* node_modules/*
hass_frontend/* hass_frontend/*

55
.yarn/releases/yarn-2.4.2.cjs vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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-3.0.2.cjs yarnPath: .yarn/releases/yarn-2.4.2.cjs

View File

@@ -35,7 +35,6 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"), __BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
__VERSION__: JSON.stringify(env.version()), __VERSION__: JSON.stringify(env.version()),
__DEMO__: false, __DEMO__: false,
__SUPERVISOR__: false,
__BACKWARDS_COMPAT__: false, __BACKWARDS_COMPAT__: false,
__STATIC_PATH__: "/static/", __STATIC_PATH__: "/static/",
"process.env.NODE_ENV": JSON.stringify( "process.env.NODE_ENV": JSON.stringify(
@@ -83,7 +82,6 @@ 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 }],
@@ -195,9 +193,6 @@ module.exports.config = {
publicPath: publicPath(latestBuild, paths.hassio_publicPath), publicPath: publicPath(latestBuild, paths.hassio_publicPath),
isProdBuild, isProdBuild,
latestBuild, latestBuild,
defineOverlay: {
__SUPERVISOR__: true,
},
}; };
}, },

View File

@@ -5,7 +5,6 @@ const env = require("../env");
require("./clean.js"); require("./clean.js");
require("./translations.js"); require("./translations.js");
require("./locale-data.js");
require("./gen-icons-json.js"); require("./gen-icons-json.js");
require("./gather-static.js"); require("./gather-static.js");
require("./compress.js"); require("./compress.js");
@@ -27,8 +26,7 @@ gulp.task(
"gen-icons-json", "gen-icons-json",
"gen-pages-dev", "gen-pages-dev",
"gen-index-app-dev", "gen-index-app-dev",
"build-translations", "build-translations"
"build-locale-data"
), ),
"copy-static-app", "copy-static-app",
env.useWDS() env.useWDS()
@@ -46,7 +44,7 @@ gulp.task(
process.env.NODE_ENV = "production"; process.env.NODE_ENV = "production";
}, },
"clean", "clean",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"), gulp.parallel("gen-icons-json", "build-translations"),
"copy-static-app", "copy-static-app",
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app", env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
// Don't compress running tests // Don't compress running tests

View File

@@ -18,7 +18,7 @@ gulp.task(
}, },
"clean-cast", "clean-cast",
"translations-enable-merge-backend", "translations-enable-merge-backend",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"), gulp.parallel("gen-icons-json", "build-translations"),
"copy-static-cast", "copy-static-cast",
"gen-index-cast-dev", "gen-index-cast-dev",
env.useRollup() ? "rollup-dev-server-cast" : "webpack-dev-server-cast" env.useRollup() ? "rollup-dev-server-cast" : "webpack-dev-server-cast"
@@ -33,7 +33,7 @@ gulp.task(
}, },
"clean-cast", "clean-cast",
"translations-enable-merge-backend", "translations-enable-merge-backend",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"), gulp.parallel("gen-icons-json", "build-translations"),
"copy-static-cast", "copy-static-cast",
env.useRollup() ? "rollup-prod-cast" : "webpack-prod-cast", env.useRollup() ? "rollup-prod-cast" : "webpack-prod-cast",
"gen-index-cast-prod" "gen-index-cast-prod"

View File

@@ -20,12 +20,7 @@ gulp.task(
}, },
"clean-demo", "clean-demo",
"translations-enable-merge-backend", "translations-enable-merge-backend",
gulp.parallel( gulp.parallel("gen-icons-json", "gen-index-demo-dev", "build-translations"),
"gen-icons-json",
"gen-index-demo-dev",
"build-translations",
"build-locale-data"
),
"copy-static-demo", "copy-static-demo",
env.useRollup() ? "rollup-dev-server-demo" : "webpack-dev-server-demo" env.useRollup() ? "rollup-dev-server-demo" : "webpack-dev-server-demo"
) )
@@ -40,7 +35,7 @@ gulp.task(
"clean-demo", "clean-demo",
// Cast needs to be backwards compatible and older HA has no translations // Cast needs to be backwards compatible and older HA has no translations
"translations-enable-merge-backend", "translations-enable-merge-backend",
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"), gulp.parallel("gen-icons-json", "build-translations"),
"copy-static-demo", "copy-static-demo",
env.useRollup() ? "rollup-prod-demo" : "webpack-prod-demo", env.useRollup() ? "rollup-prod-demo" : "webpack-prod-demo",
"gen-index-demo-prod" "gen-index-demo-prod"

View File

@@ -51,7 +51,6 @@ gulp.task(
gulp.parallel( gulp.parallel(
"gen-icons-json", "gen-icons-json",
"build-translations", "build-translations",
"build-locale-data",
"gather-gallery-demos" "gather-gallery-demos"
), ),
"copy-static-gallery", "copy-static-gallery",
@@ -71,7 +70,6 @@ gulp.task(
gulp.parallel( gulp.parallel(
"gen-icons-json", "gen-icons-json",
"build-translations", "build-translations",
"build-locale-data",
"gather-gallery-demos" "gather-gallery-demos"
), ),
"copy-static-gallery", "copy-static-gallery",

View File

@@ -22,18 +22,11 @@ function copyTranslations(staticDir) {
// Translation output // Translation output
fs.copySync( fs.copySync(
polyPath("build/translations/output"), polyPath("build-translations/output"),
staticPath("translations") staticPath("translations")
); );
} }
function copyLocaleData(staticDir) {
const staticPath = genStaticPath(staticDir);
// Locale data output
fs.copySync(polyPath("build/locale-data"), staticPath("locale-data"));
}
function copyMdiIcons(staticDir) { function copyMdiIcons(staticDir) {
const staticPath = genStaticPath(staticDir); const staticPath = genStaticPath(staticDir);
@@ -91,11 +84,6 @@ function copyMapPanel(staticDir) {
); );
} }
gulp.task("copy-locale-data", async () => {
const staticDir = paths.app_output_static;
copyLocaleData(staticDir);
});
gulp.task("copy-translations-app", async () => { gulp.task("copy-translations-app", async () => {
const staticDir = paths.app_output_static; const staticDir = paths.app_output_static;
copyTranslations(staticDir); copyTranslations(staticDir);
@@ -106,11 +94,6 @@ gulp.task("copy-translations-supervisor", async () => {
copyTranslations(staticDir); copyTranslations(staticDir);
}); });
gulp.task("copy-locale-data-supervisor", async () => {
const staticDir = paths.hassio_output_static;
copyLocaleData(staticDir);
});
gulp.task("copy-static-app", async () => { gulp.task("copy-static-app", async () => {
const staticDir = paths.app_output_static; const staticDir = paths.app_output_static;
// Basic static files // Basic static files
@@ -120,7 +103,6 @@ gulp.task("copy-static-app", async () => {
copyPolyfills(staticDir); copyPolyfills(staticDir);
copyFonts(staticDir); copyFonts(staticDir);
copyTranslations(staticDir); copyTranslations(staticDir);
copyLocaleData(staticDir);
copyMdiIcons(staticDir); copyMdiIcons(staticDir);
// Panel assets // Panel assets
@@ -141,7 +123,6 @@ gulp.task("copy-static-demo", async () => {
copyMapPanel(paths.demo_output_static); copyMapPanel(paths.demo_output_static);
copyFonts(paths.demo_output_static); copyFonts(paths.demo_output_static);
copyTranslations(paths.demo_output_static); copyTranslations(paths.demo_output_static);
copyLocaleData(paths.demo_output_static);
copyMdiIcons(paths.demo_output_static); copyMdiIcons(paths.demo_output_static);
}); });
@@ -156,7 +137,6 @@ gulp.task("copy-static-cast", async () => {
copyMapPanel(paths.cast_output_static); copyMapPanel(paths.cast_output_static);
copyFonts(paths.cast_output_static); copyFonts(paths.cast_output_static);
copyTranslations(paths.cast_output_static); copyTranslations(paths.cast_output_static);
copyLocaleData(paths.cast_output_static);
copyMdiIcons(paths.cast_output_static); copyMdiIcons(paths.cast_output_static);
}); });
@@ -172,6 +152,5 @@ gulp.task("copy-static-gallery", async () => {
copyMapPanel(paths.gallery_output_static); copyMapPanel(paths.gallery_output_static);
copyFonts(paths.gallery_output_static); copyFonts(paths.gallery_output_static);
copyTranslations(paths.gallery_output_static); copyTranslations(paths.gallery_output_static);
copyLocaleData(paths.gallery_output_static);
copyMdiIcons(paths.gallery_output_static); copyMdiIcons(paths.gallery_output_static);
}); });

View File

@@ -1,6 +1,9 @@
const gulp = require("gulp"); const gulp = require("gulp");
const fs = require("fs");
const path = require("path");
const env = require("../env"); const env = require("../env");
const paths = require("../paths");
require("./clean.js"); require("./clean.js");
require("./gen-icons-json.js"); require("./gen-icons-json.js");
@@ -21,8 +24,6 @@ gulp.task(
"gen-index-hassio-dev", "gen-index-hassio-dev",
"build-supervisor-translations", "build-supervisor-translations",
"copy-translations-supervisor", "copy-translations-supervisor",
"build-locale-data",
"copy-locale-data-supervisor",
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio" env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
) )
); );
@@ -37,8 +38,6 @@ gulp.task(
"gen-icons-json", "gen-icons-json",
"build-supervisor-translations", "build-supervisor-translations",
"copy-translations-supervisor", "copy-translations-supervisor",
"build-locale-data",
"copy-locale-data-supervisor",
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio", env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
"gen-index-hassio-prod", "gen-index-hassio-prod",
...// Don't compress running tests ...// Don't compress running tests

View File

@@ -1,74 +0,0 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const del = require("del");
const path = require("path");
const gulp = require("gulp");
const fs = require("fs");
const paths = require("../paths");
const outDir = "build/locale-data";
gulp.task("clean-locale-data", () => del([outDir]));
gulp.task("ensure-locale-data-build-dir", (done) => {
if (!fs.existsSync(outDir)) {
fs.mkdirSync(outDir, { recursive: true });
}
done();
});
const modules = {
"intl-relativetimeformat": "RelativeTimeFormat",
"intl-datetimeformat": "DateTimeFormat",
"intl-numberformat": "NumberFormat",
};
gulp.task("create-locale-data", (done) => {
const translationMeta = JSON.parse(
fs.readFileSync(
path.join(paths.translations_src, "translationMetadata.json")
)
);
Object.entries(modules).forEach(([module, className]) => {
Object.keys(translationMeta).forEach((lang) => {
try {
const localeData = String(
fs.readFileSync(
require.resolve(`@formatjs/${module}/locale-data/${lang}.js`)
)
)
.replace(
new RegExp(
`\\/\\*\\s*@generated\\s*\\*\\/\\s*\\/\\/\\s*prettier-ignore\\s*if\\s*\\(Intl\\.${className}\\s*&&\\s*typeof\\s*Intl\\.${className}\\.__addLocaleData\\s*===\\s*'function'\\)\\s*{\\s*Intl\\.${className}\\.__addLocaleData\\(`,
"im"
),
""
)
.replace(/\)\s*}/im, "");
// make sure we have valid JSON
JSON.parse(localeData);
if (!fs.existsSync(path.join(outDir, module))) {
fs.mkdirSync(path.join(outDir, module), { recursive: true });
}
fs.writeFileSync(
path.join(outDir, `${module}/${lang}.json`),
localeData
);
} catch (e) {
if (e.code !== "MODULE_NOT_FOUND") {
throw e;
}
}
});
done();
});
});
gulp.task(
"build-locale-data",
gulp.series(
"clean-locale-data",
"ensure-locale-data-build-dir",
"create-locale-data"
)
);

View File

@@ -17,7 +17,7 @@ const paths = require("../paths");
const inFrontendDir = "translations/frontend"; const inFrontendDir = "translations/frontend";
const inBackendDir = "translations/backend"; const inBackendDir = "translations/backend";
const workDir = "build/translations"; const workDir = "build-translations";
const fullDir = workDir + "/full"; const fullDir = workDir + "/full";
const coreDir = workDir + "/core"; const coreDir = workDir + "/core";
const outDir = workDir + "/output"; const outDir = workDir + "/output";
@@ -121,7 +121,7 @@ gulp.task("clean-translations", () => del([workDir]));
gulp.task("ensure-translations-build-dir", (done) => { gulp.task("ensure-translations-build-dir", (done) => {
if (!fs.existsSync(workDir)) { if (!fs.existsSync(workDir)) {
fs.mkdirSync(workDir, { recursive: true }); fs.mkdirSync(workDir);
} }
done(); done();
}); });
@@ -336,14 +336,6 @@ gulp.task("build-translation-fragment-supervisor", () =>
gulp gulp
.src(fullDir + "/*.json") .src(fullDir + "/*.json")
.pipe(transform((data) => data.supervisor)) .pipe(transform((data) => data.supervisor))
.pipe(
rename((filePath) => {
// In dev we create the file with the fake hash in the filename
if (!env.isProdBuild()) {
filePath.basename += "-dev";
}
})
)
.pipe(gulp.dest(workDir + "/supervisor")) .pipe(gulp.dest(workDir + "/supervisor"))
); );

View File

@@ -35,29 +35,26 @@ const isWsl =
* listenHost?: string * listenHost?: string
* }} * }}
*/ */
const runDevServer = async ({ const runDevServer = ({
compiler, compiler,
contentBase, contentBase,
port, port,
listenHost = "localhost", listenHost = "localhost",
}) => { }) =>
const server = new WebpackDevServer( new WebpackDevServer(compiler, {
{
open: true, open: true,
host: listenHost, watchContentBase: true,
port, contentBase,
static: { }).listen(port, listenHost, (err) => {
directory: contentBase, if (err) {
watch: true, throw err;
}, }
},
compiler
);
await server.start();
// Server listening // Server listening
log("[webpack-dev-server]", `Project is running at http://localhost:${port}`); log(
}; "[webpack-dev-server]",
`Project is running at http://localhost:${port}`
);
});
const doneHandler = (done) => (err, stats) => { const doneHandler = (done) => (err, stats) => {
if (err) { if (err) {
@@ -110,13 +107,13 @@ gulp.task("webpack-prod-app", () =>
) )
); );
gulp.task("webpack-dev-server-demo", () => gulp.task("webpack-dev-server-demo", () => {
runDevServer({ runDevServer({
compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })), compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })),
contentBase: paths.demo_output_root, contentBase: paths.demo_output_root,
port: 8090, port: 8090,
}) });
); });
gulp.task("webpack-prod-demo", () => gulp.task("webpack-prod-demo", () =>
prodBuild( prodBuild(
@@ -126,15 +123,15 @@ gulp.task("webpack-prod-demo", () =>
) )
); );
gulp.task("webpack-dev-server-cast", () => gulp.task("webpack-dev-server-cast", () => {
runDevServer({ runDevServer({
compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })), compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })),
contentBase: paths.cast_output_root, contentBase: paths.cast_output_root,
port: 8080, port: 8080,
// Accessible from the network, because that's how Cast hits it. // Accessible from the network, because that's how Cast hits it.
listenHost: "0.0.0.0", listenHost: "0.0.0.0",
}) });
); });
gulp.task("webpack-prod-cast", () => gulp.task("webpack-prod-cast", () =>
prodBuild( prodBuild(
@@ -151,7 +148,7 @@ gulp.task("webpack-watch-hassio", () => {
isProdBuild: false, isProdBuild: false,
latestBuild: true, latestBuild: true,
}) })
).watch({ ignored: /build/, poll: isWsl }, doneHandler()); ).watch({ ignored: /build-translations/, poll: isWsl }, doneHandler());
gulp.watch( gulp.watch(
path.join(paths.translations_src, "en.json"), path.join(paths.translations_src, "en.json"),
@@ -167,14 +164,14 @@ gulp.task("webpack-prod-hassio", () =>
) )
); );
gulp.task("webpack-dev-server-gallery", () => gulp.task("webpack-dev-server-gallery", () => {
runDevServer({ runDevServer({
// We don't use the es5 build, but the dev server will fuck up the publicPath if we don't // We don't use the es5 build, but the dev server will fuck up the publicPath if we don't
compiler: webpack(bothBuilds(createGalleryConfig, { isProdBuild: false })), compiler: webpack(bothBuilds(createGalleryConfig, { isProdBuild: false })),
contentBase: paths.gallery_output_root, contentBase: paths.gallery_output_root,
port: 8100, port: 8100,
}) });
); });
gulp.task("webpack-prod-gallery", () => gulp.task("webpack-prod-gallery", () =>
prodBuild( prodBuild(

View File

@@ -6,7 +6,6 @@ const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
const paths = require("./paths.js"); const paths = require("./paths.js");
const bundle = require("./bundle.js"); const bundle = require("./bundle.js");
const log = require("fancy-log"); const log = require("fancy-log");
const WebpackBar = require("webpackbar");
class LogStartCompilePlugin { class LogStartCompilePlugin {
ignoredFirst = false; ignoredFirst = false;
@@ -75,7 +74,6 @@ 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"),
@@ -127,13 +125,6 @@ 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",
}, },
}, },
@@ -151,9 +142,6 @@ const createWebpackConfig = ({
// To silence warning in worker plugin // To silence warning in worker plugin
globalObject: "self", globalObject: "self",
}, },
experiments: {
topLevelAwait: true,
},
}; };
}; };

View File

@@ -191,7 +191,7 @@ class HcCast extends LitElement {
} }
this.connection.close(); this.connection.close();
location.reload(); location.reload();
} catch (err: any) { } catch (err) {
alert("Unable to log out!"); alert("Unable to log out!");
} }
} }

View File

@@ -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: any) { } catch (err) {
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: any) { } catch (err) {
if (init === "saved-tokens" && err === ERR_CANNOT_CONNECT) { if (init === "saved-tokens" && err === ERR_CANNOT_CONNECT) {
this.cannotConnect = true; this.cannotConnect = true;
return; return;
@@ -259,7 +259,7 @@ export class HcConnect extends LitElement {
try { try {
conn = await createConnection({ auth }); conn = await createConnection({ auth });
} catch (err: any) { } catch (err) {
// In case of saved tokens, silently solve problems. // In case of saved tokens, silently solve problems.
if (init === "saved-tokens") { if (init === "saved-tokens") {
if (err === ERR_CANNOT_CONNECT) { if (err === ERR_CANNOT_CONNECT) {
@@ -285,7 +285,7 @@ export class HcConnect extends LitElement {
try { try {
saveTokens(null); saveTokens(null);
location.reload(); location.reload();
} catch (err: any) { } catch (err) {
alert("Unable to log out!"); alert("Unable to log out!");
} }
} }

View File

@@ -148,14 +148,14 @@ export class HcMain extends HassElement {
expires_in: 0, expires_in: 0,
}), }),
}); });
} catch (err: any) { } catch (err) {
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: any) { } catch (err) {
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: any) { } catch (err) {
// 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.

View File

@@ -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: any) { } catch (err) {
alert("Failed to switch config :-("); alert("Failed to switch config :-(");
} finally { } finally {
this._switching = false; this._switching = false;

View File

@@ -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;

View File

@@ -1,4 +1,3 @@
/* eslint-disable lit/no-template-arrow */
import { html, css, LitElement, TemplateResult } from "lit"; import { html, css, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import "../../../src/components/ha-card"; import "../../../src/components/ha-card";

View File

@@ -1,4 +1,3 @@
/* eslint-disable lit/no-template-arrow */
import { html, css, LitElement, TemplateResult } from "lit"; import { html, css, LitElement, TemplateResult } from "lit";
import "../../../src/components/ha-card"; import "../../../src/components/ha-card";
import "../../../src/components/trace/hat-script-graph"; import "../../../src/components/trace/hat-script-graph";

View File

@@ -107,7 +107,6 @@ export class DemoHaAlert extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<ha-card header="ha-alert demo"> <ha-card header="ha-alert demo">
<div class="card-content">
${alerts.map( ${alerts.map(
(alert) => html` (alert) => html`
<ha-alert <ha-alert
@@ -121,7 +120,6 @@ export class DemoHaAlert extends LitElement {
</ha-alert> </ha-alert>
` `
)} )}
</div>
</ha-card> </ha-card>
`; `;
} }
@@ -132,10 +130,6 @@ export class DemoHaAlert extends LitElement {
max-width: 600px; max-width: 600px;
margin: 24px auto; margin: 24px auto;
} }
ha-alert {
display: block;
margin: 24px 0;
}
.condition { .condition {
padding: 16px; padding: 16px;
display: flex; display: flex;

View File

@@ -1,212 +0,0 @@
/* eslint-disable lit/no-template-arrow */
import { LitElement, TemplateResult, css, html } from "lit";
import { customElement } from "lit/decorators";
import "../../../src/components/ha-form/ha-form";
import "../../../src/components/ha-card";
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
import type { HaFormSchema } from "../../../src/components/ha-form/ha-form";
const SCHEMAS: {
title: string;
translations?: Record<string, string>;
error?: Record<string, string>;
schema: HaFormSchema[];
}[] = [
{
title: "Authentication",
translations: {
username: "Username",
password: "Password",
invalid_login: "Invalid login",
},
error: {
base: "invalid_login",
},
schema: [
{
type: "string",
name: "username",
required: true,
},
{
type: "string",
name: "password",
required: true,
},
],
},
{
title: "One of each",
schema: [
{
type: "constant",
value: "Constant Value",
name: "constant",
required: true,
},
{
type: "boolean",
name: "bool",
optional: true,
default: false,
},
{
type: "integer",
name: "int",
optional: true,
default: 10,
},
{
type: "string",
name: "string",
optional: true,
default: "Default",
},
{
type: "select",
options: [
["default", "default"],
["other", "other"],
],
name: "select",
optional: true,
default: "default",
},
{
type: "multi_select",
options: {
default: "Default",
other: "Other",
},
name: "multi",
optional: true,
default: ["default"],
},
],
},
{
title: "Multi select",
schema: [
{
type: "multi_select",
options: {
default: "Default",
other: "Other",
},
name: "multi",
optional: true,
default: ["default"],
},
{
type: "multi_select",
options: {
default: "Default",
other: "Other",
uno: "mas",
one: "more",
and: "another_one",
option: "1000",
},
name: "multi",
optional: true,
default: ["default"],
},
],
},
];
@customElement("demo-ha-form")
class DemoHaForm extends LitElement {
private lightModeData: any = [];
private darkModeData: any = [];
protected render(): TemplateResult {
return html`
${SCHEMAS.map((info, idx) => {
const translations = info.translations || {};
const computeLabel = (schema) =>
translations[schema.name] || schema.name;
const computeError = (error) => translations[error] || error;
return [
[this.lightModeData, "light"],
[this.darkModeData, "dark"],
].map(
([data, type]) => html`
<div class="row" data-type=${type}>
<ha-card .header=${info.title}>
<div class="card-content">
<ha-form
.data=${data[idx]}
.schema=${info.schema}
.error=${info.error}
.computeError=${computeError}
.computeLabel=${computeLabel}
@value-changed=${(e) => {
data[idx] = e.detail.value;
this.requestUpdate();
}}
></ha-form>
</div>
</ha-card>
<pre>${JSON.stringify(data[idx], undefined, 2)}</pre>
</div>
`
);
})}
`;
}
firstUpdated(changedProps) {
super.firstUpdated(changedProps);
this.shadowRoot!.querySelectorAll("[data-type=dark]").forEach((el) => {
applyThemesOnElement(
el,
{
default_theme: "default",
default_dark_theme: "default",
themes: {},
darkMode: false,
},
"default",
{ dark: true }
);
});
}
static styles = css`
.row {
margin: 0 auto;
max-width: 800px;
display: flex;
padding: 50px;
background-color: var(--primary-background-color);
}
ha-card {
width: 100%;
max-width: 384px;
}
pre {
width: 400px;
margin: 0 16px;
overflow: auto;
color: var(--primary-text-color);
}
@media only screen and (max-width: 800px) {
.row {
flex-direction: column;
}
pre {
margin: 16px 0;
}
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"demo-ha-form": DemoHaForm;
}
}

View File

@@ -1,5 +1,5 @@
import "@material/mwc-button"; import "@material/mwc-button";
import { css, html, LitElement, TemplateResult } from "lit"; import { html, LitElement, TemplateResult } from "lit";
import { customElement } from "lit/decorators"; import { customElement } from "lit/decorators";
import "../../../src/components/ha-card"; import "../../../src/components/ha-card";
import { ActionHandlerEvent } from "../../../src/data/lovelace"; import { ActionHandlerEvent } from "../../../src/data/lovelace";
@@ -9,6 +9,7 @@ import { actionHandler } from "../../../src/panels/lovelace/common/directives/ac
export class DemoUtilLongPress extends LitElement { export class DemoUtilLongPress extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
${this.renderStyle()}
${[1, 2, 3].map( ${[1, 2, 3].map(
() => html` () => html`
<ha-card> <ha-card>
@@ -40,7 +41,9 @@ export class DemoUtilLongPress extends LitElement {
area.scrollTop = area.scrollHeight; area.scrollTop = area.scrollHeight;
} }
static styles = css` private renderStyle() {
return html`
<style>
ha-card { ha-card {
width: 200px; width: 200px;
margin: calc(42vh - 140px) auto; margin: calc(42vh - 140px) auto;
@@ -57,5 +60,7 @@ export class DemoUtilLongPress extends LitElement {
textarea { textarea {
height: 50px; height: 50px;
} }
</style>
`; `;
}
} }

View File

@@ -4,7 +4,6 @@ import { property } from "lit/decorators";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { atLeastVersion } from "../../../src/common/config/version"; import { atLeastVersion } from "../../../src/common/config/version";
import { navigate } from "../../../src/common/navigate"; import { navigate } from "../../../src/common/navigate";
import { caseInsensitiveStringCompare } from "../../../src/common/string/compare";
import "../../../src/components/ha-card"; import "../../../src/components/ha-card";
import { import {
HassioAddonInfo, HassioAddonInfo,
@@ -33,7 +32,7 @@ class HassioAddonRepositoryEl extends LitElement {
return filterAndSort(addons, filter); return filterAndSort(addons, filter);
} }
return addons.sort((a, b) => return addons.sort((a, b) =>
caseInsensitiveStringCompare(a.name, b.name) a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
); );
} }
); );

View File

@@ -259,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.common.update_available", "addon.common.update_available",
"error", "error",
@@ -300,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.failed_to_save", "addon.failed_to_save",
"error", "error",

View File

@@ -89,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
@@ -171,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.failed_to_reset", "addon.failed_to_reset",
"error", "error",
@@ -207,7 +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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.failed_to_save", "addon.failed_to_save",
"error", "error",

View File

@@ -79,7 +79,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
this.hass, this.hass,
this.addon!.slug this.addon!.slug
); );
} catch (err: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.documentation.get_logs", "addon.documentation.get_logs",
"error", "error",

View File

@@ -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: any) { } catch (err) {
this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`; this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`;
this.addon = undefined; this.addon = undefined;
} }

View File

@@ -123,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>
@@ -254,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
>` >`
)} )}
@@ -297,11 +297,10 @@ class HassioAddonInfo extends LitElement {
})} })}
@click=${this._showMoreInfo} @click=${this._showMoreInfo}
id="rating" id="rating"
.value=${this.addon.rating}
label="rating" label="rating"
description="" description=""
> ></ha-label-badge>
${this.addon.rating}
</ha-label-badge>
${this.addon.host_network ${this.addon.host_network
? html` ? html`
<ha-label-badge <ha-label-badge
@@ -438,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">
@@ -797,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.failed_to_save", "addon.failed_to_save",
"error", "error",
@@ -819,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.failed_to_save", "addon.failed_to_save",
"error", "error",
@@ -841,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.failed_to_save", "addon.failed_to_save",
"error", "error",
@@ -863,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.failed_to_save", "addon.failed_to_save",
"error", "error",
@@ -885,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.failed_to_save", "addon.failed_to_save",
"error", "error",
@@ -913,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: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize( title: this.supervisor.localize(
"addon.dashboard.action_error.get_changelog" "addon.dashboard.action_error.get_changelog"
@@ -935,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: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize("addon.dashboard.action_error.install"), title: this.supervisor.localize("addon.dashboard.action_error.install"),
text: extractApiErrorMessage(err), text: extractApiErrorMessage(err),
@@ -956,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: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize("addon.dashboard.action_error.stop"), title: this.supervisor.localize("addon.dashboard.action_error.stop"),
text: extractApiErrorMessage(err), text: extractApiErrorMessage(err),
@@ -977,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: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize("addon.dashboard.action_error.restart"), title: this.supervisor.localize("addon.dashboard.action_error.restart"),
text: extractApiErrorMessage(err), text: extractApiErrorMessage(err),
@@ -1036,7 +1035,7 @@ class HassioAddonInfo extends LitElement {
button.progress = false; button.progress = false;
return; return;
} }
} catch (err: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: "Failed to validate addon configuration", title: "Failed to validate addon configuration",
text: extractApiErrorMessage(err), text: extractApiErrorMessage(err),
@@ -1054,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: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize("addon.dashboard.action_error.start"), title: this.supervisor.localize("addon.dashboard.action_error.start"),
text: extractApiErrorMessage(err), text: extractApiErrorMessage(err),
@@ -1092,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: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize( title: this.supervisor.localize(
"addon.dashboard.action_error.uninstall" "addon.dashboard.action_error.uninstall"

View File

@@ -71,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: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"addon.logs.get_logs", "addon.logs.get_logs",
"error", "error",

View File

@@ -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.locale), relativeTime(new Date(entry), this.hass.localize),
}, },
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: any) { } catch (err) {
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),

View File

@@ -1,6 +1,7 @@
import { mdiHelpCircle } from "@mdi/js"; import { mdiHelpCircle } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import "../../../src/components/ha-relative-time";
import "../../../src/components/ha-svg-icon"; import "../../../src/components/ha-svg-icon";
import { HomeAssistant } from "../../../src/types"; import { HomeAssistant } from "../../../src/types";
@@ -18,6 +19,8 @@ class HassioCardContent extends LitElement {
@property() public topbarClass?: string; @property() public topbarClass?: string;
@property() public datetime?: string;
@property() public iconTitle?: string; @property() public iconTitle?: string;
@property() public iconClass?: string; @property() public iconClass?: string;
@@ -34,7 +37,7 @@ class HassioCardContent extends LitElement {
${this.iconImage ${this.iconImage
? html` ? html`
<div class="icon_image ${this.iconClass}"> <div class="icon_image ${this.iconClass}">
<img src=${this.iconImage} .title=${this.iconTitle} /> <img src="${this.iconImage}" .title=${this.iconTitle} />
<div></div> <div></div>
</div> </div>
` `
@@ -53,6 +56,15 @@ class HassioCardContent extends LitElement {
/* treat as available when undefined */ /* treat as available when undefined */
this.available === false ? " (Not available)" : "" this.available === false ? " (Not available)" : ""
} }
${this.datetime
? html`
<ha-relative-time
.hass=${this.hass}
class="addition"
.datetime=${this.datetime}
></ha-relative-time>
`
: undefined}
</div> </div>
</div> </div>
`; `;
@@ -94,6 +106,9 @@ class HassioCardContent extends LitElement {
height: 2.4em; height: 2.4em;
line-height: 1.2em; line-height: 1.2em;
} }
ha-relative-time {
display: block;
}
.icon_image img { .icon_image img {
max-height: 40px; max-height: 40px;
max-width: 40px; max-width: 40px;

View File

@@ -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: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: "Upload failed", title: "Upload failed",
text: extractApiErrorMessage(err), text: extractApiErrorMessage(err),

View File

@@ -181,7 +181,9 @@ export class SupervisorBackupContent extends LitElement {
> >
<ha-checkbox <ha-checkbox
.checked=${this.homeAssistant} .checked=${this.homeAssistant}
@click=${this.toggleHomeAssistant} @click=${() => {
this.homeAssistant = !this.homeAssistant;
}}
> >
</ha-checkbox> </ha-checkbox>
</ha-formfield> </ha-formfield>
@@ -270,10 +272,6 @@ export class SupervisorBackupContent extends LitElement {
`; `;
} }
private toggleHomeAssistant() {
this.homeAssistant = !this.homeAssistant;
}
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return css` return css`
.partial-picker ha-formfield { .partial-picker ha-formfield {

View File

@@ -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>

View File

@@ -3,7 +3,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { atLeastVersion } from "../../../src/common/config/version"; import { atLeastVersion } from "../../../src/common/config/version";
import { navigate } from "../../../src/common/navigate"; import { navigate } from "../../../src/common/navigate";
import { caseInsensitiveStringCompare } from "../../../src/common/string/compare"; import { 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) => caseInsensitiveStringCompare(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}>

View File

@@ -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: any) { } catch (err) {
// Only show an error if the status code was not expected (user behind proxy) // Only show an error if the status code was not expected (user behind proxy)
// or no status at all(connection terminated) // or no status at all(connection terminated)
if (this.hass.connection.connected && !ignoreSupervisorError(err)) { if (this.hass.connection.connected && !ignoreSupervisorError(err)) {

View File

@@ -28,7 +28,6 @@ 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
@@ -108,7 +107,7 @@ class HassioBackupDialog
fixed fixed
slot="primaryAction" slot="primaryAction"
@action=${this._handleMenuAction} @action=${this._handleMenuAction}
@closed=${stopPropagation} @closed=${(ev: Event) => ev.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>
@@ -312,7 +311,7 @@ class HassioBackupDialog
: "snapshots" : "snapshots"
}/${this._backup!.slug}/download` }/${this._backup!.slug}/download`
); );
} catch (err: any) { } catch (err) {
await showAlertDialog(this, { await showAlertDialog(this, {
text: extractApiErrorMessage(err), text: extractApiErrorMessage(err),
}); });

View File

@@ -127,7 +127,7 @@ class HassioCreateBackupDialog extends LitElement {
this._dialogParams!.onCreate(); this._dialogParams!.onCreate();
this.closeDialog(); this.closeDialog();
} catch (err: any) { } catch (err) {
this._error = extractApiErrorMessage(err); this._error = extractApiErrorMessage(err);
} }
this._creatingBackup = false; this._creatingBackup = false;

View File

@@ -1,180 +0,0 @@
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/ha-circular-progress";
import "../../../../src/components/ha-markdown";
import {
extractApiErrorMessage,
ignoreSupervisorError,
} from "../../../../src/data/hassio/common";
import {
DatadiskList,
listDatadisks,
moveDatadisk,
} from "../../../../src/data/hassio/host";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { HassioDatatiskDialogParams } from "./show-dialog-hassio-datadisk";
const calculateMoveTime = memoizeOne((supervisor: Supervisor): number => {
const speed = supervisor.host.disk_life_time !== "" ? 30 : 10;
const moveTime = (supervisor.host.disk_used * 1000) / 60 / speed;
const rebootTime = (supervisor.host.startup_time * 4) / 60;
return Math.ceil((moveTime + rebootTime) / 10) * 10;
});
@customElement("dialog-hassio-datadisk")
class HassioDatadiskDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private dialogParams?: HassioDatatiskDialogParams;
@state() private selectedDevice?: string;
@state() private devices?: DatadiskList["devices"];
@state() private moving = false;
public showDialog(params: HassioDatatiskDialogParams) {
this.dialogParams = params;
listDatadisks(this.hass).then((data) => {
this.devices = data.devices;
});
}
public closeDialog(): void {
this.dialogParams = undefined;
this.selectedDevice = undefined;
this.devices = undefined;
this.moving = false;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult {
if (!this.dialogParams) {
return html``;
}
return html`
<ha-dialog
open
scrimClickAction
escapeKeyAction
.heading=${this.moving
? this.dialogParams.supervisor.localize("dialog.datadisk_move.moving")
: this.dialogParams.supervisor.localize("dialog.datadisk_move.title")}
@closed=${this.closeDialog}
?hideActions=${this.moving}
>
${this.moving
? html` <ha-circular-progress alt="Moving" size="large" active>
</ha-circular-progress>
<p class="progress-text">
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.moving_desc"
)}
</p>`
: html` ${this.devices?.length
? html`
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.description",
{
current_path: this.dialogParams.supervisor.os.data_disk,
time: calculateMoveTime(this.dialogParams.supervisor),
}
)}
<br /><br />
<paper-dropdown-menu
.label=${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.select_device"
)}
@value-changed=${this._select_device}
>
<paper-listbox slot="dropdown-content">
${this.devices.map(
(device) => html`<paper-item>${device}</paper-item>`
)}
</paper-listbox>
</paper-dropdown-menu>
`
: this.devices === undefined
? this.dialogParams.supervisor.localize(
"dialog.datadisk_move.loading_devices"
)
: this.dialogParams.supervisor.localize(
"dialog.datadisk_move.no_devices"
)}
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.cancel"
)}
</mwc-button>
<mwc-button
.disabled=${!this.selectedDevice}
slot="primaryAction"
@click=${this._moveDatadisk}
>
${this.dialogParams.supervisor.localize(
"dialog.datadisk_move.move"
)}
</mwc-button>`}
</ha-dialog>
`;
}
private _select_device(event) {
this.selectedDevice = event.detail.value;
}
private async _moveDatadisk() {
this.moving = true;
try {
await moveDatadisk(this.hass, this.selectedDevice!);
} catch (err: any) {
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
showAlertDialog(this, {
title: this.dialogParams!.supervisor.localize(
"system.host.failed_to_move"
),
text: extractApiErrorMessage(err),
});
this.closeDialog();
}
}
}
static get styles(): CSSResultGroup {
return [
haStyle,
haStyleDialog,
css`
paper-dropdown-menu {
width: 100%;
}
ha-circular-progress {
display: block;
margin: 32px;
text-align: center;
}
.progress-text {
text-align: center;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"dialog-hassio-datadisk": HassioDatadiskDialog;
}
}

View File

@@ -1,17 +0,0 @@
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
export interface HassioDatatiskDialogParams {
supervisor: Supervisor;
}
export const showHassioDatadiskDialog = (
element: HTMLElement,
dialogParams: HassioDatatiskDialogParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-datadisk",
dialogImport: () => import("./dialog-hassio-datadisk"),
dialogParams,
});
};

View File

@@ -287,7 +287,7 @@ export class DialogHassioNetwork
this.hass, this.hass,
this._interface.interface this._interface.interface
); );
} catch (err: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: "Failed to scan for accesspoints", title: "Failed to scan for accesspoints",
text: extractApiErrorMessage(err), text: extractApiErrorMessage(err),
@@ -448,7 +448,7 @@ export class DialogHassioNetwork
this._interface!.interface, this._interface!.interface,
interfaceOptions interfaceOptions
); );
} catch (err: any) { } catch (err) {
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),

View File

@@ -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: any) { } catch (err) {
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: any) { } catch (err) {
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),

View File

@@ -9,7 +9,6 @@ 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 { caseInsensitiveStringCompare } from "../../../../src/common/string/compare";
import "../../../../src/components/ha-alert"; 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";
@@ -58,7 +57,7 @@ class HassioRepositoriesDialog extends LitElement {
private _filteredRepositories = memoizeOne((repos: HassioAddonRepository[]) => private _filteredRepositories = memoizeOne((repos: HassioAddonRepository[]) =>
repos repos
.filter((repo) => repo.slug !== "core" && repo.slug !== "local") .filter((repo) => repo.slug !== "core" && repo.slug !== "local")
.sort((a, b) => caseInsensitiveStringCompare(a.name, b.name)) .sort((a, b) => (a.name < b.name ? -1 : 1))
); );
protected render(): TemplateResult { protected render(): TemplateResult {
@@ -186,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: any) { } catch (err) {
this._error = extractApiErrorMessage(err); this._error = extractApiErrorMessage(err);
} }
} }
@@ -208,7 +207,7 @@ class HassioRepositoriesDialog extends LitElement {
await this._loadData(); await this._loadData();
input.value = ""; input.value = "";
} catch (err: any) { } catch (err) {
this._error = extractApiErrorMessage(err); this._error = extractApiErrorMessage(err);
} }
this._processing = false; this._processing = false;
@@ -230,7 +229,7 @@ class HassioRepositoriesDialog extends LitElement {
addons_repositories: newRepositories, addons_repositories: newRepositories,
}); });
await this._loadData(); await this._loadData();
} catch (err: any) { } catch (err) {
this._error = extractApiErrorMessage(err); this._error = extractApiErrorMessage(err);
} }
} }

View File

@@ -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: any) { } catch (err) {
showAlertDialog(element, { showAlertDialog(element, {
title: supervisor.localize( title: supervisor.localize(
"common.failed_to_restart_name", "common.failed_to_restart_name",

View File

@@ -148,7 +148,7 @@ class DialogSupervisorUpdate extends LitElement {
this.hass, this.hass,
this._dialogParams!.backupParams this._dialogParams!.backupParams
); );
} catch (err: any) { } catch (err) {
this._error = extractApiErrorMessage(err); this._error = extractApiErrorMessage(err);
this._action = null; this._action = null;
return; return;
@@ -158,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: any) { } catch (err) {
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;

View File

@@ -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: any) { } catch (err) {
this._error = this.supervisor.localize("my.error"); this._error = this.supervisor.localize("my.error");
return; return;
} }

View File

@@ -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: any) { } catch (err) {
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: any) { } catch (err) {
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: any) { } catch (err) {
await showAlertDialog(this, { await showAlertDialog(this, {
text: "Unable to create an Ingress session", text: "Unable to create an Ingress session",
title: addon.name, title: addon.name,
@@ -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: any) { } catch (err) {
session = await createHassioSession(this.hass); session = await createHassioSession(this.hass);
} }
}, 60000); }, 60000);

View File

@@ -144,7 +144,7 @@ class HassioCoreInfo extends LitElement {
try { try {
await restartCore(this.hass); await restartCore(this.hass);
} catch (err: any) { } catch (err) {
if (this.hass.connection.connected) { if (this.hass.connection.connected) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize( title: this.supervisor.localize(

View File

@@ -18,6 +18,7 @@ import { fetchHassioHardwareInfo } from "../../../src/data/hassio/hardware";
import { import {
changeHostOptions, changeHostOptions,
configSyncOS, configSyncOS,
dataDiskMove,
rebootHost, rebootHost,
shutdownHost, shutdownHost,
updateOS, updateOS,
@@ -39,9 +40,8 @@ import {
roundWithOneDecimal, roundWithOneDecimal,
} from "../../../src/util/calculate"; } from "../../../src/util/calculate";
import "../components/supervisor-metric"; import "../components/supervisor-metric";
import { showHassioDatadiskDialog } from "../dialogs/datadisk/show-dialog-hassio-datadisk";
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
import { showNetworkDialog } from "../dialogs/network/show-dialog-network"; import { showNetworkDialog } from "../dialogs/network/show-dialog-network";
import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware";
import { hassioStyle } from "../resources/hassio-style"; import { hassioStyle } from "../resources/hassio-style";
@customElement("hassio-host-info") @customElement("hassio-host-info")
@@ -184,34 +184,22 @@ class HassioHostInfo extends LitElement {
<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 @click=${() => this._handleMenuAction("hardware")}>
.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` ? html`<mwc-list-item
<mwc-list-item @click=${() => this._handleMenuAction("import_from_usb")}
.action=${"import_from_usb"}
@click=${this._handleMenuAction}
> >
${this.supervisor.localize("system.host.import_from_usb")} ${this.supervisor.localize("system.host.import_from_usb")}
</mwc-list-item> </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>
`
: ""} : ""}
` ${this.supervisor.host.features.includes("agent")
? html`<mwc-list-item
@click=${() => this._handleMenuAction("data_disk_move")}
>
${this.supervisor.localize("system.host.data_disk_move")}
</mwc-list-item>`
: ""} : ""}
</ha-button-menu> </ha-button-menu>
</div> </div>
@@ -234,31 +222,25 @@ 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) { private async _handleMenuAction(action: string) {
switch ((ev.target as any).action) { switch (action) {
case "hardware": case "hardware":
await this._showHardware(); await this._showHardware();
break; break;
case "import_from_usb": case "import_from_usb":
await this._importFromUSB(); await this._importFromUSB();
break; break;
case "move_datadisk": case "data_disk_move":
await this._moveDatadisk(); await this._dataDiskMove();
break; 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: any) { } catch (err) {
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"
@@ -288,7 +270,7 @@ class HassioHostInfo extends LitElement {
try { try {
await rebootHost(this.hass); await rebootHost(this.hass);
} catch (err: any) { } catch (err) {
// 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, {
@@ -318,7 +300,7 @@ class HassioHostInfo extends LitElement {
try { try {
await shutdownHost(this.hass); await shutdownHost(this.hass);
} catch (err: any) { } catch (err) {
// 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, {
@@ -359,7 +341,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: any) { } catch (err) {
if (this.hass.connection.connected) { if (this.hass.connection.connected) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize( title: this.supervisor.localize(
@@ -397,7 +379,7 @@ class HassioHostInfo extends LitElement {
fireEvent(this, "supervisor-collection-refresh", { fireEvent(this, "supervisor-collection-refresh", {
collection: "host", collection: "host",
}); });
} catch (err: any) { } catch (err) {
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),
@@ -412,7 +394,7 @@ class HassioHostInfo extends LitElement {
fireEvent(this, "supervisor-collection-refresh", { fireEvent(this, "supervisor-collection-refresh", {
collection: "host", collection: "host",
}); });
} catch (err: any) { } catch (err) {
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"
@@ -422,6 +404,34 @@ class HassioHostInfo extends LitElement {
} }
} }
private async _dataDiskMove(): Promise<void> {
const confirmed = await showConfirmationDialog(this, {
title: this.supervisor.localize("system.host.data_disk_move"),
text: html`${this.supervisor.localize(
"dialog.data_disk_move.description",
{ current_path: this.supervisor.os.data_disk }
)} <br /><br />${this.supervisor.localize(
"dialog.data_disk_move.confirm_text"
)}`,
confirmText: this.supervisor.localize("dialog.data_disk_move.move"),
dismissText: this.supervisor.localize("dialog.data_disk_move.cancel"),
});
if (!confirmed) {
return;
}
try {
await dataDiskMove(this.hass);
} catch (err) {
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
showAlertDialog(this, {
title: this.supervisor.localize("system.host.failed_to_move"),
text: extractApiErrorMessage(err),
});
}
}
}
private async _loadData(): Promise<void> { private async _loadData(): Promise<void> {
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) { if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
fireEvent(this, "supervisor-collection-refresh", { fireEvent(this, "supervisor-collection-refresh", {

View File

@@ -34,18 +34,16 @@ 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 = {
@@ -282,7 +280,7 @@ class HassioSupervisorInfo extends LitElement {
}; };
await setSupervisorOption(this.hass, data); await setSupervisorOption(this.hass, data);
await this._reloadSupervisor(); await this._reloadSupervisor();
} catch (err: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize( title: this.supervisor.localize(
"system.supervisor.failed_to_set_option" "system.supervisor.failed_to_set_option"
@@ -300,7 +298,7 @@ class HassioSupervisorInfo extends LitElement {
try { try {
await this._reloadSupervisor(); await this._reloadSupervisor();
} catch (err: any) { } catch (err) {
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),
@@ -343,7 +341,7 @@ class HassioSupervisorInfo extends LitElement {
try { try {
await restartSupervisor(this.hass); await restartSupervisor(this.hass);
} catch (err: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize( title: this.supervisor.localize(
"common.failed_to_restart_name", "common.failed_to_restart_name",
@@ -388,7 +386,7 @@ class HassioSupervisorInfo extends LitElement {
fireEvent(this, "supervisor-collection-refresh", { fireEvent(this, "supervisor-collection-refresh", {
collection: "supervisor", collection: "supervisor",
}); });
} catch (err: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize( title: this.supervisor.localize(
"common.failed_to_update_name", "common.failed_to_update_name",
@@ -427,10 +425,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"
> >
@@ -458,10 +456,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"
> >
@@ -483,7 +481,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: any) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.supervisor.localize( title: this.supervisor.localize(
"system.supervisor.failed_to_set_option" "system.supervisor.failed_to_set_option"

View File

@@ -130,7 +130,7 @@ class HassioSupervisorLog extends LitElement {
this.hass, this.hass,
this._selectedLogProvider this._selectedLogProvider
); );
} catch (err: any) { } catch (err) {
this._error = this.supervisor.localize( this._error = this.supervisor.localize(
"system.log.get_logs", "system.log.get_logs",
"provider", "provider",

View File

@@ -1,3 +1,3 @@
[build.environment] [build.environment]
YARN_VERSION = "1.22.11" YARN_VERSION = "1.22.11"
NODE_OPTIONS = "--max_old_space_size=6144" NODE_OPTIONS = "--max_old_space_size=4096"

View File

@@ -16,7 +16,8 @@
"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",
"test": "instant-mocha --webpack-config ./test/webpack.config.js --require ./test/setup.js \"test/**/*.ts\"" "mocha": "ts-mocha -p test-mocha/tsconfig.test.json \"test-mocha/**/*.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",
@@ -33,39 +34,35 @@
"@codemirror/stream-parser": "^0.19.1", "@codemirror/stream-parser": "^0.19.1",
"@codemirror/text": "^0.19.2", "@codemirror/text": "^0.19.2",
"@codemirror/view": "^0.19.4", "@codemirror/view": "^0.19.4",
"@formatjs/intl-datetimeformat": "^4.2.4",
"@formatjs/intl-getcanonicallocales": "^1.7.3", "@formatjs/intl-getcanonicallocales": "^1.7.3",
"@formatjs/intl-locale": "^2.4.38", "@formatjs/intl-locale": "^2.4.37",
"@formatjs/intl-numberformat": "^7.2.4", "@formatjs/intl-pluralrules": "^4.1.3",
"@formatjs/intl-pluralrules": "^4.1.4",
"@formatjs/intl-relativetimeformat": "^9.3.1",
"@formatjs/intl-utils": "^3.8.4",
"@fullcalendar/common": "5.9.0", "@fullcalendar/common": "5.9.0",
"@fullcalendar/core": "5.9.0", "@fullcalendar/core": "5.9.0",
"@fullcalendar/daygrid": "5.9.0", "@fullcalendar/daygrid": "5.9.0",
"@fullcalendar/interaction": "5.9.0", "@fullcalendar/interaction": "5.9.0",
"@fullcalendar/list": "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": "13.0.0-canary.65125b3a6.0", "@material/chips": "12.0.0-canary.22d29cbb4.0",
"@material/data-table": "13.0.0-canary.65125b3a6.0", "@material/data-table": "12.0.0-canary.22d29cbb4.0",
"@material/mwc-button": "0.25.1", "@material/mwc-button": "0.22.1",
"@material/mwc-checkbox": "0.25.1", "@material/mwc-checkbox": "0.22.1",
"@material/mwc-circular-progress": "0.25.1", "@material/mwc-circular-progress": "0.22.1",
"@material/mwc-dialog": "0.25.1", "@material/mwc-dialog": "0.22.1",
"@material/mwc-fab": "0.25.1", "@material/mwc-fab": "0.22.1",
"@material/mwc-formfield": "0.25.1", "@material/mwc-formfield": "0.22.1",
"@material/mwc-icon-button": "0.25.1", "@material/mwc-icon-button": "0.22.1",
"@material/mwc-linear-progress": "0.25.1", "@material/mwc-linear-progress": "0.22.1",
"@material/mwc-list": "0.25.1", "@material/mwc-list": "0.22.1",
"@material/mwc-menu": "0.25.1", "@material/mwc-menu": "0.22.1",
"@material/mwc-radio": "0.25.1", "@material/mwc-radio": "0.22.1",
"@material/mwc-ripple": "0.25.1", "@material/mwc-ripple": "0.22.1",
"@material/mwc-switch": "0.25.1", "@material/mwc-switch": "0.22.1",
"@material/mwc-tab": "0.25.1", "@material/mwc-tab": "0.22.1",
"@material/mwc-tab-bar": "0.25.1", "@material/mwc-tab-bar": "0.22.1",
"@material/top-app-bar": "13.0.0-canary.65125b3a6.0", "@material/top-app-bar": "12.0.0-canary.22d29cbb4.0",
"@mdi/js": "6.2.95", "@mdi/js": "6.1.95",
"@mdi/svg": "6.2.95", "@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",
@@ -92,8 +89,8 @@
"@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.4", "@thomasloven/round-slider": "0.5.4",
"@vaadin/vaadin-combo-box": "^21.0.2", "@vaadin/vaadin-combo-box": "^20.0.4",
"@vaadin/vaadin-date-picker": "^21.0.2", "@vaadin/vaadin-date-picker": "^20.0.4",
"@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",
@@ -106,17 +103,18 @@
"date-fns": "^2.23.0", "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.11", "hls.js": "^1.0.10",
"home-assistant-js-websocket": "^5.11.1", "home-assistant-js-websocket": "^5.11.1",
"idb-keyval": "^5.1.3", "idb-keyval": "^5.1.3",
"intl-messageformat": "^9.9.1", "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", "lit": "^2.0.0-rc.3",
"lit-vaadin-helpers": "^0.2.1", "lit-vaadin-helpers": "^0.1.3",
"marked": "^3.0.2", "marked": "^3.0.2",
"memoize-one": "^5.2.1", "memoize-one": "^5.2.1",
"node-vibrant": "3.2.1-alpha.1", "node-vibrant": "3.2.1-alpha.1",
@@ -145,18 +143,17 @@
"xss": "^1.0.9" "xss": "^1.0.9"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.15.5", "@babel/core": "^7.14.6",
"@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.15.4", "@babel/plugin-proposal-decorators": "^7.14.5",
"@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.15.6", "@babel/plugin-proposal-object-rest-spread": "^7.14.7",
"@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/plugin-syntax-top-level-await": "^7.14.5", "@babel/preset-env": "^7.14.7",
"@babel/preset-env": "^7.15.6", "@babel/preset-typescript": "^7.14.5",
"@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",
@@ -173,24 +170,23 @@
"@types/mocha": "^8", "@types/mocha": "^8",
"@types/sortablejs": "^1", "@types/sortablejs": "^1",
"@types/webspeechapi": "^0.0.29", "@types/webspeechapi": "^0.0.29",
"@typescript-eslint/eslint-plugin": "^4.32.0", "@typescript-eslint/eslint-plugin": "^4.28.3",
"@typescript-eslint/parser": "^4.32.0", "@typescript-eslint/parser": "^4.28.3",
"@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.32.0", "eslint": "^7.30.0",
"eslint-config-airbnb-base": "^14.2.1", "eslint-config-airbnb-typescript": "^12.3.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.24.2", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-lit": "^1.5.1", "eslint-plugin-lit": "^1.5.1",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-unused-imports": "^1.1.5", "eslint-plugin-unused-imports": "^1.1.2",
"eslint-plugin-wc": "^1.3.2", "eslint-plugin-wc": "^1.3.0",
"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",
@@ -201,8 +197,7 @@
"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",
"instant-mocha": "^1.3.1", "lint-staged": "^11.0.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",
@@ -211,7 +206,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.4.1", "prettier": "^2.3.2",
"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",
@@ -221,26 +216,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.2.4", "terser-webpack-plugin": "^5.1.4",
"ts-lit-plugin": "^1.2.1", "ts-lit-plugin": "^1.2.1",
"typescript": "^4.4.3", "ts-mocha": "^8.0.0",
"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.55.1", "webpack": "^5.43.0",
"webpack-cli": "^4.8.0", "webpack-cli": "^4.7.2",
"webpack-dev-server": "^4.3.0", "webpack-dev-server": "^3.11.2",
"webpack-manifest-plugin": "^4.0.2", "webpack-manifest-plugin": "^3.1.1",
"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": "^2.0.0", "lit": "^2.0.0-rc.3",
"lit-html": "2.0.0", "lit-html": "2.0.0-rc.4",
"lit-element": "3.0.0", "lit-element": "3.0.0-rc.3",
"@lit/reactive-element": "1.0.0" "@lit/reactive-element": "1.0.0-rc.3"
}, },
"main": "src/home-assistant.js", "main": "src/home-assistant.js",
"husky": { "husky": {

View File

@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup( setup(
name="home-assistant-frontend", name="home-assistant-frontend",
version="20211007.1", version="20210911.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",

View File

@@ -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: any) { } catch (err) {
// 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: any) { } catch (err) {
// 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";

View File

@@ -76,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>
` `
: ""} : ""}
@@ -158,7 +158,7 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
this._authProviders = authProviders; this._authProviders = authProviders;
this._authProvider = authProviders[0]; this._authProvider = authProviders[0];
} catch (err: any) { } catch (err) {
// eslint-disable-next-line // eslint-disable-next-line
console.error("Error loading auth providers", err); console.error("Error loading auth providers", err);
} }

View File

@@ -1,4 +1,3 @@
/* 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";

View File

@@ -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 { css, html, LitElement } from "lit"; import { 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,6 +18,14 @@ 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`
@@ -33,14 +41,5 @@ 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);

View File

@@ -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: any) { } catch (err) {
// 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: any) { } catch (err) {
tokenCache.tokens = null; tokenCache.tokens = null;
} }
} }

View File

@@ -57,29 +57,28 @@ export const FIXED_DOMAIN_ICONS = {
export const FIXED_DEVICE_CLASS_ICONS = { export const FIXED_DEVICE_CLASS_ICONS = {
aqi: "hass:air-filter", aqi: "hass:air-filter",
battery: "hass:battery", current: "hass:current-ac",
carbon_dioxide: "mdi:molecule-co2", carbon_dioxide: "mdi:molecule-co2",
carbon_monoxide: "mdi:molecule-co", carbon_monoxide: "mdi:molecule-co",
current: "hass:current-ac",
date: "hass:calendar", date: "hass:calendar",
energy: "hass:lightning-bolt", energy: "hass:lightning-bolt",
gas: "hass:gas-cylinder", gas: "hass:gas-cylinder",
humidity: "hass:water-percent", humidity: "hass:water-percent",
illuminance: "hass:brightness-5", illuminance: "hass:brightness-5",
monetary: "mdi:cash",
nitrogen_dioxide: "mdi:molecule", nitrogen_dioxide: "mdi:molecule",
nitrogen_monoxide: "mdi:molecule", nitrogen_monoxide: "mdi:molecule",
nitrous_oxide: "mdi:molecule", nitrous_oxide: "mdi:molecule",
ozone: "mdi:molecule", ozone: "mdi:molecule",
temperature: "hass:thermometer",
monetary: "mdi:cash",
pm25: "mdi:molecule",
pm1: "mdi:molecule", pm1: "mdi:molecule",
pm10: "mdi:molecule", pm10: "mdi:molecule",
pm25: "mdi:molecule", pressure: "hass:gauge",
power: "hass:flash", power: "hass:flash",
power_factor: "hass:angle-acute", power_factor: "hass:angle-acute",
pressure: "hass:gauge",
signal_strength: "hass:wifi", signal_strength: "hass:wifi",
sulphur_dioxide: "mdi:molecule", sulphur_dioxide: "mdi:molecule",
temperature: "hass:thermometer",
timestamp: "hass:clock", timestamp: "hass:clock",
volatile_organic_compounds: "mdi:molecule", volatile_organic_compounds: "mdi:molecule",
voltage: "hass:sine-wave", voltage: "hass:sine-wave",

View File

@@ -0,0 +1,34 @@
// 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();

View File

@@ -1,15 +1,13 @@
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 { polyfillsLoaded } from "../translations/localize"; import { toLocaleDateStringSupportsOptions } from "./check_options_support";
if (__BUILD__ === "latest" && polyfillsLoaded) {
await polyfillsLoaded;
}
// Tuesday, August 10 // Tuesday, August 10
export const formatDateWeekday = (dateObj: Date, locale: FrontendLocaleData) => export const formatDateWeekday = toLocaleDateStringSupportsOptions
formatDateWeekdayMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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, {
@@ -20,9 +18,10 @@ const formatDateWeekdayMem = memoizeOne(
); );
// August 10, 2021 // August 10, 2021
export const formatDate = (dateObj: Date, locale: FrontendLocaleData) => export const formatDate = toLocaleDateStringSupportsOptions
formatDateMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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, {
@@ -33,9 +32,10 @@ const formatDateMem = memoizeOne(
); );
// 10/08/2021 // 10/08/2021
export const formatDateNumeric = (dateObj: Date, locale: FrontendLocaleData) => export const formatDateNumeric = toLocaleDateStringSupportsOptions
formatDateNumericMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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,9 +46,10 @@ const formatDateNumericMem = memoizeOne(
); );
// Aug 10 // Aug 10
export const formatDateShort = (dateObj: Date, locale: FrontendLocaleData) => export const formatDateShort = toLocaleDateStringSupportsOptions
formatDateShortMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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, {
@@ -58,11 +59,10 @@ const formatDateShortMem = memoizeOne(
); );
// August 2021 // August 2021
export const formatDateMonthYear = ( export const formatDateMonthYear = toLocaleDateStringSupportsOptions
dateObj: Date, ? (dateObj: Date, locale: FrontendLocaleData) =>
locale: FrontendLocaleData formatDateMonthYearMem(locale).format(dateObj)
) => formatDateMonthYearMem(locale).format(dateObj); : (dateObj: Date) => format(dateObj, "MMMM YYYY");
const formatDateMonthYearMem = memoizeOne( const formatDateMonthYearMem = memoizeOne(
(locale: FrontendLocaleData) => (locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(locale.language, { new Intl.DateTimeFormat(locale.language, {
@@ -72,9 +72,10 @@ const formatDateMonthYearMem = memoizeOne(
); );
// August // August
export const formatDateMonth = (dateObj: Date, locale: FrontendLocaleData) => export const formatDateMonth = toLocaleDateStringSupportsOptions
formatDateMonthMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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, {
@@ -83,9 +84,10 @@ const formatDateMonthMem = memoizeOne(
); );
// 2021 // 2021
export const formatDateYear = (dateObj: Date, locale: FrontendLocaleData) => export const formatDateYear = toLocaleDateStringSupportsOptions
formatDateYearMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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, {

View File

@@ -1,16 +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 { 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 = (dateObj: Date, locale: FrontendLocaleData) => export const formatDateTime = toLocaleStringSupportsOptions
formatDateTimeMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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, {
@@ -24,11 +23,11 @@ const formatDateTimeMem = memoizeOne(
); );
// August 9, 2021, 8:23:15 AM // August 9, 2021, 8:23:15 AM
export const formatDateTimeWithSeconds = ( export const formatDateTimeWithSeconds = toLocaleStringSupportsOptions
dateObj: Date, ? (dateObj: Date, locale: FrontendLocaleData) =>
locale: FrontendLocaleData formatDateTimeWithSecondsMem(locale).format(dateObj)
) => formatDateTimeWithSecondsMem(locale).format(dateObj); : (dateObj: Date, locale: FrontendLocaleData) =>
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, {
@@ -43,11 +42,11 @@ const formatDateTimeWithSecondsMem = memoizeOne(
); );
// 9/8/2021, 8:23 AM // 9/8/2021, 8:23 AM
export const formatDateTimeNumeric = ( export const formatDateTimeNumeric = toLocaleStringSupportsOptions
dateObj: Date, ? (dateObj: Date, locale: FrontendLocaleData) =>
locale: FrontendLocaleData formatDateTimeNumericMem(locale).format(dateObj)
) => formatDateTimeNumericMem(locale).format(dateObj); : (dateObj: Date, locale: FrontendLocaleData) =>
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, {

View File

@@ -1,31 +1,30 @@
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 = (dateObj: Date, locale: FrontendLocaleData) => export const formatTime = toLocaleTimeStringSupportsOptions
formatTimeMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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, {
hour: "numeric", hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit", minute: "2-digit",
hour12: useAmPm(locale), hour12: useAmPm(locale),
}) })
); );
// 9:15:24 PM || 21:15:24 // 9:15:24 PM || 21:15:24
export const formatTimeWithSeconds = ( export const formatTimeWithSeconds = toLocaleTimeStringSupportsOptions
dateObj: Date, ? (dateObj: Date, locale: FrontendLocaleData) =>
locale: FrontendLocaleData formatTimeWithSecondsMem(locale).format(dateObj)
) => formatTimeWithSecondsMem(locale).format(dateObj); : (dateObj: Date, locale: FrontendLocaleData) =>
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, {
@@ -37,15 +36,17 @@ const formatTimeWithSecondsMem = memoizeOne(
); );
// Tuesday 7:00 PM || Tuesday 19:00 // Tuesday 7:00 PM || Tuesday 19:00
export const formatTimeWeekday = (dateObj: Date, locale: FrontendLocaleData) => export const formatTimeWeekday = toLocaleTimeStringSupportsOptions
formatTimeWeekdayMem(locale).format(dateObj); ? (dateObj: Date, locale: FrontendLocaleData) =>
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: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit", minute: "2-digit",
second: "2-digit",
hour12: useAmPm(locale), hour12: useAmPm(locale),
}) })
); );

View File

@@ -1,32 +1,48 @@
import { selectUnit } from "@formatjs/intl-utils"; import { LocalizeFunc } from "../translations/localize";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import { polyfillsLoaded } from "../translations/localize";
if (__BUILD__ === "latest" && polyfillsLoaded) { /**
await polyfillsLoaded; * Calculate a string representing a date object as relative time from now.
} *
* Example output: 5 minutes ago, in 3 days.
*/
const tests = [60, 60, 24, 7];
const langKey = ["second", "minute", "hour", "day"];
const formatRelTimeMem = memoizeOne( export default function relativeTime(
(locale: FrontendLocaleData) => dateObj: Date,
// @ts-expect-error localize: LocalizeFunc,
new Intl.RelativeTimeFormat(locale.language, { numeric: "auto" }) 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);
export const relativeTime = ( if (roundedDelta === 0) {
from: Date, return localize("ui.components.relative_time.just_now");
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", let unit = "week";
// @ts-expect-error
unit: diff.unit, for (let i = 0; i < tests.length; i++) {
unitDisplay: "long", if (roundedDelta < tests[i]) {
}).format(Math.abs(diff.value)); 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
);
}

View File

@@ -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: any) { } catch (err) {
// Safari in private mode doesn't allow localstorage // Safari in private mode doesn't allow localstorage
} }
} }

View File

@@ -115,7 +115,7 @@ export const applyThemesOnElement = (
} }
const newTheme = const newTheme =
Object.keys(themeRules).length && cacheKey themeRules && cacheKey
? PROCESSED_THEMES[cacheKey] || processTheme(cacheKey, themeRules) ? PROCESSED_THEMES[cacheKey] || processTheme(cacheKey, themeRules)
: undefined; : undefined;
@@ -167,7 +167,7 @@ const processTheme = (
const prefixedRgbKey = `--${rgbKey}`; const prefixedRgbKey = `--${rgbKey}`;
styles[prefixedRgbKey] = rgbValue; styles[prefixedRgbKey] = rgbValue;
keys[prefixedRgbKey] = ""; keys[prefixedRgbKey] = "";
} catch (err: any) { } catch (e) {
continue; continue;
} }
} }

View File

@@ -5,4 +5,4 @@ export const mainWindow =
? window ? window
: parent.name === MAIN_WINDOW_NAME : parent.name === MAIN_WINDOW_NAME
? parent ? parent
: top!; : top;

View File

@@ -1,24 +0,0 @@
/** 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";
}
};

View File

@@ -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 "../number/format_number"; import { formatNumber } from "../string/format_number";
import { LocalizeFunc } from "../translations/localize"; import { LocalizeFunc } from "../translations/localize";
import { computeStateDomain } from "./compute_state_domain"; import { computeStateDomain } from "./compute_state_domain";

View File

@@ -5,7 +5,6 @@ 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";
@@ -19,7 +18,18 @@ export const domainIcon = (
switch (domain) { switch (domain) {
case "alarm_control_panel": case "alarm_control_panel":
return alarmPanelIcon(compareState); switch (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);

View File

@@ -1,2 +0,0 @@
export const capitalizeFirstLetter = (str: string) =>
str.charAt(0).toUpperCase() + str.slice(1);

View File

@@ -180,10 +180,10 @@ export function fuzzyScore(
wordLow wordLow
); );
let row: number; let row = 1;
let column = 1; let column = 1;
let patternPos: number; let patternPos = patternStart;
let wordPos: number; let wordPos = wordStart;
const hasStrongFirstMatch = [false]; const hasStrongFirstMatch = [false];

View File

@@ -1,5 +1,5 @@
import { FrontendLocaleData, NumberFormat } from "../../data/translation"; import { FrontendLocaleData, NumberFormat } from "../../data/translation";
import { round } from "./round"; import { round } from "../number/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 (err: any) { } catch (error) {
// 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(err); console.error(error);
return new Intl.NumberFormat( return new Intl.NumberFormat(
undefined, undefined,
getDefaultFormatOptions(num, options) getDefaultFormatOptions(num, options)

View File

@@ -1,10 +1,6 @@
import { shouldPolyfill as shouldPolyfillLocale } from "@formatjs/intl-locale/lib/should-polyfill"; import { shouldPolyfill } from "@formatjs/intl-pluralrules/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";
import { getLocalLanguage } from "../../util/common-translation";
export type LocalizeFunc = (key: string, ...args: any[]) => string; export type LocalizeFunc = (key: string, ...args: any[]) => string;
interface FormatType { interface FormatType {
@@ -16,32 +12,17 @@ export interface FormatsType {
time: FormatType; time: FormatType;
} }
const loadedPolyfillLocale = new Set(); let loadedPolyfillLocale: Set<string> | undefined;
const polyfills: Promise<any>[] = []; let polyfillLoaded = !shouldPolyfill();
if (__BUILD__ === "latest") { const polyfillProm = polyfillLoaded
if (shouldPolyfillLocale()) {
polyfills.push(import("@formatjs/intl-locale/polyfill"));
}
if (shouldPolyfillPluralRules()) {
polyfills.push(import("@formatjs/intl-pluralrules/polyfill"));
polyfills.push(import("@formatjs/intl-pluralrules/locale-data/en"));
}
if (shouldPolyfillRelativeTime()) {
polyfills.push(import("@formatjs/intl-relativetimeformat/polyfill"));
}
if (shouldPolyfillDateTime()) {
polyfills.push(import("@formatjs/intl-datetimeformat/polyfill"));
}
}
export const polyfillsLoaded =
polyfills.length === 0
? undefined ? undefined
: Promise.all(polyfills).then(() => : import("@formatjs/intl-locale/polyfill")
// Load the default language .then(() => import("@formatjs/intl-pluralrules/polyfill"))
loadPolyfillLocales(getLocalLanguage()) .then(() => {
); loadedPolyfillLocale = new Set();
polyfillLoaded = true;
});
/** /**
* Adapted from Polymer app-localize-behavior. * Adapted from Polymer app-localize-behavior.
@@ -70,11 +51,18 @@ export const computeLocalize = async (
resources: Resources, resources: Resources,
formats?: FormatsType formats?: FormatsType
): Promise<LocalizeFunc> => { ): Promise<LocalizeFunc> => {
if (polyfillsLoaded) { if (!polyfillLoaded) {
await polyfillsLoaded; await polyfillProm;
} }
await loadPolyfillLocales(language); if (loadedPolyfillLocale && !loadedPolyfillLocale.has(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 = {};
@@ -104,7 +92,7 @@ export const computeLocalize = async (
language, language,
formats formats
); );
} catch (err: any) { } catch (err) {
return "Translation error: " + err.message; return "Translation error: " + err.message;
} }
cache._localizationCache[messageKey] = translatedMessage; cache._localizationCache[messageKey] = translatedMessage;
@@ -121,53 +109,8 @@ export const computeLocalize = async (
try { try {
return translatedMessage.format<string>(argObject) as string; return translatedMessage.format<string>(argObject) as string;
} catch (err: any) { } catch (err) {
return "Translation " + err; return "Translation " + err;
} }
}; };
}; };
export const loadPolyfillLocales = async (language: string) => {
if (loadedPolyfillLocale.has(language)) {
return;
}
loadedPolyfillLocale.add(language);
try {
if (
Intl.NumberFormat &&
// @ts-ignore
typeof Intl.NumberFormat.__addLocaleData === "function"
) {
const result = await fetch(
`/static/locale-data/intl-numberformat/${language}.json`
);
// @ts-ignore
Intl.NumberFormat.__addLocaleData(await result.json());
}
if (
// @ts-expect-error
Intl.RelativeTimeFormat &&
// @ts-ignore
typeof Intl.RelativeTimeFormat.__addLocaleData === "function"
) {
const result = await fetch(
`/static/locale-data/intl-relativetimeformat/${language}.json`
);
// @ts-ignore
Intl.RelativeTimeFormat.__addLocaleData(await result.json());
}
if (
Intl.DateTimeFormat &&
// @ts-ignore
typeof Intl.DateTimeFormat.__addLocaleData === "function"
) {
const result = await fetch(
`/static/locale-data/intl-datetimeformat/${language}.json`
);
// @ts-ignore
Intl.DateTimeFormat.__addLocaleData(await result.json());
}
} catch (_e) {
// Ignore
}
};

View File

@@ -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: any) { } catch (err) {
// Ignore the error // Ignore the error
} }
return null; return null;

View File

@@ -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: any) { } catch (err) {
this.progress = false; this.progress = false;
this._progressButton.actionError(); this._progressButton.actionError();
eventData.success = false; eventData.success = false;

View File

@@ -86,7 +86,6 @@ export default class HaChartBase extends LitElement {
class=${classMap({ class=${classMap({
hidden: this._hiddenDatasets.has(index), hidden: this._hiddenDatasets.has(index),
})} })}
.title=${dataset.label}
> >
<div <div
class="bullet" class="bullet"

View File

@@ -5,7 +5,7 @@ import { getColorByIndex } from "../../common/color/colors";
import { import {
formatNumber, formatNumber,
numberFormatToLocale, numberFormatToLocale,
} from "../../common/number/format_number"; } from "../../common/string/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";

View File

@@ -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/number/format_number"; import { numberFormatToLocale } from "../../common/string/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";
@@ -21,7 +21,6 @@ const BINARY_SENSOR_DEVICE_CLASS_COLOR_INVERTED = new Set([
"garage_door", "garage_door",
"gas", "gas",
"lock", "lock",
"motion",
"opening", "opening",
"problem", "problem",
"safety", "safety",
@@ -56,11 +55,7 @@ const getColor = (
entityState: HassEntity, entityState: HassEntity,
computedStyles: CSSStyleDeclaration computedStyles: CSSStyleDeclaration
) => { ) => {
// Inversion is only valid for "on" or "off" state if (invertOnOff(entityState)) {
if (
(stateString === "on" || stateString === "off") &&
invertOnOff(entityState)
) {
stateString = stateString === "on" ? "off" : "on"; stateString = stateString === "on" ? "off" : "on";
} }
if (stateColorMap.has(stateString)) { if (stateColorMap.has(stateString)) {

View File

@@ -19,7 +19,7 @@ import { computeStateName } from "../../common/entity/compute_state_name";
import { import {
formatNumber, formatNumber,
numberFormatToLocale, numberFormatToLocale,
} from "../../common/number/format_number"; } from "../../common/string/format_number";
import { import {
getStatisticIds, getStatisticIds,
Statistics, Statistics,

View File

@@ -1,5 +1,4 @@
import { Layout1d, scroll } from "@lit-labs/virtualizer"; import { Layout1d, scroll } from "@lit-labs/virtualizer";
import { mdiArrowDown, mdiArrowUp } from "@mdi/js";
import deepClone from "deep-clone-simple"; import deepClone from "deep-clone-simple";
import { import {
css, css,
@@ -28,7 +27,7 @@ import { nextRender } from "../../common/util/render-status";
import { haStyleScrollbar } from "../../resources/styles"; import { haStyleScrollbar } from "../../resources/styles";
import "../ha-checkbox"; import "../ha-checkbox";
import type { HaCheckbox } from "../ha-checkbox"; import type { HaCheckbox } from "../ha-checkbox";
import "../ha-svg-icon"; import "../ha-icon";
import { filterData, sortData } from "./sort-filter"; import { filterData, sortData } from "./sort-filter";
declare global { declare global {
@@ -312,11 +311,11 @@ export class HaDataTable extends LitElement {
> >
${column.sortable ${column.sortable
? html` ? html`
<ha-svg-icon <ha-icon
.path=${sorted && this._sortDirection === "desc" .icon=${sorted && this._sortDirection === "desc"
? mdiArrowDown ? "hass:arrow-down"
: mdiArrowUp} : "hass:arrow-up"}
></ha-svg-icon> ></ha-icon>
` `
: ""} : ""}
<span>${column.title}</span> <span>${column.title}</span>
@@ -551,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 (["HA-CHECKBOX", "MWC-BUTTON"].includes(target.tagName)) { if (target.tagName === "HA-CHECKBOX") {
return; return;
} }
const rowId = (ev.currentTarget as any).rowId; const rowId = (ev.currentTarget as any).rowId;
@@ -864,14 +863,14 @@ export class HaDataTable extends LitElement {
:host([dir="rtl"]) .mdc-data-table__header-cell > * { :host([dir="rtl"]) .mdc-data-table__header-cell > * {
transition: right 0.2s ease; transition: right 0.2s ease;
} }
.mdc-data-table__header-cell ha-svg-icon { .mdc-data-table__header-cell ha-icon {
top: -3px; top: -3px;
position: absolute; position: absolute;
} }
.mdc-data-table__header-cell.not-sorted ha-svg-icon { .mdc-data-table__header-cell.not-sorted ha-icon {
left: -20px; left: -20px;
} }
:host([dir="rtl"]) .mdc-data-table__header-cell.not-sorted ha-svg-icon { :host([dir="rtl"]) .mdc-data-table__header-cell.not-sorted ha-icon {
right: -20px; right: -20px;
} }
.mdc-data-table__header-cell.sortable:not(.not-sorted) span, .mdc-data-table__header-cell.sortable:not(.not-sorted) span,
@@ -887,16 +886,16 @@ export class HaDataTable extends LitElement {
left: auto; left: auto;
right: 24px; right: 24px;
} }
.mdc-data-table__header-cell.sortable:not(.not-sorted) ha-svg-icon, .mdc-data-table__header-cell.sortable:not(.not-sorted) ha-icon,
.mdc-data-table__header-cell.sortable:hover.not-sorted ha-svg-icon { .mdc-data-table__header-cell.sortable:hover.not-sorted ha-icon {
left: 12px; left: 12px;
} }
:host([dir="rtl"]) :host([dir="rtl"])
.mdc-data-table__header-cell.sortable:not(.not-sorted) .mdc-data-table__header-cell.sortable:not(.not-sorted)
ha-svg-icon, ha-icon,
:host([dir="rtl"]) :host([dir="rtl"])
.mdc-data-table__header-cell.sortable:hover.not-sorted .mdc-data-table__header-cell.sortable:hover.not-sorted
ha-svg-icon { ha-icon {
left: auto; left: auto;
right: 12px; right: 12px;
} }

View File

@@ -50,7 +50,6 @@ 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;

View File

@@ -46,7 +46,6 @@ 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;

View File

@@ -15,7 +15,7 @@ const haTabFixBehaviorImpl = {
}, },
}; };
// paper-dialog that uses the haTabFixBehaviorImpl behavior // paper-dialog that uses the haTabFixBehaviorImpl behvaior
// export class HaPaperDialog extends paperDialogClass {} // export class HaPaperDialog extends paperDialogClass {}
// @ts-ignore // @ts-ignore
export class HaPaperDialog export class HaPaperDialog

View File

@@ -23,7 +23,6 @@ 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;

View File

@@ -26,7 +26,6 @@ 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;

View File

@@ -1,4 +1,3 @@
import { mdiAlert } from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket"; import { HassEntity } from "home-assistant-js-websocket";
import { import {
css, css,
@@ -14,13 +13,13 @@ 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 { formatNumber } from "../../common/number/format_number";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { timerTimeRemaining } from "../../data/timer"; import { timerTimeRemaining } from "../../data/timer";
import { formatNumber } from "../../common/string/format_number";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import "../ha-label-badge"; import "../ha-label-badge";
import "../ha-icon";
@customElement("ha-state-label-badge") @customElement("ha-state-label-badge")
export class HaStateLabelBadge extends LitElement { export class HaStateLabelBadge extends LitElement {
@@ -59,49 +58,41 @@ 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")}"
description=${this.hass!.localize( icon="hass:alert"
description="${this.hass!.localize(
"state_badge.default.entity_not_found" "state_badge.default.entity_not_found"
)} )}"
> ></ha-label-badge>
<ha-svg-icon .path=${mdiAlert}></ha-svg-icon>
</ha-label-badge>
`; `;
} }
const domain = computeStateDomain(entityState); const domain = computeStateDomain(entityState);
const value = this._computeValue(domain, entityState); return html`
const icon = this.icon ? this.icon : this._computeIcon(domain, entityState); <ha-label-badge
const image = this.icon class="${classMap({
[domain]: true,
"has-unit_of_measurement":
"unit_of_measurement" in entityState.attributes,
})}"
.value="${this._computeValue(domain, entityState)}"
.icon="${this.icon
? 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(
return html`
<ha-label-badge
class=${classMap({
[domain]: true,
"has-unit_of_measurement":
"unit_of_measurement" in entityState.attributes,
})}
.image=${image}
.label=${this._computeLabel(
domain, domain,
entityState, entityState,
this._timerTimeRemaining this._timerTimeRemaining
)} )}"
.description=${this.name ?? computeStateName(entityState)} .description="${this.name ? this.name : computeStateName(entityState)}"
> ></ha-label-badge>
${!image && icon ? html`<ha-icon .icon=${icon}></ha-icon>` : ""}
${value && (this.icon || !this.image)
? html`<span class=${value && value.length > 4 ? "big" : ""}
>${value}</span
>`
: ""}
</ha-label-badge>
`; `;
} }
@@ -150,6 +141,26 @@ 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":
@@ -220,9 +231,7 @@ export class HaStateLabelBadge extends LitElement {
:host { :host {
cursor: pointer; cursor: pointer;
} }
.big {
font-size: 70%;
}
ha-label-badge { ha-label-badge {
--ha-label-badge-color: var(--label-badge-red, #df4c1e); --ha-label-badge-color: var(--label-badge-red, #df4c1e);
} }

View File

@@ -51,14 +51,6 @@ export class HaStatisticPicker extends LitElement {
@property({ type: Array, attribute: "include-unit-of-measurement" }) @property({ type: Array, attribute: "include-unit-of-measurement" })
public includeUnitOfMeasurement?: string[]; public includeUnitOfMeasurement?: string[];
/**
* Show only statistics with these device classes.
* @type {Array}
* @attr include-device-classes
*/
@property({ type: Array, attribute: "include-device-classes" })
public includeDeviceClasses?: string[];
/** /**
* Show only statistics on entities. * Show only statistics on entities.
* @type {Boolean} * @type {Boolean}
@@ -77,7 +69,6 @@ export class HaStatisticPicker extends LitElement {
id: string; id: string;
name: string; name: string;
state?: HassEntity; state?: HassEntity;
// eslint-disable-next-line lit/prefer-static-styles
}> = (item) => html`<style> }> = (item) => html`<style>
paper-icon-item { paper-icon-item {
padding: 0; padding: 0;
@@ -111,7 +102,7 @@ export class HaStatisticPicker extends LitElement {
? html`<a ? html`<a
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href=${documentationUrl(this.hass, "/more-info/statistics/")} href="${documentationUrl(this.hass, "/more-info/statistics/")}"
>${this.hass.localize( >${this.hass.localize(
"ui.components.statistic-picker.learn_more" "ui.components.statistic-picker.learn_more"
)}</a )}</a
@@ -125,7 +116,6 @@ export class HaStatisticPicker extends LitElement {
( (
statisticIds: StatisticsMetaData[], statisticIds: StatisticsMetaData[],
includeUnitOfMeasurement?: string[], includeUnitOfMeasurement?: string[],
includeDeviceClasses?: string[],
entitiesOnly?: boolean entitiesOnly?: boolean
): Array<{ id: string; name: string; state?: HassEntity }> => { ): Array<{ id: string; name: string; state?: HassEntity }> => {
if (!statisticIds.length) { if (!statisticIds.length) {
@@ -158,18 +148,11 @@ export class HaStatisticPicker extends LitElement {
} }
return; return;
} }
if (
!includeDeviceClasses ||
includeDeviceClasses.includes(
entityState!.attributes.device_class || ""
)
) {
output.push({ output.push({
id: meta.statistic_id, id: meta.statistic_id,
name: computeStateName(entityState), name: computeStateName(entityState),
state: entityState, state: entityState,
}); });
}
}); });
if (!output.length) { if (!output.length) {
@@ -220,7 +203,6 @@ export class HaStatisticPicker extends LitElement {
(this.comboBox as any).items = this._getStatistics( (this.comboBox as any).items = this._getStatistics(
this.statisticIds!, this.statisticIds!,
this.includeUnitOfMeasurement, this.includeUnitOfMeasurement,
this.includeDeviceClasses,
this.entitiesOnly this.entitiesOnly
); );
} else { } else {
@@ -228,7 +210,6 @@ export class HaStatisticPicker extends LitElement {
(this.comboBox as any).items = this._getStatistics( (this.comboBox as any).items = this._getStatistics(
this.statisticIds!, this.statisticIds!,
this.includeUnitOfMeasurement, this.includeUnitOfMeasurement,
this.includeDeviceClasses,
this.entitiesOnly this.entitiesOnly
); );
}); });

View File

@@ -24,15 +24,13 @@ class StateInfo extends LitElement {
return html``; return html``;
} }
const name = computeStateName(this.stateObj);
return html`<state-badge return html`<state-badge
.stateObj=${this.stateObj} .stateObj=${this.stateObj}
.stateColor=${true} .stateColor=${true}
></state-badge> ></state-badge>
<div class="info"> <div class="info">
<div class="name" .title=${name} .inDialog=${this.inDialog}> <div class="name" .inDialog=${this.inDialog}>
${name} ${computeStateName(this.stateObj)}
</div> </div>
${this.inDialog ${this.inDialog
? html`<div class="time-ago"> ? html`<div class="time-ago">
@@ -40,7 +38,6 @@ class StateInfo extends LitElement {
id="last_changed" id="last_changed"
.hass=${this.hass} .hass=${this.hass}
.datetime=${this.stateObj.last_changed} .datetime=${this.stateObj.last_changed}
capitalize
></ha-relative-time> ></ha-relative-time>
<paper-tooltip animation-delay="0" for="last_changed"> <paper-tooltip animation-delay="0" for="last_changed">
<div> <div>
@@ -95,6 +92,7 @@ class StateInfo extends LitElement {
state-badge { state-badge {
float: left; float: left;
} }
:host([rtl]) state-badge { :host([rtl]) state-badge {
float: right; float: right;
} }

View File

@@ -12,7 +12,6 @@ import { PolymerChangedEvent } from "../polymer-types";
import { HomeAssistant } from "../types"; import { HomeAssistant } from "../types";
import { HaComboBox } from "./ha-combo-box"; import { HaComboBox } from "./ha-combo-box";
// eslint-disable-next-line lit/prefer-static-styles
const rowRenderer: ComboBoxLitRenderer<HassioAddonInfo> = (item) => html`<style> const rowRenderer: ComboBoxLitRenderer<HassioAddonInfo> = (item) => html`<style>
paper-item { paper-item {
padding: 0; padding: 0;
@@ -110,7 +109,7 @@ class HaAddonPicker extends LitElement {
), ),
}); });
} }
} catch (err: any) { } catch (error) {
showAlertDialog(this, { showAlertDialog(this, {
title: this.hass.localize( title: this.hass.localize(
"ui.componencts.addon-picker.error.fetch_addons.title" "ui.componencts.addon-picker.error.fetch_addons.title"

Some files were not shown because too many files have changed in this diff Show More