Compare commits
150 Commits
20200311.0
...
card-helpe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fbfdec546 | ||
|
|
6692fa439a | ||
|
|
0535247bb3 | ||
|
|
a0a4fcaf5f | ||
|
|
454d81facc | ||
|
|
0bfa8260fa | ||
|
|
f2124f1c95 | ||
|
|
451bc2370a | ||
|
|
0b17642c31 | ||
|
|
214dc25576 | ||
|
|
158eddfd44 | ||
|
|
5daa6dbd25 | ||
|
|
645ef3e61f | ||
|
|
5dcea51712 | ||
|
|
6995968d50 | ||
|
|
c4cb42f3c2 | ||
|
|
0d4a7a2b3e | ||
|
|
20cc9c9b42 | ||
|
|
8a6bd04543 | ||
|
|
263138a388 | ||
|
|
e645342131 | ||
|
|
6e4c707f9e | ||
|
|
fca286d6c0 | ||
|
|
5a2e08647f | ||
|
|
f6dac98abd | ||
|
|
ddb525f6cd | ||
|
|
f7ee712456 | ||
|
|
ff873e2f71 | ||
|
|
54b57e6222 | ||
|
|
375abfb95e | ||
|
|
30a38fa6d1 | ||
|
|
554c0b692d | ||
|
|
61ac831882 | ||
|
|
59e89a0daf | ||
|
|
1e3950cd1d | ||
|
|
f514ea453c | ||
|
|
cc046478e5 | ||
|
|
a17c1052cd | ||
|
|
2408f9b8fa | ||
|
|
6aae1b3378 | ||
|
|
ed51223226 | ||
|
|
013808b7f5 | ||
|
|
af584e1d12 | ||
|
|
3763d7a1d0 | ||
|
|
ce92add096 | ||
|
|
40c94b6596 | ||
|
|
c894bc2e40 | ||
|
|
415a4fa1af | ||
|
|
b9367a33a8 | ||
|
|
7170f06c08 | ||
|
|
f2578a58b4 | ||
|
|
1950656bd5 | ||
|
|
eed3263c70 | ||
|
|
02e01626f5 | ||
|
|
41a2d9604e | ||
|
|
7d6f188bfc | ||
|
|
15a144f17a | ||
|
|
c54f2b66da | ||
|
|
685a0807d8 | ||
|
|
0d404e0e37 | ||
|
|
39bb859f57 | ||
|
|
90e32b7e45 | ||
|
|
63a2d9dd18 | ||
|
|
4982693883 | ||
|
|
f4211e3fa3 | ||
|
|
eacf58b5a5 | ||
|
|
f9349bc731 | ||
|
|
3840671764 | ||
|
|
fd62cf02d6 | ||
|
|
254744cd7d | ||
|
|
595d04c922 | ||
|
|
a3969fe2c8 | ||
|
|
220e4134b7 | ||
|
|
56e176a6f1 | ||
|
|
780c15d6b3 | ||
|
|
55ff848b78 | ||
|
|
dbe829bc7d | ||
|
|
8d0508f320 | ||
|
|
2741bb8b38 | ||
|
|
16cadd53cf | ||
|
|
a8d21c6112 | ||
|
|
6b2e707653 | ||
|
|
205b7451fa | ||
|
|
1d3aeec0de | ||
|
|
ac911dcd31 | ||
|
|
89a94b3efc | ||
|
|
71793dcfa5 | ||
|
|
1e527a8350 | ||
|
|
262b12eb93 | ||
|
|
7fb1e699ae | ||
|
|
9ee647329b | ||
|
|
cd6dcec644 | ||
|
|
d8f248c60e | ||
|
|
2925b930ad | ||
|
|
127aaba47b | ||
|
|
8bc8761af6 | ||
|
|
a88321d243 | ||
|
|
4e19232960 | ||
|
|
5b95bdb6b7 | ||
|
|
0fc59ccb16 | ||
|
|
a9daf9835a | ||
|
|
2110d9c3b9 | ||
|
|
b77e0b8125 | ||
|
|
5197f102ea | ||
|
|
447d4604c6 | ||
|
|
5a84e34f93 | ||
|
|
fb6d3cccdc | ||
|
|
fad3cb185b | ||
|
|
f61ce395f5 | ||
|
|
17f3299152 | ||
|
|
17e04589d0 | ||
|
|
4b2edde81b | ||
|
|
5d3d766f56 | ||
|
|
94e2a0dea0 | ||
|
|
21fe68add0 | ||
|
|
af6ebea4a3 | ||
|
|
3c17ee03b6 | ||
|
|
0c3c007faf | ||
|
|
330eb0957b | ||
|
|
02923475e6 | ||
|
|
01ff97b366 | ||
|
|
f0a4a99654 | ||
|
|
02d2368654 | ||
|
|
e19d07e434 | ||
|
|
669ed5cb28 | ||
|
|
785ae4a83d | ||
|
|
d327045802 | ||
|
|
785ef19cce | ||
|
|
f5653d0da5 | ||
|
|
e0a6d2efe5 | ||
|
|
9971e2e934 | ||
|
|
558802c7dd | ||
|
|
91edcf9b52 | ||
|
|
f401aa2897 | ||
|
|
1d0389327f | ||
|
|
06cd7556f3 | ||
|
|
3b1f9a5dab | ||
|
|
f54cd18da4 | ||
|
|
73e0fd614e | ||
|
|
9b220cc6ce | ||
|
|
c7a5f63e33 | ||
|
|
11192e6065 | ||
|
|
d83b308100 | ||
|
|
f67bf6908f | ||
|
|
2784edc689 | ||
|
|
8f41e99464 | ||
|
|
7c2b37e8ca | ||
|
|
dbdbad2deb | ||
|
|
e5db86363c | ||
|
|
b2026c1cd7 |
@@ -8,7 +8,7 @@ trigger:
|
||||
pr: none
|
||||
variables:
|
||||
- name: versionWheels
|
||||
value: '1.3-3.7-alpine3.10'
|
||||
value: '1.10.1-3.7-alpine3.11'
|
||||
- name: versionNode
|
||||
value: '12.1'
|
||||
- group: twine
|
||||
@@ -50,15 +50,8 @@ stages:
|
||||
- template: templates/azp-job-wheels.yaml@azure
|
||||
parameters:
|
||||
builderVersion: '$(versionWheels)'
|
||||
builderApk: 'build-base'
|
||||
wheelsLocal: true
|
||||
wheelsRequirement: 'requirement.txt'
|
||||
preBuild:
|
||||
- task: NodeTool@0
|
||||
displayName: "Use Node $(versionNode)"
|
||||
inputs:
|
||||
versionSpec: "$(versionNode)"
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
yarn install
|
||||
script/build_frontend
|
||||
sleep 240
|
||||
echo "home-assistant-frontend==$(Build.SourceBranchName)" > requirement.txt
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
module.exports = {
|
||||
isProdBuild: process.env.NODE_ENV === "production",
|
||||
isStatsBuild: process.env.STATS === "1",
|
||||
isTravis: process.env.TRAVIS === "true",
|
||||
isNetlify: process.env.NETLIFY === "true",
|
||||
isProdBuild() {
|
||||
return process.env.NODE_ENV === "production";
|
||||
},
|
||||
isStatsBuild() {
|
||||
return process.env.STATS === "1";
|
||||
},
|
||||
isTravis() {
|
||||
return process.env.TRAVIS === "true";
|
||||
},
|
||||
isNetlify() {
|
||||
return process.env.NETLIFY === "true";
|
||||
},
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ gulp.task(
|
||||
"copy-static",
|
||||
"webpack-prod-app",
|
||||
...// Don't compress running tests
|
||||
(envVars.isTravis ? [] : ["compress-app"]),
|
||||
(envVars.isTravis() ? [] : ["compress-app"]),
|
||||
gulp.parallel(
|
||||
"gen-pages-prod",
|
||||
"gen-index-app-prod",
|
||||
|
||||
@@ -29,6 +29,6 @@ gulp.task(
|
||||
gulp.parallel("gen-icons-hassio", "gen-icons-mdi"),
|
||||
"webpack-prod-hassio",
|
||||
...// Don't compress running tests
|
||||
(envVars.isTravis ? [] : ["compress-hassio"])
|
||||
(envVars.isTravis() ? [] : ["compress-hassio"])
|
||||
)
|
||||
);
|
||||
|
||||
@@ -292,10 +292,11 @@ gulp.task(
|
||||
function fingerprintTranslationFiles() {
|
||||
// Fingerprint full file of each language
|
||||
const files = fs.readdirSync(fullDir);
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
fingerprints[files[i].split(".")[0]] = {
|
||||
// In dev we create fake hashes
|
||||
hash: env.isProdBuild
|
||||
hash: env.isProdBuild()
|
||||
? crypto
|
||||
.createHash("md5")
|
||||
.update(fs.readFileSync(path.join(fullDir, files[i]), "utf-8"))
|
||||
@@ -332,7 +333,7 @@ gulp.task(
|
||||
gulp.series(
|
||||
"clean-translations",
|
||||
"ensure-translations-build-dir",
|
||||
env.isProdBuild ? (done) => done() : "create-test-translation",
|
||||
env.isProdBuild() ? (done) => done() : "create-test-translation",
|
||||
"build-master-translation",
|
||||
"build-merged-translations",
|
||||
gulp.parallel(...splitTasks),
|
||||
|
||||
@@ -155,7 +155,7 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
`/static/translations/${englishFilename}`
|
||||
] = `build-translations/output/${englishFilename}`;
|
||||
|
||||
Object.keys(translationMetadata.fragments).forEach((fragment) => {
|
||||
translationMetadata.fragments.forEach((fragment) => {
|
||||
workBoxTranslationsTemplatedURLs[
|
||||
`/static/translations/${fragment}/${englishFilename}`
|
||||
] = `build-translations/output/${fragment}/${englishFilename}`;
|
||||
|
||||
@@ -172,6 +172,9 @@ export class HcMain extends HassElement {
|
||||
return;
|
||||
}
|
||||
if (!this._unsubLovelace || this._urlPath !== msg.urlPath) {
|
||||
if (msg.urlPath === "lovelace") {
|
||||
msg.urlPath = null;
|
||||
}
|
||||
this._urlPath = msg.urlPath;
|
||||
if (this._unsubLovelace) {
|
||||
this._unsubLovelace();
|
||||
|
||||
@@ -6,6 +6,6 @@ const { isProdBuild } = require("../build-scripts/env.js");
|
||||
const latestBuild = true;
|
||||
|
||||
module.exports = createCastConfig({
|
||||
isProdBuild,
|
||||
isProdBuild: isProdBuild(),
|
||||
latestBuild,
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 805 B After Width: | Height: | Size: 803 B |
BIN
demo/public/assets/arsaboo/images/camera.backyard.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
demo/public/assets/arsaboo/images/camera.driveway.jpg
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
demo/public/assets/arsaboo/images/camera.patio.jpg
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
demo/public/assets/arsaboo/images/camera.porch.jpg
Normal file
|
After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 781 B After Width: | Height: | Size: 375 B |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
BIN
demo/public/stub_config/bedroom.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
demo/public/stub_config/floorplan.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
demo/public/stub_config/kitchen.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
demo/public/stub_config/t-shirt-promo.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
@@ -291,16 +291,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
state: "13:21",
|
||||
attributes: {
|
||||
attribution: "Data provided by Ring.com",
|
||||
device_id: "e04f434dca02",
|
||||
firmware: "Up to Date",
|
||||
kind: "lpd_v2",
|
||||
timezone: "America/New_York",
|
||||
type: "doorbots",
|
||||
wifi_name: "RingOfSecurity-hUrGKNlhR",
|
||||
created_at: "2019-01-22T13:21:03-05:00",
|
||||
answered: false,
|
||||
recording_status: "ready",
|
||||
category: "motion",
|
||||
friendly_name: "Front Door Last Motion",
|
||||
icon: "hademo:history",
|
||||
},
|
||||
@@ -313,8 +304,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
"cbd8dfac9efb441f19168e271cb8629b0372d0c1f721353394b23ed0202013b0",
|
||||
motion_detection: true,
|
||||
friendly_name: "Patio",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.patio?token=cbd8dfac9efb441f19168e271cb8629b0372d0c1f721353394b23ed0202013b0",
|
||||
entity_picture: "/assets/arsaboo/images/camera.patio.jpg",
|
||||
supported_features: 0,
|
||||
},
|
||||
},
|
||||
@@ -326,8 +316,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
"479b332e0a7cad4c58e0fb98a1ecb7942e3b225190adb93a1341edfa7daf45b0",
|
||||
motion_detection: true,
|
||||
friendly_name: "Porch",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.porch?token=479b332e0a7cad4c58e0fb98a1ecb7942e3b225190adb93a1341edfa7daf45b0",
|
||||
entity_picture: "/assets/arsaboo/images/camera.porch.jpg",
|
||||
supported_features: 0,
|
||||
},
|
||||
},
|
||||
@@ -339,8 +328,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
"9381b2e4edd1bb21e868e2193f5d132a5fae153ce4f458451d979a02712b4642",
|
||||
motion_detection: true,
|
||||
friendly_name: "Backyard",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.backyard?token=9381b2e4edd1bb21e868e2193f5d132a5fae153ce4f458451d979a02712b4642",
|
||||
entity_picture: "/assets/arsaboo/images/camera.backyard.jpg",
|
||||
supported_features: 0,
|
||||
},
|
||||
},
|
||||
@@ -352,8 +340,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
"ac38bf88c2c5896eed66ae15739a3e726677f92d79e0d57f83f726ac28bda746",
|
||||
motion_detection: true,
|
||||
friendly_name: "Driveway",
|
||||
entity_picture:
|
||||
"/api/camera_proxy/camera.driveway?token=ac38bf88c2c5896eed66ae15739a3e726677f92d79e0d57f83f726ac28bda746",
|
||||
entity_picture: "/assets/arsaboo/images/camera.driveway.jpg",
|
||||
supported_features: 0,
|
||||
},
|
||||
},
|
||||
@@ -477,8 +464,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.names.family_room"
|
||||
),
|
||||
entity_picture:
|
||||
"/api/media_player_proxy/media_player.family_room_2?token=be41a86e2a360761d67c36a010b09654b730deec092016ee92aafef79b1978ff&cache=e03d22fb103202e7",
|
||||
entity_picture: "/assets/arsaboo/images/media_player_family_room.jpg",
|
||||
supported_features: 64063,
|
||||
},
|
||||
},
|
||||
@@ -487,16 +473,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
state: "06:44",
|
||||
attributes: {
|
||||
attribution: "Data provided by Ring.com",
|
||||
device_id: "e04f434dca02",
|
||||
firmware: "Up to Date",
|
||||
kind: "lpd_v2",
|
||||
timezone: "America/New_York",
|
||||
type: "doorbots",
|
||||
wifi_name: "RingOfSecurity-hUrGKNlhR",
|
||||
created_at: "2019-01-22T06:44:31-05:00",
|
||||
answered: false,
|
||||
recording_status: "ready",
|
||||
category: "ding",
|
||||
friendly_name: "Front Door Last Ding",
|
||||
icon: "hademo:history",
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ const { isProdBuild, isStatsBuild } = require("../build-scripts/env.js");
|
||||
const latestBuild = true;
|
||||
|
||||
module.exports = createDemoConfig({
|
||||
isProdBuild,
|
||||
isStatsBuild,
|
||||
isProdBuild: isProdBuild(),
|
||||
isStatsBuild: isStatsBuild(),
|
||||
latestBuild,
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 24 KiB |
BIN
gallery/public/images/album_cover_2.jpg
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
gallery/public/images/frenck.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
gallery/public/images/netflix.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
@@ -1,26 +1,40 @@
|
||||
import { getEntity } from "../../../src/fake_data/entity";
|
||||
|
||||
export const createMediaPlayerEntities = () => [
|
||||
getEntity("media_player", "bedroom", "playing", {
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
friendly_name: "Skip, no pause",
|
||||
supported_features: 32,
|
||||
}),
|
||||
getEntity("media_player", "family_room", "paused", {
|
||||
friendly_name: "Paused, music",
|
||||
getEntity("media_player", "music_paused", "paused", {
|
||||
friendly_name: "Pausing The Music",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
supported_features: 16417,
|
||||
entity_picture: "/images/album_cover.jpg",
|
||||
supported_features: 64063,
|
||||
entity_picture: "/images/album_cover_2.jpg",
|
||||
media_duration: 300,
|
||||
media_position: 50,
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
}),
|
||||
getEntity("media_player", "family_room_no_play", "paused", {
|
||||
friendly_name: "Paused, no play",
|
||||
getEntity("media_player", "music_playing", "playing", {
|
||||
friendly_name: "Playing The Music",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
supported_features: 64063,
|
||||
entity_picture: "/images/album_cover.jpg",
|
||||
media_duration: 300,
|
||||
media_position: 0,
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
}),
|
||||
getEntity("media_player", "stream_playing", "playing", {
|
||||
friendly_name: "Playing the Stream",
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
entity_picture: "/images/frenck.jpg",
|
||||
supported_features: 33,
|
||||
}),
|
||||
getEntity("media_player", "living_room", "playing", {
|
||||
@@ -29,27 +43,22 @@ export const createMediaPlayerEntities = () => [
|
||||
media_title: "Chapter 1",
|
||||
media_series_title: "House of Cards",
|
||||
app_name: "Netflix",
|
||||
entity_picture: "/images/netflix.jpg",
|
||||
supported_features: 1,
|
||||
}),
|
||||
getEntity("media_player", "lounge_room", "idle", {
|
||||
friendly_name: "Screen casting",
|
||||
media_content_type: "music",
|
||||
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
|
||||
media_artist: "Technohead",
|
||||
supported_features: 1,
|
||||
getEntity("media_player", "sonos_idle", "idle", {
|
||||
friendly_name: "Sonos Idle",
|
||||
supported_features: 64063,
|
||||
}),
|
||||
getEntity("media_player", "theater", "off", {
|
||||
friendly_name: "Chromcast Idle",
|
||||
media_content_type: "movie",
|
||||
media_title: "Epic sax guy 10 hours",
|
||||
app_name: "YouTube",
|
||||
supported_features: 33,
|
||||
friendly_name: "TV Off",
|
||||
supported_features: 161,
|
||||
}),
|
||||
getEntity("media_player", "android_cast", "playing", {
|
||||
friendly_name: "Player Off",
|
||||
friendly_name: "Casting App",
|
||||
media_title: "Android Screen Casting",
|
||||
app_name: "Screen Mirroring",
|
||||
supported_features: 21437,
|
||||
// supported_features: 21437,
|
||||
}),
|
||||
getEntity("media_player", "unavailable", "unavailable", {
|
||||
friendly_name: "Player Unavailable",
|
||||
@@ -59,4 +68,17 @@ export const createMediaPlayerEntities = () => [
|
||||
friendly_name: "Player Unknown",
|
||||
supported_features: 21437,
|
||||
}),
|
||||
getEntity("media_player", "receiver_on", "on", {
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
volume_level: 0.63,
|
||||
is_volume_muted: false,
|
||||
source: "TV",
|
||||
friendly_name: "Receiver",
|
||||
supported_features: 84364,
|
||||
}),
|
||||
getEntity("media_player", "receiver_off", "off", {
|
||||
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
|
||||
friendly_name: "Receiver",
|
||||
supported_features: 84364,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -4,27 +4,28 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||
import "../components/demo-cards";
|
||||
import { createMediaPlayerEntities } from "../data/media_players";
|
||||
import "../../../src/panels/lovelace/cards/hui-media-control-card";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
heading: "Skip, no pause",
|
||||
heading: "Paused music",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.bedroom
|
||||
entity: media_player.music_paused
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Paused, music",
|
||||
heading: "Playing music",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.family_room
|
||||
entity: media_player.music_playing
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Paused, no play",
|
||||
heading: "Playing stream",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.family_room_no_play
|
||||
entity: media_player.stream_playing
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -42,10 +43,10 @@ const CONFIGS = [
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Chromcast Idle",
|
||||
heading: "Sonos Idle",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.lounge_room
|
||||
entity: media_player.sonos_idle
|
||||
`,
|
||||
},
|
||||
{
|
||||
@@ -69,6 +70,20 @@ const CONFIGS = [
|
||||
entity: media_player.unknown
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Receiver On",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.receiver_on
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Receiver Off",
|
||||
config: `
|
||||
- type: media-control
|
||||
entity: media_player.receiver_off
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
class DemoHuiMediControlCard extends PolymerElement {
|
||||
|
||||
@@ -11,17 +11,17 @@ const CONFIGS = [
|
||||
config: `
|
||||
- type: entities
|
||||
entities:
|
||||
- entity: media_player.bedroom
|
||||
name: Skip, no pause
|
||||
- entity: media_player.family_room
|
||||
name: Paused, music
|
||||
- entity: media_player.family_room_no_play
|
||||
- entity: media_player.music_paused
|
||||
name: Paused music
|
||||
- entity: media_player.music_playing
|
||||
name: Playing music
|
||||
- entity: media_player.stream_playing
|
||||
name: Paused, no play
|
||||
- entity: media_player.living_room
|
||||
name: Pause, No skip, tvshow
|
||||
- entity: media_player.android_cast
|
||||
name: Screen casting
|
||||
- entity: media_player.lounge_room
|
||||
- entity: media_player.sonos_idle
|
||||
name: Chromcast Idle
|
||||
- entity: media_player.theater
|
||||
name: Player Off
|
||||
|
||||
@@ -93,7 +93,7 @@ class HassioAddonRepositoryEl extends LitElement {
|
||||
? "not_available"
|
||||
: ""}
|
||||
.iconImage=${atLeastVersion(
|
||||
this.hass.connection.haVersion,
|
||||
this.hass.config.version,
|
||||
0,
|
||||
105
|
||||
) && addon.icon
|
||||
|
||||
@@ -107,7 +107,7 @@ class HassioAddonInfo extends LitElement {
|
||||
<hassio-card-content
|
||||
.hass=${this.hass}
|
||||
.title="${this.addon.name} ${this.addon
|
||||
.last_version} is available"
|
||||
.version_latest} is available"
|
||||
.description="You are currently running version ${this.addon
|
||||
.version}"
|
||||
icon="hassio:arrow-up-bold-circle"
|
||||
@@ -179,7 +179,7 @@ class HassioAddonInfo extends LitElement {
|
||||
`}
|
||||
`
|
||||
: html`
|
||||
${this.addon.last_version}
|
||||
${this.addon.version_latest}
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
@@ -636,7 +636,7 @@ class HassioAddonInfo extends LitElement {
|
||||
this.addon &&
|
||||
!this.addon.detached &&
|
||||
this.addon.version &&
|
||||
this.addon.version !== this.addon.last_version
|
||||
this.addon.version !== this.addon.version_latest
|
||||
);
|
||||
}
|
||||
|
||||
@@ -661,8 +661,7 @@ class HassioAddonInfo extends LitElement {
|
||||
|
||||
private get _computeCannotIngressSidebar(): boolean {
|
||||
return (
|
||||
!this.addon.ingress ||
|
||||
!atLeastVersion(this.hass.connection.haVersion, 0, 92)
|
||||
!this.addon.ingress || !atLeastVersion(this.hass.config.version, 0, 92)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class HassioAddons extends LitElement {
|
||||
? "running"
|
||||
: "stopped"}
|
||||
.iconImage=${atLeastVersion(
|
||||
this.hass.connection.haVersion,
|
||||
this.hass.config.version,
|
||||
0,
|
||||
105
|
||||
) && addon.icon
|
||||
|
||||
@@ -40,8 +40,8 @@ export class HassioUpdate extends LitElement {
|
||||
].filter((value) => {
|
||||
return (
|
||||
!!value &&
|
||||
(value.last_version
|
||||
? value.version !== value.last_version
|
||||
(value.version_latest
|
||||
? value.version !== value.version_latest
|
||||
: value.version_latest
|
||||
? value.version !== value.version_latest
|
||||
: false)
|
||||
@@ -68,26 +68,26 @@ export class HassioUpdate extends LitElement {
|
||||
${this._renderUpdateCard(
|
||||
"Home Assistant Core",
|
||||
this.hassInfo.version,
|
||||
this.hassInfo.last_version,
|
||||
this.hassInfo.version_latest,
|
||||
"hassio/homeassistant/update",
|
||||
`https://${
|
||||
this.hassInfo.last_version.includes("b") ? "rc" : "www"
|
||||
this.hassInfo.version_latest.includes("b") ? "rc" : "www"
|
||||
}.home-assistant.io/latest-release-notes/`,
|
||||
"hassio:home-assistant"
|
||||
)}
|
||||
${this._renderUpdateCard(
|
||||
"Supervisor",
|
||||
this.supervisorInfo.version,
|
||||
this.supervisorInfo.last_version,
|
||||
this.supervisorInfo.version_latest,
|
||||
"hassio/supervisor/update",
|
||||
`https://github.com//home-assistant/hassio/releases/tag/${this.supervisorInfo.last_version}`
|
||||
`https://github.com//home-assistant/hassio/releases/tag/${this.supervisorInfo.version_latest}`
|
||||
)}
|
||||
${this.hassOsInfo
|
||||
? this._renderUpdateCard(
|
||||
"Operating System",
|
||||
this.hassOsInfo.version,
|
||||
this.hassOsInfo.version_latest,
|
||||
"hassio/hassos/update",
|
||||
"hassio/os/update",
|
||||
`https://github.com//home-assistant/hassos/releases/tag/${this.hassOsInfo.version_latest}`
|
||||
)
|
||||
: ""}
|
||||
|
||||
@@ -87,8 +87,7 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
|
||||
applyThemesOnElement(
|
||||
this.parentElement,
|
||||
this.hass.themes,
|
||||
this.hass.selectedTheme,
|
||||
true
|
||||
this.hass.selectedTheme || this.hass.themes.default_theme
|
||||
);
|
||||
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
|
||||
// Paulus - March 17, 2019
|
||||
|
||||
@@ -100,7 +100,7 @@ class HassioHostInfo extends LitElement {
|
||||
<ha-call-api-button
|
||||
class="warning"
|
||||
.hass=${this.hass}
|
||||
path="hassio/hassos/config/sync"
|
||||
path="hassio/os/config/sync"
|
||||
title="Load HassOS configs or updates from USB"
|
||||
>Import from USB</ha-call-api-button
|
||||
>
|
||||
@@ -108,9 +108,7 @@ class HassioHostInfo extends LitElement {
|
||||
: ""}
|
||||
${this.hostInfo.version !== this.hostInfo.version_latest
|
||||
? html`
|
||||
<ha-call-api-button
|
||||
.hass=${this.hass}
|
||||
path="hassio/hassos/update"
|
||||
<ha-call-api-button .hass=${this.hass} path="hassio/os/update"
|
||||
>Update</ha-call-api-button
|
||||
>
|
||||
`
|
||||
|
||||
@@ -41,7 +41,7 @@ class HassioSupervisorInfo extends LitElement {
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Latest version</td>
|
||||
<td>${this.supervisorInfo.last_version}</td>
|
||||
<td>${this.supervisorInfo.version_latest}</td>
|
||||
</tr>
|
||||
${this.supervisorInfo.channel !== "stable"
|
||||
? html`
|
||||
@@ -63,7 +63,7 @@ class HassioSupervisorInfo extends LitElement {
|
||||
<ha-call-api-button .hass=${this.hass} path="hassio/supervisor/reload"
|
||||
>Reload</ha-call-api-button
|
||||
>
|
||||
${this.supervisorInfo.version !== this.supervisorInfo.last_version
|
||||
${this.supervisorInfo.version !== this.supervisorInfo.version_latest
|
||||
? html`
|
||||
<ha-call-api-button
|
||||
.hass=${this.hass}
|
||||
|
||||
@@ -6,6 +6,6 @@ const { isProdBuild } = require("../build-scripts/env.js");
|
||||
const latestBuild = false;
|
||||
|
||||
module.exports = createHassioConfig({
|
||||
isProdBuild,
|
||||
isProdBuild: isProdBuild(),
|
||||
latestBuild,
|
||||
});
|
||||
|
||||
BIN
public/static/images/config_freebox.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
@@ -1 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="36" height="36" viewBox="0 0 24 24"><path fill="#505050" d="M19,3A2,2 0 0,1 21,5V11H19V13H19L17,13V15H15V17H13V19H11V21H5C3.89,21 3,20.1 3,19V5A2,2 0 0,1 5,3H19M21,15V19A2,2 0 0,1 19,21H19L15,21V19H17V17H19V15H21M19,8.5A0.5,0.5 0 0,0 18.5,8H5.5A0.5,0.5 0 0,0 5,8.5V15.5A0.5,0.5 0 0,0 5.5,16H11V15H13V13H15V11H17V9H19V8.5Z" /></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="36" height="36" version="1.1" viewBox="0 0 24 24"><path fill="#505050" d="M19,3A2,2 0 0,1 21,5V11H19V13H19L17,13V15H15V17H13V19H11V21H5C3.89,21 3,20.1 3,19V5A2,2 0 0,1 5,3H19M21,15V19A2,2 0 0,1 19,21H19L15,21V19H17V17H19V15H21M19,8.5A0.5,0.5 0 0,0 18.5,8H5.5A0.5,0.5 0 0,0 5,8.5V15.5A0.5,0.5 0 0,0 5.5,16H11V15H13V13H15V11H17V9H19V8.5Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 571 B After Width: | Height: | Size: 434 B |
2
setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20200311.0",
|
||||
version="20200330.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
/** Icon to use when no icon specified for domain. */
|
||||
export const DEFAULT_DOMAIN_ICON = "hass:bookmark";
|
||||
|
||||
/** Panel to show when no panel is picked. */
|
||||
export const DEFAULT_PANEL = "lovelace";
|
||||
|
||||
/** Domains that have a state card. */
|
||||
export const DOMAINS_WITH_CARD = [
|
||||
"climate",
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { derivedStyles } from "../../resources/styles";
|
||||
import { HomeAssistant, Theme } from "../../types";
|
||||
|
||||
interface ProcessedTheme {
|
||||
keys: { [key: string]: "" };
|
||||
styles: { [key: string]: string };
|
||||
}
|
||||
|
||||
const hexToRgb = (hex: string): string | null => {
|
||||
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
@@ -15,67 +21,82 @@ const hexToRgb = (hex: string): string | null => {
|
||||
: null;
|
||||
};
|
||||
|
||||
let PROCESSED_THEMES: { [key: string]: ProcessedTheme } = {};
|
||||
|
||||
/**
|
||||
* Apply a theme to an element by setting the CSS variables on it.
|
||||
*
|
||||
* element: Element to apply theme on.
|
||||
* themes: HASS Theme information
|
||||
* localTheme: selected theme.
|
||||
* updateMeta: boolean if we should update the theme-color meta element.
|
||||
* selectedTheme: selected theme.
|
||||
*/
|
||||
export const applyThemesOnElement = (
|
||||
element,
|
||||
themes,
|
||||
localTheme,
|
||||
updateMeta = false
|
||||
themes: HomeAssistant["themes"],
|
||||
selectedTheme?: string
|
||||
) => {
|
||||
if (!element._themes) {
|
||||
element._themes = {};
|
||||
}
|
||||
let themeName = themes.default_theme;
|
||||
if (localTheme === "default" || (localTheme && themes.themes[localTheme])) {
|
||||
themeName = localTheme;
|
||||
}
|
||||
const styles = { ...element._themes };
|
||||
if (themeName !== "default") {
|
||||
const theme = { ...derivedStyles, ...themes.themes[themeName] };
|
||||
Object.keys(theme).forEach((key) => {
|
||||
const prefixedKey = `--${key}`;
|
||||
element._themes[prefixedKey] = "";
|
||||
styles[prefixedKey] = theme[key];
|
||||
if (key.startsWith("rgb")) {
|
||||
return;
|
||||
}
|
||||
const rgbKey = `rgb-${key}`;
|
||||
if (theme[rgbKey] !== undefined) {
|
||||
return;
|
||||
}
|
||||
const prefixedRgbKey = `--${rgbKey}`;
|
||||
element._themes[prefixedRgbKey] = "";
|
||||
const rgbValue = hexToRgb(theme[key]);
|
||||
if (rgbValue !== null) {
|
||||
styles[prefixedRgbKey] = rgbValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (element.updateStyles) {
|
||||
element.updateStyles(styles);
|
||||
} else if (window.ShadyCSS) {
|
||||
// implement updateStyles() method of Polymer elements
|
||||
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ element, styles);
|
||||
}
|
||||
const newTheme = selectedTheme
|
||||
? PROCESSED_THEMES[selectedTheme] || processTheme(selectedTheme, themes)
|
||||
: undefined;
|
||||
|
||||
if (!updateMeta) {
|
||||
if (!element._themes && !newTheme) {
|
||||
// No styles to reset, and no styles to set
|
||||
return;
|
||||
}
|
||||
|
||||
const meta = document.querySelector("meta[name=theme-color]");
|
||||
if (meta) {
|
||||
if (!meta.hasAttribute("default-content")) {
|
||||
meta.setAttribute("default-content", meta.getAttribute("content")!);
|
||||
}
|
||||
const themeColor =
|
||||
styles["--primary-color"] || meta.getAttribute("default-content");
|
||||
meta.setAttribute("content", themeColor);
|
||||
// Add previous set keys to reset them, and new theme
|
||||
const styles = { ...element._themes, ...newTheme?.styles };
|
||||
element._themes = newTheme?.keys;
|
||||
|
||||
// Set and/or reset styles
|
||||
if (element.updateStyles) {
|
||||
element.updateStyles(styles);
|
||||
} else if (window.ShadyCSS) {
|
||||
// Implement updateStyles() method of Polymer elements
|
||||
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ element, styles);
|
||||
}
|
||||
};
|
||||
|
||||
const processTheme = (
|
||||
themeName: string,
|
||||
themes: HomeAssistant["themes"]
|
||||
): ProcessedTheme | undefined => {
|
||||
if (!themes.themes[themeName]) {
|
||||
return;
|
||||
}
|
||||
const theme: Theme = {
|
||||
...derivedStyles,
|
||||
...themes.themes[themeName],
|
||||
};
|
||||
const styles = {};
|
||||
const keys = {};
|
||||
for (const key of Object.keys(theme)) {
|
||||
const prefixedKey = `--${key}`;
|
||||
const value = theme[key];
|
||||
styles[prefixedKey] = value;
|
||||
keys[prefixedKey] = "";
|
||||
|
||||
// Try to create a rgb value for this key if it is a hex color
|
||||
if (!value.startsWith("#")) {
|
||||
// Not a hex color
|
||||
continue;
|
||||
}
|
||||
const rgbKey = `rgb-${key}`;
|
||||
if (theme[rgbKey] !== undefined) {
|
||||
// Theme has it's own rgb value
|
||||
continue;
|
||||
}
|
||||
const rgbValue = hexToRgb(value);
|
||||
if (rgbValue !== null) {
|
||||
const prefixedRgbKey = `--${rgbKey}`;
|
||||
styles[prefixedRgbKey] = rgbValue;
|
||||
keys[prefixedRgbKey] = "";
|
||||
}
|
||||
}
|
||||
PROCESSED_THEMES[themeName] = { styles, keys };
|
||||
return { styles, keys };
|
||||
};
|
||||
|
||||
export const invalidateThemeCache = () => {
|
||||
PROCESSED_THEMES = {};
|
||||
};
|
||||
|
||||
@@ -4,17 +4,58 @@ import { domainIcon } from "./domain_icon";
|
||||
|
||||
export const coverIcon = (state: HassEntity): string => {
|
||||
const open = state.state !== "closed";
|
||||
|
||||
switch (state.attributes.device_class) {
|
||||
case "garage":
|
||||
return open ? "hass:garage-open" : "hass:garage";
|
||||
switch (state.state) {
|
||||
case "opening":
|
||||
return "hass:arrow-up-box";
|
||||
case "closing":
|
||||
return "hass:arrow-down-box";
|
||||
case "closed":
|
||||
return "hass:garage";
|
||||
default:
|
||||
return "hass:garage-open";
|
||||
}
|
||||
case "gate":
|
||||
switch (state.state) {
|
||||
case "opening":
|
||||
case "closing":
|
||||
return "hass:gate-arrow-right";
|
||||
case "closed":
|
||||
return "hass:gate";
|
||||
default:
|
||||
return "hass:gate-open";
|
||||
}
|
||||
case "door":
|
||||
return open ? "hass:door-open" : "hass:door-closed";
|
||||
case "damper":
|
||||
return open ? "hass:circle" : "hass:circle-slice-8";
|
||||
case "shutter":
|
||||
return open ? "hass:window-shutter-open" : "hass:window-shutter";
|
||||
case "blind":
|
||||
return open ? "hass:blinds-open" : "hass:blinds";
|
||||
case "curtain":
|
||||
switch (state.state) {
|
||||
case "opening":
|
||||
return "hass:arrow-up-box";
|
||||
case "closing":
|
||||
return "hass:arrow-down-box";
|
||||
case "closed":
|
||||
return "hass:blinds";
|
||||
default:
|
||||
return "hass:blinds-open";
|
||||
}
|
||||
case "window":
|
||||
return open ? "hass:window-open" : "hass:window-closed";
|
||||
switch (state.state) {
|
||||
case "opening":
|
||||
return "hass:arrow-up-box";
|
||||
case "closing":
|
||||
return "hass:arrow-down-box";
|
||||
case "closed":
|
||||
return "hass:window-closed";
|
||||
default:
|
||||
return "hass:window-open";
|
||||
}
|
||||
default:
|
||||
return domainIcon("cover", state.state);
|
||||
}
|
||||
|
||||
@@ -77,15 +77,22 @@ export const domainIcon = (domain: string, state?: string): string => {
|
||||
: "hass:checkbox-marked-circle";
|
||||
|
||||
case "cover":
|
||||
return state === "closed" ? "hass:window-closed" : "hass:window-open";
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return "hass:arrow-up-box";
|
||||
case "closing":
|
||||
return "hass:arrow-down-box";
|
||||
case "closed":
|
||||
return "hass:window-closed";
|
||||
default:
|
||||
return "hass:window-open";
|
||||
}
|
||||
|
||||
case "lock":
|
||||
return state && state === "unlocked" ? "hass:lock-open" : "hass:lock";
|
||||
|
||||
case "media_player":
|
||||
return state && state !== "off" && state !== "idle"
|
||||
? "hass:cast-connected"
|
||||
: "hass:cast";
|
||||
return state && state === "playing" ? "hass:cast-connected" : "hass:cast";
|
||||
|
||||
case "zwave":
|
||||
switch (state) {
|
||||
|
||||
@@ -11,6 +11,7 @@ export const iconColorCSS = css`
|
||||
ha-icon[data-domain="light"][data-state="on"],
|
||||
ha-icon[data-domain="input_boolean"][data-state="on"],
|
||||
ha-icon[data-domain="lock"][data-state="unlocked"],
|
||||
ha-icon[data-domain="media_player"][data-state="on"],
|
||||
ha-icon[data-domain="media_player"][data-state="paused"],
|
||||
ha-icon[data-domain="media_player"][data-state="playing"],
|
||||
ha-icon[data-domain="script"][data-state="running"],
|
||||
|
||||
@@ -69,9 +69,10 @@ export interface DataTableSortColumnData {
|
||||
|
||||
export interface DataTableColumnData extends DataTableSortColumnData {
|
||||
title: string;
|
||||
type?: "numeric" | "icon";
|
||||
type?: "numeric" | "icon" | "icon-button";
|
||||
template?: <T>(data: any, row: T) => TemplateResult | string;
|
||||
width?: string;
|
||||
maxWidth?: string;
|
||||
grows?: boolean;
|
||||
}
|
||||
|
||||
@@ -227,10 +228,13 @@ export class HaDataTable extends LitElement {
|
||||
const sorted = key === this._sortColumn;
|
||||
const classes = {
|
||||
"mdc-data-table__header-cell--numeric": Boolean(
|
||||
column.type && column.type === "numeric"
|
||||
column.type === "numeric"
|
||||
),
|
||||
"mdc-data-table__header-cell--icon": Boolean(
|
||||
column.type && column.type === "icon"
|
||||
column.type === "icon"
|
||||
),
|
||||
"mdc-data-table__header-cell--icon-button": Boolean(
|
||||
column.type === "icon-button"
|
||||
),
|
||||
sortable: Boolean(column.sortable),
|
||||
"not-sorted": Boolean(column.sortable && !sorted),
|
||||
@@ -241,9 +245,8 @@ export class HaDataTable extends LitElement {
|
||||
class="mdc-data-table__header-cell ${classMap(classes)}"
|
||||
style=${column.width
|
||||
? styleMap({
|
||||
[column.grows ? "minWidth" : "width"]: String(
|
||||
column.width
|
||||
),
|
||||
[column.grows ? "minWidth" : "width"]: column.width,
|
||||
maxWidth: column.maxWidth || "",
|
||||
})
|
||||
: ""}
|
||||
role="columnheader"
|
||||
@@ -318,10 +321,13 @@ export class HaDataTable extends LitElement {
|
||||
<div
|
||||
class="mdc-data-table__cell ${classMap({
|
||||
"mdc-data-table__cell--numeric": Boolean(
|
||||
column.type && column.type === "numeric"
|
||||
column.type === "numeric"
|
||||
),
|
||||
"mdc-data-table__cell--icon": Boolean(
|
||||
column.type && column.type === "icon"
|
||||
column.type === "icon"
|
||||
),
|
||||
"mdc-data-table__cell--icon-button": Boolean(
|
||||
column.type === "icon-button"
|
||||
),
|
||||
grows: Boolean(column.grows),
|
||||
})}"
|
||||
@@ -329,7 +335,10 @@ export class HaDataTable extends LitElement {
|
||||
? styleMap({
|
||||
[column.grows
|
||||
? "minWidth"
|
||||
: "width"]: String(column.width),
|
||||
: "width"]: column.width,
|
||||
maxWidth: column.maxWidth
|
||||
? column.maxWidth
|
||||
: "",
|
||||
})
|
||||
: ""}
|
||||
>
|
||||
@@ -532,6 +541,11 @@ export class HaDataTable extends LitElement {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell.mdc-data-table__cell--icon {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--checkbox,
|
||||
@@ -540,7 +554,7 @@ export class HaDataTable extends LitElement {
|
||||
padding-left: 16px;
|
||||
/* @noflip */
|
||||
padding-right: 0;
|
||||
width: 40px;
|
||||
width: 56px;
|
||||
}
|
||||
[dir="rtl"] .mdc-data-table__header-cell--checkbox,
|
||||
.mdc-data-table__header-cell--checkbox[dir="rtl"],
|
||||
@@ -587,7 +601,7 @@ export class HaDataTable extends LitElement {
|
||||
|
||||
.mdc-data-table__header-cell--icon,
|
||||
.mdc-data-table__cell--icon {
|
||||
width: 24px;
|
||||
width: 54px;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell.mdc-data-table__header-cell--icon {
|
||||
@@ -606,6 +620,28 @@ export class HaDataTable extends LitElement {
|
||||
margin-right: -8px;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--icon-button,
|
||||
.mdc-data-table__cell--icon-button {
|
||||
width: 56px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--icon-button:first-child,
|
||||
.mdc-data-table__cell--icon-button:first-child {
|
||||
width: 64px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--icon-button:last-child,
|
||||
.mdc-data-table__cell--icon-button:last-child {
|
||||
width: 64px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--icon-button a {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell {
|
||||
font-family: Roboto, sans-serif;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
@@ -691,6 +727,9 @@ export class HaDataTable extends LitElement {
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.scroller {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
@@ -246,7 +246,7 @@ class HaEntityPicker extends LitElement {
|
||||
paper-input > paper-icon-button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 2px;
|
||||
padding: 0px 2px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
[hidden] {
|
||||
|
||||
@@ -53,7 +53,7 @@ class HaCameraStream extends LitElement {
|
||||
<img
|
||||
@load=${this._elementResized}
|
||||
.src=${__DEMO__
|
||||
? `/api/camera_proxy_stream/${this.stateObj.entity_id}`
|
||||
? this.stateObj!.attributes.entity_picture
|
||||
: computeMJPEGStreamUrl(this.stateObj)}
|
||||
.alt=${`Preview of the ${computeStateName(
|
||||
this.stateObj
|
||||
|
||||
@@ -19,7 +19,7 @@ class HaCoverControls extends PolymerElement {
|
||||
<div class="state">
|
||||
<paper-icon-button
|
||||
aria-label="Open cover"
|
||||
icon="hass:arrow-up"
|
||||
icon="[[computeOpenIcon(stateObj)]]"
|
||||
on-click="onOpenTap"
|
||||
invisible$="[[!entityObj.supportsOpen]]"
|
||||
disabled="[[computeOpenDisabled(stateObj, entityObj)]]"
|
||||
@@ -32,7 +32,7 @@ class HaCoverControls extends PolymerElement {
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
aria-label="Close cover"
|
||||
icon="hass:arrow-down"
|
||||
icon="[[computeCloseIcon(stateObj)]]"
|
||||
on-click="onCloseTap"
|
||||
invisible$="[[!entityObj.supportsClose]]"
|
||||
disabled="[[computeClosedDisabled(stateObj, entityObj)]]"
|
||||
@@ -60,6 +60,26 @@ class HaCoverControls extends PolymerElement {
|
||||
return new CoverEntity(hass, stateObj);
|
||||
}
|
||||
|
||||
computeOpenIcon(stateObj) {
|
||||
switch (stateObj.attributes.device_class) {
|
||||
case "awning":
|
||||
case "gate":
|
||||
return "hass:arrow-expand-horizontal";
|
||||
default:
|
||||
return "hass:arrow-up";
|
||||
}
|
||||
}
|
||||
|
||||
computeCloseIcon(stateObj) {
|
||||
switch (stateObj.attributes.device_class) {
|
||||
case "awning":
|
||||
case "gate":
|
||||
return "hass:arrow-collapse-horizontal";
|
||||
default:
|
||||
return "hass:arrow-down";
|
||||
}
|
||||
}
|
||||
|
||||
computeOpenDisabled(stateObj, entityObj) {
|
||||
var assumedState = stateObj.attributes.assumed_state === true;
|
||||
return (entityObj.isFullyOpen || entityObj.isOpening) && !assumedState;
|
||||
|
||||
@@ -18,7 +18,6 @@ import "../components/user/ha-user-badge";
|
||||
import "../components/ha-menu-button";
|
||||
import { HomeAssistant, PanelInfo } from "../types";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { DEFAULT_PANEL } from "../common/const";
|
||||
import {
|
||||
getExternalConfig,
|
||||
ExternalConfig,
|
||||
@@ -33,6 +32,7 @@ import { classMap } from "lit-html/directives/class-map";
|
||||
import { PaperIconItemElement } from "@polymer/paper-item/paper-icon-item";
|
||||
import { computeRTL } from "../common/util/compute_rtl";
|
||||
import { compare } from "../common/string/compare";
|
||||
import { getDefaultPanel } from "../data/panel";
|
||||
|
||||
const SHOW_AFTER_SPACER = ["config", "developer-tools", "hassio"];
|
||||
|
||||
@@ -77,7 +77,6 @@ const panelSorter = (a: PanelInfo, b: PanelInfo) => {
|
||||
// both not built in, sort by title
|
||||
return compare(a.title!, b.title!);
|
||||
};
|
||||
const DEFAULT_PAGE = localStorage.defaultPage || DEFAULT_PANEL;
|
||||
|
||||
const computePanels = (hass: HomeAssistant): [PanelInfo[], PanelInfo[]] => {
|
||||
const panels = hass.panels;
|
||||
@@ -89,7 +88,7 @@ const computePanels = (hass: HomeAssistant): [PanelInfo[], PanelInfo[]] => {
|
||||
const afterSpacer: PanelInfo[] = [];
|
||||
|
||||
Object.values(panels).forEach((panel) => {
|
||||
if (!panel.title || panel.url_path === DEFAULT_PAGE) {
|
||||
if (!panel.title || panel.url_path === hass.defaultPanel) {
|
||||
return;
|
||||
}
|
||||
(SHOW_AFTER_SPACER.includes(panel.url_path)
|
||||
@@ -142,8 +141,7 @@ class HaSidebar extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
const defaultPanel =
|
||||
this.hass.panels[DEFAULT_PAGE] || this.hass.panels[DEFAULT_PANEL];
|
||||
const defaultPanel = getDefaultPanel(hass);
|
||||
|
||||
return html`
|
||||
<div class="menu">
|
||||
@@ -297,7 +295,8 @@ class HaSidebar extends LitElement {
|
||||
hass.panelUrl !== oldHass.panelUrl ||
|
||||
hass.user !== oldHass.user ||
|
||||
hass.localize !== oldHass.localize ||
|
||||
hass.states !== oldHass.states
|
||||
hass.states !== oldHass.states ||
|
||||
hass.defaultPanel !== oldHass.defaultPanel
|
||||
);
|
||||
}
|
||||
|
||||
@@ -530,6 +529,7 @@ class HaSidebar extends LitElement {
|
||||
overflow-x: hidden;
|
||||
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
||||
scrollbar-width: thin;
|
||||
background: none;
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
@@ -90,6 +90,27 @@ class HaMap extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps) {
|
||||
if (!changedProps.has("hass") || changedProps.size > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
|
||||
if (!oldHass || !this.entities) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if any state has changed
|
||||
for (const entity of this.entities) {
|
||||
if (oldHass.states[entity] !== this.hass!.states[entity]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
if (changedProps.has("hass")) {
|
||||
this._drawEntities();
|
||||
|
||||
@@ -12,9 +12,9 @@ export const callAlarmAction = (
|
||||
| "arm_night"
|
||||
| "arm_custom_bypass"
|
||||
| "disarm",
|
||||
code: string
|
||||
code?: string
|
||||
) => {
|
||||
hass!.callService("alarm_control_panel", "alarm_" + action, {
|
||||
hass!.callService("alarm_control_panel", `alarm_${action}`, {
|
||||
entity_id: entity,
|
||||
code,
|
||||
});
|
||||
|
||||
@@ -25,3 +25,16 @@ export const fetchAuthProviders = () =>
|
||||
fetch("/auth/providers", {
|
||||
credentials: "same-origin",
|
||||
});
|
||||
|
||||
export const createAuthForUser = async (
|
||||
hass: HomeAssistant,
|
||||
userId: string,
|
||||
username: string,
|
||||
password: string
|
||||
) =>
|
||||
hass.callWS({
|
||||
type: "config/auth_provider/homeassistant/create",
|
||||
user_id: userId,
|
||||
username,
|
||||
password,
|
||||
});
|
||||
|
||||
@@ -69,7 +69,7 @@ export const fetchDeviceTriggerCapabilities = (
|
||||
const whitelist = [
|
||||
"above",
|
||||
"below",
|
||||
"brightness",
|
||||
"brightness_pct",
|
||||
"code",
|
||||
"for",
|
||||
"position",
|
||||
|
||||
@@ -53,6 +53,9 @@ export const fallbackDeviceName = (
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const devicesInArea = (devices: DeviceRegistryEntry[], areaId: string) =>
|
||||
devices.filter((device) => device.area_id === areaId);
|
||||
|
||||
export const updateDeviceRegistryEntry = (
|
||||
hass: HomeAssistant,
|
||||
deviceId: string,
|
||||
|
||||
@@ -27,6 +27,16 @@ export interface EntityRegistryEntryUpdateParams {
|
||||
new_entity_id?: string;
|
||||
}
|
||||
|
||||
export const findBatteryEntity = (
|
||||
hass: HomeAssistant,
|
||||
entities: EntityRegistryEntry[]
|
||||
): EntityRegistryEntry | undefined =>
|
||||
entities.find(
|
||||
(entity) =>
|
||||
hass.states[entity.entity_id] &&
|
||||
hass.states[entity.entity_id].attributes.device_class === "battery"
|
||||
);
|
||||
|
||||
export const computeEntityRegistryName = (
|
||||
hass: HomeAssistant,
|
||||
entry: EntityRegistryEntry
|
||||
|
||||