mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-30 04:36:36 +00:00
commit
8408b8d41f
@ -20,7 +20,7 @@ gulp.task(
|
||||
"gen-service-worker-dev",
|
||||
"gen-icons",
|
||||
"gen-pages-dev",
|
||||
"gen-index-html-dev",
|
||||
"gen-index-app-dev",
|
||||
"build-translations"
|
||||
),
|
||||
"copy-static",
|
||||
@ -44,7 +44,7 @@ gulp.task(
|
||||
),
|
||||
gulp.parallel(
|
||||
"gen-pages-prod",
|
||||
"gen-index-html-prod",
|
||||
"gen-index-app-prod",
|
||||
"gen-service-worker-prod"
|
||||
)
|
||||
)
|
||||
|
@ -16,7 +16,12 @@ gulp.task(
|
||||
process.env.NODE_ENV = "development";
|
||||
},
|
||||
"clean-demo",
|
||||
gulp.parallel("gen-icons", "gen-icons-demo", "build-translations"),
|
||||
gulp.parallel(
|
||||
"gen-icons",
|
||||
"gen-icons-demo",
|
||||
"gen-index-demo-dev",
|
||||
"build-translations"
|
||||
),
|
||||
"copy-static-demo",
|
||||
"webpack-dev-server-demo"
|
||||
)
|
||||
@ -31,6 +36,7 @@ gulp.task(
|
||||
"clean-demo",
|
||||
gulp.parallel("gen-icons", "gen-icons-demo", "build-translations"),
|
||||
"copy-static-demo",
|
||||
"webpack-prod-demo"
|
||||
"webpack-prod-demo",
|
||||
"gen-index-demo-prod"
|
||||
)
|
||||
);
|
||||
|
@ -11,13 +11,19 @@ const config = require("../paths.js");
|
||||
const templatePath = (tpl) =>
|
||||
path.resolve(config.polymer_dir, "src/html/", `${tpl}.html.template`);
|
||||
|
||||
const demoTemplatePath = (tpl) =>
|
||||
path.resolve(config.demo_dir, "src/html/", `${tpl}.html.template`);
|
||||
|
||||
const readFile = (pth) => fs.readFileSync(pth).toString();
|
||||
|
||||
const renderTemplate = (pth, data = {}) => {
|
||||
const compiled = template(readFile(templatePath(pth)));
|
||||
const renderTemplate = (pth, data = {}, pathFunc = templatePath) => {
|
||||
const compiled = template(readFile(pathFunc(pth)));
|
||||
return compiled({ ...data, renderTemplate });
|
||||
};
|
||||
|
||||
const renderDemoTemplate = (pth, data = {}) =>
|
||||
renderTemplate(pth, data, demoTemplatePath);
|
||||
|
||||
const minifyHtml = (content) =>
|
||||
minify(content, {
|
||||
collapseWhitespace: true,
|
||||
@ -66,7 +72,7 @@ gulp.task("gen-pages-prod", (done) => {
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-html-dev", (done) => {
|
||||
gulp.task("gen-index-app-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderTemplate("index", {
|
||||
@ -86,7 +92,7 @@ gulp.task("gen-index-html-dev", (done) => {
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-html-prod", (done) => {
|
||||
gulp.task("gen-index-app-prod", (done) => {
|
||||
const latestManifest = require(path.resolve(config.output, "manifest.json"));
|
||||
const es5Manifest = require(path.resolve(config.output_es5, "manifest.json"));
|
||||
const content = renderTemplate("index", {
|
||||
@ -106,3 +112,52 @@ gulp.task("gen-index-html-prod", (done) => {
|
||||
fs.outputFileSync(path.resolve(config.root, "index.html"), minified);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-demo-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderDemoTemplate("index", {
|
||||
latestDemoJS: "/frontend_latest/main.js",
|
||||
|
||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
||||
es5DemoJS: "/frontend_es5/main.js",
|
||||
});
|
||||
|
||||
fs.outputFileSync(path.resolve(config.demo_root, "index.html"), content);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-demo-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderDemoTemplate("index", {
|
||||
latestDemoJS: "/frontend_latest/main.js",
|
||||
|
||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
||||
es5DemoJS: "/frontend_es5/main.js",
|
||||
});
|
||||
|
||||
fs.outputFileSync(path.resolve(config.demo_root, "index.html"), content);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-demo-prod", (done) => {
|
||||
const latestManifest = require(path.resolve(
|
||||
config.demo_output,
|
||||
"manifest.json"
|
||||
));
|
||||
const es5Manifest = require(path.resolve(
|
||||
config.demo_output_es5,
|
||||
"manifest.json"
|
||||
));
|
||||
const content = renderDemoTemplate("index", {
|
||||
latestDemoJS: latestManifest["main.js"],
|
||||
|
||||
es5Compatibility: es5Manifest["compatibility.js"],
|
||||
es5DemoJS: es5Manifest["main.js"],
|
||||
});
|
||||
const minified = minifyHtml(content).replace(/#THEMEC/g, "{{ theme_color }}");
|
||||
|
||||
fs.outputFileSync(path.resolve(config.demo_root, "index.html"), minified);
|
||||
done();
|
||||
});
|
||||
|
@ -13,5 +13,5 @@ module.exports = {
|
||||
demo_root: path.resolve(__dirname, "../demo/dist"),
|
||||
demo_static: path.resolve(__dirname, "../demo/dist/static"),
|
||||
demo_output: path.resolve(__dirname, "../demo/dist/frontend_latest"),
|
||||
demo_output_es5: path.resolve(__dirname, "../demo/frontend_es5"),
|
||||
demo_output_es5: path.resolve(__dirname, "../demo/dist/frontend_es5"),
|
||||
};
|
||||
|
@ -20,6 +20,12 @@ version = version[0];
|
||||
const genMode = (isProdBuild) => (isProdBuild ? "production" : "development");
|
||||
const genDevTool = (isProdBuild) =>
|
||||
isProdBuild ? "cheap-source-map" : "inline-cheap-module-source-map";
|
||||
const genFilename = (isProdBuild, dontHash = new Set()) => ({ chunk }) => {
|
||||
if (!isProdBuild || dontHash.has(chunk.name)) {
|
||||
return `${chunk.name}.js`;
|
||||
}
|
||||
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
||||
};
|
||||
const genChunkFilename = (isProdBuild, isStatsBuild) =>
|
||||
isProdBuild && !isStatsBuild ? "chunk.[chunkhash].js" : "[name].chunk.js";
|
||||
|
||||
@ -158,14 +164,7 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
}),
|
||||
].filter(Boolean),
|
||||
output: {
|
||||
filename: ({ chunk }) => {
|
||||
const dontHash = new Set([
|
||||
// Files who'se names should not be hashed.
|
||||
// We currently have none.
|
||||
]);
|
||||
if (!isProdBuild || dontHash.has(chunk.name)) return `${chunk.name}.js`;
|
||||
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
||||
},
|
||||
filename: genFilename(isProdBuild),
|
||||
chunkFilename: genChunkFilename(isProdBuild, isStatsBuild),
|
||||
path: latestBuild ? paths.output : paths.output_es5,
|
||||
publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/",
|
||||
@ -187,6 +186,7 @@ const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
},
|
||||
optimization: optimization(latestBuild),
|
||||
plugins: [
|
||||
new ManifestPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
__DEV__: !isProdBuild,
|
||||
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
||||
@ -201,7 +201,7 @@ const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
].filter(Boolean),
|
||||
resolve,
|
||||
output: {
|
||||
filename: "[name].js",
|
||||
filename: genFilename(isProdBuild),
|
||||
chunkFilename: genChunkFilename(isProdBuild, isStatsBuild),
|
||||
path: path.resolve(
|
||||
paths.demo_root,
|
||||
|
@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
const fs = require("fs");
|
||||
const {
|
||||
findIcons,
|
||||
generateIconset,
|
||||
genMDIIcons,
|
||||
} = require("../../build-scripts/gulp/gen-icons.js");
|
||||
|
||||
function genHademoIcons() {
|
||||
const iconNames = findIcons("./src", "hademo");
|
||||
fs.writeFileSync("./hademo-icons.html", generateIconset("hademo", iconNames));
|
||||
}
|
||||
|
||||
genMDIIcons();
|
||||
genHademoIcons();
|
@ -95,43 +95,17 @@
|
||||
<body>
|
||||
<div id="ha-init-skeleton"></div>
|
||||
<ha-demo></ha-demo>
|
||||
<script>
|
||||
function _ls(src) {
|
||||
var doc = document.documentElement;
|
||||
var script = doc.insertBefore(
|
||||
document.createElement("script"),
|
||||
doc.lastChild
|
||||
);
|
||||
script.type = "text/javascript";
|
||||
script.src = src;
|
||||
}
|
||||
window.Polymer = {
|
||||
lazyRegister: true,
|
||||
useNativeCSSProperties: true,
|
||||
dom: "shadow",
|
||||
suppressTemplateNotifications: true,
|
||||
suppressBindingNotifications: true,
|
||||
};
|
||||
var webComponentsSupported =
|
||||
"customElements" in window &&
|
||||
"content" in document.createElement("template");
|
||||
if (!webComponentsSupported) {
|
||||
_ls("/static/polyfills/webcomponents-bundle.js");
|
||||
}
|
||||
var isS101 = /\s+Version\/10\.1(?:\.\d+)?\s+Safari\//.test(
|
||||
navigator.userAgent
|
||||
);
|
||||
</script>
|
||||
<%= renderTemplate('_js_base') %>
|
||||
|
||||
<script type="module" src="./frontend_latest/main.js"></script>
|
||||
<script type="module" src="<%= latestDemoJS %>"></script>
|
||||
|
||||
<script nomodule>
|
||||
(function() {
|
||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||
if (!isS101) {
|
||||
_ls("./static/polyfills/custom-elements-es5-adapter.js");
|
||||
_ls("./frontend_es5/compatibility.js");
|
||||
_ls("./frontend_es5/main.js");
|
||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||
_ls("<%= es5Compatibility %>");
|
||||
_ls("<%= es5DemoJS %>");
|
||||
}
|
||||
})();
|
||||
</script>
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20190509.0",
|
||||
version="20190510.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
2
src/common/feature-detect/support-web-components.ts
Normal file
2
src/common/feature-detect/support-web-components.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const webComponentsSupported =
|
||||
"customElements" in window && "content" in document.createElement("template");
|
@ -5,6 +5,7 @@ import { setCustomPanelProperties } from "../util/custom-panel/set-custom-panel-
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { PolymerElement } from "@polymer/polymer";
|
||||
import { CustomPanelInfo } from "../data/panel_custom";
|
||||
import { webComponentsSupported } from "../common/feature-detect/support-web-components";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -12,18 +13,13 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
const webComponentsSupported =
|
||||
"customElements" in window &&
|
||||
"import" in document.createElement("link") &&
|
||||
"content" in document.createElement("template");
|
||||
|
||||
let es5Loaded: Promise<unknown> | undefined;
|
||||
|
||||
window.loadES5Adapter = () => {
|
||||
if (!es5Loaded) {
|
||||
es5Loaded = Promise.all([
|
||||
loadJS(
|
||||
`${__STATIC_PATH__}/polyfills/custom-elements-es5-adapter.js`
|
||||
`${__STATIC_PATH__}polyfills/custom-elements-es5-adapter.js`
|
||||
).catch(),
|
||||
import(/* webpackChunkName: "compat" */ "./compatibility"),
|
||||
]);
|
||||
@ -50,7 +46,7 @@ function initialize(panel: CustomPanelInfo, properties: {}) {
|
||||
|
||||
if (!webComponentsSupported) {
|
||||
start = start.then(() =>
|
||||
loadJS(`${__STATIC_PATH__}/polyfills/webcomponents-bundle.js`)
|
||||
loadJS(`${__STATIC_PATH__}polyfills/webcomponents-bundle.js`)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -603,6 +603,12 @@
|
||||
"device_unavailable": "dispositiu no disponible",
|
||||
"entity_unavailable": "entitat no disponible",
|
||||
"no_area": "Sense àrea"
|
||||
},
|
||||
"config_flow": {
|
||||
"external_step": {
|
||||
"description": "Aquest pas requereix que visitis un lloc web extern per completar-lo.",
|
||||
"open_site": "Vés al lloc web"
|
||||
}
|
||||
}
|
||||
},
|
||||
"zha": {
|
||||
|
@ -603,6 +603,12 @@
|
||||
"device_unavailable": "Gerät nicht verfügbar",
|
||||
"entity_unavailable": "Entität nicht verfügbar",
|
||||
"no_area": "Kein Bereich"
|
||||
},
|
||||
"config_flow": {
|
||||
"external_step": {
|
||||
"description": "Für diesen Schritt musst du eine externe Website besuchen, um den Vorgang abzuschließen.",
|
||||
"open_site": "Website öffnen"
|
||||
}
|
||||
}
|
||||
},
|
||||
"zha": {
|
||||
@ -855,6 +861,11 @@
|
||||
"required_fields": "Fülle alle Pflichtfelder aus.",
|
||||
"password_not_match": "Passwörter stimmen nicht überein"
|
||||
}
|
||||
},
|
||||
"integration": {
|
||||
"intro": "Geräte und Dienste werden in Home Assistant als Integrationen dargestellt. Sie können jetzt oder später über die Konfigurationsseite eingerichtet werden.",
|
||||
"more_integrations": "Mehr",
|
||||
"finish": "Fertig"
|
||||
}
|
||||
},
|
||||
"lovelace": {
|
||||
|
@ -925,7 +925,8 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"log_out": "Esci",
|
||||
"developer_tools": "Strumenti per gli sviluppatori"
|
||||
"developer_tools": "Strumenti per gli sviluppatori",
|
||||
"external_app_configuration": "Configurazione dell'App"
|
||||
},
|
||||
"common": {
|
||||
"loading": "Caricamento",
|
||||
|
@ -603,6 +603,12 @@
|
||||
"device_unavailable": "Apparat net erreechbar",
|
||||
"entity_unavailable": "Entitéit net erreechbar",
|
||||
"no_area": "Kee Beräich"
|
||||
},
|
||||
"config_flow": {
|
||||
"external_step": {
|
||||
"description": "Fir dës Etapp ofzeschléisse muss dir eng externe Internetsäit besichen.",
|
||||
"open_site": "Internetsäit opmaachen"
|
||||
}
|
||||
}
|
||||
},
|
||||
"zha": {
|
||||
|
@ -603,6 +603,12 @@
|
||||
"device_unavailable": "enheten er utilgjengelig",
|
||||
"entity_unavailable": "oppføringen er utilgjengelig",
|
||||
"no_area": "Ingen område"
|
||||
},
|
||||
"config_flow": {
|
||||
"external_step": {
|
||||
"description": "Dette trinnet krever at du besøker et eksternt nettsted som skal fylles ut.",
|
||||
"open_site": "Åpne nettsted"
|
||||
}
|
||||
}
|
||||
},
|
||||
"zha": {
|
||||
@ -855,6 +861,11 @@
|
||||
"required_fields": "Fyll ut alle nødvendige felt",
|
||||
"password_not_match": "Passordene er ikke like"
|
||||
}
|
||||
},
|
||||
"integration": {
|
||||
"intro": "Enheter og tjenester er representert i Home Assistant som integrasjoner. Du kan sette dem opp nå, eller gjøre det senere fra konfigurasjonen skjermen.",
|
||||
"more_integrations": "Mer",
|
||||
"finish": "Fullfør"
|
||||
}
|
||||
},
|
||||
"lovelace": {
|
||||
@ -873,6 +884,8 @@
|
||||
"hold": "Hold:",
|
||||
"tap": "Trykk:",
|
||||
"navigate_to": "Naviger til {location}",
|
||||
"toggle": "Veksle {name}",
|
||||
"call_service": "Kall tjeneste {navn}",
|
||||
"more_info": "Vis mer info: {name}"
|
||||
}
|
||||
},
|
||||
@ -931,7 +944,8 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"log_out": "Logg ut",
|
||||
"developer_tools": "Utviklerverktøy"
|
||||
"developer_tools": "Utviklerverktøy",
|
||||
"external_app_configuration": "Appkonfigurasjon"
|
||||
},
|
||||
"common": {
|
||||
"loading": "Laster",
|
||||
|
@ -603,6 +603,12 @@
|
||||
"device_unavailable": "устройство недоступно",
|
||||
"entity_unavailable": "объект недоступен",
|
||||
"no_area": "Не указано"
|
||||
},
|
||||
"config_flow": {
|
||||
"external_step": {
|
||||
"description": "Для завершения этого шага требуется посетить внешний веб-сайт.",
|
||||
"open_site": "Открыть веб-сайт"
|
||||
}
|
||||
}
|
||||
},
|
||||
"zha": {
|
||||
@ -858,7 +864,7 @@
|
||||
},
|
||||
"integration": {
|
||||
"intro": "Устройства и сервисы представлены в Home Assistant как интеграции. Вы можете добавить их сейчас или сделать это позже в разделе настроек.",
|
||||
"more_integrations": "Все интеграции",
|
||||
"more_integrations": "Ещё",
|
||||
"finish": "Готово"
|
||||
}
|
||||
},
|
||||
|
@ -603,6 +603,12 @@
|
||||
"device_unavailable": "裝置不可用",
|
||||
"entity_unavailable": "物件不可用",
|
||||
"no_area": "無分區"
|
||||
},
|
||||
"config_flow": {
|
||||
"external_step": {
|
||||
"description": "此步驟將需要開啟外部網站方能完成。",
|
||||
"open_site": "開啟網站"
|
||||
}
|
||||
}
|
||||
},
|
||||
"zha": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user