mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-07 16:37:48 +00:00
Merge branch 'dev' into entity-filter/add_value_entity_id_compatibility
This commit is contained in:
commit
cf51598f9f
@ -5,6 +5,7 @@
|
||||
"context": ".."
|
||||
},
|
||||
"appPort": "8124:8123",
|
||||
"postCreateCommand": "sudo apt update && sudo apt upgrade -y && sudo apt install -y libpcap-dev",
|
||||
"postStartCommand": "script/bootstrap",
|
||||
"containerEnv": {
|
||||
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
||||
|
4
.github/workflows/cast_deployment.yaml
vendored
4
.github/workflows/cast_deployment.yaml
vendored
@ -26,7 +26,7 @@ jobs:
|
||||
ref: dev
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@ -62,7 +62,7 @@ jobs:
|
||||
ref: master
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
14
.github/workflows/ci.yaml
vendored
14
.github/workflows/ci.yaml
vendored
@ -26,7 +26,7 @@ jobs:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@ -37,7 +37,7 @@ jobs:
|
||||
- name: Build resources
|
||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
|
||||
- name: Setup lint cache
|
||||
uses: actions/cache@v3.3.3
|
||||
uses: actions/cache@v4.0.1
|
||||
with:
|
||||
path: |
|
||||
node_modules/.cache/prettier
|
||||
@ -60,7 +60,7 @@ jobs:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@ -78,7 +78,7 @@ jobs:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@ -89,7 +89,7 @@ jobs:
|
||||
env:
|
||||
IS_TEST: "true"
|
||||
- name: Upload bundle stats
|
||||
uses: actions/upload-artifact@v4.1.0
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: frontend-bundle-stats
|
||||
path: build/stats/*.json
|
||||
@ -102,7 +102,7 @@ jobs:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@v4.1.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@ -113,7 +113,7 @@ jobs:
|
||||
env:
|
||||
IS_TEST: "true"
|
||||
- name: Upload bundle stats
|
||||
uses: actions/upload-artifact@v4.1.0
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: supervisor-bundle-stats
|
||||
path: build/stats/*.json
|
||||
|
4
.github/workflows/demo_deployment.yaml
vendored
4
.github/workflows/demo_deployment.yaml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
ref: dev
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@ -63,7 +63,7 @@ jobs:
|
||||
ref: master
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
2
.github/workflows/design_deployment.yaml
vendored
2
.github/workflows/design_deployment.yaml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
2
.github/workflows/design_preview.yaml
vendored
2
.github/workflows/design_preview.yaml
vendored
@ -24,7 +24,7 @@ jobs:
|
||||
uses: actions/checkout@v4.1.1
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
6
.github/workflows/nightly.yaml
vendored
6
.github/workflows/nightly.yaml
vendored
@ -28,7 +28,7 @@ jobs:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@ -57,14 +57,14 @@ jobs:
|
||||
run: tar -czvf translations.tar.gz translations
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.1.0
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: wheels
|
||||
path: dist/home_assistant_frontend*.whl
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload translations
|
||||
uses: actions/upload-artifact@v4.1.0
|
||||
uses: actions/upload-artifact@v4.3.1
|
||||
with:
|
||||
name: translations
|
||||
path: translations.tar.gz
|
||||
|
2
.github/workflows/release-drafter.yaml
vendored
2
.github/workflows/release-drafter.yaml
vendored
@ -18,6 +18,6 @@ jobs:
|
||||
pull-requests: read
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@v5
|
||||
- uses: release-drafter/release-drafter@v6.0.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
@ -34,7 +34,7 @@ jobs:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4.0.1
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@ -55,7 +55,7 @@ jobs:
|
||||
script/release
|
||||
|
||||
- name: Upload release assets
|
||||
uses: softprops/action-gh-release@v0.1.15
|
||||
uses: softprops/action-gh-release@v2.0.2
|
||||
with:
|
||||
files: |
|
||||
dist/*.whl
|
||||
|
18
.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch
Normal file
18
.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch
Normal file
@ -0,0 +1,18 @@
|
||||
diff --git a/dist/hls.light.mjs b/dist/hls.light.mjs
|
||||
index eed9d788fafdb159975e1a2eb08ac88ba9c9ac33..ace881935e6665946f1c8110ebd2f739cde4427e 100644
|
||||
--- a/dist/hls.light.mjs
|
||||
+++ b/dist/hls.light.mjs
|
||||
@@ -20523,9 +20523,9 @@ class Hls {
|
||||
}
|
||||
Hls.defaultConfig = void 0;
|
||||
|
||||
-var KeySystemFormats = empty.KeySystemFormats;
|
||||
-var KeySystems = empty.KeySystems;
|
||||
-var SubtitleStreamController = empty.SubtitleStreamController;
|
||||
-var TimelineController = empty.TimelineController;
|
||||
+var KeySystemFormats = empty;
|
||||
+var KeySystems = empty;
|
||||
+var SubtitleStreamController = empty;
|
||||
+var TimelineController = empty;
|
||||
export { AbrController, AttrList, Cues as AudioStreamController, Cues as AudioTrackController, BasePlaylistController, BaseSegment, BaseStreamController, BufferController, Cues as CMCDController, CapLevelController, ChunkMetadata, ContentSteeringController, DateRange, Cues as EMEController, ErrorActionFlags, ErrorController, ErrorDetails, ErrorTypes, Events, FPSController, Fragment, Hls, HlsSkip, HlsUrlParameters, KeySystemFormats, KeySystems, Level, LevelDetails, LevelKey, LoadStats, MetadataSchema, NetworkErrorAction, Part, PlaylistLevelType, SubtitleStreamController, Cues as SubtitleTrackController, TimelineController, Hls as default, getMediaSource, isMSESupported, isSupported };
|
||||
//# sourceMappingURL=hls.light.mjs.map
|
@ -1,39 +0,0 @@
|
||||
diff --git a/modular/sortable.complete.esm.js b/modular/sortable.complete.esm.js
|
||||
index 02e9f2d6bebeb430fe6e7c1cc3f9c3c9df051f14..bb8268b0844a1faa4108cc92c0be2a3dbaf23f83 100644
|
||||
--- a/modular/sortable.complete.esm.js
|
||||
+++ b/modular/sortable.complete.esm.js
|
||||
@@ -1657,7 +1657,7 @@ Sortable.prototype =
|
||||
target = parent; // store last element
|
||||
}
|
||||
/* jshint boss:true */
|
||||
- while (parent = parent.parentNode);
|
||||
+ while (parent = parent.parentNode || parent.getRootNode().host);
|
||||
}
|
||||
|
||||
_unhideGhostForTarget();
|
||||
diff --git a/modular/sortable.core.esm.js b/modular/sortable.core.esm.js
|
||||
index b04c8b4634f7c6b4ef1aadbb48afe6564306dea9..39a107163c8c336ebd669b5ea8a936af87e1c1e7 100644
|
||||
--- a/modular/sortable.core.esm.js
|
||||
+++ b/modular/sortable.core.esm.js
|
||||
@@ -1657,7 +1657,7 @@ Sortable.prototype =
|
||||
target = parent; // store last element
|
||||
}
|
||||
/* jshint boss:true */
|
||||
- while (parent = parent.parentNode);
|
||||
+ while (parent = parent.parentNode || parent.getRootNode().host);
|
||||
}
|
||||
|
||||
_unhideGhostForTarget();
|
||||
diff --git a/modular/sortable.esm.js b/modular/sortable.esm.js
|
||||
index 6ec7ed1bb557e21c2578200161e989c65d23150b..0a05475a22904472fac6c13f524c674da76584b0 100644
|
||||
--- a/modular/sortable.esm.js
|
||||
+++ b/modular/sortable.esm.js
|
||||
@@ -1657,7 +1657,7 @@ Sortable.prototype =
|
||||
target = parent; // store last element
|
||||
}
|
||||
/* jshint boss:true */
|
||||
- while (parent = parent.parentNode);
|
||||
+ while (parent = parent.parentNode || parent.getRootNode().host);
|
||||
}
|
||||
|
||||
_unhideGhostForTarget();
|
73
.yarn/patches/sortablejs-npm-1.15.2-73347ae85a.patch
Normal file
73
.yarn/patches/sortablejs-npm-1.15.2-73347ae85a.patch
Normal file
@ -0,0 +1,73 @@
|
||||
diff --git a/modular/sortable.core.esm.js b/modular/sortable.core.esm.js
|
||||
index 93ba17509e2e8583ab241fea6845fbe714c584a2..de0651ddb5dced30d36f7d764da0dd0b441f523f 100644
|
||||
--- a/modular/sortable.core.esm.js
|
||||
+++ b/modular/sortable.core.esm.js
|
||||
@@ -1461,7 +1461,7 @@ Sortable.prototype = /** @lends Sortable.prototype */{
|
||||
}
|
||||
target = parent; // store last element
|
||||
}
|
||||
- /* jshint boss:true */ while (parent = parent.parentNode);
|
||||
+ /* jshint boss:true */ while (parent = parent.parentNode || parent.getRootNode().host);
|
||||
}
|
||||
_unhideGhostForTarget();
|
||||
}
|
||||
@@ -1781,11 +1781,16 @@ Sortable.prototype = /** @lends Sortable.prototype */{
|
||||
}
|
||||
if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
|
||||
capture();
|
||||
- if (elLastChild && elLastChild.nextSibling) {
|
||||
- // the last draggable element is not the last node
|
||||
- el.insertBefore(dragEl, elLastChild.nextSibling);
|
||||
- } else {
|
||||
- el.appendChild(dragEl);
|
||||
+ try {
|
||||
+ if (elLastChild && elLastChild.nextSibling) {
|
||||
+ // the last draggable element is not the last node
|
||||
+ el.insertBefore(dragEl, elLastChild.nextSibling);
|
||||
+ } else {
|
||||
+ el.appendChild(dragEl);
|
||||
+ }
|
||||
+ }
|
||||
+ catch(err) {
|
||||
+ return completed(false);
|
||||
}
|
||||
parentEl = el; // actualization
|
||||
|
||||
@@ -1802,7 +1807,13 @@ Sortable.prototype = /** @lends Sortable.prototype */{
|
||||
targetRect = getRect(target);
|
||||
if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, false) !== false) {
|
||||
capture();
|
||||
- el.insertBefore(dragEl, firstChild);
|
||||
+ try {
|
||||
+ el.insertBefore(dragEl, firstChild);
|
||||
+ }
|
||||
+ catch(err) {
|
||||
+ return completed(false);
|
||||
+ }
|
||||
+
|
||||
parentEl = el; // actualization
|
||||
|
||||
changed();
|
||||
@@ -1849,12 +1860,17 @@ Sortable.prototype = /** @lends Sortable.prototype */{
|
||||
_silent = true;
|
||||
setTimeout(_unsilent, 30);
|
||||
capture();
|
||||
- if (after && !nextSibling) {
|
||||
- el.appendChild(dragEl);
|
||||
- } else {
|
||||
- target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
|
||||
- }
|
||||
|
||||
+ try {
|
||||
+ if (after && !nextSibling) {
|
||||
+ el.appendChild(dragEl);
|
||||
+ } else {
|
||||
+ target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
|
||||
+ }
|
||||
+ }
|
||||
+ catch(err) {
|
||||
+ return completed(false);
|
||||
+ }
|
||||
// Undo chrome's scroll adjustment (has no effect on other browsers)
|
||||
if (scrolledPastTop) {
|
||||
scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
|
File diff suppressed because one or more lines are too long
@ -6,4 +6,4 @@ enableGlobalCache: false
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.0.2.cjs
|
||||
yarnPath: .yarn/releases/yarn-4.1.1.cjs
|
||||
|
@ -115,7 +115,9 @@ gulp.task("webpack-prod-app", () =>
|
||||
|
||||
gulp.task("webpack-dev-server-demo", () =>
|
||||
runDevServer({
|
||||
compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })),
|
||||
compiler: webpack(
|
||||
createDemoConfig({ isProdBuild: false, latestBuild: true })
|
||||
),
|
||||
contentBase: paths.demo_output_root,
|
||||
port: 8090,
|
||||
})
|
||||
@ -131,7 +133,9 @@ gulp.task("webpack-prod-demo", () =>
|
||||
|
||||
gulp.task("webpack-dev-server-cast", () =>
|
||||
runDevServer({
|
||||
compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })),
|
||||
compiler: webpack(
|
||||
createCastConfig({ isProdBuild: false, latestBuild: true })
|
||||
),
|
||||
contentBase: paths.cast_output_root,
|
||||
port: 8080,
|
||||
// Accessible from the network, because that's how Cast hits it.
|
||||
@ -174,8 +178,9 @@ gulp.task("webpack-prod-hassio", () =>
|
||||
|
||||
gulp.task("webpack-dev-server-gallery", () =>
|
||||
runDevServer({
|
||||
// We don't use the es5 build, but the dev server will fuck up the publicPath if we don't
|
||||
compiler: webpack(bothBuilds(createGalleryConfig, { isProdBuild: false })),
|
||||
compiler: webpack(
|
||||
createGalleryConfig({ isProdBuild: false, latestBuild: true })
|
||||
),
|
||||
contentBase: paths.gallery_output_root,
|
||||
port: 8100,
|
||||
listenHost: "0.0.0.0",
|
||||
|
@ -31,11 +31,11 @@ import "./hc-layout";
|
||||
|
||||
@customElement("hc-cast")
|
||||
class HcCast extends LitElement {
|
||||
@property() public auth!: Auth;
|
||||
@property({ attribute: false }) public auth!: Auth;
|
||||
|
||||
@property() public connection!: Connection;
|
||||
@property({ attribute: false }) public connection!: Connection;
|
||||
|
||||
@property() public castManager!: CastManager;
|
||||
@property({ attribute: false }) public castManager!: CastManager;
|
||||
|
||||
@state() private askWrite = false;
|
||||
|
||||
@ -241,6 +241,8 @@ class HcCast extends LitElement {
|
||||
|
||||
mwc-button ha-svg-icon {
|
||||
margin-right: 8px;
|
||||
margin-inline-end: 8px;
|
||||
margin-inline-start: initial;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
|
@ -10,13 +10,13 @@ import "../../../../src/components/ha-card";
|
||||
|
||||
@customElement("hc-layout")
|
||||
class HcLayout extends LitElement {
|
||||
@property() public subtitle?: string | undefined;
|
||||
@property() public subtitle?: string;
|
||||
|
||||
@property() public auth?: Auth;
|
||||
@property({ attribute: false }) public auth?: Auth;
|
||||
|
||||
@property() public connection?: Connection;
|
||||
@property({ attribute: false }) public connection?: Connection;
|
||||
|
||||
@property() public user?: HassUser;
|
||||
@property({ attribute: false }) public user?: HassUser;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
|
@ -28,23 +28,23 @@ class HcLaunchScreen extends LitElement {
|
||||
:host {
|
||||
display: block;
|
||||
height: 100vh;
|
||||
padding-top: 64px;
|
||||
background-color: white;
|
||||
background-color: #f2f4f9;
|
||||
font-size: 24px;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
img {
|
||||
width: 717px;
|
||||
height: 376px;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 80%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.status {
|
||||
padding-right: 54px;
|
||||
color: #1d2126;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class HcLovelace extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public lovelaceConfig!: LovelaceConfig;
|
||||
|
||||
@property() public viewPath?: string | number;
|
||||
@property() public viewPath?: string | number | null;
|
||||
|
||||
@property() public urlPath: string | null = null;
|
||||
|
||||
@ -93,6 +93,9 @@ class HcLovelace extends LitElement {
|
||||
}
|
||||
|
||||
private get _viewIndex() {
|
||||
if (this.viewPath === null) {
|
||||
return 0;
|
||||
}
|
||||
const selectedView = this.viewPath;
|
||||
const selectedViewInt = parseInt(selectedView as string, 10);
|
||||
for (let i = 0; i < this.lovelaceConfig.views.length; i++) {
|
||||
|
@ -51,10 +51,10 @@ export class HcMain extends HassElement {
|
||||
|
||||
@state() private _lovelacePath: string | number | null = null;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
@state() private _urlPath?: string | null;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
private _hassUUID?: string;
|
||||
|
||||
private _unsubLovelace?: UnsubscribeFunc;
|
||||
@ -81,7 +81,7 @@ export class HcMain extends HassElement {
|
||||
|
||||
if (
|
||||
!this._lovelaceConfig ||
|
||||
this._lovelacePath === null ||
|
||||
this._urlPath === undefined ||
|
||||
// Guard against part of HA not being loaded yet.
|
||||
!this.hass ||
|
||||
!this.hass.states ||
|
||||
@ -99,8 +99,8 @@ export class HcMain extends HassElement {
|
||||
<hc-lovelace
|
||||
.hass=${this.hass}
|
||||
.lovelaceConfig=${this._lovelaceConfig}
|
||||
.viewPath=${this._lovelacePath}
|
||||
.urlPath=${this._urlPath}
|
||||
.viewPath=${this._lovelacePath}
|
||||
@config-refresh=${this._generateDefaultLovelaceConfig}
|
||||
></hc-lovelace>
|
||||
`;
|
||||
@ -205,7 +205,6 @@ export class HcMain extends HassElement {
|
||||
expires_in: 0,
|
||||
}),
|
||||
});
|
||||
this._hassUUID = msg.hassUUID;
|
||||
} catch (err: any) {
|
||||
const errorMessage = this._getErrorMessage(err);
|
||||
this._error = errorMessage;
|
||||
@ -225,6 +224,17 @@ export class HcMain extends HassElement {
|
||||
this.hass.connection.close();
|
||||
}
|
||||
this.initializeHass(auth, connection);
|
||||
if (this._hassUUID !== msg.hassUUID) {
|
||||
this._hassUUID = msg.hassUUID;
|
||||
this._lovelaceConfig = undefined;
|
||||
this._urlPath = undefined;
|
||||
this._lovelacePath = null;
|
||||
if (this._unsubLovelace) {
|
||||
this._unsubLovelace();
|
||||
this._unsubLovelace = undefined;
|
||||
}
|
||||
resourcesLoaded = false;
|
||||
}
|
||||
this._error = undefined;
|
||||
this._sendStatus();
|
||||
}
|
||||
@ -233,7 +243,7 @@ export class HcMain extends HassElement {
|
||||
this._showDemo = false;
|
||||
// We should not get this command before we are connected.
|
||||
// Means a client got out of sync. Let's send status to them.
|
||||
if (!this.hass) {
|
||||
if (!this.hass?.connected) {
|
||||
this._sendStatus(msg.senderId!);
|
||||
this._error = "Cannot show Lovelace because we're not connected.";
|
||||
this._sendError(
|
||||
@ -260,7 +270,7 @@ export class HcMain extends HassElement {
|
||||
}
|
||||
|
||||
this._error = undefined;
|
||||
if (msg.urlPath === "lovelace") {
|
||||
if (msg.urlPath === "lovelace" || msg.urlPath === undefined) {
|
||||
msg.urlPath = null;
|
||||
}
|
||||
this._lovelacePath = msg.viewPath;
|
||||
@ -275,7 +285,7 @@ export class HcMain extends HassElement {
|
||||
],
|
||||
};
|
||||
this._urlPath = "energy";
|
||||
this._lovelacePath = 0;
|
||||
this._lovelacePath = null;
|
||||
this._sendStatus();
|
||||
return;
|
||||
}
|
||||
@ -284,6 +294,7 @@ export class HcMain extends HassElement {
|
||||
this._lovelaceConfig = undefined;
|
||||
if (this._unsubLovelace) {
|
||||
this._unsubLovelace();
|
||||
this._unsubLovelace = undefined;
|
||||
}
|
||||
const llColl = atLeastVersion(this.hass.connection.haVersion, 0, 107)
|
||||
? getLovelaceCollection(this.hass.connection, msg.urlPath)
|
||||
|
@ -4,6 +4,7 @@ import { energyEntities } from "../stubs/entities";
|
||||
import { DemoConfig } from "./types";
|
||||
|
||||
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
||||
() => import("./sections").then((mod) => mod.demoSections),
|
||||
() => import("./arsaboo").then((mod) => mod.demoArsaboo),
|
||||
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
|
||||
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
||||
|
16
demo/src/configs/sections/description.ts
Normal file
16
demo/src/configs/sections/description.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { html } from "lit";
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoLovelaceDescription: DemoConfig["description"] = (
|
||||
localize
|
||||
) => html`
|
||||
<p>
|
||||
${localize("ui.panel.page-demo.config.sections.description", {
|
||||
blog_post: html`<a
|
||||
href="https://www.home-assistant.io/blog/2024/03/04/dashboard-chapter-1/"
|
||||
target="_blank"
|
||||
>${localize("ui.panel.page-demo.config.sections.description_blog_post")}
|
||||
</a>`,
|
||||
})}
|
||||
</p>
|
||||
`;
|
474
demo/src/configs/sections/entities.ts
Normal file
474
demo/src/configs/sections/entities.ts
Normal file
@ -0,0 +1,474 @@
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesSections: DemoConfig["entities"] = () =>
|
||||
convertEntities({
|
||||
"cover.living_room_garden_shutter": {
|
||||
entity_id: "cover.living_room_garden_shutter",
|
||||
state: "open",
|
||||
attributes: {
|
||||
current_position: 100,
|
||||
device_class: "shutter",
|
||||
friendly_name: "Living room garden shutter",
|
||||
supported_features: 15,
|
||||
},
|
||||
},
|
||||
"cover.living_room_graveyard_shutter": {
|
||||
entity_id: "cover.living_room_graveyard_shutter",
|
||||
state: "open",
|
||||
attributes: {
|
||||
current_position: 100,
|
||||
device_class: "shutter",
|
||||
friendly_name: "Living room graveyard shutter",
|
||||
supported_features: 15,
|
||||
},
|
||||
},
|
||||
"cover.living_room_left_shutter": {
|
||||
entity_id: "cover.living_room_left_shutter",
|
||||
state: "open",
|
||||
attributes: {
|
||||
current_position: 100,
|
||||
device_class: "shutter",
|
||||
friendly_name: "Living room left shutter",
|
||||
supported_features: 15,
|
||||
},
|
||||
},
|
||||
"cover.living_room_right_shutter": {
|
||||
entity_id: "cover.living_room_right_shutter",
|
||||
state: "open",
|
||||
attributes: {
|
||||
current_position: 100,
|
||||
device_class: "shutter",
|
||||
friendly_name: "Living room right shutter",
|
||||
supported_features: 15,
|
||||
},
|
||||
},
|
||||
"light.floor_lamp": {
|
||||
entity_id: "light.floor_lamp",
|
||||
state: "on",
|
||||
attributes: {
|
||||
min_color_temp_kelvin: 2000,
|
||||
max_color_temp_kelvin: 6535,
|
||||
min_mireds: 153,
|
||||
max_mireds: 500,
|
||||
supported_color_modes: ["color_temp", "xy"],
|
||||
color_mode: "color_temp",
|
||||
brightness: 178,
|
||||
color_temp_kelvin: 2583,
|
||||
color_temp: 387,
|
||||
hs_color: [28.664, 69.597],
|
||||
rgb_color: [255, 162, 77],
|
||||
xy_color: [0.538, 0.389],
|
||||
icon: "mdi:floor-lamp",
|
||||
friendly_name: "Floor lamp",
|
||||
supported_features: 44,
|
||||
},
|
||||
},
|
||||
"light.living_room_spotlights": {
|
||||
entity_id: "light.living_room_spotlights",
|
||||
state: "on",
|
||||
attributes: {
|
||||
supported_color_modes: ["brightness"],
|
||||
color_mode: "brightness",
|
||||
brightness: 126,
|
||||
icon: "mdi:ceiling-light-multiple",
|
||||
friendly_name: "Living room spotlights",
|
||||
supported_features: 32,
|
||||
},
|
||||
},
|
||||
"light.bar_lamp": {
|
||||
entity_id: "light.bar_lamp",
|
||||
state: "on",
|
||||
attributes: {
|
||||
min_color_temp_kelvin: 2202,
|
||||
max_color_temp_kelvin: 4504,
|
||||
min_mireds: 222,
|
||||
max_mireds: 454,
|
||||
effect_list: ["None", "candle"],
|
||||
supported_color_modes: ["color_temp"],
|
||||
effect: null,
|
||||
color_mode: null,
|
||||
brightness: null,
|
||||
color_temp_kelvin: null,
|
||||
color_temp: null,
|
||||
hs_color: null,
|
||||
rgb_color: null,
|
||||
xy_color: null,
|
||||
mode: "normal",
|
||||
dynamics: "none",
|
||||
icon: "mdi:lightbulb-variant",
|
||||
friendly_name: "Bar lamp",
|
||||
supported_features: 44,
|
||||
},
|
||||
},
|
||||
"sensor.living_room_temperature": {
|
||||
entity_id: "sensor.living_room_temperature",
|
||||
state: "22.8",
|
||||
attributes: {
|
||||
state_class: "measurement",
|
||||
unit_of_measurement: "°C",
|
||||
device_class: "temperature",
|
||||
friendly_name: "Living room Temperature",
|
||||
},
|
||||
},
|
||||
"media_player.living_room_nest_mini": {
|
||||
entity_id: "media_player.living_room_nest_mini",
|
||||
state: "off",
|
||||
attributes: {
|
||||
device_class: "speaker",
|
||||
friendly_name: "Living room Nest Mini",
|
||||
supported_features: 152461,
|
||||
},
|
||||
},
|
||||
"cover.kitchen_shutter": {
|
||||
entity_id: "cover.kitchen_shutter",
|
||||
state: "open",
|
||||
attributes: {
|
||||
current_position: 100,
|
||||
device_class: "shutter",
|
||||
friendly_name: "Kitchen shutter ",
|
||||
supported_features: 15,
|
||||
},
|
||||
},
|
||||
"light.kitchen_spotlights": {
|
||||
entity_id: "light.kitchen_spotlights",
|
||||
state: "off",
|
||||
attributes: {
|
||||
supported_color_modes: ["brightness"],
|
||||
color_mode: null,
|
||||
brightness: null,
|
||||
icon: "mdi:ceiling-light-multiple",
|
||||
friendly_name: "Kitchen spotlights ",
|
||||
supported_features: 32,
|
||||
},
|
||||
},
|
||||
"light.worktop_spotlights": {
|
||||
entity_id: "light.worktop_spotlights",
|
||||
state: "off",
|
||||
attributes: {
|
||||
supported_color_modes: ["brightness"],
|
||||
color_mode: null,
|
||||
brightness: null,
|
||||
icon: "mdi:ceiling-light-multiple",
|
||||
friendly_name: "Worktop spotlights ",
|
||||
supported_features: 32,
|
||||
},
|
||||
},
|
||||
"binary_sensor.fridge_door": {
|
||||
entity_id: "binary_sensor.fridge_door",
|
||||
state: "off",
|
||||
attributes: {
|
||||
device_class: "door",
|
||||
icon: "mdi:fridge",
|
||||
friendly_name: "Fridge door",
|
||||
},
|
||||
},
|
||||
"media_player.kitchen_nest_audio": {
|
||||
entity_id: "media_player.kitchen_nest_audio",
|
||||
state: "on",
|
||||
attributes: {
|
||||
device_class: "speaker",
|
||||
friendly_name: "Kitchen Nest Audio",
|
||||
supported_features: 152461,
|
||||
},
|
||||
},
|
||||
"binary_sensor.tesla_wall_connector_vehicle_connected": {
|
||||
entity_id: "binary_sensor.tesla_wall_connector_vehicle_connected",
|
||||
state: "off",
|
||||
attributes: {
|
||||
device_class: "plug",
|
||||
friendly_name: "Wall Connector Vehicle connected",
|
||||
},
|
||||
},
|
||||
"sensor.tesla_wall_connector_session_energy": {
|
||||
entity_id: "sensor.tesla_wall_connector_session_energy",
|
||||
state: "16.3",
|
||||
attributes: {
|
||||
state_class: "total_increasing",
|
||||
unit_of_measurement: "kWh",
|
||||
device_class: "energy",
|
||||
friendly_name: "Tesla Wall Connector Session energy",
|
||||
},
|
||||
},
|
||||
"sensor.electric_meter_power": {
|
||||
entity_id: "sensor.electric_meter_power",
|
||||
state: "797.86",
|
||||
attributes: {
|
||||
state_class: "measurement",
|
||||
unit_of_measurement: "W",
|
||||
device_class: "power",
|
||||
icon: "mdi:meter-electric",
|
||||
friendly_name: "Electric meter Power",
|
||||
},
|
||||
},
|
||||
"sensor.eletric_meter_voltage": {
|
||||
entity_id: "sensor.eletric_meter_voltage",
|
||||
state: "232.19",
|
||||
attributes: {
|
||||
state_class: "measurement",
|
||||
unit_of_measurement: "V",
|
||||
device_class: "voltage",
|
||||
friendly_name: "Electric meter voltage",
|
||||
},
|
||||
},
|
||||
"sensor.electricity_maps_grid_fossil_fuel_percentage": {
|
||||
entity_id: "sensor.electricity_maps_grid_fossil_fuel_percentage",
|
||||
state: "9.84",
|
||||
attributes: {
|
||||
state_class: "measurement",
|
||||
country_code: "FR",
|
||||
unit_of_measurement: "%",
|
||||
attribution: "Data provided by Electricity Maps",
|
||||
icon: "mdi:barrel",
|
||||
friendly_name: "Electricity Maps Grid fossil fuel percentage",
|
||||
},
|
||||
},
|
||||
"sensor.electricity_maps_co2_intensity": {
|
||||
entity_id: "sensor.electricity_maps_co2_intensity",
|
||||
state: "62.0",
|
||||
attributes: {
|
||||
state_class: "measurement",
|
||||
country_code: "FR",
|
||||
unit_of_measurement: "gCO2eq/kWh",
|
||||
attribution: "Data provided by Electricity Maps",
|
||||
friendly_name: "Electricity Maps CO2 intensity",
|
||||
icon: "mdi:molecule-co2",
|
||||
},
|
||||
},
|
||||
"sun.sun": {
|
||||
entity_id: "sun.sun",
|
||||
state: "above_horizon",
|
||||
attributes: {
|
||||
next_dawn: "2024-03-05T05:50:21.964405+00:00",
|
||||
next_dusk: "2024-03-04T18:08:54.311334+00:00",
|
||||
next_midnight: "2024-03-05T00:00:00+00:00",
|
||||
next_noon: "2024-03-05T12:00:05+00:00",
|
||||
next_rising: "2024-03-05T06:23:42.739159+00:00",
|
||||
next_setting: "2024-03-04T17:35:26.271171+00:00",
|
||||
elevation: 30.38,
|
||||
azimuth: 204.42,
|
||||
rising: false,
|
||||
friendly_name: "Sun",
|
||||
},
|
||||
},
|
||||
"sensor.rain": {
|
||||
entity_id: "sensor.moon_phase",
|
||||
state: "7.2",
|
||||
attributes: {
|
||||
state_class: "total_increasing",
|
||||
unit_of_measurement: "mm",
|
||||
device_class: "precipitation",
|
||||
friendly_name: "Rain",
|
||||
},
|
||||
},
|
||||
"climate.ground_floor": {
|
||||
entity_id: "climate.ground_floor",
|
||||
state: "heat",
|
||||
attributes: {
|
||||
hvac_modes: ["auto", "heat", "off"],
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
preset_modes: [
|
||||
"comfort",
|
||||
"away",
|
||||
"eco",
|
||||
"frost_protection",
|
||||
"external",
|
||||
"home",
|
||||
],
|
||||
current_temperature: 20.8,
|
||||
temperature: 21,
|
||||
preset_mode: "comfort",
|
||||
icon: "mdi:home-floor-0",
|
||||
friendly_name: "Ground floor Thermostat",
|
||||
supported_features: 401,
|
||||
},
|
||||
},
|
||||
"climate.first_floor": {
|
||||
entity_id: "climate.first_floor",
|
||||
state: "heat",
|
||||
attributes: {
|
||||
hvac_modes: ["auto", "heat", "off"],
|
||||
min_temp: 7,
|
||||
max_temp: 35,
|
||||
preset_modes: [
|
||||
"comfort",
|
||||
"away",
|
||||
"eco",
|
||||
"frost_protection",
|
||||
"external",
|
||||
"home",
|
||||
],
|
||||
current_temperature: 21.7,
|
||||
temperature: 21,
|
||||
preset_mode: "comfort",
|
||||
icon: "mdi:home-floor-1",
|
||||
friendly_name: "First floor Thermostat",
|
||||
supported_features: 401,
|
||||
},
|
||||
},
|
||||
"cover.study_shutter": {
|
||||
entity_id: "cover.study_shutter",
|
||||
state: "open",
|
||||
attributes: {
|
||||
current_position: 100,
|
||||
device_class: "shutter",
|
||||
friendly_name: "Study shutter",
|
||||
supported_features: 15,
|
||||
},
|
||||
},
|
||||
"light.study_spotlights": {
|
||||
entity_id: "light.study_spotlights",
|
||||
state: "off",
|
||||
attributes: {
|
||||
supported_color_modes: ["brightness"],
|
||||
color_mode: null,
|
||||
brightness: null,
|
||||
icon: "mdi:ceiling-light-multiple",
|
||||
friendly_name: "Study spotlights",
|
||||
supported_features: 32,
|
||||
},
|
||||
},
|
||||
"media_player.study_nest_hub": {
|
||||
entity_id: "media_player.study_nest_hub",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Study Nest Hub",
|
||||
supported_features: 152461,
|
||||
},
|
||||
},
|
||||
"sensor.standing_desk_height": {
|
||||
entity_id: "sensor.standing_desk_height",
|
||||
state: "72",
|
||||
attributes: {
|
||||
unit_of_measurement: "cm",
|
||||
icon: "mdi:tape-measure",
|
||||
friendly_name: "Standing desk Height",
|
||||
},
|
||||
},
|
||||
"light.outdoor_light": {
|
||||
entity_id: "light.outdoor_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
supported_color_modes: ["brightness"],
|
||||
color_mode: null,
|
||||
brightness: 255,
|
||||
icon: "mdi:outdoor-lamp",
|
||||
friendly_name: "Outdoor light",
|
||||
supported_features: 32,
|
||||
},
|
||||
},
|
||||
"light.flood_light": {
|
||||
entity_id: "light.flood_light",
|
||||
state: "off",
|
||||
attributes: {
|
||||
effect_list: ["None", "candle"],
|
||||
supported_color_modes: ["brightness"],
|
||||
effect: null,
|
||||
color_mode: null,
|
||||
brightness: null,
|
||||
mode: "normal",
|
||||
dynamics: "none",
|
||||
icon: "mdi:light-flood-down",
|
||||
friendly_name: "Flood light",
|
||||
supported_features: 44,
|
||||
},
|
||||
},
|
||||
"sensor.outdoor_motion_sensor_temperature": {
|
||||
entity_id: "sensor.outdoor_motion_sensor_temperature",
|
||||
state: "10.2",
|
||||
attributes: {
|
||||
state_class: "measurement",
|
||||
unit_of_measurement: "°C",
|
||||
device_class: "temperature",
|
||||
friendly_name: "Outdoor motion sensor Temperature",
|
||||
},
|
||||
},
|
||||
"binary_sensor.outdoor_motion_sensor_motion": {
|
||||
entity_id: "binary_sensor.outdoor_motion_sensor_motion",
|
||||
state: "off",
|
||||
attributes: {
|
||||
device_class: "motion",
|
||||
friendly_name: "Outdoor motion sensor Motion",
|
||||
},
|
||||
},
|
||||
"sensor.outdoor_motion_sensor_illuminance": {
|
||||
entity_id: "sensor.outdoor_motion_sensor_illuminance",
|
||||
state: "555",
|
||||
attributes: {
|
||||
state_class: "measurement",
|
||||
light_level: 27444,
|
||||
unit_of_measurement: "lx",
|
||||
device_class: "illuminance",
|
||||
friendly_name: "Outdoor motion sensor Illuminance",
|
||||
},
|
||||
},
|
||||
"automation.home_assistant_auto_update": {
|
||||
entity_id: "automation.home_assistant_auto_update",
|
||||
state: "off",
|
||||
attributes: {
|
||||
id: "1700669321947",
|
||||
last_triggered: "2024-02-29T18:02:05.343139+00:00",
|
||||
mode: "queued",
|
||||
current: 0,
|
||||
max: 50,
|
||||
icon: "mdi:auto-mode",
|
||||
friendly_name: "Home Assistant Auto-update",
|
||||
},
|
||||
},
|
||||
"update.home_assistant_operating_system_update": {
|
||||
entity_id: "update.home_assistant_operating_system_update",
|
||||
state: "off",
|
||||
attributes: {
|
||||
auto_update: false,
|
||||
installed_version: "12.1",
|
||||
in_progress: false,
|
||||
latest_version: "12.1",
|
||||
release_summary: null,
|
||||
release_url:
|
||||
"https://github.com/home-assistant/operating-system/commits/dev",
|
||||
skipped_version: null,
|
||||
title: "Home Assistant Operating System",
|
||||
entity_picture:
|
||||
"https://brands.home-assistant.io/homeassistant/icon.png",
|
||||
friendly_name: "Home Assistant Operating System Update",
|
||||
supported_features: 3,
|
||||
},
|
||||
},
|
||||
"update.home_assistant_supervisor_update": {
|
||||
entity_id: "update.home_assistant_supervisor_update",
|
||||
state: "off",
|
||||
attributes: {
|
||||
auto_update: true,
|
||||
installed_version: "2024.02.2",
|
||||
in_progress: false,
|
||||
latest_version: "2024.02.2",
|
||||
release_summary: null,
|
||||
release_url:
|
||||
"https://github.com/home-assistant/supervisor/commits/main",
|
||||
skipped_version: null,
|
||||
title: "Home Assistant Supervisor",
|
||||
entity_picture: "https://brands.home-assistant.io/hassio/icon.png",
|
||||
friendly_name: "Home Assistant Supervisor Update",
|
||||
supported_features: 1,
|
||||
},
|
||||
},
|
||||
"update.home_assistant_core_update": {
|
||||
entity_id: "update.home_assistant_supervisor_update",
|
||||
state: "off",
|
||||
attributes: {
|
||||
auto_update: false,
|
||||
installed_version: "2024.4.0",
|
||||
in_progress: false,
|
||||
latest_version: "2024.4.0",
|
||||
release_summary: null,
|
||||
release_url: "https://github.com/home-assistant/core/commits/dev",
|
||||
skipped_version: null,
|
||||
title: "Home Assistant Core",
|
||||
entity_picture:
|
||||
"https://brands.home-assistant.io/homeassistant/icon.png",
|
||||
friendly_name: "Home Assistant Core Update",
|
||||
supported_features: 11,
|
||||
},
|
||||
},
|
||||
});
|
14
demo/src/configs/sections/index.ts
Normal file
14
demo/src/configs/sections/index.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { DemoConfig } from "../types";
|
||||
import { demoLovelaceDescription } from "./description";
|
||||
import { demoEntitiesSections } from "./entities";
|
||||
import { demoLovelaceSections } from "./lovelace";
|
||||
|
||||
export const demoSections: DemoConfig = {
|
||||
authorName: "Home Assistant",
|
||||
authorUrl: "https://github.com/home-assistant/frontend/",
|
||||
name: "Home Demo",
|
||||
description: demoLovelaceDescription,
|
||||
lovelace: demoLovelaceSections,
|
||||
entities: demoEntitiesSections,
|
||||
theme: () => ({}),
|
||||
};
|
281
demo/src/configs/sections/lovelace.ts
Normal file
281
demo/src/configs/sections/lovelace.ts
Normal file
@ -0,0 +1,281 @@
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
|
||||
title: "Home Assistant Demo",
|
||||
views: [
|
||||
{
|
||||
type: "sections",
|
||||
title: "Demo",
|
||||
path: "home",
|
||||
icon: "mdi:home-assistant",
|
||||
sections: [
|
||||
{
|
||||
title: "Welcome 👋",
|
||||
cards: [{ type: "custom:ha-demo-card" }],
|
||||
},
|
||||
{
|
||||
cards: [
|
||||
{
|
||||
type: "tile",
|
||||
entity: "cover.living_room_garden_shutter",
|
||||
name: "Garden",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "cover.living_room_graveyard_shutter",
|
||||
name: "Rear",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "cover.living_room_left_shutter",
|
||||
name: "Left",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "cover.living_room_right_shutter",
|
||||
name: "Right",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "light.floor_lamp",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "light.living_room_spotlights",
|
||||
name: "Spotlights",
|
||||
features: [
|
||||
{
|
||||
type: "light-brightness",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "light.bar_lamp",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.living_room_temperature",
|
||||
detail: 1,
|
||||
name: "Temperature",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "media_player.living_room_nest_mini",
|
||||
name: "Nest Mini",
|
||||
},
|
||||
],
|
||||
title: "🛋️ Living room ",
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
cards: [
|
||||
{
|
||||
type: "tile",
|
||||
entity: "cover.kitchen_shutter",
|
||||
name: "Shutter",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "light.kitchen_spotlights",
|
||||
name: "Spotlights",
|
||||
features: [
|
||||
{
|
||||
type: "light-brightness",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "light.worktop_spotlights",
|
||||
name: "Worktop",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "binary_sensor.fridge_door",
|
||||
name: "Fridge",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "media_player.kitchen_nest_audio",
|
||||
name: "Nest Audio",
|
||||
},
|
||||
],
|
||||
title: "👩🍳 Kitchen",
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
cards: [
|
||||
{
|
||||
type: "tile",
|
||||
entity: "binary_sensor.tesla_wall_connector_vehicle_connected",
|
||||
name: "EV",
|
||||
icon: "mdi:car",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.tesla_wall_connector_session_energy",
|
||||
name: "Last charge",
|
||||
color: "green",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.electric_meter_power",
|
||||
color: "deep-orange",
|
||||
name: "Home power",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.eletric_meter_voltage",
|
||||
name: "Voltage",
|
||||
color: "deep-orange",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.electricity_maps_grid_fossil_fuel_percentage",
|
||||
name: "Fossil fuel",
|
||||
color: "brown",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.electricity_maps_co2_intensity",
|
||||
name: "CO2 Intensity",
|
||||
color: "dark-grey",
|
||||
},
|
||||
],
|
||||
title: "⚡️ Energy",
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
cards: [
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sun.sun",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.rain",
|
||||
color: "blue",
|
||||
},
|
||||
{
|
||||
features: [
|
||||
{
|
||||
type: "target-temperature",
|
||||
},
|
||||
],
|
||||
type: "tile",
|
||||
name: "Downstairs",
|
||||
entity: "climate.ground_floor",
|
||||
state_content: ["preset_mode", "current_temperature"],
|
||||
},
|
||||
{
|
||||
features: [
|
||||
{
|
||||
type: "target-temperature",
|
||||
},
|
||||
],
|
||||
type: "tile",
|
||||
name: "Upstairs",
|
||||
entity: "climate.first_floor",
|
||||
state_content: ["preset_mode", "current_temperature"],
|
||||
},
|
||||
],
|
||||
title: "🌤️ Climate",
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
cards: [
|
||||
{
|
||||
type: "tile",
|
||||
entity: "cover.study_shutter",
|
||||
name: "Shutter",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "light.study_spotlights",
|
||||
name: "Spotlights",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "media_player.study_nest_hub",
|
||||
name: "Nest Hub",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.standing_desk_height",
|
||||
name: "Desk",
|
||||
color: "brown",
|
||||
icon: "mdi:desk",
|
||||
},
|
||||
],
|
||||
title: "🧑💻 Study",
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
cards: [
|
||||
{
|
||||
type: "tile",
|
||||
entity: "light.outdoor_light",
|
||||
name: "Door light",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "light.flood_light",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.outdoor_motion_sensor_temperature",
|
||||
detail: 1,
|
||||
name: "Temperature",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "binary_sensor.outdoor_motion_sensor_motion",
|
||||
name: "Motion",
|
||||
color: "blue",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.outdoor_motion_sensor_illuminance",
|
||||
color: "amber",
|
||||
name: "Illuminance",
|
||||
},
|
||||
],
|
||||
title: "🌳 Outdoor",
|
||||
},
|
||||
{
|
||||
type: "grid",
|
||||
cards: [
|
||||
{
|
||||
type: "tile",
|
||||
entity: "automation.home_assistant_auto_update",
|
||||
name: "Auto-update",
|
||||
color: "green",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "update.home_assistant_operating_system_update",
|
||||
name: "OS",
|
||||
icon: "mdi:home-assistant",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "update.home_assistant_supervisor_update",
|
||||
icon: "mdi:home-assistant",
|
||||
name: "Supervisor",
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "update.home_assistant_core_update",
|
||||
name: "Core",
|
||||
icon: "mdi:home-assistant",
|
||||
},
|
||||
],
|
||||
title: "🎉 Updates",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
@ -1,3 +1,4 @@
|
||||
import { TemplateResult } from "lit";
|
||||
import { LocalizeFunc } from "../../../src/common/translations/localize";
|
||||
import { LovelaceConfig } from "../../../src/data/lovelace/config/types";
|
||||
import { Entity } from "../../../src/fake_data/entity";
|
||||
@ -7,6 +8,9 @@ export interface DemoConfig {
|
||||
name: string;
|
||||
authorName: string;
|
||||
authorUrl: string;
|
||||
description?:
|
||||
| string
|
||||
| ((localize: LocalizeFunc) => string | TemplateResult<1>);
|
||||
lovelace: (localize: LocalizeFunc) => LovelaceConfig;
|
||||
entities: (localize: LocalizeFunc) => Entity[];
|
||||
theme: () => Record<string, string> | null;
|
||||
|
@ -39,32 +39,51 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
<div class="picker">
|
||||
<div class="label">
|
||||
${this._switching
|
||||
? html`<ha-circular-progress
|
||||
indeterminate
|
||||
></ha-circular-progress>`
|
||||
? html`
|
||||
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||
`
|
||||
: until(
|
||||
selectedDemoConfig.then(
|
||||
(conf) => html`
|
||||
${conf.name}
|
||||
<small>
|
||||
<a target="_blank" href=${conf.authorUrl}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.page-demo.cards.demo.demo_by",
|
||||
{ name: conf.authorName }
|
||||
)}
|
||||
</a>
|
||||
${this.hass.localize(
|
||||
"ui.panel.page-demo.cards.demo.demo_by",
|
||||
{
|
||||
name: html`
|
||||
<a target="_blank" href=${conf.authorUrl}>
|
||||
${conf.authorName}
|
||||
</a>
|
||||
`,
|
||||
}
|
||||
)}
|
||||
</small>
|
||||
`
|
||||
),
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
|
||||
<mwc-button @click=${this._nextConfig} .disabled=${this._switching}>
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.next_demo")}
|
||||
</mwc-button>
|
||||
</div>
|
||||
<div class="content small-hidden">
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.introduction")}
|
||||
<div class="content">
|
||||
<p class="small-hidden">
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.introduction")}
|
||||
</p>
|
||||
${until(
|
||||
selectedDemoConfig.then((conf) => {
|
||||
if (typeof conf.description === "function") {
|
||||
return conf.description(this.hass.localize);
|
||||
}
|
||||
if (conf.description) {
|
||||
return html`<p>${conf.description}</p>`;
|
||||
}
|
||||
return nothing;
|
||||
}),
|
||||
nothing
|
||||
)}
|
||||
</div>
|
||||
<div class="actions small-hidden">
|
||||
<a href="https://www.home-assistant.io" target="_blank">
|
||||
@ -108,6 +127,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
css`
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.actions a {
|
||||
@ -115,7 +135,11 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.content p {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.picker {
|
||||
@ -138,9 +162,8 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding-left: 8px;
|
||||
padding: 0px 8px 4px 8px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
.small-hidden {
|
||||
display: none;
|
||||
|
@ -17,12 +17,14 @@ import { energyEntities } from "./stubs/entities";
|
||||
import { mockEntityRegistry } from "./stubs/entity_registry";
|
||||
import { mockEvents } from "./stubs/events";
|
||||
import { mockFrontend } from "./stubs/frontend";
|
||||
import { mockIcons } from "./stubs/icons";
|
||||
import { mockHistory } from "./stubs/history";
|
||||
import { mockLovelace } from "./stubs/lovelace";
|
||||
import { mockMediaPlayer } from "./stubs/media_player";
|
||||
import { mockPersistentNotification } from "./stubs/persistent_notification";
|
||||
import { mockRecorder } from "./stubs/recorder";
|
||||
import { mockTodo } from "./stubs/todo";
|
||||
import { mockSensor } from "./stubs/sensor";
|
||||
import { mockSystemLog } from "./stubs/system_log";
|
||||
import { mockTemplate } from "./stubs/template";
|
||||
import { mockTranslations } from "./stubs/translations";
|
||||
@ -50,11 +52,13 @@ export class HaDemo extends HomeAssistantAppEl {
|
||||
mockHistory(hass);
|
||||
mockRecorder(hass);
|
||||
mockTodo(hass);
|
||||
mockSensor(hass);
|
||||
mockSystemLog(hass);
|
||||
mockTemplate(hass);
|
||||
mockEvents(hass);
|
||||
mockMediaPlayer(hass);
|
||||
mockFrontend(hass);
|
||||
mockIcons(hass);
|
||||
mockEnergy(hass);
|
||||
mockPersistentNotification(hass);
|
||||
mockConfigEntries(hass);
|
||||
|
@ -10,6 +10,7 @@ export const mockConfigEntries = (hass: MockHomeAssistant) => {
|
||||
supports_options: false,
|
||||
supports_remove_device: false,
|
||||
supports_unload: true,
|
||||
supports_reconfigure: true,
|
||||
pref_disable_new_entities: false,
|
||||
pref_disable_polling: false,
|
||||
disabled_by: null,
|
||||
|
33
demo/src/stubs/icons.ts
Normal file
33
demo/src/stubs/icons.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { IconCategory } from "../../../src/data/icons";
|
||||
import { ENTITY_COMPONENT_ICONS } from "../../../src/fake_data/entity_component_icons";
|
||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
|
||||
export const mockIcons = (hass: MockHomeAssistant) => {
|
||||
hass.mockWS(
|
||||
"frontend/get_icons",
|
||||
async ({
|
||||
category,
|
||||
integration,
|
||||
}: {
|
||||
category: IconCategory;
|
||||
integration?: string;
|
||||
}) => {
|
||||
if (integration) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://raw.githubusercontent.com/home-assistant/core/dev/homeassistant/components/${integration}/icons.json`
|
||||
).then((resp) => resp.json());
|
||||
return { resources: { [integration]: response[category] || {} } };
|
||||
} catch {
|
||||
return { resources: {} };
|
||||
}
|
||||
}
|
||||
if (category === "entity_component") {
|
||||
return {
|
||||
resources: ENTITY_COMPONENT_ICONS,
|
||||
};
|
||||
}
|
||||
return { resources: {} };
|
||||
}
|
||||
);
|
||||
};
|
58
demo/src/stubs/sensor.ts
Normal file
58
demo/src/stubs/sensor.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
|
||||
export const mockSensor = (hass: MockHomeAssistant) => {
|
||||
hass.mockWS("sensor/numeric_device_classes", () => [
|
||||
{
|
||||
numeric_device_classes: [
|
||||
"volume_storage",
|
||||
"gas",
|
||||
"data_size",
|
||||
"irradiance",
|
||||
"wind_speed",
|
||||
"volatile_organic_compounds",
|
||||
"volatile_organic_compounds_parts",
|
||||
"voltage",
|
||||
"frequency",
|
||||
"precipitation_intensity",
|
||||
"volume",
|
||||
"precipitation",
|
||||
"battery",
|
||||
"nitrogen_dioxide",
|
||||
"speed",
|
||||
"signal_strength",
|
||||
"pm1",
|
||||
"nitrous_oxide",
|
||||
"atmospheric_pressure",
|
||||
"data_rate",
|
||||
"temperature",
|
||||
"power_factor",
|
||||
"aqi",
|
||||
"current",
|
||||
"volume_flow_rate",
|
||||
"humidity",
|
||||
"duration",
|
||||
"ozone",
|
||||
"distance",
|
||||
"pressure",
|
||||
"pm25",
|
||||
"weight",
|
||||
"energy",
|
||||
"carbon_monoxide",
|
||||
"apparent_power",
|
||||
"illuminance",
|
||||
"energy_storage",
|
||||
"moisture",
|
||||
"power",
|
||||
"water",
|
||||
"carbon_dioxide",
|
||||
"ph",
|
||||
"reactive_power",
|
||||
"monetary",
|
||||
"nitrogen_monoxide",
|
||||
"pm10",
|
||||
"sound_pressure",
|
||||
"sulphur_dioxide",
|
||||
],
|
||||
},
|
||||
]);
|
||||
};
|
@ -21,4 +21,5 @@ export const mockTodo = (hass: MockHomeAssistant) => {
|
||||
},
|
||||
] as TodoItem[],
|
||||
}));
|
||||
hass.mockWS("todo/item/subscribe", (_msg, _hass) => () => {});
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Button } from "@material/mwc-button";
|
||||
import { html, LitElement, css, TemplateResult } from "lit";
|
||||
import { html, LitElement, css, TemplateResult, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||
@ -9,7 +9,7 @@ import "../../../src/components/ha-card";
|
||||
class DemoBlackWhiteRow extends LitElement {
|
||||
@property() title!: string;
|
||||
|
||||
@property() value!: any;
|
||||
@property() value?: any;
|
||||
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
||||
@ -45,7 +45,9 @@ class DemoBlackWhiteRow extends LitElement {
|
||||
</mwc-button>
|
||||
</div>
|
||||
</ha-card>
|
||||
<pre>${JSON.stringify(this.value, undefined, 2)}</pre>
|
||||
${this.value
|
||||
? html`<pre>${JSON.stringify(this.value, undefined, 2)}</pre>`
|
||||
: nothing}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -10,7 +10,7 @@ import "../ha-demo-options";
|
||||
|
||||
@customElement("demo-cards")
|
||||
class DemoCards extends LitElement {
|
||||
@property() public configs!: DemoCardConfig[];
|
||||
@property({ attribute: false }) public configs!: DemoCardConfig[];
|
||||
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
|
@ -11,7 +11,7 @@ import "./demo-more-info";
|
||||
class DemoMoreInfos extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public entities!: [];
|
||||
@property({ type: Array }) public entities!: string[];
|
||||
|
||||
@state() private _showConfig = false;
|
||||
|
||||
|
@ -17,6 +17,7 @@ export const basicTrace: DemoTrace = {
|
||||
{
|
||||
path: "trigger/0",
|
||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
||||
changed_variables: {},
|
||||
},
|
||||
],
|
||||
"condition/0": [
|
||||
|
@ -17,6 +17,7 @@ export const motionLightTrace: DemoTrace = {
|
||||
{
|
||||
path: "trigger/0",
|
||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
||||
changed_variables: {},
|
||||
},
|
||||
],
|
||||
"action/0": [
|
||||
|
@ -3,7 +3,6 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../../src/components/ha-card";
|
||||
import "../../../../src/components/trace/hat-script-graph";
|
||||
import "../../../../src/components/trace/hat-trace-timeline";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
@ -56,6 +55,7 @@ export class DemoAutomationTraceTimeline extends LitElement {
|
||||
super.firstUpdated(changedProps);
|
||||
const hass = provideHass(this);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("config", "en");
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
|
@ -60,6 +60,7 @@ export class DemoAutomationTrace extends LitElement {
|
||||
super.firstUpdated(changedProps);
|
||||
const hass = provideHass(this);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("config", "en");
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
|
@ -10,6 +10,7 @@ import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervis
|
||||
import { computeInitialHaFormData } from "../../../../src/components/ha-form/compute-initial-ha-form-data";
|
||||
import "../../../../src/components/ha-form/ha-form";
|
||||
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
|
||||
import type { AreaRegistryEntry } from "../../../../src/data/area_registry";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
@ -97,22 +98,25 @@ const DEVICES = [
|
||||
},
|
||||
];
|
||||
|
||||
const AREAS = [
|
||||
const AREAS: AreaRegistryEntry[] = [
|
||||
{
|
||||
area_id: "backyard",
|
||||
name: "Backyard",
|
||||
icon: null,
|
||||
picture: null,
|
||||
aliases: [],
|
||||
},
|
||||
{
|
||||
area_id: "bedroom",
|
||||
name: "Bedroom",
|
||||
icon: "mdi:bed",
|
||||
picture: null,
|
||||
aliases: [],
|
||||
},
|
||||
{
|
||||
area_id: "livingroom",
|
||||
name: "Livingroom",
|
||||
icon: "mdi:sofa",
|
||||
picture: null,
|
||||
aliases: [],
|
||||
},
|
||||
|
@ -9,6 +9,7 @@ import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
|
||||
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
|
||||
import "../../../../src/components/ha-selector/ha-selector";
|
||||
import "../../../../src/components/ha-settings-row";
|
||||
import type { AreaRegistryEntry } from "../../../../src/data/area_registry";
|
||||
import { BlueprintInput } from "../../../../src/data/blueprint";
|
||||
import { showDialog } from "../../../../src/dialogs/make-dialog-manager";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
@ -93,22 +94,25 @@ const DEVICES = [
|
||||
},
|
||||
];
|
||||
|
||||
const AREAS = [
|
||||
const AREAS: AreaRegistryEntry[] = [
|
||||
{
|
||||
area_id: "backyard",
|
||||
name: "Backyard",
|
||||
icon: null,
|
||||
picture: null,
|
||||
aliases: [],
|
||||
},
|
||||
{
|
||||
area_id: "bedroom",
|
||||
name: "Bedroom",
|
||||
icon: "mdi:bed",
|
||||
picture: null,
|
||||
aliases: [],
|
||||
},
|
||||
{
|
||||
area_id: "livingroom",
|
||||
name: "Livingroom",
|
||||
icon: "mdi:sofa",
|
||||
picture: null,
|
||||
aliases: [],
|
||||
},
|
||||
@ -271,6 +275,14 @@ const SCHEMAS: {
|
||||
selector: { color_temp: {} },
|
||||
},
|
||||
color_rgb: { name: "Color", selector: { color_rgb: {} } },
|
||||
qr_code: {
|
||||
name: "QR Code",
|
||||
selector: { qr_code: { data: "https://home-assistant.io" } },
|
||||
},
|
||||
constant: {
|
||||
name: "Constant",
|
||||
selector: { constant: { value: true, label: "Yes!" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -497,7 +509,7 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
||||
this.requestUpdate();
|
||||
};
|
||||
return html`
|
||||
<demo-black-white-row .title=${info.name} .value=${this.data[idx]}>
|
||||
<demo-black-white-row .title=${info.name}>
|
||||
${["light", "dark"].map((slot) =>
|
||||
Object.entries(info.input).map(
|
||||
([key, value]) => html`
|
||||
@ -530,8 +542,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
ha-selector {
|
||||
width: 60;
|
||||
ha-settings-row {
|
||||
--paper-item-body-two-line-min-height: 0;
|
||||
}
|
||||
.options {
|
||||
max-width: 800px;
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
||||
@ -84,6 +85,7 @@ class DemoAlarmPanelEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
@ -146,6 +147,7 @@ class DemoArea extends LitElement {
|
||||
entity_id: "binary_sensor.kitchen_door",
|
||||
},
|
||||
]);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "controller_1", "on", {
|
||||
@ -82,6 +83,7 @@ class DemoConditional extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
@ -323,6 +324,7 @@ class DemoEntities extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
@ -82,6 +83,7 @@ class DemoButtonEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("device_tracker", "demo_paulus", "work", {
|
||||
@ -276,6 +277,7 @@ class DemoEntityFilter extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("sensor", "brightness", "12", {}),
|
||||
@ -128,6 +129,7 @@ class DemoGaugeEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("device_tracker", "demo_paulus", "home", {
|
||||
@ -238,6 +239,7 @@ class DemoGlanceEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "kitchen_lights", "on", {
|
||||
@ -214,6 +215,7 @@ class DemoStack extends LitElement {
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockHistory(hass);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
@ -76,6 +77,7 @@ class DemoLightEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,9 @@ const CONFIGS = [
|
||||
> [!CAUTION]
|
||||
> This is a GitHub caution alert
|
||||
|
||||
> [!TIP]
|
||||
> - This is a list entry in GitHub tip alert
|
||||
|
||||
## Lists
|
||||
|
||||
Unordered
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "bed_light", "on", {
|
||||
@ -138,6 +139,7 @@ class DemoPictureElements extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("light", "kitchen_lights", "on", {
|
||||
@ -93,6 +94,7 @@ class DemoPictureEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("switch", "decorative_lights", "on", {
|
||||
@ -134,6 +135,7 @@ class DemoPictureGlance extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { createPlantEntities } from "../../data/plants";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const CONFIGS = [
|
||||
{
|
||||
@ -43,6 +44,7 @@ export class DemoPlantEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(createPlantEntities());
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("climate", "ecobee", "auto", {
|
||||
@ -45,7 +46,9 @@ const ENTITIES = [
|
||||
friendly_name: "Sensibo purifier",
|
||||
fan_modes: ["low", "high"],
|
||||
fan_mode: "low",
|
||||
supported_features: 9,
|
||||
swing_modes: ["on", "off", "both", "vertical", "horizontal"],
|
||||
swing_mode: "vertical",
|
||||
supported_features: 41,
|
||||
}),
|
||||
getEntity("climate", "unavailable", "unavailable", {
|
||||
supported_features: 43,
|
||||
@ -84,6 +87,14 @@ const CONFIGS = [
|
||||
fan_modes:
|
||||
- low
|
||||
- high
|
||||
- type: climate-swing-modes
|
||||
style: icons
|
||||
swing_modes:
|
||||
- 'on'
|
||||
- 'off'
|
||||
- 'both'
|
||||
- 'vertical'
|
||||
- 'horizontal'
|
||||
`,
|
||||
},
|
||||
{
|
||||
@ -116,6 +127,7 @@ class DemoThermostatEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { VacuumEntityFeature } from "../../../../src/data/vacuum";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("switch", "tv_outlet", "on", {
|
||||
@ -79,6 +80,18 @@ const CONFIGS = [
|
||||
color: pink
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Whole tile tap action",
|
||||
config: `
|
||||
- type: tile
|
||||
entity: switch.tv_outlet
|
||||
color: pink
|
||||
tap_action:
|
||||
action: toggle
|
||||
icon_tap_action:
|
||||
action: none
|
||||
`,
|
||||
},
|
||||
{
|
||||
heading: "Unknown entity",
|
||||
config: `
|
||||
@ -172,6 +185,7 @@ class DemoTile extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import "../../components/demo-cards";
|
||||
import { getEntity } from "../../../../src/fake_data/entity";
|
||||
import { mockTodo } from "../../../../demo/src/stubs/todo";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
|
||||
const ENTITIES = [
|
||||
getEntity("todo", "shopping_list", "2", {
|
||||
@ -47,6 +48,7 @@ class DemoTodoListEntity extends LitElement {
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("lovelace", "en");
|
||||
hass.addEntities(ENTITIES);
|
||||
mockIcons(hass);
|
||||
|
||||
mockTodo(hass);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import "../../../../src/components/data-table/ha-data-table";
|
||||
import type { DataTableColumnContainer } from "../../../../src/components/data-table/ha-data-table";
|
||||
import "../../../../src/components/entity/state-badge";
|
||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
|
||||
const SENSOR_DEVICE_CLASSES = [
|
||||
@ -53,6 +54,7 @@ const SENSOR_DEVICE_CLASSES = [
|
||||
"volatile_organic_compounds_parts",
|
||||
"voltage",
|
||||
"volume",
|
||||
"volume_flow_rate",
|
||||
"water",
|
||||
"weight",
|
||||
"wind_speed",
|
||||
@ -290,6 +292,7 @@ const ENTITIES: HassEntity[] = [
|
||||
createEntity("water_heater.high_demand", "high_demand"),
|
||||
createEntity("water_heater.heat_pump", "heat_pump"),
|
||||
createEntity("water_heater.gas", "gas"),
|
||||
createEntity("select.speed", "ridiculous_speed"),
|
||||
];
|
||||
|
||||
function createEntity(
|
||||
@ -396,6 +399,16 @@ export class DemoEntityState extends LitElement {
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
const hass = provideHass(this);
|
||||
mockIcons(hass);
|
||||
hass.updateHass({
|
||||
entities: {
|
||||
"select.speed": {
|
||||
entity_id: "select.speed",
|
||||
translation_key: "speed",
|
||||
platform: "demo",
|
||||
},
|
||||
},
|
||||
});
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("config", "en");
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ const createConfigEntry = (
|
||||
supports_options: false,
|
||||
supports_remove_device: false,
|
||||
supports_unload: true,
|
||||
supports_reconfigure: true,
|
||||
disabled_by: null,
|
||||
pref_disable_new_entities: false,
|
||||
pref_disable_polling: false,
|
||||
|
@ -243,6 +243,8 @@ export class HassioAddonStore extends LitElement {
|
||||
}
|
||||
.advanced a {
|
||||
margin-left: 0.5em;
|
||||
margin-inline-start: 0.5em;
|
||||
margin-inline-end: initial;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`;
|
||||
|
@ -1188,11 +1188,13 @@ class HassioAddonInfo extends LitElement {
|
||||
}
|
||||
.addon-header {
|
||||
padding-left: 8px;
|
||||
padding-inline-start: 8px;
|
||||
padding-inline-end: initial;
|
||||
font-size: 24px;
|
||||
color: var(--ha-card-header-color, --primary-text-color);
|
||||
}
|
||||
.addon-version {
|
||||
float: right;
|
||||
float: var(--float-end);
|
||||
font-size: 15px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@ -1261,6 +1263,7 @@ class HassioAddonInfo extends LitElement {
|
||||
.card-actions {
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.changelog {
|
||||
display: contents;
|
||||
|
@ -395,6 +395,8 @@ export class HassioBackups extends LitElement {
|
||||
.selected-txt {
|
||||
font-weight: bold;
|
||||
padding-left: 16px;
|
||||
padding-inline-start: 16px;
|
||||
padding-inline-end: initial;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.table-header .selected-txt {
|
||||
@ -405,6 +407,8 @@ export class HassioBackups extends LitElement {
|
||||
}
|
||||
.header-toolbar .header-btns {
|
||||
margin-right: -12px;
|
||||
margin-inline-end: -12px;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
.header-btns > mwc-button,
|
||||
.header-btns > ha-icon-button {
|
||||
|
@ -60,6 +60,10 @@ class HassioCardContent extends LitElement {
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
:host {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
ha-svg-icon {
|
||||
margin-right: 24px;
|
||||
margin-left: 8px;
|
||||
|
@ -72,7 +72,7 @@ const _computeAddons = (addons): AddonCheckboxItem[] =>
|
||||
export class SupervisorBackupContent extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public localize?: LocalizeFunc;
|
||||
@property({ attribute: false }) public localize?: LocalizeFunc;
|
||||
|
||||
@property({ attribute: false }) public supervisor?: Supervisor;
|
||||
|
||||
@ -316,6 +316,8 @@ export class SupervisorBackupContent extends LitElement {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 30px;
|
||||
margin-inline-start: 30px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
ha-formfield.password {
|
||||
display: block;
|
||||
@ -324,6 +326,8 @@ export class SupervisorBackupContent extends LitElement {
|
||||
.backup-types {
|
||||
display: flex;
|
||||
margin-left: -13px;
|
||||
margin-inline-start: -13px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
.sub-header {
|
||||
margin-top: 8px;
|
||||
|
@ -37,6 +37,8 @@ class SupervisorFormfieldLabel extends LitElement {
|
||||
}
|
||||
.label {
|
||||
margin-right: 4px;
|
||||
margin-inline-end: 4px;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
.version {
|
||||
color: var(--secondary-text-color);
|
||||
@ -45,6 +47,8 @@ class SupervisorFormfieldLabel extends LitElement {
|
||||
max-height: 22px;
|
||||
max-width: 22px;
|
||||
margin-right: 8px;
|
||||
margin-inline-end: 8px;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -64,6 +64,8 @@ class SupervisorMetric extends LitElement {
|
||||
.value {
|
||||
width: 48px;
|
||||
padding-right: 4px;
|
||||
padding-inline-start: initial;
|
||||
padding-inline-end: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`;
|
||||
|
@ -138,6 +138,9 @@ class HassioCreateBackupDialog extends LitElement {
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
:host {
|
||||
direction: var(--direction);
|
||||
}
|
||||
ha-circular-progress {
|
||||
display: block;
|
||||
text-align: center;
|
||||
|
@ -154,12 +154,16 @@ class HassioHardwareDialog extends LitElement {
|
||||
ha-icon-button {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
inset-inline-end: 16px;
|
||||
inset-inline-start: initial;
|
||||
top: 10px;
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
h2 {
|
||||
margin: 18px 42px 0 18px;
|
||||
margin-inline-start: 18px;
|
||||
margin-inline-end: 42px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
|
@ -597,6 +597,8 @@ export class DialogHassioNetwork
|
||||
|
||||
mwc-button.scan {
|
||||
margin-left: 8px;
|
||||
margin-inline-start: 8px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
|
||||
.container {
|
||||
|
@ -229,6 +229,8 @@ class HassioRegistriesDialog extends LitElement {
|
||||
ha-icon-button {
|
||||
color: var(--error-color);
|
||||
margin-right: -10px;
|
||||
margin-inline-end: -10px;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
@ -1,7 +1,5 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { mdiDelete, mdiDeleteOff } from "@mdi/js";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
@ -27,6 +25,8 @@ import type { HomeAssistant } from "../../../../src/types";
|
||||
import { HassioRepositoryDialogParams } from "./show-dialog-repositories";
|
||||
import type { HaTextField } from "../../../../src/components/ha-textfield";
|
||||
import "../../../../src/components/ha-textfield";
|
||||
import "../../../../src/components/ha-list-new";
|
||||
import "../../../../src/components/ha-list-item-new";
|
||||
|
||||
@customElement("dialog-hassio-repositories")
|
||||
class HassioRepositoriesDialog extends LitElement {
|
||||
@ -106,44 +106,46 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
<div class="form">
|
||||
${repositories.length
|
||||
? repositories.map(
|
||||
(repo) => html`
|
||||
<paper-item class="option">
|
||||
<paper-item-body three-line>
|
||||
<div>${repo.name}</div>
|
||||
<div secondary>${repo.maintainer}</div>
|
||||
<div secondary>${repo.url}</div>
|
||||
</paper-item-body>
|
||||
<div class="delete">
|
||||
<ha-icon-button
|
||||
.label=${this._dialogParams!.supervisor.localize(
|
||||
"dialog.repositories.remove"
|
||||
)}
|
||||
.disabled=${usedRepositories.includes(repo.slug)}
|
||||
.slug=${repo.slug}
|
||||
.path=${usedRepositories.includes(repo.slug)
|
||||
? mdiDeleteOff
|
||||
: mdiDelete}
|
||||
@click=${this._removeRepository}
|
||||
>
|
||||
</ha-icon-button>
|
||||
<simple-tooltip
|
||||
animation-delay="0"
|
||||
position="bottom"
|
||||
offset="1"
|
||||
>
|
||||
${this._dialogParams!.supervisor.localize(
|
||||
usedRepositories.includes(repo.slug)
|
||||
? "dialog.repositories.used"
|
||||
: "dialog.repositories.remove"
|
||||
)}
|
||||
</simple-tooltip>
|
||||
</div>
|
||||
</paper-item>
|
||||
`
|
||||
)
|
||||
: html`<paper-item> No repositories </paper-item>`}
|
||||
<ha-list-new>
|
||||
${repositories.length
|
||||
? repositories.map(
|
||||
(repo) => html`
|
||||
<ha-list-item-new class="option">
|
||||
${repo.name}
|
||||
<div slot="supporting-text">
|
||||
<div>${repo.maintainer}</div>
|
||||
<div>${repo.url}</div>
|
||||
</div>
|
||||
<div class="delete" slot="end">
|
||||
<ha-icon-button
|
||||
.label=${this._dialogParams!.supervisor.localize(
|
||||
"dialog.repositories.remove"
|
||||
)}
|
||||
.disabled=${usedRepositories.includes(repo.slug)}
|
||||
.slug=${repo.slug}
|
||||
.path=${usedRepositories.includes(repo.slug)
|
||||
? mdiDeleteOff
|
||||
: mdiDelete}
|
||||
@click=${this._removeRepository}
|
||||
>
|
||||
</ha-icon-button>
|
||||
<simple-tooltip
|
||||
animation-delay="0"
|
||||
position="bottom"
|
||||
offset="1"
|
||||
>
|
||||
${this._dialogParams!.supervisor.localize(
|
||||
usedRepositories.includes(repo.slug)
|
||||
? "dialog.repositories.used"
|
||||
: "dialog.repositories.remove"
|
||||
)}
|
||||
</simple-tooltip>
|
||||
</div>
|
||||
</ha-list-item-new>
|
||||
`
|
||||
)
|
||||
: html`<ha-list-item-new> No repositories </ha-list-item-new>`}
|
||||
</ha-list-new>
|
||||
<div class="layout horizontal bottom">
|
||||
<ha-textfield
|
||||
class="flex-auto"
|
||||
@ -195,6 +197,8 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
}
|
||||
mwc-button {
|
||||
margin-left: 8px;
|
||||
margin-inline-start: 8px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
ha-circular-progress {
|
||||
display: block;
|
||||
@ -204,6 +208,9 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
div.delete ha-icon-button {
|
||||
color: var(--error-color);
|
||||
}
|
||||
ha-list-item-new {
|
||||
position: relative;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ class HassioIngressView extends LitElement {
|
||||
}
|
||||
|
||||
.main-title {
|
||||
margin: 0 0 0 24px;
|
||||
margin: var(--margin-title);
|
||||
line-height: 20px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
@ -19,10 +19,14 @@ export const hassioStyle = css`
|
||||
letter-spacing: var(--paper-font-headline_-_letter-spacing);
|
||||
line-height: var(--paper-font-headline_-_line-height);
|
||||
padding-left: 8px;
|
||||
padding-inline-start: 8px;
|
||||
padding-inline-end: initial;
|
||||
}
|
||||
.description {
|
||||
margin-top: 4px;
|
||||
padding-left: 8px;
|
||||
padding-inline-start: 8px;
|
||||
padding-inline-end: initial;
|
||||
}
|
||||
.card-group {
|
||||
display: grid;
|
||||
|
@ -73,6 +73,8 @@ class HassioSystem extends LitElement {
|
||||
color: var(--primary-text-color);
|
||||
font-size: 2em;
|
||||
padding-left: 8px;
|
||||
padding-inline-start: 8px;
|
||||
padding-inline-end: initial;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
hassio-supervisor-log {
|
||||
|
118
package.json
118
package.json
@ -25,36 +25,36 @@
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.23.8",
|
||||
"@babel/runtime": "7.24.0",
|
||||
"@braintree/sanitize-url": "7.0.0",
|
||||
"@codemirror/autocomplete": "6.12.0",
|
||||
"@codemirror/autocomplete": "6.13.0",
|
||||
"@codemirror/commands": "6.3.3",
|
||||
"@codemirror/language": "6.10.0",
|
||||
"@codemirror/language": "6.10.1",
|
||||
"@codemirror/legacy-modes": "6.3.3",
|
||||
"@codemirror/search": "6.5.5",
|
||||
"@codemirror/state": "6.4.0",
|
||||
"@codemirror/view": "6.23.0",
|
||||
"@codemirror/search": "6.5.6",
|
||||
"@codemirror/state": "6.4.1",
|
||||
"@codemirror/view": "6.25.1",
|
||||
"@egjs/hammerjs": "2.0.17",
|
||||
"@formatjs/intl-datetimeformat": "6.12.2",
|
||||
"@formatjs/intl-displaynames": "6.6.6",
|
||||
"@formatjs/intl-getcanonicallocales": "2.3.0",
|
||||
"@formatjs/intl-listformat": "7.5.5",
|
||||
"@formatjs/intl-locale": "3.4.5",
|
||||
"@formatjs/intl-numberformat": "8.9.2",
|
||||
"@formatjs/intl-numberformat": "8.10.0",
|
||||
"@formatjs/intl-pluralrules": "5.2.12",
|
||||
"@formatjs/intl-relativetimeformat": "11.2.12",
|
||||
"@fullcalendar/core": "6.1.10",
|
||||
"@fullcalendar/daygrid": "6.1.10",
|
||||
"@fullcalendar/interaction": "6.1.10",
|
||||
"@fullcalendar/list": "6.1.10",
|
||||
"@fullcalendar/luxon3": "6.1.10",
|
||||
"@fullcalendar/timegrid": "6.1.10",
|
||||
"@fullcalendar/core": "6.1.11",
|
||||
"@fullcalendar/daygrid": "6.1.11",
|
||||
"@fullcalendar/interaction": "6.1.11",
|
||||
"@fullcalendar/list": "6.1.11",
|
||||
"@fullcalendar/luxon3": "6.1.11",
|
||||
"@fullcalendar/timegrid": "6.1.11",
|
||||
"@lezer/highlight": "1.2.0",
|
||||
"@lit-labs/context": "0.4.1",
|
||||
"@lit-labs/motion": "1.0.6",
|
||||
"@lit-labs/motion": "1.0.7",
|
||||
"@lit-labs/observers": "2.0.2",
|
||||
"@lit-labs/virtualizer": "2.0.12",
|
||||
"@lrnwebcomponents/simple-tooltip": "7.0.18",
|
||||
"@lrnwebcomponents/simple-tooltip": "8.0.2",
|
||||
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/mwc-base": "0.27.0",
|
||||
@ -72,6 +72,7 @@
|
||||
"@material/mwc-radio": "0.27.0",
|
||||
"@material/mwc-ripple": "0.27.0",
|
||||
"@material/mwc-select": "0.27.0",
|
||||
"@material/mwc-snackbar": "0.27.0",
|
||||
"@material/mwc-switch": "0.27.0",
|
||||
"@material/mwc-tab": "0.27.0",
|
||||
"@material/mwc-tab-bar": "0.27.0",
|
||||
@ -80,17 +81,16 @@
|
||||
"@material/mwc-top-app-bar": "0.27.0",
|
||||
"@material/mwc-top-app-bar-fixed": "0.27.0",
|
||||
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/web": "=1.1.1",
|
||||
"@material/web": "=1.3.0",
|
||||
"@mdi/js": "7.4.47",
|
||||
"@mdi/svg": "7.4.47",
|
||||
"@polymer/paper-item": "3.0.1",
|
||||
"@polymer/paper-listbox": "3.0.1",
|
||||
"@polymer/paper-tabs": "3.1.0",
|
||||
"@polymer/paper-toast": "3.0.1",
|
||||
"@polymer/polymer": "3.5.1",
|
||||
"@thomasloven/round-slider": "0.6.0",
|
||||
"@vaadin/combo-box": "24.3.3",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.3",
|
||||
"@vaadin/combo-box": "24.3.8",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.8",
|
||||
"@vibrant/color": "3.2.1-alpha.1",
|
||||
"@vibrant/core": "3.2.1-alpha.1",
|
||||
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
|
||||
@ -98,9 +98,10 @@
|
||||
"@webcomponents/scoped-custom-element-registry": "0.0.9",
|
||||
"@webcomponents/webcomponentsjs": "2.8.0",
|
||||
"app-datepicker": "5.1.1",
|
||||
"chart.js": "4.4.1",
|
||||
"chart.js": "4.4.2",
|
||||
"color-name": "2.0.0",
|
||||
"comlink": "4.4.1",
|
||||
"core-js": "3.35.0",
|
||||
"core-js": "3.36.0",
|
||||
"cropperjs": "1.6.1",
|
||||
"date-fns": "2.30.0",
|
||||
"date-fns-tz": "2.0.0",
|
||||
@ -109,16 +110,16 @@
|
||||
"element-internals-polyfill": "1.3.10",
|
||||
"fuse.js": "7.0.0",
|
||||
"google-timezones-json": "1.2.0",
|
||||
"hls.js": "1.5.1",
|
||||
"hls.js": "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch",
|
||||
"home-assistant-js-websocket": "9.1.0",
|
||||
"idb-keyval": "6.2.1",
|
||||
"intl-messageformat": "10.5.10",
|
||||
"intl-messageformat": "10.5.11",
|
||||
"js-yaml": "4.1.0",
|
||||
"leaflet": "1.9.4",
|
||||
"leaflet-draw": "1.0.4",
|
||||
"lit": "2.8.0",
|
||||
"luxon": "3.4.4",
|
||||
"marked": "11.1.1",
|
||||
"marked": "12.0.1",
|
||||
"memoize-one": "6.0.0",
|
||||
"node-vibrant": "3.2.1-alpha.1",
|
||||
"proxy-polyfill": "0.3.2",
|
||||
@ -146,20 +147,20 @@
|
||||
"workbox-precaching": "7.0.0",
|
||||
"workbox-routing": "7.0.0",
|
||||
"workbox-strategies": "7.0.0",
|
||||
"xss": "1.0.14"
|
||||
"xss": "1.0.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.23.7",
|
||||
"@babel/helper-define-polyfill-provider": "0.4.4",
|
||||
"@babel/plugin-proposal-decorators": "7.23.7",
|
||||
"@babel/plugin-transform-runtime": "7.23.7",
|
||||
"@babel/preset-env": "7.23.8",
|
||||
"@babel/core": "7.24.0",
|
||||
"@babel/helper-define-polyfill-provider": "0.6.0",
|
||||
"@babel/plugin-proposal-decorators": "7.24.0",
|
||||
"@babel/plugin-transform-runtime": "7.24.0",
|
||||
"@babel/preset-env": "7.24.0",
|
||||
"@babel/preset-typescript": "7.23.3",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.8.4",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.12.0",
|
||||
"@koa/cors": "5.0.0",
|
||||
"@lokalise/node-api": "12.1.0",
|
||||
"@octokit/auth-oauth-device": "6.0.1",
|
||||
"@octokit/plugin-retry": "6.0.1",
|
||||
"@octokit/auth-oauth-device": "7.0.1",
|
||||
"@octokit/plugin-retry": "7.0.3",
|
||||
"@octokit/rest": "20.0.2",
|
||||
"@open-wc/dev-server-hmr": "0.1.4",
|
||||
"@rollup/plugin-babel": "6.0.4",
|
||||
@ -169,62 +170,63 @@
|
||||
"@rollup/plugin-replace": "5.0.5",
|
||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||
"@types/chromecast-caf-receiver": "6.0.13",
|
||||
"@types/chromecast-caf-sender": "1.0.8",
|
||||
"@types/chromecast-caf-sender": "1.0.9",
|
||||
"@types/color-name": "1.1.3",
|
||||
"@types/glob": "8.1.0",
|
||||
"@types/html-minifier-terser": "7.0.2",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/leaflet": "1.9.8",
|
||||
"@types/leaflet-draw": "1.0.11",
|
||||
"@types/luxon": "3.4.1",
|
||||
"@types/luxon": "3.4.2",
|
||||
"@types/mocha": "10.0.6",
|
||||
"@types/qrcode": "1.5.5",
|
||||
"@types/serve-handler": "6.1.4",
|
||||
"@types/sortablejs": "1.15.7",
|
||||
"@types/tar": "6.1.10",
|
||||
"@types/sortablejs": "1.15.8",
|
||||
"@types/tar": "6.1.11",
|
||||
"@types/ua-parser-js": "0.7.39",
|
||||
"@types/webspeechapi": "0.0.29",
|
||||
"@typescript-eslint/eslint-plugin": "6.19.0",
|
||||
"@typescript-eslint/parser": "6.19.0",
|
||||
"@typescript-eslint/eslint-plugin": "7.1.1",
|
||||
"@typescript-eslint/parser": "7.1.1",
|
||||
"@web/dev-server": "0.1.38",
|
||||
"@web/dev-server-rollup": "0.4.1",
|
||||
"babel-loader": "9.1.3",
|
||||
"babel-plugin-template-html-minifier": "4.1.0",
|
||||
"chai": "5.0.0",
|
||||
"chai": "5.1.0",
|
||||
"del": "7.1.0",
|
||||
"eslint": "8.56.0",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
"eslint-config-airbnb-typescript": "17.1.0",
|
||||
"eslint-config-airbnb-typescript": "18.0.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-import-resolver-webpack": "0.13.8",
|
||||
"eslint-plugin-disable": "2.0.3",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-lit": "1.11.0",
|
||||
"eslint-plugin-lit-a11y": "4.1.1",
|
||||
"eslint-plugin-unused-imports": "3.0.0",
|
||||
"eslint-plugin-lit-a11y": "4.1.2",
|
||||
"eslint-plugin-unused-imports": "3.1.0",
|
||||
"eslint-plugin-wc": "2.0.4",
|
||||
"fancy-log": "2.0.0",
|
||||
"fs-extra": "11.2.0",
|
||||
"glob": "10.3.10",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-flatmap": "1.0.2",
|
||||
"gulp-json-transform": "0.4.8",
|
||||
"gulp-merge-json": "2.1.2",
|
||||
"gulp-json-transform": "0.5.0",
|
||||
"gulp-merge-json": "2.2.1",
|
||||
"gulp-rename": "2.0.0",
|
||||
"gulp-zopfli-green": "6.0.1",
|
||||
"html-minifier-terser": "7.2.0",
|
||||
"husky": "8.0.3",
|
||||
"husky": "9.0.11",
|
||||
"instant-mocha": "1.5.2",
|
||||
"jszip": "3.10.1",
|
||||
"lint-staged": "15.2.0",
|
||||
"lint-staged": "15.2.2",
|
||||
"lit-analyzer": "2.0.3",
|
||||
"lodash.template": "4.5.0",
|
||||
"magic-string": "0.30.5",
|
||||
"magic-string": "0.30.8",
|
||||
"map-stream": "0.0.7",
|
||||
"mocha": "10.2.0",
|
||||
"mocha": "10.3.0",
|
||||
"object-hash": "3.0.0",
|
||||
"open": "10.0.3",
|
||||
"open": "10.1.0",
|
||||
"pinst": "3.0.0",
|
||||
"prettier": "3.2.2",
|
||||
"prettier": "3.2.5",
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-string": "3.0.0",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
@ -237,15 +239,15 @@
|
||||
"terser-webpack-plugin": "5.3.10",
|
||||
"transform-async-modules-webpack-plugin": "1.0.2",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.3.3",
|
||||
"typescript": "5.4.2",
|
||||
"vinyl-buffer": "1.0.1",
|
||||
"vinyl-source-stream": "2.0.0",
|
||||
"webpack": "5.89.0",
|
||||
"webpack": "5.90.3",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"webpack-dev-server": "5.0.2",
|
||||
"webpack-manifest-plugin": "5.0.0",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
"webpackbar": "6.0.0",
|
||||
"webpackbar": "6.0.1",
|
||||
"workbox-build": "7.0.0"
|
||||
},
|
||||
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
|
||||
@ -255,8 +257,8 @@
|
||||
"lit": "2.8.0",
|
||||
"clean-css": "5.3.3",
|
||||
"@lit/reactive-element": "1.6.3",
|
||||
"sortablejs@1.15.0": "patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch",
|
||||
"sortablejs@1.15.2": "patch:sortablejs@npm%3A1.15.2#~/.yarn/patches/sortablejs-npm-1.15.2-73347ae85a.patch",
|
||||
"leaflet-draw@1.0.4": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch"
|
||||
},
|
||||
"packageManager": "yarn@4.0.2"
|
||||
"packageManager": "yarn@4.1.1"
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20240112.0"
|
||||
version = "20240228.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "The Home Assistant frontend"
|
||||
readme = "README.md"
|
||||
|
@ -40,6 +40,7 @@ if [ -n "$ref" ]; then
|
||||
echo "Installing Home Assistant core at ${ref}..."
|
||||
python3 -m pip install --user --upgrade --src "$HOME/src" \
|
||||
--editable "git+${coreURL}@${ref}#egg=homeassistant"
|
||||
(cd ~/src/homeassistant && exec python3 -m script.translations develop --all)
|
||||
fi
|
||||
|
||||
if [ ! -d "${WD}/config" ]; then
|
||||
|
@ -34,7 +34,7 @@ export class HaAuthFlow extends LitElement {
|
||||
|
||||
@property() public oauth2State?: string;
|
||||
|
||||
@property() public localize!: LocalizeFunc;
|
||||
@property({ attribute: false }) public localize!: LocalizeFunc;
|
||||
|
||||
@property({ attribute: false }) public step?: DataEntryFlowStep;
|
||||
|
||||
@ -93,6 +93,8 @@ export class HaAuthFlow extends LitElement {
|
||||
<style>
|
||||
ha-auth-flow .store-token {
|
||||
margin-left: -16px;
|
||||
margin-inline-start: -16px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
a.forgot-password {
|
||||
color: var(--primary-color);
|
||||
|
@ -149,6 +149,8 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
margin-right: 16px;
|
||||
margin-inline-end: 16px;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
|
@ -18,9 +18,9 @@ declare global {
|
||||
|
||||
@customElement("ha-pick-auth-provider")
|
||||
export class HaPickAuthProvider extends LitElement {
|
||||
@property() public authProviders: AuthProvider[] = [];
|
||||
@property({ attribute: false }) public authProviders: AuthProvider[] = [];
|
||||
|
||||
@property() public localize!: LocalizeFunc;
|
||||
@property({ attribute: false }) public localize!: LocalizeFunc;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
|
@ -1,19 +1,25 @@
|
||||
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { ensureArray } from "../array/ensure-array";
|
||||
import { isComponentLoaded } from "./is_component_loaded";
|
||||
|
||||
export const canShowPage = (hass: HomeAssistant, page: PageNavigation) =>
|
||||
(isCore(page) || isLoadedIntegration(hass, page)) &&
|
||||
!hideAdvancedPage(hass, page);
|
||||
!hideAdvancedPage(hass, page) &&
|
||||
isNotLoadedIntegration(hass, page);
|
||||
|
||||
const isLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
|
||||
page.component
|
||||
? isComponentLoaded(hass, page.component)
|
||||
: page.components
|
||||
? page.components.some((integration) =>
|
||||
isComponentLoaded(hass, integration)
|
||||
)
|
||||
: true;
|
||||
!page.component ||
|
||||
ensureArray(page.component).some((integration) =>
|
||||
isComponentLoaded(hass, integration)
|
||||
);
|
||||
|
||||
const isNotLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
|
||||
!page.not_component ||
|
||||
!ensureArray(page.not_component).some((integration) =>
|
||||
isComponentLoaded(hass, integration)
|
||||
);
|
||||
|
||||
const isCore = (page: PageNavigation) => page.core;
|
||||
const isAdvancedPage = (page: PageNavigation) => page.advancedOnly;
|
||||
const userWantsAdvanced = (hass: HomeAssistant) => hass.userData?.showAdvanced;
|
||||
|
@ -1,6 +1,7 @@
|
||||
/** Constants to be used in the frontend. */
|
||||
|
||||
import {
|
||||
mdiAccount,
|
||||
mdiAirFilter,
|
||||
mdiAlert,
|
||||
mdiAngleAcute,
|
||||
@ -18,7 +19,6 @@ import {
|
||||
mdiChatSleep,
|
||||
mdiClipboardList,
|
||||
mdiClock,
|
||||
mdiCloudUpload,
|
||||
mdiCog,
|
||||
mdiCommentAlert,
|
||||
mdiCounter,
|
||||
@ -48,11 +48,14 @@ import {
|
||||
mdiMoleculeCo2,
|
||||
mdiPalette,
|
||||
mdiPh,
|
||||
mdiPipe,
|
||||
mdiProgressClock,
|
||||
mdiRayVertex,
|
||||
mdiRemote,
|
||||
mdiRobot,
|
||||
mdiRobotMower,
|
||||
mdiRobotVacuum,
|
||||
mdiRoomService,
|
||||
mdiScriptText,
|
||||
mdiSineWave,
|
||||
mdiSpeakerMessage,
|
||||
@ -62,6 +65,7 @@ import {
|
||||
mdiThermometerLines,
|
||||
mdiThermostat,
|
||||
mdiTimerOutline,
|
||||
mdiToggleSwitch,
|
||||
mdiTransmissionTower,
|
||||
mdiWater,
|
||||
mdiWaterPercent,
|
||||
@ -70,6 +74,7 @@ import {
|
||||
mdiWeatherRainy,
|
||||
mdiWeatherWindy,
|
||||
mdiWeight,
|
||||
mdiWhiteBalanceSunny,
|
||||
mdiWifi,
|
||||
} from "@mdi/js";
|
||||
|
||||
@ -79,6 +84,9 @@ import { mdiHomeAssistant } from "../resources/home-assistant-logo-svg";
|
||||
// Arrays with values should be alphabetically sorted if order doesn't matter.
|
||||
// Each constant should have a description what it is supposed to be used for.
|
||||
|
||||
/** Icon to use when no icon specified for service. */
|
||||
export const DEFAULT_SERVICE_ICON = mdiRoomService;
|
||||
|
||||
/** Icon to use when no icon specified for domain. */
|
||||
export const DEFAULT_DOMAIN_ICON = mdiBookmark;
|
||||
|
||||
@ -86,20 +94,23 @@ export const DEFAULT_DOMAIN_ICON = mdiBookmark;
|
||||
export const FIXED_DOMAIN_ICONS = {
|
||||
air_quality: mdiAirFilter,
|
||||
alert: mdiAlert,
|
||||
automation: mdiRobot,
|
||||
calendar: mdiCalendar,
|
||||
climate: mdiThermostat,
|
||||
configurator: mdiCog,
|
||||
conversation: mdiMicrophoneMessage,
|
||||
counter: mdiCounter,
|
||||
datetime: mdiCalendarClock,
|
||||
date: mdiCalendar,
|
||||
datetime: mdiCalendarClock,
|
||||
demo: mdiHomeAssistant,
|
||||
device_tracker: mdiAccount,
|
||||
google_assistant: mdiGoogleAssistant,
|
||||
group: mdiGoogleCirclesCommunities,
|
||||
homeassistant: mdiHomeAssistant,
|
||||
homekit: mdiHomeAutomation,
|
||||
image: mdiImage,
|
||||
image_processing: mdiImageFilterFrames,
|
||||
image: mdiImage,
|
||||
input_boolean: mdiToggleSwitch,
|
||||
input_button: mdiButtonPointer,
|
||||
input_datetime: mdiCalendarClock,
|
||||
input_number: mdiRayVertex,
|
||||
@ -111,6 +122,7 @@ export const FIXED_DOMAIN_ICONS = {
|
||||
notify: mdiCommentAlert,
|
||||
number: mdiRayVertex,
|
||||
persistent_notification: mdiBell,
|
||||
person: mdiAccount,
|
||||
plant: mdiFlower,
|
||||
proximity: mdiAppleSafari,
|
||||
remote: mdiRemote,
|
||||
@ -122,12 +134,12 @@ export const FIXED_DOMAIN_ICONS = {
|
||||
simple_alarm: mdiBell,
|
||||
siren: mdiBullhorn,
|
||||
stt: mdiMicrophoneMessage,
|
||||
sun: mdiWhiteBalanceSunny,
|
||||
text: mdiFormTextbox,
|
||||
todo: mdiClipboardList,
|
||||
time: mdiClock,
|
||||
timer: mdiTimerOutline,
|
||||
todo: mdiClipboardList,
|
||||
tts: mdiSpeakerMessage,
|
||||
updater: mdiCloudUpload,
|
||||
vacuum: mdiRobotVacuum,
|
||||
wake_word: mdiChatSleep,
|
||||
weather: mdiWeatherPartlyCloudy,
|
||||
@ -180,6 +192,7 @@ export const FIXED_DEVICE_CLASS_ICONS = {
|
||||
volatile_organic_compounds_parts: mdiMolecule,
|
||||
voltage: mdiSineWave,
|
||||
volume: mdiCarCoolantLevel,
|
||||
volume_flow_rate: mdiPipe,
|
||||
water: mdiWater,
|
||||
weight: mdiWeight,
|
||||
wind_speed: mdiWeatherWindy,
|
||||
|
@ -41,7 +41,9 @@ export const applyThemesOnElement = (
|
||||
// If there is no explicitly desired dark mode provided, we automatically
|
||||
// use the active one from `themes`.
|
||||
const darkMode =
|
||||
themeSettings?.dark !== undefined ? themeSettings.dark : themes.darkMode;
|
||||
themeSettings?.dark !== undefined
|
||||
? themeSettings.dark
|
||||
: themes?.darkMode || false;
|
||||
|
||||
let cacheKey = themeToApply;
|
||||
let themeRules: Partial<ThemeVars> = {};
|
||||
|
@ -1,8 +1,13 @@
|
||||
import { MAIN_WINDOW_NAME } from "../../data/main_window";
|
||||
|
||||
export const mainWindow =
|
||||
window.name === MAIN_WINDOW_NAME
|
||||
? window
|
||||
: parent.name === MAIN_WINDOW_NAME
|
||||
? parent
|
||||
: top!;
|
||||
export const mainWindow = (() => {
|
||||
try {
|
||||
return window.name === MAIN_WINDOW_NAME
|
||||
? window
|
||||
: parent.name === MAIN_WINDOW_NAME
|
||||
? parent
|
||||
: top!;
|
||||
} catch {
|
||||
return window;
|
||||
}
|
||||
})();
|
||||
|
@ -1,36 +0,0 @@
|
||||
/** Return an icon representing a alarm panel state. */
|
||||
|
||||
import {
|
||||
mdiShieldLock,
|
||||
mdiShieldAirplane,
|
||||
mdiShieldHome,
|
||||
mdiShieldMoon,
|
||||
mdiSecurity,
|
||||
mdiShieldOutline,
|
||||
mdiBellRing,
|
||||
mdiShieldOff,
|
||||
mdiShield,
|
||||
} from "@mdi/js";
|
||||
|
||||
export const alarmPanelIcon = (state?: string) => {
|
||||
switch (state) {
|
||||
case "armed_away":
|
||||
return mdiShieldLock;
|
||||
case "armed_vacation":
|
||||
return mdiShieldAirplane;
|
||||
case "armed_home":
|
||||
return mdiShieldHome;
|
||||
case "armed_night":
|
||||
return mdiShieldMoon;
|
||||
case "armed_custom_bypass":
|
||||
return mdiSecurity;
|
||||
case "pending":
|
||||
return mdiShieldOutline;
|
||||
case "triggered":
|
||||
return mdiBellRing;
|
||||
case "disarmed":
|
||||
return mdiShieldOff;
|
||||
default:
|
||||
return mdiShield;
|
||||
}
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
/** Return an icon representing a attribute. */
|
||||
import { mdiCircleMedium, mdiCreation } from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import {
|
||||
computeFanModeIcon,
|
||||
computeHvacModeIcon,
|
||||
computePresetModeIcon,
|
||||
computeSwingModeIcon,
|
||||
} from "../../data/climate";
|
||||
import { computeHumidiferModeIcon } from "../../data/humidifier";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
|
||||
const iconGenerators: Record<string, Record<string, (value: any) => string>> = {
|
||||
climate: {
|
||||
fan_mode: computeFanModeIcon,
|
||||
hvac_mode: computeHvacModeIcon,
|
||||
preset_mode: computePresetModeIcon,
|
||||
swing_mode: computeSwingModeIcon,
|
||||
},
|
||||
humidifier: {
|
||||
mode: computeHumidiferModeIcon,
|
||||
},
|
||||
light: {
|
||||
effect: () => mdiCreation,
|
||||
},
|
||||
fan: {
|
||||
preset_mode: () => mdiCircleMedium,
|
||||
},
|
||||
};
|
||||
|
||||
export const attributeIconPath = (
|
||||
state: HassEntity | undefined,
|
||||
attribute: string,
|
||||
attributeValue?: string
|
||||
) => {
|
||||
if (!state) {
|
||||
return undefined;
|
||||
}
|
||||
const domain = computeDomain(state.entity_id);
|
||||
if (iconGenerators[domain]?.[attribute]) {
|
||||
return iconGenerators[domain]?.[attribute](
|
||||
attributeValue || state.attributes[attribute]
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
};
|
@ -1,92 +1,59 @@
|
||||
/** Return an icon representing a battery state. */
|
||||
import {
|
||||
mdiBattery,
|
||||
mdiBattery10,
|
||||
mdiBattery20,
|
||||
mdiBattery30,
|
||||
mdiBattery40,
|
||||
mdiBattery50,
|
||||
mdiBattery60,
|
||||
mdiBattery70,
|
||||
mdiBattery80,
|
||||
mdiBattery90,
|
||||
mdiBatteryAlert,
|
||||
mdiBatteryAlertVariantOutline,
|
||||
mdiBatteryCharging,
|
||||
mdiBatteryCharging10,
|
||||
mdiBatteryCharging20,
|
||||
mdiBatteryCharging30,
|
||||
mdiBatteryCharging40,
|
||||
mdiBatteryCharging50,
|
||||
mdiBatteryCharging60,
|
||||
mdiBatteryCharging70,
|
||||
mdiBatteryCharging80,
|
||||
mdiBatteryCharging90,
|
||||
mdiBatteryChargingOutline,
|
||||
mdiBatteryUnknown,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
const BATTERY_ICONS = {
|
||||
10: mdiBattery10,
|
||||
20: mdiBattery20,
|
||||
30: mdiBattery30,
|
||||
40: mdiBattery40,
|
||||
50: mdiBattery50,
|
||||
60: mdiBattery60,
|
||||
70: mdiBattery70,
|
||||
80: mdiBattery80,
|
||||
90: mdiBattery90,
|
||||
100: mdiBattery,
|
||||
10: "mdi:battery-10",
|
||||
20: "mdi:battery-20",
|
||||
30: "mdi:battery-30",
|
||||
40: "mdi:battery-40",
|
||||
50: "mdi:battery-50",
|
||||
60: "mdi:battery-60",
|
||||
70: "mdi:battery-70",
|
||||
80: "mdi:battery-80",
|
||||
90: "mdi:battery-90",
|
||||
100: "mdi:battery",
|
||||
};
|
||||
const BATTERY_CHARGING_ICONS = {
|
||||
10: mdiBatteryCharging10,
|
||||
20: mdiBatteryCharging20,
|
||||
30: mdiBatteryCharging30,
|
||||
40: mdiBatteryCharging40,
|
||||
50: mdiBatteryCharging50,
|
||||
60: mdiBatteryCharging60,
|
||||
70: mdiBatteryCharging70,
|
||||
80: mdiBatteryCharging80,
|
||||
90: mdiBatteryCharging90,
|
||||
100: mdiBatteryCharging,
|
||||
10: "mdi:battery-charging-10",
|
||||
20: "mdi:battery-charging-20",
|
||||
30: "mdi:battery-charging-30",
|
||||
40: "mdi:battery-charging-40",
|
||||
50: "mdi:battery-charging-50",
|
||||
60: "mdi:battery-charging-60",
|
||||
70: "mdi:battery-charging-70",
|
||||
80: "mdi:battery-charging-80",
|
||||
90: "mdi:battery-charging-90",
|
||||
100: "mdi:battery-charging",
|
||||
};
|
||||
|
||||
export const batteryStateIcon = (
|
||||
batteryState: HassEntity,
|
||||
batteryChargingState?: HassEntity
|
||||
) => {
|
||||
const battery = batteryState.state;
|
||||
const batteryCharging =
|
||||
batteryChargingState && batteryChargingState.state === "on";
|
||||
|
||||
return batteryIcon(battery, batteryCharging);
|
||||
export const batteryIcon = (stateObj: HassEntity, state?: string) => {
|
||||
const level = state ?? stateObj.state;
|
||||
return batteryLevelIcon(level);
|
||||
};
|
||||
|
||||
export const batteryIcon = (
|
||||
batteryState: number | string,
|
||||
batteryCharging?: boolean
|
||||
) => {
|
||||
const batteryValue = Number(batteryState);
|
||||
export const batteryLevelIcon = (
|
||||
batteryLevel: number | string,
|
||||
isBatteryCharging?: boolean
|
||||
): string => {
|
||||
const batteryValue = Number(batteryLevel);
|
||||
if (isNaN(batteryValue)) {
|
||||
if (batteryState === "off") {
|
||||
return mdiBattery;
|
||||
if (batteryLevel === "off") {
|
||||
return "mdi:battery";
|
||||
}
|
||||
if (batteryState === "on") {
|
||||
return mdiBatteryAlert;
|
||||
if (batteryLevel === "on") {
|
||||
return "mdi:battery-alert";
|
||||
}
|
||||
return mdiBatteryUnknown;
|
||||
return "mdi:battery-unknown";
|
||||
}
|
||||
|
||||
const batteryRound = Math.round(batteryValue / 10) * 10;
|
||||
if (batteryCharging && batteryValue >= 10) {
|
||||
if (isBatteryCharging && batteryValue >= 10) {
|
||||
return BATTERY_CHARGING_ICONS[batteryRound];
|
||||
}
|
||||
if (batteryCharging) {
|
||||
return mdiBatteryChargingOutline;
|
||||
if (isBatteryCharging) {
|
||||
return "mdi:battery-charging-outline";
|
||||
}
|
||||
if (batteryValue <= 5) {
|
||||
return mdiBatteryAlertVariantOutline;
|
||||
return "mdi:battery-alert-variant-outline";
|
||||
}
|
||||
return BATTERY_ICONS[batteryRound];
|
||||
};
|
||||
|
@ -1,108 +0,0 @@
|
||||
import {
|
||||
mdiAlertCircle,
|
||||
mdiBattery,
|
||||
mdiBatteryCharging,
|
||||
mdiBatteryOutline,
|
||||
mdiBrightness5,
|
||||
mdiBrightness7,
|
||||
mdiCheckboxMarkedCircle,
|
||||
mdiCheckNetworkOutline,
|
||||
mdiCloseNetworkOutline,
|
||||
mdiCheckCircle,
|
||||
mdiCropPortrait,
|
||||
mdiDoorClosed,
|
||||
mdiDoorOpen,
|
||||
mdiFire,
|
||||
mdiGarage,
|
||||
mdiGarageOpen,
|
||||
mdiHome,
|
||||
mdiHomeOutline,
|
||||
mdiLock,
|
||||
mdiLockOpen,
|
||||
mdiMusicNote,
|
||||
mdiMusicNoteOff,
|
||||
mdiMotionSensor,
|
||||
mdiMotionSensorOff,
|
||||
mdiPackage,
|
||||
mdiPackageUp,
|
||||
mdiPlay,
|
||||
mdiPowerPlug,
|
||||
mdiPowerPlugOff,
|
||||
mdiRadioboxBlank,
|
||||
mdiSnowflake,
|
||||
mdiSmokeDetector,
|
||||
mdiSmokeDetectorAlert,
|
||||
mdiSmokeDetectorVariant,
|
||||
mdiSmokeDetectorVariantAlert,
|
||||
mdiSquare,
|
||||
mdiSquareOutline,
|
||||
mdiStop,
|
||||
mdiThermometer,
|
||||
mdiVibrate,
|
||||
mdiWater,
|
||||
mdiWaterOff,
|
||||
mdiWindowClosed,
|
||||
mdiWindowOpen,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
/** Return an icon representing a binary sensor state. */
|
||||
|
||||
export const binarySensorIcon = (state?: string, stateObj?: HassEntity) => {
|
||||
const is_off = state === "off";
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "battery":
|
||||
return is_off ? mdiBattery : mdiBatteryOutline;
|
||||
case "battery_charging":
|
||||
return is_off ? mdiBattery : mdiBatteryCharging;
|
||||
case "carbon_monoxide":
|
||||
return is_off ? mdiSmokeDetector : mdiSmokeDetectorAlert;
|
||||
case "cold":
|
||||
return is_off ? mdiThermometer : mdiSnowflake;
|
||||
case "connectivity":
|
||||
return is_off ? mdiCloseNetworkOutline : mdiCheckNetworkOutline;
|
||||
case "door":
|
||||
return is_off ? mdiDoorClosed : mdiDoorOpen;
|
||||
case "garage_door":
|
||||
return is_off ? mdiGarage : mdiGarageOpen;
|
||||
case "power":
|
||||
return is_off ? mdiPowerPlugOff : mdiPowerPlug;
|
||||
case "gas":
|
||||
case "problem":
|
||||
case "safety":
|
||||
case "tamper":
|
||||
return is_off ? mdiCheckCircle : mdiAlertCircle;
|
||||
case "smoke":
|
||||
return is_off ? mdiSmokeDetectorVariant : mdiSmokeDetectorVariantAlert;
|
||||
case "heat":
|
||||
return is_off ? mdiThermometer : mdiFire;
|
||||
case "light":
|
||||
return is_off ? mdiBrightness5 : mdiBrightness7;
|
||||
case "lock":
|
||||
return is_off ? mdiLock : mdiLockOpen;
|
||||
case "moisture":
|
||||
return is_off ? mdiWaterOff : mdiWater;
|
||||
case "motion":
|
||||
return is_off ? mdiMotionSensorOff : mdiMotionSensor;
|
||||
case "occupancy":
|
||||
return is_off ? mdiHomeOutline : mdiHome;
|
||||
case "opening":
|
||||
return is_off ? mdiSquare : mdiSquareOutline;
|
||||
case "plug":
|
||||
return is_off ? mdiPowerPlugOff : mdiPowerPlug;
|
||||
case "presence":
|
||||
return is_off ? mdiHomeOutline : mdiHome;
|
||||
case "running":
|
||||
return is_off ? mdiStop : mdiPlay;
|
||||
case "sound":
|
||||
return is_off ? mdiMusicNoteOff : mdiMusicNote;
|
||||
case "update":
|
||||
return is_off ? mdiPackage : mdiPackageUp;
|
||||
case "vibration":
|
||||
return is_off ? mdiCropPortrait : mdiVibrate;
|
||||
case "window":
|
||||
return is_off ? mdiWindowClosed : mdiWindowOpen;
|
||||
default:
|
||||
return is_off ? mdiRadioboxBlank : mdiCheckboxMarkedCircle;
|
||||
}
|
||||
};
|
@ -53,9 +53,7 @@ export const computeAttributeValueDisplay = (
|
||||
|
||||
if (domain === "weather") {
|
||||
unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute);
|
||||
}
|
||||
|
||||
if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
|
||||
} else if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
|
||||
unit = config.unit_system.temperature;
|
||||
}
|
||||
|
||||
|
@ -1,132 +1,12 @@
|
||||
/** Return an icon representing a cover state. */
|
||||
import {
|
||||
mdiArrowUpBox,
|
||||
mdiArrowDownBox,
|
||||
mdiGarage,
|
||||
mdiGarageOpen,
|
||||
mdiGateArrowRight,
|
||||
mdiGate,
|
||||
mdiGateOpen,
|
||||
mdiDoorOpen,
|
||||
mdiDoorClosed,
|
||||
mdiCircle,
|
||||
mdiWindowShutter,
|
||||
mdiWindowShutterOpen,
|
||||
mdiBlindsHorizontal,
|
||||
mdiBlindsHorizontalClosed,
|
||||
mdiRollerShade,
|
||||
mdiRollerShadeClosed,
|
||||
mdiWindowClosed,
|
||||
mdiWindowOpen,
|
||||
mdiArrowExpandHorizontal,
|
||||
mdiArrowUp,
|
||||
mdiArrowCollapseHorizontal,
|
||||
mdiArrowDown,
|
||||
mdiCircleSlice8,
|
||||
mdiArrowSplitVertical,
|
||||
mdiCurtains,
|
||||
mdiCurtainsClosed,
|
||||
mdiArrowExpandHorizontal,
|
||||
mdiArrowUp,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
export const coverIcon = (state?: string, stateObj?: HassEntity): string => {
|
||||
const open = state !== "closed";
|
||||
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "garage":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiGarage;
|
||||
default:
|
||||
return mdiGarageOpen;
|
||||
}
|
||||
case "gate":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
case "closing":
|
||||
return mdiGateArrowRight;
|
||||
case "closed":
|
||||
return mdiGate;
|
||||
default:
|
||||
return mdiGateOpen;
|
||||
}
|
||||
case "door":
|
||||
return open ? mdiDoorOpen : mdiDoorClosed;
|
||||
case "damper":
|
||||
return open ? mdiCircle : mdiCircleSlice8;
|
||||
case "shutter":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiWindowShutter;
|
||||
default:
|
||||
return mdiWindowShutterOpen;
|
||||
}
|
||||
case "curtain":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowSplitVertical;
|
||||
case "closing":
|
||||
return mdiArrowCollapseHorizontal;
|
||||
case "closed":
|
||||
return mdiCurtainsClosed;
|
||||
default:
|
||||
return mdiCurtains;
|
||||
}
|
||||
case "blind":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiBlindsHorizontalClosed;
|
||||
default:
|
||||
return mdiBlindsHorizontal;
|
||||
}
|
||||
case "shade":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiRollerShadeClosed;
|
||||
default:
|
||||
return mdiRollerShade;
|
||||
}
|
||||
case "window":
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiWindowClosed;
|
||||
default:
|
||||
return mdiWindowOpen;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case "opening":
|
||||
return mdiArrowUpBox;
|
||||
case "closing":
|
||||
return mdiArrowDownBox;
|
||||
case "closed":
|
||||
return mdiWindowClosed;
|
||||
default:
|
||||
return mdiWindowOpen;
|
||||
}
|
||||
};
|
||||
|
||||
export const computeOpenIcon = (stateObj: HassEntity): string => {
|
||||
switch (stateObj.attributes.device_class) {
|
||||
case "awning":
|
||||
|
16
src/common/entity/device_tracker_icon.ts
Normal file
16
src/common/entity/device_tracker_icon.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
|
||||
export const deviceTrackerIcon = (stateObj: HassEntity, state?: string) => {
|
||||
const compareState = state ?? stateObj.state;
|
||||
if (stateObj?.attributes.source_type === "router") {
|
||||
return compareState === "home" ? "mdi:lan-connect" : "mdi:lan-disconnect";
|
||||
}
|
||||
if (
|
||||
["bluetooth", "bluetooth_le"].includes(stateObj?.attributes.source_type)
|
||||
) {
|
||||
return compareState === "home" ? "mdi:bluetooth-connect" : "mdi:bluetooth";
|
||||
}
|
||||
return compareState === "not_home"
|
||||
? "mdi:account-arrow-right"
|
||||
: "mdi:account";
|
||||
};
|
@ -1,301 +0,0 @@
|
||||
import {
|
||||
mdiAccount,
|
||||
mdiAccountArrowRight,
|
||||
mdiAirHumidifier,
|
||||
mdiAirHumidifierOff,
|
||||
mdiAudioVideo,
|
||||
mdiAudioVideoOff,
|
||||
mdiBluetooth,
|
||||
mdiBluetoothConnect,
|
||||
mdiButtonPointer,
|
||||
mdiCalendar,
|
||||
mdiCast,
|
||||
mdiCastConnected,
|
||||
mdiCastOff,
|
||||
mdiChartSankey,
|
||||
mdiCheckCircleOutline,
|
||||
mdiClock,
|
||||
mdiCloseCircleOutline,
|
||||
mdiCrosshairsQuestion,
|
||||
mdiDoorbell,
|
||||
mdiEyeCheck,
|
||||
mdiFan,
|
||||
mdiFanOff,
|
||||
mdiGestureTapButton,
|
||||
mdiLanConnect,
|
||||
mdiLanDisconnect,
|
||||
mdiLock,
|
||||
mdiLockAlert,
|
||||
mdiLockClock,
|
||||
mdiLockOpen,
|
||||
mdiMeterGas,
|
||||
mdiMotionSensor,
|
||||
mdiPackage,
|
||||
mdiPackageDown,
|
||||
mdiPackageUp,
|
||||
mdiPipeValve,
|
||||
mdiPowerPlug,
|
||||
mdiPowerPlugOff,
|
||||
mdiRestart,
|
||||
mdiRobot,
|
||||
mdiRobotConfused,
|
||||
mdiRobotOff,
|
||||
mdiSpeaker,
|
||||
mdiSpeakerOff,
|
||||
mdiSpeakerPause,
|
||||
mdiSpeakerPlay,
|
||||
mdiSwapHorizontal,
|
||||
mdiTelevision,
|
||||
mdiTelevisionOff,
|
||||
mdiTelevisionPause,
|
||||
mdiTelevisionPlay,
|
||||
mdiToggleSwitchVariant,
|
||||
mdiToggleSwitchVariantOff,
|
||||
mdiVideo,
|
||||
mdiVideoOff,
|
||||
mdiWaterBoiler,
|
||||
mdiWaterBoilerOff,
|
||||
mdiWeatherNight,
|
||||
mdiWhiteBalanceSunny,
|
||||
} from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UpdateEntity, updateIsInstalling } from "../../data/update";
|
||||
import { weatherIcon } from "../../data/weather";
|
||||
/**
|
||||
* Return the icon to be used for a domain.
|
||||
*
|
||||
* Optionally pass in a state to influence the domain icon.
|
||||
*/
|
||||
import { DEFAULT_DOMAIN_ICON, FIXED_DOMAIN_ICONS } from "../const";
|
||||
import { alarmPanelIcon } from "./alarm_panel_icon";
|
||||
import { binarySensorIcon } from "./binary_sensor_icon";
|
||||
import { coverIcon } from "./cover_icon";
|
||||
import { numberIcon } from "./number_icon";
|
||||
import { sensorIcon } from "./sensor_icon";
|
||||
|
||||
export const domainIcon = (
|
||||
domain: string,
|
||||
stateObj?: HassEntity,
|
||||
state?: string
|
||||
): string => {
|
||||
const icon = domainIconWithoutDefault(domain, stateObj, state);
|
||||
if (icon) {
|
||||
return icon;
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
console.warn(`Unable to find icon for domain ${domain}`);
|
||||
return DEFAULT_DOMAIN_ICON;
|
||||
};
|
||||
|
||||
export const domainIconWithoutDefault = (
|
||||
domain: string,
|
||||
stateObj?: HassEntity,
|
||||
state?: string
|
||||
): string | undefined => {
|
||||
const compareState = state !== undefined ? state : stateObj?.state;
|
||||
|
||||
switch (domain) {
|
||||
case "alarm_control_panel":
|
||||
return alarmPanelIcon(compareState);
|
||||
|
||||
case "automation":
|
||||
return compareState === "unavailable"
|
||||
? mdiRobotConfused
|
||||
: compareState === "off"
|
||||
? mdiRobotOff
|
||||
: mdiRobot;
|
||||
|
||||
case "binary_sensor":
|
||||
return binarySensorIcon(compareState, stateObj);
|
||||
|
||||
case "button":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "identify":
|
||||
return mdiCrosshairsQuestion;
|
||||
case "restart":
|
||||
return mdiRestart;
|
||||
case "update":
|
||||
return mdiPackageUp;
|
||||
default:
|
||||
return mdiButtonPointer;
|
||||
}
|
||||
|
||||
case "camera":
|
||||
return compareState === "off" ? mdiVideoOff : mdiVideo;
|
||||
|
||||
case "cover":
|
||||
return coverIcon(compareState, stateObj);
|
||||
|
||||
case "device_tracker":
|
||||
if (stateObj?.attributes.source_type === "router") {
|
||||
return compareState === "home" ? mdiLanConnect : mdiLanDisconnect;
|
||||
}
|
||||
if (
|
||||
["bluetooth", "bluetooth_le"].includes(stateObj?.attributes.source_type)
|
||||
) {
|
||||
return compareState === "home" ? mdiBluetoothConnect : mdiBluetooth;
|
||||
}
|
||||
return compareState === "not_home" ? mdiAccountArrowRight : mdiAccount;
|
||||
|
||||
case "event":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "doorbell":
|
||||
return mdiDoorbell;
|
||||
case "button":
|
||||
return mdiGestureTapButton;
|
||||
case "motion":
|
||||
return mdiMotionSensor;
|
||||
default:
|
||||
return mdiEyeCheck;
|
||||
}
|
||||
|
||||
case "fan":
|
||||
return compareState === "off" ? mdiFanOff : mdiFan;
|
||||
|
||||
case "humidifier":
|
||||
return compareState === "off" ? mdiAirHumidifierOff : mdiAirHumidifier;
|
||||
|
||||
case "input_boolean":
|
||||
return compareState === "on"
|
||||
? mdiCheckCircleOutline
|
||||
: mdiCloseCircleOutline;
|
||||
|
||||
case "input_datetime":
|
||||
if (!stateObj?.attributes.has_date) {
|
||||
return mdiClock;
|
||||
}
|
||||
if (!stateObj.attributes.has_time) {
|
||||
return mdiCalendar;
|
||||
}
|
||||
break;
|
||||
|
||||
case "lock":
|
||||
switch (compareState) {
|
||||
case "unlocked":
|
||||
return mdiLockOpen;
|
||||
case "jammed":
|
||||
return mdiLockAlert;
|
||||
case "locking":
|
||||
case "unlocking":
|
||||
return mdiLockClock;
|
||||
default:
|
||||
return mdiLock;
|
||||
}
|
||||
|
||||
case "media_player":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "speaker":
|
||||
switch (compareState) {
|
||||
case "playing":
|
||||
return mdiSpeakerPlay;
|
||||
case "paused":
|
||||
return mdiSpeakerPause;
|
||||
case "off":
|
||||
return mdiSpeakerOff;
|
||||
default:
|
||||
return mdiSpeaker;
|
||||
}
|
||||
case "tv":
|
||||
switch (compareState) {
|
||||
case "playing":
|
||||
return mdiTelevisionPlay;
|
||||
case "paused":
|
||||
return mdiTelevisionPause;
|
||||
case "off":
|
||||
return mdiTelevisionOff;
|
||||
default:
|
||||
return mdiTelevision;
|
||||
}
|
||||
case "receiver":
|
||||
switch (compareState) {
|
||||
case "off":
|
||||
return mdiAudioVideoOff;
|
||||
default:
|
||||
return mdiAudioVideo;
|
||||
}
|
||||
default:
|
||||
switch (compareState) {
|
||||
case "playing":
|
||||
case "paused":
|
||||
return mdiCastConnected;
|
||||
case "off":
|
||||
return mdiCastOff;
|
||||
default:
|
||||
return mdiCast;
|
||||
}
|
||||
}
|
||||
|
||||
case "number": {
|
||||
const icon = numberIcon(stateObj);
|
||||
if (icon) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "person":
|
||||
return compareState === "not_home" ? mdiAccountArrowRight : mdiAccount;
|
||||
|
||||
case "switch":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "outlet":
|
||||
return compareState === "on" ? mdiPowerPlug : mdiPowerPlugOff;
|
||||
case "switch":
|
||||
return compareState === "on"
|
||||
? mdiToggleSwitchVariant
|
||||
: mdiToggleSwitchVariantOff;
|
||||
default:
|
||||
return mdiToggleSwitchVariant;
|
||||
}
|
||||
|
||||
case "sensor": {
|
||||
const icon = sensorIcon(stateObj);
|
||||
if (icon) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "sun":
|
||||
return stateObj?.state === "above_horizon"
|
||||
? mdiWhiteBalanceSunny
|
||||
: mdiWeatherNight;
|
||||
|
||||
case "switch_as_x":
|
||||
return mdiSwapHorizontal;
|
||||
|
||||
case "threshold":
|
||||
return mdiChartSankey;
|
||||
|
||||
case "update":
|
||||
return compareState === "on"
|
||||
? updateIsInstalling(stateObj as UpdateEntity)
|
||||
? mdiPackageDown
|
||||
: mdiPackageUp
|
||||
: mdiPackage;
|
||||
|
||||
case "valve":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "water":
|
||||
return mdiPipeValve;
|
||||
case "gas":
|
||||
return mdiMeterGas;
|
||||
default:
|
||||
return mdiPipeValve;
|
||||
}
|
||||
|
||||
case "water_heater":
|
||||
return compareState === "off" ? mdiWaterBoilerOff : mdiWaterBoiler;
|
||||
|
||||
case "weather":
|
||||
return weatherIcon(stateObj?.state);
|
||||
}
|
||||
|
||||
if (domain in FIXED_DOMAIN_ICONS) {
|
||||
return FIXED_DOMAIN_ICONS[domain];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
@ -211,6 +211,7 @@ const FIXED_DOMAIN_ATTRIBUTE_STATES = {
|
||||
"volatile_organic_compounds",
|
||||
"volatile_organic_compounds_parts",
|
||||
"voltage",
|
||||
"volume_flow_rate",
|
||||
],
|
||||
state_class: ["measurement", "total", "total_increasing"],
|
||||
},
|
||||
|
@ -1,13 +0,0 @@
|
||||
/** Return an icon representing a number state. */
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { FIXED_DEVICE_CLASS_ICONS } from "../const";
|
||||
|
||||
export const numberIcon = (stateObj?: HassEntity): string | undefined => {
|
||||
const dclass = stateObj?.attributes.device_class;
|
||||
|
||||
if (dclass && dclass in FIXED_DEVICE_CLASS_ICONS) {
|
||||
return FIXED_DEVICE_CLASS_ICONS[dclass];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
@ -1,25 +0,0 @@
|
||||
/** Return an icon representing a sensor state. */
|
||||
import { mdiBattery, mdiThermometer } from "@mdi/js";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { SENSOR_DEVICE_CLASS_BATTERY } from "../../data/sensor";
|
||||
import { FIXED_DEVICE_CLASS_ICONS, UNIT_C, UNIT_F } from "../const";
|
||||
import { batteryStateIcon } from "./battery_icon";
|
||||
|
||||
export const sensorIcon = (stateObj?: HassEntity): string | undefined => {
|
||||
const dclass = stateObj?.attributes.device_class;
|
||||
|
||||
if (dclass && dclass in FIXED_DEVICE_CLASS_ICONS) {
|
||||
return FIXED_DEVICE_CLASS_ICONS[dclass];
|
||||
}
|
||||
|
||||
if (dclass === SENSOR_DEVICE_CLASS_BATTERY) {
|
||||
return stateObj ? batteryStateIcon(stateObj) : mdiBattery;
|
||||
}
|
||||
|
||||
const unit = stateObj?.attributes.unit_of_measurement;
|
||||
if (unit === UNIT_C || unit === UNIT_F) {
|
||||
return mdiThermometer;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
42
src/common/entity/state_icon.ts
Normal file
42
src/common/entity/state_icon.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { computeStateDomain } from "./compute_state_domain";
|
||||
import { updateIcon } from "./update_icon";
|
||||
import { deviceTrackerIcon } from "./device_tracker_icon";
|
||||
import { batteryIcon } from "./battery_icon";
|
||||
|
||||
export const stateIcon = (
|
||||
stateObj: HassEntity,
|
||||
state?: string
|
||||
): string | undefined => {
|
||||
const domain = computeStateDomain(stateObj);
|
||||
const compareState = state ?? stateObj.state;
|
||||
const dc = stateObj.attributes.device_class;
|
||||
switch (domain) {
|
||||
case "update":
|
||||
return updateIcon(stateObj, compareState);
|
||||
|
||||
case "sensor":
|
||||
if (dc === "battery") {
|
||||
return batteryIcon(stateObj, compareState);
|
||||
}
|
||||
break;
|
||||
|
||||
case "device_tracker":
|
||||
return deviceTrackerIcon(stateObj, compareState);
|
||||
|
||||
case "sun":
|
||||
return compareState === "above_horizon"
|
||||
? "mdi:white-balance-sunny"
|
||||
: "mdi:weather-night";
|
||||
|
||||
case "input_datetime":
|
||||
if (!stateObj.attributes.has_date) {
|
||||
return "mdi:clock";
|
||||
}
|
||||
if (!stateObj.attributes.has_time) {
|
||||
return "mdi:calendar";
|
||||
}
|
||||
break;
|
||||
}
|
||||
return undefined;
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
/** Return an icon representing a state. */
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { DEFAULT_DOMAIN_ICON } from "../const";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
import { domainIcon } from "./domain_icon";
|
||||
|
||||
export const stateIconPath = (state: HassEntity | undefined) => {
|
||||
if (!state) {
|
||||
return DEFAULT_DOMAIN_ICON;
|
||||
}
|
||||
return domainIcon(computeDomain(state.entity_id), state);
|
||||
};
|
11
src/common/entity/update_icon.ts
Normal file
11
src/common/entity/update_icon.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UpdateEntity, updateIsInstalling } from "../../data/update";
|
||||
|
||||
export const updateIcon = (stateObj: HassEntity, state?: string) => {
|
||||
const compareState = state ?? stateObj.state;
|
||||
return compareState === "on"
|
||||
? updateIsInstalling(stateObj as UpdateEntity)
|
||||
? "mdi:package-down"
|
||||
: "mdi:package-up"
|
||||
: "mdi:package";
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user