mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 13:37:47 +00:00
Merge pull request #5848 from home-assistant/dev
This commit is contained in:
commit
51e7aaa805
@ -20,7 +20,7 @@ gulp.task(
|
||||
},
|
||||
"clean",
|
||||
gulp.parallel(
|
||||
"gen-service-worker-dev",
|
||||
"gen-service-worker-app-dev",
|
||||
"gen-icons-json",
|
||||
"gen-pages-dev",
|
||||
"gen-index-app-dev",
|
||||
@ -46,7 +46,7 @@ gulp.task(
|
||||
gulp.parallel(
|
||||
"gen-pages-prod",
|
||||
"gen-index-app-prod",
|
||||
"gen-service-worker-prod"
|
||||
"gen-service-worker-app-prod"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -5,13 +5,15 @@
|
||||
const gulp = require("gulp");
|
||||
const path = require("path");
|
||||
const fs = require("fs-extra");
|
||||
const config = require("../paths.js");
|
||||
const workboxBuild = require("workbox-build");
|
||||
const sourceMapUrl = require("source-map-url");
|
||||
const paths = require("../paths.js");
|
||||
|
||||
const swPath = path.resolve(config.root, "service_worker.js");
|
||||
const swDest = path.resolve(paths.root, "service_worker.js");
|
||||
|
||||
const writeSW = (content) => fs.outputFileSync(swPath, content.trim() + "\n");
|
||||
const writeSW = (content) => fs.outputFileSync(swDest, content.trim() + "\n");
|
||||
|
||||
gulp.task("gen-service-worker-dev", (done) => {
|
||||
gulp.task("gen-service-worker-app-dev", (done) => {
|
||||
writeSW(
|
||||
`
|
||||
console.debug('Service worker disabled in development');
|
||||
@ -24,10 +26,58 @@ self.addEventListener('install', (event) => {
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-service-worker-prod", (done) => {
|
||||
fs.copySync(
|
||||
path.resolve(config.output, "service_worker.js"),
|
||||
path.resolve(config.root, "service_worker.js")
|
||||
gulp.task("gen-service-worker-app-prod", async () => {
|
||||
const workboxManifest = await workboxBuild.getManifest({
|
||||
// Files that mach this pattern will be considered unique and skip revision check
|
||||
// ignore JS files + translation files
|
||||
dontCacheBustURLsMatching: /(frontend_latest\/.+|static\/translations\/.+)/,
|
||||
|
||||
globDirectory: paths.root,
|
||||
globPatterns: [
|
||||
"frontend_latest/*.js",
|
||||
// Cache all English translations because we catch them as fallback
|
||||
// Using pattern to match hash instead of * to avoid caching en-GB
|
||||
"static/translations/**/en-+([a-f0-9]).json",
|
||||
// Icon shown on splash screen
|
||||
"static/icons/favicon-192x192.png",
|
||||
"static/icons/favicon.ico",
|
||||
// Common fonts
|
||||
"static/fonts/roboto/Roboto-Light.woff2",
|
||||
"static/fonts/roboto/Roboto-Medium.woff2",
|
||||
"static/fonts/roboto/Roboto-Regular.woff2",
|
||||
"static/fonts/roboto/Roboto-Bold.woff2",
|
||||
],
|
||||
});
|
||||
|
||||
for (const warning of workboxManifest.warnings) {
|
||||
console.warn(warning);
|
||||
}
|
||||
|
||||
// Replace `null` with 0 for better compression
|
||||
for (const entry of workboxManifest.manifestEntries) {
|
||||
if (entry.revision === null) {
|
||||
entry.revision = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const manifest = require(path.resolve(paths.output, "manifest.json"));
|
||||
|
||||
// Write bundled source file
|
||||
let serviceWorkerContent = fs.readFileSync(
|
||||
paths.root + manifest["service_worker.js"],
|
||||
"utf-8"
|
||||
);
|
||||
done();
|
||||
// remove source map and add WB manifest
|
||||
serviceWorkerContent = sourceMapUrl.removeFrom(serviceWorkerContent);
|
||||
serviceWorkerContent = serviceWorkerContent.replace(
|
||||
"WB_MANIFEST",
|
||||
JSON.stringify(workboxManifest.manifestEntries)
|
||||
);
|
||||
|
||||
// Write new file to root
|
||||
fs.writeFileSync(swDest, serviceWorkerContent);
|
||||
|
||||
// Delete old file from frontend_latest
|
||||
fs.removeSync(paths.root + manifest["service_worker.js"]);
|
||||
fs.removeSync(paths.root + manifest["service_worker.js.map"]);
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const WorkboxPlugin = require("workbox-webpack-plugin");
|
||||
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||
const paths = require("./paths.js");
|
||||
const env = require("./env.js");
|
||||
@ -107,8 +106,9 @@ const createWebpackConfig = ({
|
||||
};
|
||||
|
||||
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
const config = createWebpackConfig({
|
||||
return createWebpackConfig({
|
||||
entry: {
|
||||
service_worker: "./src/entrypoints/service_worker.ts",
|
||||
app: "./src/entrypoints/app.ts",
|
||||
authorize: "./src/entrypoints/authorize.ts",
|
||||
onboarding: "./src/entrypoints/onboarding.ts",
|
||||
@ -121,48 +121,6 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
latestBuild,
|
||||
isStatsBuild,
|
||||
});
|
||||
|
||||
if (latestBuild) {
|
||||
// Create an object mapping browser urls to their paths during build
|
||||
const translationMetadata = require("../build-translations/translationMetadata.json");
|
||||
const workBoxTranslationsTemplatedURLs = {};
|
||||
const englishFilename = `en-${translationMetadata.translations.en.hash}.json`;
|
||||
|
||||
// core
|
||||
workBoxTranslationsTemplatedURLs[
|
||||
`/static/translations/${englishFilename}`
|
||||
] = `build-translations/output/${englishFilename}`;
|
||||
|
||||
translationMetadata.fragments.forEach((fragment) => {
|
||||
workBoxTranslationsTemplatedURLs[
|
||||
`/static/translations/${fragment}/${englishFilename}`
|
||||
] = `build-translations/output/${fragment}/${englishFilename}`;
|
||||
});
|
||||
|
||||
config.plugins.push(
|
||||
new WorkboxPlugin.InjectManifest({
|
||||
swSrc: "./src/entrypoints/service-worker-hass.js",
|
||||
swDest: "service_worker.js",
|
||||
importWorkboxFrom: "local",
|
||||
include: [/\.js$/],
|
||||
templatedURLs: {
|
||||
...workBoxTranslationsTemplatedURLs,
|
||||
"/static/icons/favicon-192x192.png":
|
||||
"public/icons/favicon-192x192.png",
|
||||
"/static/fonts/roboto/Roboto-Light.woff2":
|
||||
"node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff2",
|
||||
"/static/fonts/roboto/Roboto-Medium.woff2":
|
||||
"node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff2",
|
||||
"/static/fonts/roboto/Roboto-Regular.woff2":
|
||||
"node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff2",
|
||||
"/static/fonts/roboto/Roboto-Bold.woff2":
|
||||
"node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff2",
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
|
@ -114,6 +114,10 @@
|
||||
"tslib": "^1.10.0",
|
||||
"unfetch": "^4.1.0",
|
||||
"web-animations-js": "^2.3.2",
|
||||
"workbox-core": "^5.1.3",
|
||||
"workbox-precaching": "^5.1.3",
|
||||
"workbox-routing": "^5.1.3",
|
||||
"workbox-strategies": "^5.1.3",
|
||||
"xss": "^1.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -177,6 +181,7 @@
|
||||
"reify": "^0.18.1",
|
||||
"require-dir": "^1.2.0",
|
||||
"sinon": "^7.3.1",
|
||||
"source-map-url": "^0.4.0",
|
||||
"terser-webpack-plugin": "^1.2.3",
|
||||
"ts-lit-plugin": "^1.1.10",
|
||||
"ts-mocha": "^6.0.0",
|
||||
@ -188,7 +193,7 @@
|
||||
"webpack-cli": "^3.3.9",
|
||||
"webpack-dev-server": "^3.10.3",
|
||||
"webpack-manifest-plugin": "^2.0.4",
|
||||
"workbox-webpack-plugin": "^4.1.1",
|
||||
"workbox-build": "^5.1.3",
|
||||
"workerize-loader": "^1.1.0"
|
||||
},
|
||||
"_comment": "Polymer fixed to 3.1 because 3.2 throws on logbook page",
|
||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20200512.0",
|
||||
version="20200513.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
import {
|
||||
css,
|
||||
CSSResult,
|
||||
@ -6,7 +7,6 @@ import {
|
||||
LitElement,
|
||||
property,
|
||||
PropertyValues,
|
||||
query,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { ifDefined } from "lit-html/directives/if-defined";
|
||||
@ -16,7 +16,6 @@ import { stateIcon } from "../../common/entity/state_icon";
|
||||
import { iconColorCSS } from "../../common/style/icon_color_css";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import "../ha-icon";
|
||||
import type { HaIcon } from "../ha-icon";
|
||||
|
||||
export class StateBadge extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
@ -29,12 +28,15 @@ export class StateBadge extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public stateColor?: boolean;
|
||||
|
||||
@query("ha-icon") private _icon!: HaIcon;
|
||||
@property({ type: Boolean, reflect: true, attribute: "icon" })
|
||||
private _showIcon = true;
|
||||
|
||||
@property() private _iconStyle: { [name: string]: string } = {};
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const stateObj = this.stateObj;
|
||||
|
||||
if (!stateObj) {
|
||||
if (!stateObj || !this._showIcon) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
@ -42,7 +44,7 @@ export class StateBadge extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-icon
|
||||
id="icon"
|
||||
style=${styleMap(this._iconStyle)}
|
||||
data-domain=${ifDefined(
|
||||
this.stateColor || (domain === "light" && this.stateColor !== false)
|
||||
? domain
|
||||
@ -60,14 +62,13 @@ export class StateBadge extends LitElement {
|
||||
}
|
||||
const stateObj = this.stateObj;
|
||||
|
||||
const iconStyle: Partial<CSSStyleDeclaration> = {
|
||||
color: "",
|
||||
filter: "",
|
||||
display: "",
|
||||
};
|
||||
const iconStyle: { [name: string]: string } = {};
|
||||
const hostStyle: Partial<CSSStyleDeclaration> = {
|
||||
backgroundImage: "",
|
||||
};
|
||||
|
||||
this._showIcon = true;
|
||||
|
||||
if (stateObj) {
|
||||
// hide icon if we have entity picture
|
||||
if (
|
||||
@ -79,7 +80,7 @@ export class StateBadge extends LitElement {
|
||||
imageUrl = this.hass.hassUrl(imageUrl);
|
||||
}
|
||||
hostStyle.backgroundImage = `url(${imageUrl})`;
|
||||
iconStyle.display = "none";
|
||||
this._showIcon = false;
|
||||
} else if (stateObj.state === "on") {
|
||||
if (stateObj.attributes.hs_color && this.stateColor !== false) {
|
||||
const hue = stateObj.attributes.hs_color[0];
|
||||
@ -102,7 +103,7 @@ export class StateBadge extends LitElement {
|
||||
}
|
||||
}
|
||||
}
|
||||
Object.assign(this._icon.style, iconStyle);
|
||||
this._iconStyle = iconStyle;
|
||||
Object.assign(this.style, hostStyle);
|
||||
}
|
||||
|
||||
@ -119,8 +120,17 @@ export class StateBadge extends LitElement {
|
||||
background-size: cover;
|
||||
line-height: 40px;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host(:focus) {
|
||||
outline: none;
|
||||
}
|
||||
:host(:not([icon]):focus) {
|
||||
border: 2px solid var(--divider-color);
|
||||
}
|
||||
:host([icon]:focus) {
|
||||
background: var(--divider-color);
|
||||
}
|
||||
|
||||
ha-icon {
|
||||
transition: color 0.3s ease-in-out, filter 0.3s ease-in-out;
|
||||
}
|
||||
|
@ -1,40 +1,51 @@
|
||||
/*
|
||||
This file is not run through webpack, but instead is directly manipulated
|
||||
by Workbox Webpack plugin. So we cannot use __DEV__ or other constants.
|
||||
*/
|
||||
/* global workbox clients */
|
||||
/* eslint-disable @typescript-eslint/triple-slash-reference */
|
||||
// eslint-disable-next-line spaced-comment
|
||||
/// <reference path="../types/service-worker.d.ts" />
|
||||
/* eslint-env serviceworker */
|
||||
import {
|
||||
CacheFirst,
|
||||
StaleWhileRevalidate,
|
||||
NetworkOnly,
|
||||
} from "workbox-strategies";
|
||||
import { cleanupOutdatedCaches, precacheAndRoute } from "workbox-precaching";
|
||||
import { registerRoute } from "workbox-routing";
|
||||
import { cacheNames } from "workbox-core";
|
||||
|
||||
// Clean up caches from older workboxes and old service workers.
|
||||
// Will help with cleaning up Workbox v4 stuff
|
||||
cleanupOutdatedCaches();
|
||||
|
||||
function initRouting() {
|
||||
workbox.precaching.precacheAndRoute(self.__precacheManifest || []);
|
||||
precacheAndRoute(
|
||||
// @ts-ignore
|
||||
WB_MANIFEST
|
||||
);
|
||||
|
||||
// Cache static content (including translations) on first access.
|
||||
workbox.routing.registerRoute(
|
||||
registerRoute(
|
||||
new RegExp(`${location.host}/(static|frontend_latest|frontend_es5)/.+`),
|
||||
new workbox.strategies.CacheFirst()
|
||||
new CacheFirst()
|
||||
);
|
||||
|
||||
// Get api from network.
|
||||
workbox.routing.registerRoute(
|
||||
registerRoute(
|
||||
new RegExp(`${location.host}/(api|auth)/.*`),
|
||||
new workbox.strategies.NetworkOnly()
|
||||
new NetworkOnly()
|
||||
);
|
||||
|
||||
// Get manifest, service worker, onboarding from network.
|
||||
workbox.routing.registerRoute(
|
||||
registerRoute(
|
||||
new RegExp(
|
||||
`${location.host}/(service_worker.js|manifest.json|onboarding.html)`
|
||||
),
|
||||
new workbox.strategies.NetworkOnly()
|
||||
new NetworkOnly()
|
||||
);
|
||||
|
||||
// For rest of the files (on Home Assistant domain only) try both cache and network.
|
||||
// This includes the root "/" or "/states" response and user files from "/local".
|
||||
// First access might bring stale data from cache, but a single refresh will bring updated
|
||||
// file.
|
||||
workbox.routing.registerRoute(
|
||||
new RegExp(`${location.host}/.*`),
|
||||
new workbox.strategies.StaleWhileRevalidate()
|
||||
);
|
||||
registerRoute(new RegExp(`${location.host}/.*`), new StaleWhileRevalidate());
|
||||
}
|
||||
|
||||
function initPushNotifications() {
|
||||
@ -149,7 +160,7 @@ function initPushNotifications() {
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
// Delete all runtime caching, so that index.html has to be refetched.
|
||||
const cacheName = workbox.core.cacheNames.runtime;
|
||||
const cacheName = cacheNames.runtime;
|
||||
event.waitUntil(caches.delete(cacheName));
|
||||
});
|
||||
|
||||
@ -160,9 +171,5 @@ self.addEventListener("message", (message) => {
|
||||
}
|
||||
});
|
||||
|
||||
workbox.setConfig({
|
||||
debug: false,
|
||||
});
|
||||
|
||||
initRouting();
|
||||
initPushNotifications();
|
@ -18,7 +18,6 @@ import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { findEntities } from "../common/find-entites";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-warning";
|
||||
@ -108,46 +107,40 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
: !UNAVAILABLE_STATES.includes(stateObj.state);
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<div
|
||||
@action=${this._handleClick}
|
||||
.actionHandler=${actionHandler()}
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="header">
|
||||
<div class="name">
|
||||
${this._config.name || computeStateName(stateObj)}
|
||||
</div>
|
||||
<div class="icon">
|
||||
<ha-icon
|
||||
.icon=${this._config.icon || stateIcon(stateObj)}
|
||||
></ha-icon>
|
||||
</div>
|
||||
<ha-card @click=${this._handleClick} tabindex="0">
|
||||
<div class="header">
|
||||
<div class="name">
|
||||
${this._config.name || computeStateName(stateObj)}
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="value"
|
||||
>${"attribute" in this._config
|
||||
? stateObj.attributes[this._config.attribute!] ||
|
||||
this.hass.localize("state.default.unknown")
|
||||
: stateObj.attributes.unit_of_measurement
|
||||
? stateObj.state
|
||||
: computeStateDisplay(
|
||||
this.hass.localize,
|
||||
stateObj,
|
||||
this.hass.language
|
||||
)}</span
|
||||
>${showUnit
|
||||
? html`
|
||||
<span class="measurement"
|
||||
>${this._config.unit ||
|
||||
(this._config.attribute
|
||||
? ""
|
||||
: stateObj.attributes.unit_of_measurement)}</span
|
||||
>
|
||||
`
|
||||
: ""}
|
||||
<div class="icon">
|
||||
<ha-icon
|
||||
.icon=${this._config.icon || stateIcon(stateObj)}
|
||||
></ha-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="value"
|
||||
>${"attribute" in this._config
|
||||
? stateObj.attributes[this._config.attribute!] ||
|
||||
this.hass.localize("state.default.unknown")
|
||||
: stateObj.attributes.unit_of_measurement
|
||||
? stateObj.state
|
||||
: computeStateDisplay(
|
||||
this.hass.localize,
|
||||
stateObj,
|
||||
this.hass.language
|
||||
)}</span
|
||||
>${showUnit
|
||||
? html`
|
||||
<span class="measurement"
|
||||
>${this._config.unit ||
|
||||
(this._config.attribute
|
||||
? ""
|
||||
: stateObj.attributes.unit_of_measurement)}</span
|
||||
>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
${this._footerElement}
|
||||
</ha-card>
|
||||
`;
|
||||
@ -194,9 +187,8 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
ha-card > div {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
|
@ -327,6 +327,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
|
||||
ha-card {
|
||||
cursor: pointer;
|
||||
padding: 16px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
|
@ -184,11 +184,6 @@ class HuiGenericEntityRow extends LitElement {
|
||||
state-badge {
|
||||
flex: 0 0 40px;
|
||||
}
|
||||
state-badge:focus {
|
||||
outline: none;
|
||||
background: var(--divider-color);
|
||||
border-radius: 100%;
|
||||
}
|
||||
:host([rtl]) .flex {
|
||||
margin-left: 0;
|
||||
margin-right: 16px;
|
||||
|
@ -13,15 +13,23 @@ import { HomeAssistant } from "../../../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
import "../components/hui-warning";
|
||||
import { EntityConfig, LovelaceRow } from "./types";
|
||||
import { LovelaceRow } from "./types";
|
||||
import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { EntitiesCardEntityConfig } from "../cards/types";
|
||||
|
||||
@customElement("hui-text-entity-row")
|
||||
class HuiTextEntityRow extends LitElement implements LovelaceRow {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: EntityConfig;
|
||||
@property() private _config?: EntitiesCardEntityConfig;
|
||||
|
||||
public setConfig(config: EntityConfig): void {
|
||||
public setConfig(config: EntitiesCardEntityConfig): void {
|
||||
if (!config) {
|
||||
throw new Error("Configuration error");
|
||||
}
|
||||
@ -51,9 +59,23 @@ class HuiTextEntityRow extends LitElement implements LovelaceRow {
|
||||
`;
|
||||
}
|
||||
|
||||
const pointer =
|
||||
(this._config.tap_action && this._config.tap_action.action !== "none") ||
|
||||
(this._config.entity &&
|
||||
!DOMAINS_HIDE_MORE_INFO.includes(computeDomain(this._config.entity)));
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||
<div class="text-content">
|
||||
<div
|
||||
class="text-content ${classMap({
|
||||
pointer,
|
||||
})}"
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler({
|
||||
hasHold: hasAction(this._config.hold_action),
|
||||
hasDoubleClick: hasAction(this._config.double_tap_action),
|
||||
})}
|
||||
>
|
||||
${computeStateDisplay(
|
||||
this.hass!.localize,
|
||||
stateObj,
|
||||
@ -64,11 +86,18 @@ class HuiTextEntityRow extends LitElement implements LovelaceRow {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleAction(ev: ActionHandlerEvent) {
|
||||
handleAction(this, this.hass!, this._config!, ev.detail.action);
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
div {
|
||||
text-align: right;
|
||||
}
|
||||
.pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="icon-image${classMap({
|
||||
class="icon-image ${classMap({
|
||||
pointer,
|
||||
})}"
|
||||
@action=${this._handleAction}
|
||||
@ -165,6 +165,12 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.icon-image:focus {
|
||||
outline: none;
|
||||
background-color: var(--divider-color);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.weather-icon {
|
||||
--iron-icon-width: 40px;
|
||||
--iron-icon-height: 40px;
|
||||
|
@ -75,7 +75,7 @@ export class HuiGraphHeaderFooter extends LitElement
|
||||
`;
|
||||
}
|
||||
|
||||
if (this._coordinates.length < 1) {
|
||||
if (!this._coordinates.length) {
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="info">
|
||||
@ -146,12 +146,13 @@ export class HuiGraphHeaderFooter extends LitElement
|
||||
this._stateHistory!.push(...stateHistory[0]);
|
||||
}
|
||||
|
||||
this._coordinates = coordinates(
|
||||
this._stateHistory,
|
||||
this._config!.hours_to_show!,
|
||||
500,
|
||||
this._config!.detail!
|
||||
);
|
||||
this._coordinates =
|
||||
coordinates(
|
||||
this._stateHistory,
|
||||
this._config!.hours_to_show!,
|
||||
500,
|
||||
this._config!.detail!
|
||||
) || [];
|
||||
|
||||
this._date = endTime;
|
||||
this._fetching = false;
|
||||
|
@ -224,6 +224,9 @@ export class HUIView extends LitElement {
|
||||
});
|
||||
this._createColumns(wrappedCards);
|
||||
} else {
|
||||
this._cards.forEach((card) => {
|
||||
(card as LovelaceCard).editMode = false;
|
||||
});
|
||||
this._createColumns(this._cards);
|
||||
}
|
||||
}
|
||||
|
126
src/types/service-worker.d.ts
vendored
Normal file
126
src/types/service-worker.d.ts
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
// From https://gist.githubusercontent.com/tiernan/c18a380935e45a6d942ac1e88c5bbaf3/raw/1d103eb5882504505ccc84cbc9398ac20418ef8a/serviceworker.d.ts
|
||||
/**
|
||||
* Copyright (c) 2018, Tiernan Cridland
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
||||
* granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Service Worker Typings to supplement lib.webworker.ts
|
||||
* @author Tiernan Cridland
|
||||
* @email tiernanc@gmail.com
|
||||
* @license: ISC
|
||||
*
|
||||
* lib.webworker.d.ts as well as an es5+ library (es5, es2015, etc) are required.
|
||||
* Recommended to be used with a triple slash directive in the files requiring the typings only.
|
||||
* e.g. your-service-worker.js, register-service-worker.js
|
||||
* e.g. /// <reference path="path/to/serviceworker.d.ts" />
|
||||
*/
|
||||
/* eslint-disable */
|
||||
// Registration
|
||||
|
||||
interface WorkerNavigator {
|
||||
readonly serviceWorker: ServiceWorkerContainer;
|
||||
}
|
||||
|
||||
interface ServiceWorkerContainer {
|
||||
readonly controller: ServiceWorker;
|
||||
readonly ready: Promise<ServiceWorkerRegistration>;
|
||||
oncontrollerchange:
|
||||
| ((this: ServiceWorkerContainer, event: Event) => any)
|
||||
| null;
|
||||
onerror: ((this: ServiceWorkerContainer, event?: Event) => any) | null;
|
||||
onmessage:
|
||||
| ((this: ServiceWorkerContainer, event: ServiceWorkerMessageEvent) => any)
|
||||
| null;
|
||||
getRegistration(scope?: string): Promise<ServiceWorkerRegistration>;
|
||||
getRegistrations(): Promise<ServiceWorkerRegistration[]>;
|
||||
register(
|
||||
url: string,
|
||||
options?: ServiceWorkerRegistrationOptions
|
||||
): Promise<ServiceWorkerRegistration>;
|
||||
}
|
||||
|
||||
interface ServiceWorkerMessageEvent extends Event {
|
||||
readonly data: any;
|
||||
readonly lastEventId: string;
|
||||
readonly origin: string;
|
||||
readonly ports: ReadonlyArray<MessagePort> | null;
|
||||
readonly source: ServiceWorker | MessagePort | null;
|
||||
}
|
||||
|
||||
interface ServiceWorkerRegistrationOptions {
|
||||
scope?: string;
|
||||
}
|
||||
|
||||
// Client API
|
||||
|
||||
interface Client {
|
||||
readonly frameType: ClientFrameType;
|
||||
}
|
||||
|
||||
type ClientFrameType = "auxiliary" | "top-level" | "nested" | "none";
|
||||
|
||||
// Events
|
||||
|
||||
interface ActivateEvent extends ExtendableEvent {}
|
||||
|
||||
interface InstallEvent extends ExtendableEvent {
|
||||
readonly activeWorker: ServiceWorker;
|
||||
}
|
||||
|
||||
// Fetch API
|
||||
|
||||
interface Body {
|
||||
readonly body: ReadableStream;
|
||||
}
|
||||
|
||||
interface Headers {
|
||||
entries(): string[][];
|
||||
keys(): string[];
|
||||
values(): string[];
|
||||
}
|
||||
|
||||
interface Response extends Body {
|
||||
readonly useFinalURL: boolean;
|
||||
clone(): Response;
|
||||
error(): Response;
|
||||
redirect(): Response;
|
||||
}
|
||||
|
||||
// Notification API
|
||||
|
||||
interface Notification {
|
||||
readonly actions: NotificationAction[];
|
||||
readonly requireInteraction: boolean;
|
||||
readonly silent: boolean;
|
||||
readonly tag: string;
|
||||
readonly renotify: boolean;
|
||||
readonly timestamp: number;
|
||||
readonly title: string;
|
||||
readonly vibrate: number[];
|
||||
close(): void;
|
||||
requestPermission(): Promise<string>;
|
||||
}
|
||||
|
||||
interface NotificationAction {}
|
||||
|
||||
// ServiceWorkerGlobalScope
|
||||
|
||||
declare var clients: Clients;
|
||||
declare var onactivate: ((event?: ActivateEvent) => any) | null;
|
||||
declare var onfetch: ((event?: FetchEvent) => any) | null;
|
||||
declare var oninstall: ((event?: InstallEvent) => any) | null;
|
||||
declare var onnotificationclick: ((event?: NotificationEvent) => any) | null;
|
||||
declare var onnotificationclose: ((event?: NotificationEvent) => any) | null;
|
||||
declare var onpush: ((event?: PushEvent) => any) | null;
|
||||
declare var onpushsubscriptionchange: (() => any) | null;
|
||||
declare var onsync: ((event?: SyncEvent) => any) | null;
|
||||
declare var registration: ServiceWorkerRegistration;
|
||||
|
||||
declare function skipWaiting(): void;
|
@ -1878,10 +1878,13 @@
|
||||
"built_using": "Creat utilitzant",
|
||||
"custom_uis": "Interfícies d'usuari personalitzades:",
|
||||
"developed_by": "Desenvolupat per un munt de gent fantàstica.",
|
||||
"documentation": "Documentació",
|
||||
"frontend": "frontend-ui",
|
||||
"frontend_version": "Versió de la interfície web d'usuari: {version} - {type}",
|
||||
"home_assistant_logo": "Logotip de Home Assistant",
|
||||
"icons_by": "Icones de",
|
||||
"integrations": "Integracions",
|
||||
"issues": "Problemes",
|
||||
"license": "Publicat amb la llicència Apache 2.0",
|
||||
"path_configuration": "Ruta al fitxer configuration.yaml: {path}",
|
||||
"server": "servidor",
|
||||
@ -2072,6 +2075,7 @@
|
||||
"name": "Nom",
|
||||
"no_theme": "Sense tema",
|
||||
"refresh_interval": "Interval d'actualització",
|
||||
"secondary_info_attribute": "Atribut d’informació secundària",
|
||||
"show_icon": "Mostra icona?",
|
||||
"show_name": "Mostra nom?",
|
||||
"show_state": "Mostra estat?",
|
||||
@ -2162,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "La targeta de previsió meteorològica, és molt útil per incloure en interfícies integrades en parets.",
|
||||
"name": "Previsió meteorològica"
|
||||
"name": "Previsió meteorològica",
|
||||
"show_forecast": "Mostra la previsió"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -1181,9 +1181,9 @@
|
||||
"edit_requires_storage": "Editor deaktiviert, da die Konfiguration in configuration.yaml gespeichert ist.",
|
||||
"elevation": "Höhe",
|
||||
"elevation_meters": "Meter",
|
||||
"external_url": "Externe Adresse",
|
||||
"external_url": "Externe URL",
|
||||
"imperial_example": "Fahrenheit, Pfund",
|
||||
"internal_url": "Interne Adresse",
|
||||
"internal_url": "Interne URL",
|
||||
"latitude": "Breitengrad",
|
||||
"location_name": "Name deiner Home Assistant Installation",
|
||||
"longitude": "Längengrad",
|
||||
@ -1878,10 +1878,13 @@
|
||||
"built_using": "Gebaut mit",
|
||||
"custom_uis": "Benutzerdefinierte UIs:",
|
||||
"developed_by": "Entwickelt von einem Haufen toller Leute.",
|
||||
"documentation": "Dokumentation",
|
||||
"frontend": "Frontend-UI",
|
||||
"frontend_version": "Frontend-Version: {version} - {type}",
|
||||
"home_assistant_logo": "Home Assistant-Logo",
|
||||
"icons_by": "Icons von",
|
||||
"integrations": "Integrationen",
|
||||
"issues": "Probleme",
|
||||
"license": "Veröffentlicht unter der Apache 2.0 Lizenz",
|
||||
"path_configuration": "Pfad zu configuration.yaml: {path}",
|
||||
"server": "Server",
|
||||
@ -2072,6 +2075,7 @@
|
||||
"name": "Name",
|
||||
"no_theme": "Kein Theme",
|
||||
"refresh_interval": "Aktualisierungsintervall",
|
||||
"secondary_info_attribute": "Zweites Infoattribut",
|
||||
"show_icon": "Symbol anzeigen?",
|
||||
"show_name": "Namen anzeigen?",
|
||||
"show_state": "Status anzeigen?",
|
||||
@ -2162,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "Die Wettervorhersagekarte zeigt das vorhergesagte Wetter an. Sehr nützlich für wandmontierte Displays.",
|
||||
"name": "Wettervorhersage"
|
||||
"name": "Wettervorhersage",
|
||||
"show_forecast": "Wettervorhersage anzeigen"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -40,7 +40,7 @@
|
||||
},
|
||||
"preset_mode": {
|
||||
"activity": "Actividad",
|
||||
"away": "Fuera de casa",
|
||||
"away": "Ausente",
|
||||
"boost": "Impulso",
|
||||
"comfort": "Confort",
|
||||
"eco": "Eco",
|
||||
@ -52,11 +52,11 @@
|
||||
},
|
||||
"state_badge": {
|
||||
"alarm_control_panel": {
|
||||
"armed": "Armado",
|
||||
"armed_away": "Armado",
|
||||
"armed_custom_bypass": "Armado",
|
||||
"armed_home": "Armado",
|
||||
"armed_night": "Armado",
|
||||
"armed": "Armada",
|
||||
"armed_away": "Armada",
|
||||
"armed_custom_bypass": "Armada",
|
||||
"armed_home": "Armada",
|
||||
"armed_night": "Armada",
|
||||
"arming": "Armando",
|
||||
"disarmed": "Desarmar",
|
||||
"disarming": "Desarmar",
|
||||
@ -80,13 +80,13 @@
|
||||
},
|
||||
"state": {
|
||||
"alarm_control_panel": {
|
||||
"armed": "Armado",
|
||||
"armed_away": "Armado fuera de casa",
|
||||
"armed": "Armada",
|
||||
"armed_away": "Armada ausente",
|
||||
"armed_custom_bypass": "Armada Zona Específica",
|
||||
"armed_home": "Armado en casa",
|
||||
"armed_night": "Armado noche",
|
||||
"armed_home": "Armada en casa",
|
||||
"armed_night": "Armada noche",
|
||||
"arming": "Armando",
|
||||
"disarmed": "Desarmado",
|
||||
"disarmed": "Desarmada",
|
||||
"disarming": "Desarmando",
|
||||
"pending": "Pendiente",
|
||||
"triggered": "Disparada"
|
||||
@ -311,7 +311,7 @@
|
||||
"rainy": "Lluvioso",
|
||||
"snowy": "Nevado",
|
||||
"snowy-rainy": "Nevado, lluvioso",
|
||||
"sunny": "Soleado",
|
||||
"sunny": "Despejado",
|
||||
"windy": "Ventoso",
|
||||
"windy-variant": "Ventoso"
|
||||
},
|
||||
@ -336,7 +336,7 @@
|
||||
},
|
||||
"card": {
|
||||
"alarm_control_panel": {
|
||||
"arm_away": "Armar fuera de casa",
|
||||
"arm_away": "Armar ausente",
|
||||
"arm_custom_bypass": "Bypass personalizada",
|
||||
"arm_home": "Armar en casa",
|
||||
"arm_night": "Armar noche",
|
||||
@ -1878,10 +1878,13 @@
|
||||
"built_using": "Construido usando",
|
||||
"custom_uis": "IU personalizadas:",
|
||||
"developed_by": "Desarrollado por un montón de gente impresionante.",
|
||||
"documentation": "Documentación",
|
||||
"frontend": "interfaz de usuario",
|
||||
"frontend_version": "Versión del frontend: {version} - {type}",
|
||||
"home_assistant_logo": "Logotipo de Home Assistant",
|
||||
"icons_by": "Iconos por",
|
||||
"integrations": "Integraciones",
|
||||
"issues": "Incidencias",
|
||||
"license": "Publicado bajo la licencia Apache 2.0",
|
||||
"path_configuration": "Ruta a configuration.yaml: {path}",
|
||||
"server": "servidor",
|
||||
@ -2162,7 +2165,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "La tarjeta de Pronóstico del tiempo muestra el clima. Muy útil para incluir en las interfaces que las personas muestran en la pared.",
|
||||
"name": "Pronóstico del tiempo"
|
||||
"name": "Pronóstico del tiempo",
|
||||
"show_forecast": "Mostrar pronóstico"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -1878,10 +1878,13 @@
|
||||
"built_using": "Construit en utilisant",
|
||||
"custom_uis": "Interfaces utilisateur personnalisées :",
|
||||
"developed_by": "Développé par un groupe de personnes formidables.",
|
||||
"documentation": "Documentation",
|
||||
"frontend": "interface utilisateur",
|
||||
"frontend_version": "Version interface utilisateur : {version} - {type}",
|
||||
"home_assistant_logo": "Logo de Home Assistant",
|
||||
"icons_by": "Icônes par",
|
||||
"integrations": "Intégrations",
|
||||
"issues": "Problèmes",
|
||||
"license": "Publié sous la licence Apache 2.0",
|
||||
"path_configuration": "Chemin vers configuration.yaml : {path}",
|
||||
"server": "serveur",
|
||||
@ -2072,6 +2075,7 @@
|
||||
"name": "Nom",
|
||||
"no_theme": "Pas de thème",
|
||||
"refresh_interval": "Intervalle de rafraîchissement",
|
||||
"secondary_info_attribute": "Attribut d'informations secondaires",
|
||||
"show_icon": "Afficher l'icône ?",
|
||||
"show_name": "Afficher le nom ?",
|
||||
"show_state": "Afficher l'état ?",
|
||||
@ -2162,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "La carte Prévisions météorologiques affiche la météo. Très utile pour les écrans placés au mur.",
|
||||
"name": "Prévisions Météo"
|
||||
"name": "Prévisions Météo",
|
||||
"show_forecast": "Afficher les prévisions"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -1878,10 +1878,13 @@
|
||||
"built_using": "Costruito usando",
|
||||
"custom_uis": "Interfacce Utente personalizzate:",
|
||||
"developed_by": "Sviluppato da un gruppo di persone fantastiche.",
|
||||
"documentation": "Documentazione",
|
||||
"frontend": "frontend-ui",
|
||||
"frontend_version": "Versione Frontend: {version} - {type}",
|
||||
"home_assistant_logo": "Logo Home Assistant",
|
||||
"icons_by": "Icone di",
|
||||
"integrations": "integrazioni",
|
||||
"issues": "Problemi",
|
||||
"license": "Pubblicato sotto la licenza Apache 2.0",
|
||||
"path_configuration": "Percorso del file configuration.yaml: {path}",
|
||||
"server": "server",
|
||||
@ -2072,6 +2075,7 @@
|
||||
"name": "Nome",
|
||||
"no_theme": "Nessun tema",
|
||||
"refresh_interval": "Intervallo di aggiornamento",
|
||||
"secondary_info_attribute": "Attributo informazioni secondarie",
|
||||
"show_icon": "Mostrare l'icona?",
|
||||
"show_name": "Mostrare il nome?",
|
||||
"show_state": "Mostrare lo stato?",
|
||||
@ -2162,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "La scheda Previsioni Meteo mostra le condizioni meteorologiche. Molto utili da includere nelle interfacce che le persone visualizzano sulla parete.",
|
||||
"name": "Previsioni del tempo"
|
||||
"name": "Previsioni del tempo",
|
||||
"show_forecast": "Mostra Previsioni"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -473,6 +473,7 @@
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"and": "an",
|
||||
"cancel": "Ofbriechen",
|
||||
"close": "Zoumaachen",
|
||||
"delete": "Läschen",
|
||||
@ -1180,7 +1181,9 @@
|
||||
"edit_requires_storage": "Editeur ass desaktivéiert well d'Konfiguratioun an der configuration.yaml gespäichert ass.",
|
||||
"elevation": "Héicht",
|
||||
"elevation_meters": "Meter",
|
||||
"external_url": "Externe URL",
|
||||
"imperial_example": "Fahrenheit, Pënner",
|
||||
"internal_url": "Interne URL",
|
||||
"latitude": "Breedegrad",
|
||||
"location_name": "Numm vun der Home Assistant Installatioun",
|
||||
"longitude": "Längegrad",
|
||||
@ -1875,10 +1878,13 @@
|
||||
"built_using": "Gebaut mat",
|
||||
"custom_uis": "Personaliséierte Benotzer Interface:",
|
||||
"developed_by": "Entwéckelt vun enger ganzer Rei fantastesche Leit.",
|
||||
"documentation": "Dokumentatioun",
|
||||
"frontend": "frontend-ui",
|
||||
"frontend_version": "Frontend Versioun: {version} - {type}",
|
||||
"home_assistant_logo": "Home Assistant logo",
|
||||
"icons_by": "Ikonen vun",
|
||||
"integrations": "Integratioune",
|
||||
"issues": "Problemer",
|
||||
"license": "Verëffentlecht ënnert der Apache 2.0 Lizenz",
|
||||
"path_configuration": "Pad zur configuration.yaml: {path}",
|
||||
"server": "server",
|
||||
@ -2069,6 +2075,7 @@
|
||||
"name": "Numm",
|
||||
"no_theme": "Kee Thema",
|
||||
"refresh_interval": "Aktualiséierungs Intervall",
|
||||
"secondary_info_attribute": "Sekundär Informatiouns Attribut",
|
||||
"show_icon": "Ikon uweisen?",
|
||||
"show_name": "Numm uweisen?",
|
||||
"show_state": "Zoustand uweisen?",
|
||||
@ -2159,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "Wieder Previsoune Kaart weist d'Météo un. Immens nëtzlech fir Interfacen déi Benotzer un d'Mauer hänken.",
|
||||
"name": "Wiederprevisioune"
|
||||
"name": "Wiederprevisioune",
|
||||
"show_forecast": "Prévisioun uweisen"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -1878,10 +1878,13 @@
|
||||
"built_using": "Zbudowany przy użyciu",
|
||||
"custom_uis": "Niestandardowe interfejsy użytkownika:",
|
||||
"developed_by": "Opracowany przez grono wspaniałych ludzi.",
|
||||
"documentation": "Dokumentacja",
|
||||
"frontend": "frontend-ui",
|
||||
"frontend_version": "Wersja interfejsu użytkownika: {version} - {type}",
|
||||
"home_assistant_logo": "Logo Home Assistant",
|
||||
"icons_by": "ikon",
|
||||
"integrations": "Integracje",
|
||||
"issues": "Problemy",
|
||||
"license": "Opublikowany na licencji Apache 2.0",
|
||||
"path_configuration": "Ścieżka do pliku configuration.yaml: {path}",
|
||||
"server": "serwer",
|
||||
@ -2072,6 +2075,7 @@
|
||||
"name": "Nazwa",
|
||||
"no_theme": "Bez motywu",
|
||||
"refresh_interval": "Częstotliwość odświeżania",
|
||||
"secondary_info_attribute": "Dodatkowy atrybut informacyjny",
|
||||
"show_icon": "Wyświetlanie ikony",
|
||||
"show_name": "Wyświetlanie nazwy",
|
||||
"show_state": "Wyświetlanie stanu",
|
||||
@ -2162,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "Karta prognozy pogody wyświetla pogodę. Bardzo przydatna w przypadku interfejsów wyświetlanych na urządzeniach zawieszonych na ścianie.",
|
||||
"name": "Prognoza pogody"
|
||||
"name": "Prognoza pogody",
|
||||
"show_forecast": "Wyświetlanie prognozy"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -331,6 +331,7 @@
|
||||
"ui": {
|
||||
"auth_store": {
|
||||
"ask": "Deseja continuar com sessão iniciada?",
|
||||
"confirm": "Sim",
|
||||
"decline": "Não"
|
||||
},
|
||||
"card": {
|
||||
@ -1863,10 +1864,13 @@
|
||||
"built_using": "Construído com",
|
||||
"custom_uis": "IUs personalizados:",
|
||||
"developed_by": "Desenvolvido por um punhado de pessoas incríveis.",
|
||||
"documentation": "Documentação",
|
||||
"frontend": "",
|
||||
"frontend_version": "Versão frontend: {version} - {type}",
|
||||
"home_assistant_logo": "Logotipo do Home Assistant",
|
||||
"icons_by": "Ícones por",
|
||||
"integrations": "Integrações",
|
||||
"issues": "Problemas",
|
||||
"license": "Publicado sob a licença de Apache 2.0",
|
||||
"path_configuration": "Caminho para configuration.yaml: {path}",
|
||||
"server": "servidor",
|
||||
@ -1934,7 +1938,7 @@
|
||||
"editor": "Editor de Templates",
|
||||
"jinja_documentation": "Documentação do template Jinja2",
|
||||
"template_extensions": "Extensões de templates do Home Assistant",
|
||||
"title": "Modelos",
|
||||
"title": "Modelo",
|
||||
"unknown_error_template": "Erro desconhecido ao processar o template"
|
||||
}
|
||||
}
|
||||
@ -1950,6 +1954,7 @@
|
||||
},
|
||||
"lovelace": {
|
||||
"add_entities": {
|
||||
"saving_failed": "Falha ao salvar a configuração da interface Lovelace.",
|
||||
"yaml_unsupported": "Você não pode usar esta função ao usar o Lovelace IU no modo YAML."
|
||||
},
|
||||
"cards": {
|
||||
@ -2053,6 +2058,7 @@
|
||||
"name": "Nome",
|
||||
"no_theme": "Nenhum tema",
|
||||
"refresh_interval": "Intervalo entre atualizações",
|
||||
"secondary_info_attribute": "Atributo de informação secundária",
|
||||
"show_icon": "Mostrar Ícone?",
|
||||
"show_name": "Mostrar nome?",
|
||||
"show_state": "Mostrar Estado?",
|
||||
@ -2065,7 +2071,8 @@
|
||||
},
|
||||
"glance": {
|
||||
"columns": "Colunas",
|
||||
"description": "O cartão Glance é útil para agrupar vários sensores numa visão geral compacta."
|
||||
"description": "O cartão Glance é útil para agrupar vários sensores numa visão geral compacta.",
|
||||
"name": "Relance"
|
||||
},
|
||||
"history-graph": {
|
||||
"description": "O cartão Gráfico de histórico permite exibir um gráfico para cada uma das entidades listadas.",
|
||||
@ -2141,7 +2148,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "O cartão Previsão do tempo exibe o tempo. Muito útil para incluir nos interfaces que coloca-mos na parede.",
|
||||
"name": "Previsão do tempo"
|
||||
"name": "Previsão do tempo",
|
||||
"show_forecast": "Mostrar previsão do tempo"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
@ -2221,6 +2229,7 @@
|
||||
},
|
||||
"suggest_card": {
|
||||
"add": "Adicionar à Lovelace UI",
|
||||
"create_own": "Escolha um cartão diferente",
|
||||
"header": "Criamos uma sugestão para você."
|
||||
},
|
||||
"view": {
|
||||
|
@ -1878,10 +1878,13 @@
|
||||
"built_using": "Создано с использованием",
|
||||
"custom_uis": "Кастомные интерфейсы:",
|
||||
"developed_by": "Разработано множеством замечательных людей.",
|
||||
"documentation": "Документация",
|
||||
"frontend": "пользовательский интерфейс",
|
||||
"frontend_version": "Версия интерфейса: {version} - {type}",
|
||||
"home_assistant_logo": "Логотип Home Assistant",
|
||||
"icons_by": "Значки от",
|
||||
"integrations": "Интеграции",
|
||||
"issues": "Вопросы",
|
||||
"license": "Опубликовано под лицензией Apache 2.0",
|
||||
"path_configuration": "Путь к configuration.yaml: {path}",
|
||||
"server": "сервер",
|
||||
@ -2072,6 +2075,7 @@
|
||||
"name": "Название",
|
||||
"no_theme": "Нет темы",
|
||||
"refresh_interval": "Интервал обновления",
|
||||
"secondary_info_attribute": "Дополнительная информация",
|
||||
"show_icon": "Значок",
|
||||
"show_name": "Название",
|
||||
"show_state": "Состояние",
|
||||
@ -2162,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "Отображает погоду. Может быть полезна на устройствах, размещаемых на стене.",
|
||||
"name": "Прогноз погоды"
|
||||
"name": "Прогноз погоды",
|
||||
"show_forecast": "Показывать прогноз"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -1878,10 +1878,13 @@
|
||||
"built_using": "建于",
|
||||
"custom_uis": "自定义用户界面:",
|
||||
"developed_by": "由一帮很 Awesome~~~ 的人开发。",
|
||||
"documentation": "文档",
|
||||
"frontend": "前端用户界面",
|
||||
"frontend_version": "前端版本: {version} - {type}",
|
||||
"home_assistant_logo": "Home Assistant logo",
|
||||
"icons_by": "图标来自",
|
||||
"integrations": "集成",
|
||||
"issues": "问题",
|
||||
"license": "根据 Apache 2.0 许可发布",
|
||||
"path_configuration": "configuration.yaml 路径:{path}",
|
||||
"server": "服务器",
|
||||
@ -2072,6 +2075,7 @@
|
||||
"name": "名称",
|
||||
"no_theme": "没有主题",
|
||||
"refresh_interval": "刷新间隔",
|
||||
"secondary_info_attribute": "次要信息属性",
|
||||
"show_icon": "显示图标?",
|
||||
"show_name": "显示名称?",
|
||||
"show_state": "显示状态?",
|
||||
@ -2162,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "“天气预报”卡片用于显示天气。对于将界面挂墙显示的情况非常有用。",
|
||||
"name": "天气预报"
|
||||
"name": "天气预报",
|
||||
"show_forecast": "显示预报"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -1878,10 +1878,13 @@
|
||||
"built_using": "建置使用",
|
||||
"custom_uis": "自定介面:",
|
||||
"developed_by": "由一群充滿熱情的人們所開發。",
|
||||
"documentation": "相關文件",
|
||||
"frontend": "frontend-ui",
|
||||
"frontend_version": "Frontend 版本:{version} - {type}",
|
||||
"home_assistant_logo": "Home Assistant logo",
|
||||
"icons_by": "圖示使用",
|
||||
"integrations": "整合",
|
||||
"issues": "問題",
|
||||
"license": "依據 Apache 2.0 授權許可發行",
|
||||
"path_configuration": "configuration.yaml 路徑:{path}",
|
||||
"server": "伺服器",
|
||||
@ -2072,6 +2075,7 @@
|
||||
"name": "名稱",
|
||||
"no_theme": "沒有主題",
|
||||
"refresh_interval": "更新間隔",
|
||||
"secondary_info_attribute": "次要資訊屬性",
|
||||
"show_icon": "顯示圖示?",
|
||||
"show_name": "顯示名稱?",
|
||||
"show_state": "顯示狀態?",
|
||||
@ -2162,7 +2166,8 @@
|
||||
},
|
||||
"weather-forecast": {
|
||||
"description": "天氣預報面板顯示天氣狀態。對於放置於牆上顯示非常實用。",
|
||||
"name": "天氣預報面板"
|
||||
"name": "天氣預報面板",
|
||||
"show_forecast": "顯示預報"
|
||||
}
|
||||
},
|
||||
"cardpicker": {
|
||||
|
@ -3,7 +3,7 @@
|
||||
"target": "es2017",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"lib": ["es2017", "dom", "dom.iterable"],
|
||||
"lib": ["es2017", "dom", "dom.iterable", "WebWorker"],
|
||||
"noEmit": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user