mirror of
https://github.com/home-assistant/frontend.git
synced 2025-09-18 01:19:49 +00:00
Compare commits
101 Commits
20240131.0
...
remove-unc
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f4bfcc6a69 | ||
![]() |
50cf6d2af9 | ||
![]() |
86626b1855 | ||
![]() |
63603a281e | ||
![]() |
faf05f5339 | ||
![]() |
4de3db52cb | ||
![]() |
9a9fbda08b | ||
![]() |
ea642515c1 | ||
![]() |
add2dedc7f | ||
![]() |
4ba4a28aa0 | ||
![]() |
7050453783 | ||
![]() |
8f984517bb | ||
![]() |
2524c96db6 | ||
![]() |
26600e3d78 | ||
![]() |
316756d06a | ||
![]() |
7357b914d0 | ||
![]() |
8548c9767b | ||
![]() |
a30a35f82f | ||
![]() |
84938ccc94 | ||
![]() |
8136cc8008 | ||
![]() |
2dc9d268ec | ||
![]() |
226dad309c | ||
![]() |
33cdd51f00 | ||
![]() |
a3a099126e | ||
![]() |
4e22fea6e2 | ||
![]() |
fd06f28253 | ||
![]() |
553230ca23 | ||
![]() |
208bfebc12 | ||
![]() |
802b0949ac | ||
![]() |
b65dc47f72 | ||
![]() |
c5a3670838 | ||
![]() |
cd167ac645 | ||
![]() |
eb3e756637 | ||
![]() |
5049210524 | ||
![]() |
eeaad86c4b | ||
![]() |
71483e0bc7 | ||
![]() |
10650e8937 | ||
![]() |
99d72ba817 | ||
![]() |
e21ad742b1 | ||
![]() |
1bcb1e7768 | ||
![]() |
618fee98ce | ||
![]() |
83da89437f | ||
![]() |
fac82fa185 | ||
![]() |
17bd7f9476 | ||
![]() |
045ff7a45e | ||
![]() |
8624853ec4 | ||
![]() |
336376d2a5 | ||
![]() |
189793bff4 | ||
![]() |
1e35f973d6 | ||
![]() |
6033f8b31a | ||
![]() |
c3b2ebf380 | ||
![]() |
23cbecb2c4 | ||
![]() |
b1e1b44c75 | ||
![]() |
abb014745a | ||
![]() |
e51c98e1a7 | ||
![]() |
9513699332 | ||
![]() |
b57bc8cd06 | ||
![]() |
d61fc9ec6c | ||
![]() |
d1592bf262 | ||
![]() |
3c744c09f1 | ||
![]() |
3ef61aaf02 | ||
![]() |
c738127c09 | ||
![]() |
6e62f568fc | ||
![]() |
2ba3a991a9 | ||
![]() |
55c6d3a7c4 | ||
![]() |
242f3813bc | ||
![]() |
aa93cb17a7 | ||
![]() |
4692d885d1 | ||
![]() |
b39ac984f9 | ||
![]() |
9894d83e22 | ||
![]() |
113083a241 | ||
![]() |
32971cc875 | ||
![]() |
137f59feb1 | ||
![]() |
6675121b85 | ||
![]() |
aed0a35c9c | ||
![]() |
65a8518d99 | ||
![]() |
cb690e9d4e | ||
![]() |
5da67de95f | ||
![]() |
b9609f2154 | ||
![]() |
aaabb6e1fb | ||
![]() |
6561de34f0 | ||
![]() |
016ff74483 | ||
![]() |
f5e9839b42 | ||
![]() |
eb3b168975 | ||
![]() |
aa400ce6ab | ||
![]() |
682f9a0f04 | ||
![]() |
e478038206 | ||
![]() |
259a9a4f58 | ||
![]() |
b08d1ae7e9 | ||
![]() |
3970fdd070 | ||
![]() |
946445b2df | ||
![]() |
17b090af58 | ||
![]() |
6690a0e4b1 | ||
![]() |
c291448ffa | ||
![]() |
6f831699be | ||
![]() |
fb73bfb964 | ||
![]() |
28a0d216f9 | ||
![]() |
69f2566526 | ||
![]() |
7b3797502a | ||
![]() |
cf960be07e | ||
![]() |
8a410d6c82 |
@@ -2,12 +2,13 @@
|
||||
"name": "Home Assistant Frontend",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"context": "..",
|
||||
"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}",
|
||||
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
||||
},
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
@@ -16,7 +17,7 @@
|
||||
"esbenp.prettier-vscode",
|
||||
"runem.lit-plugin",
|
||||
"github.vscode-pull-request-github",
|
||||
"eamodio.gitlens",
|
||||
"eamodio.gitlens"
|
||||
],
|
||||
"settings": {
|
||||
"files.eol": "\n",
|
||||
@@ -27,17 +28,17 @@
|
||||
"editor.renderWhitespace": "boundary",
|
||||
"editor.rulers": [80],
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"terminal.integrated.shell.linux": "/usr/bin/zsh",
|
||||
"gitlens.showWelcomeOnInstall": false,
|
||||
"gitlens.showWhatsNewAfterUpgrades": false,
|
||||
"workbench.startupEditor": "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
"workbench.startupEditor": "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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
|
||||
|
12
.github/workflows/ci.yaml
vendored
12
.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
|
||||
@@ -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.3.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.3.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.3.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.3.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 }}
|
||||
|
2
.github/workflows/release.yaml
vendored
2
.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
|
||||
|
@@ -0,0 +1,13 @@
|
||||
diff --git a/simple-tooltip.js b/simple-tooltip.js
|
||||
index 78a87f6a223925f0e29fbedb268c85a142ec6985..3d686dd6a3d5a93342b4b01408089fc316b408ca 100644
|
||||
--- a/simple-tooltip.js
|
||||
+++ b/simple-tooltip.js
|
||||
@@ -195,6 +195,8 @@ class SimpleTooltip extends LitElement {
|
||||
.hidden {
|
||||
position: absolute;
|
||||
left: -10000px;
|
||||
+ inset-inline-start: -10000px;
|
||||
+ inset-inline-end: initial;
|
||||
top: auto;
|
||||
width: 1px;
|
||||
height: 1px;
|
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.0.cjs
|
||||
|
@@ -1,19 +1,26 @@
|
||||
// Tasks to compress
|
||||
|
||||
import { deleteAsync } from "del";
|
||||
import gulp from "gulp";
|
||||
import gulpIf from "gulp-if";
|
||||
import vinylPaths from "vinyl-paths";
|
||||
import zopfli from "gulp-zopfli-green";
|
||||
import paths from "../paths.cjs";
|
||||
|
||||
const zopfliOptions = { threshold: 150 };
|
||||
|
||||
const compressedExt = /\.gz$/;
|
||||
const deleteUncompressed = (p) => deleteAsync(p.replace(compressedExt, ""));
|
||||
|
||||
const compressDist = (rootDir) =>
|
||||
gulp
|
||||
.src([
|
||||
`${rootDir}/**/*.{js,json,css,svg,xml}`,
|
||||
`${rootDir}/**/*.{js?(.map),json,css,svg,xml}`,
|
||||
`${rootDir}/{authorize,onboarding}.html`,
|
||||
])
|
||||
.pipe(zopfli(zopfliOptions))
|
||||
.pipe(gulp.dest(rootDir));
|
||||
.pipe(gulp.dest(rootDir))
|
||||
.pipe(gulpIf(compressedExt, vinylPaths(deleteUncompressed)));
|
||||
|
||||
gulp.task("compress-app", () => compressDist(paths.app_output_root));
|
||||
gulp.task("compress-hassio", () => compressDist(paths.hassio_output_root));
|
||||
|
@@ -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",
|
||||
|
@@ -28,7 +28,6 @@ class HcLaunchScreen extends LitElement {
|
||||
:host {
|
||||
display: block;
|
||||
height: 100vh;
|
||||
padding-top: 64px;
|
||||
background-color: white;
|
||||
font-size: 24px;
|
||||
}
|
||||
@@ -36,17 +35,13 @@ class HcLaunchScreen extends LitElement {
|
||||
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;
|
||||
}
|
||||
.status {
|
||||
padding-right: 54px;
|
||||
padding-inline-end: 54px;
|
||||
padding-inline-start: initial;
|
||||
max-width: 80%;
|
||||
object-fit: cover;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@@ -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>
|
||||
`;
|
||||
@@ -226,9 +226,9 @@ export class HcMain extends HassElement {
|
||||
this.initializeHass(auth, connection);
|
||||
if (this._hassUUID !== msg.hassUUID) {
|
||||
this._hassUUID = msg.hassUUID;
|
||||
this._lovelacePath = null;
|
||||
this._urlPath = undefined;
|
||||
this._lovelaceConfig = undefined;
|
||||
this._urlPath = undefined;
|
||||
this._lovelacePath = null;
|
||||
if (this._unsubLovelace) {
|
||||
this._unsubLovelace();
|
||||
this._unsubLovelace = undefined;
|
||||
@@ -285,7 +285,7 @@ export class HcMain extends HassElement {
|
||||
],
|
||||
};
|
||||
this._urlPath = "energy";
|
||||
this._lovelacePath = 0;
|
||||
this._lovelacePath = null;
|
||||
this._sendStatus();
|
||||
return;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
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>
|
||||
`;
|
||||
|
@@ -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";
|
||||
|
@@ -275,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!" } },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -501,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`
|
||||
@@ -534,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", {
|
||||
@@ -66,6 +67,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", {
|
||||
@@ -123,6 +124,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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", {
|
||||
@@ -116,6 +117,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", {
|
||||
@@ -184,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 = [
|
||||
@@ -291,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(
|
||||
@@ -397,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");
|
||||
}
|
||||
|
49
package.json
49
package.json
@@ -29,11 +29,11 @@
|
||||
"@braintree/sanitize-url": "7.0.0",
|
||||
"@codemirror/autocomplete": "6.12.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/search": "6.5.6",
|
||||
"@codemirror/state": "6.4.0",
|
||||
"@codemirror/view": "6.23.1",
|
||||
"@codemirror/view": "6.24.0",
|
||||
"@egjs/hammerjs": "2.0.17",
|
||||
"@formatjs/intl-datetimeformat": "6.12.2",
|
||||
"@formatjs/intl-displaynames": "6.6.6",
|
||||
@@ -51,10 +51,10 @@
|
||||
"@fullcalendar/timegrid": "6.1.10",
|
||||
"@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": "8.0.0",
|
||||
"@lrnwebcomponents/simple-tooltip": "patch:@lrnwebcomponents/simple-tooltip@npm%3A8.0.0#~/.yarn/patches/@lrnwebcomponents-simple-tooltip-npm-8.0.0-77591f2e0c.patch",
|
||||
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/mwc-base": "0.27.0",
|
||||
@@ -89,8 +89,8 @@
|
||||
"@polymer/paper-toast": "3.0.1",
|
||||
"@polymer/polymer": "3.5.1",
|
||||
"@thomasloven/round-slider": "0.6.0",
|
||||
"@vaadin/combo-box": "24.3.4",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.4",
|
||||
"@vaadin/combo-box": "24.3.6",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.6",
|
||||
"@vibrant/color": "3.2.1-alpha.1",
|
||||
"@vibrant/core": "3.2.1-alpha.1",
|
||||
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
|
||||
@@ -100,7 +100,7 @@
|
||||
"app-datepicker": "5.1.1",
|
||||
"chart.js": "4.4.1",
|
||||
"comlink": "4.4.1",
|
||||
"core-js": "3.35.1",
|
||||
"core-js": "3.36.0",
|
||||
"cropperjs": "1.6.1",
|
||||
"date-fns": "2.30.0",
|
||||
"date-fns-tz": "2.0.0",
|
||||
@@ -109,7 +109,7 @@
|
||||
"element-internals-polyfill": "1.3.10",
|
||||
"fuse.js": "7.0.0",
|
||||
"google-timezones-json": "1.2.0",
|
||||
"hls.js": "1.5.2",
|
||||
"hls.js": "1.5.5",
|
||||
"home-assistant-js-websocket": "9.1.0",
|
||||
"idb-keyval": "6.2.1",
|
||||
"intl-messageformat": "10.5.11",
|
||||
@@ -118,7 +118,7 @@
|
||||
"leaflet-draw": "1.0.4",
|
||||
"lit": "2.8.0",
|
||||
"luxon": "3.4.4",
|
||||
"marked": "11.2.0",
|
||||
"marked": "12.0.0",
|
||||
"memoize-one": "6.0.0",
|
||||
"node-vibrant": "3.2.1-alpha.1",
|
||||
"proxy-polyfill": "0.3.2",
|
||||
@@ -155,7 +155,7 @@
|
||||
"@babel/plugin-transform-runtime": "7.23.9",
|
||||
"@babel/preset-env": "7.23.9",
|
||||
"@babel/preset-typescript": "7.23.3",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.9.2",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.10.0",
|
||||
"@koa/cors": "5.0.0",
|
||||
"@lokalise/node-api": "12.1.0",
|
||||
"@octokit/auth-oauth-device": "6.0.1",
|
||||
@@ -171,6 +171,7 @@
|
||||
"@types/chromecast-caf-receiver": "6.0.13",
|
||||
"@types/chromecast-caf-sender": "1.0.8",
|
||||
"@types/glob": "8.1.0",
|
||||
"@types/gulp-if": "^3",
|
||||
"@types/html-minifier-terser": "7.0.2",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/leaflet": "1.9.8",
|
||||
@@ -183,13 +184,13 @@
|
||||
"@types/tar": "6.1.11",
|
||||
"@types/ua-parser-js": "0.7.39",
|
||||
"@types/webspeechapi": "0.0.29",
|
||||
"@typescript-eslint/eslint-plugin": "6.19.1",
|
||||
"@typescript-eslint/parser": "6.19.1",
|
||||
"@typescript-eslint/eslint-plugin": "7.0.1",
|
||||
"@typescript-eslint/parser": "7.0.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.3",
|
||||
"chai": "5.1.0",
|
||||
"del": "7.1.0",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
@@ -199,32 +200,33 @@
|
||||
"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-if": "3.0.0",
|
||||
"gulp-json-transform": "0.4.8",
|
||||
"gulp-merge-json": "2.1.2",
|
||||
"gulp-rename": "2.0.0",
|
||||
"gulp-zopfli-green": "6.0.1",
|
||||
"html-minifier-terser": "7.2.0",
|
||||
"husky": "9.0.6",
|
||||
"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.7",
|
||||
"map-stream": "0.0.7",
|
||||
"mocha": "10.2.0",
|
||||
"mocha": "10.3.0",
|
||||
"object-hash": "3.0.0",
|
||||
"open": "10.0.3",
|
||||
"pinst": "3.0.0",
|
||||
"prettier": "3.2.4",
|
||||
"prettier": "3.2.5",
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-string": "3.0.0",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
@@ -239,8 +241,9 @@
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.3.3",
|
||||
"vinyl-buffer": "1.0.1",
|
||||
"vinyl-paths": "5.0.0",
|
||||
"vinyl-source-stream": "2.0.0",
|
||||
"webpack": "5.90.0",
|
||||
"webpack": "5.90.2",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"webpack-manifest-plugin": "5.0.0",
|
||||
@@ -258,5 +261,5 @@
|
||||
"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.0"
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20240131.0"
|
||||
version = "20240207.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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -38,4 +38,8 @@ export function setDirectionStyles(direction: string, element: LitElement) {
|
||||
"--margin-title",
|
||||
direction === "ltr" ? "var(--margin-title-ltr)" : "var(--margin-title-rtl)"
|
||||
);
|
||||
element.style.setProperty(
|
||||
"--scale-direction",
|
||||
direction === "ltr" ? "1" : "-1"
|
||||
);
|
||||
}
|
||||
|
@@ -5,12 +5,19 @@ import type {
|
||||
ChartOptions,
|
||||
TooltipModel,
|
||||
} from "chart.js";
|
||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
nothing,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { clamp } from "../../common/number/clamp";
|
||||
import { computeRTL } from "../../common/util/compute_rtl";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
|
||||
@@ -28,6 +35,11 @@ interface Tooltip
|
||||
left: string;
|
||||
}
|
||||
|
||||
export interface ChartDatasetExtra {
|
||||
show_legend?: boolean;
|
||||
legend_label?: string;
|
||||
}
|
||||
|
||||
@customElement("ha-chart-base")
|
||||
export class HaChartBase extends LitElement {
|
||||
public chart?: Chart;
|
||||
@@ -39,6 +51,8 @@ export class HaChartBase extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public data: ChartData = { datasets: [] };
|
||||
|
||||
@property({ attribute: false }) public extraData?: ChartDatasetExtra[];
|
||||
|
||||
@property({ attribute: false }) public options?: ChartOptions;
|
||||
|
||||
@property({ attribute: false }) public plugins?: any[];
|
||||
@@ -47,6 +61,8 @@ export class HaChartBase extends LitElement {
|
||||
|
||||
@property({ type: Number }) public paddingYAxis = 0;
|
||||
|
||||
@property({ type: Boolean }) public externalHidden = false;
|
||||
|
||||
@state() private _chartHeight?: number;
|
||||
|
||||
@state() private _tooltip?: Tooltip;
|
||||
@@ -149,6 +165,19 @@ export class HaChartBase extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
if (changedProps.has("data")) {
|
||||
if (this.externalHidden) {
|
||||
this._hiddenDatasets = new Set();
|
||||
if (this.data?.datasets) {
|
||||
this.data.datasets.forEach((dataset, index) => {
|
||||
if (dataset.hidden) {
|
||||
this._hiddenDatasets.add(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.hasUpdated || !this.chart) {
|
||||
return;
|
||||
}
|
||||
@@ -158,7 +187,7 @@ export class HaChartBase extends LitElement {
|
||||
return;
|
||||
}
|
||||
if (changedProps.has("data")) {
|
||||
if (this._hiddenDatasets.size) {
|
||||
if (this._hiddenDatasets.size && !this.externalHidden) {
|
||||
this.data.datasets.forEach((dataset, index) => {
|
||||
dataset.hidden = this._hiddenDatasets.has(index);
|
||||
});
|
||||
@@ -176,25 +205,30 @@ export class HaChartBase extends LitElement {
|
||||
${this.options?.plugins?.legend?.display === true
|
||||
? html`<div class="chartLegend">
|
||||
<ul>
|
||||
${this.data.datasets.map(
|
||||
(dataset, index) =>
|
||||
html`<li
|
||||
.datasetIndex=${index}
|
||||
@click=${this._legendClick}
|
||||
class=${classMap({
|
||||
hidden: this._hiddenDatasets.has(index),
|
||||
})}
|
||||
.title=${dataset.label}
|
||||
>
|
||||
<div
|
||||
class="bullet"
|
||||
style=${styleMap({
|
||||
backgroundColor: dataset.backgroundColor as string,
|
||||
borderColor: dataset.borderColor as string,
|
||||
${this.data.datasets.map((dataset, index) =>
|
||||
this.extraData?.[index]?.show_legend === false
|
||||
? nothing
|
||||
: html`<li
|
||||
.datasetIndex=${index}
|
||||
@click=${this._legendClick}
|
||||
class=${classMap({
|
||||
hidden: this._hiddenDatasets.has(index),
|
||||
})}
|
||||
></div>
|
||||
<div class="label">${dataset.label}</div>
|
||||
</li>`
|
||||
.title=${this.extraData?.[index]?.legend_label ??
|
||||
dataset.label}
|
||||
>
|
||||
<div
|
||||
class="bullet"
|
||||
style=${styleMap({
|
||||
backgroundColor: dataset.backgroundColor as string,
|
||||
borderColor: dataset.borderColor as string,
|
||||
})}
|
||||
></div>
|
||||
<div class="label">
|
||||
${this.extraData?.[index]?.legend_label ??
|
||||
dataset.label}
|
||||
</div>
|
||||
</li>`
|
||||
)}
|
||||
</ul>
|
||||
</div>`
|
||||
@@ -212,12 +246,10 @@ export class HaChartBase extends LitElement {
|
||||
height: `${
|
||||
this.height ?? this._chartHeight ?? this.clientWidth / 2
|
||||
}px`,
|
||||
"padding-left": `${
|
||||
computeRTL(this.hass) ? 0 : this._paddingYAxisInternal
|
||||
}px`,
|
||||
"padding-right": `${
|
||||
computeRTL(this.hass) ? this._paddingYAxisInternal : 0
|
||||
}px`,
|
||||
"padding-left": `${this._paddingYAxisInternal}px`,
|
||||
"padding-right": 0,
|
||||
"padding-inline-start": `${this._paddingYAxisInternal}px`,
|
||||
"padding-inline-end": 0,
|
||||
})}
|
||||
>
|
||||
<canvas></canvas>
|
||||
@@ -342,9 +374,19 @@ export class HaChartBase extends LitElement {
|
||||
if (this.chart.isDatasetVisible(index)) {
|
||||
this.chart.setDatasetVisibility(index, false);
|
||||
this._hiddenDatasets.add(index);
|
||||
if (this.externalHidden) {
|
||||
fireEvent(this, "dataset-hidden", {
|
||||
index,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.chart.setDatasetVisibility(index, true);
|
||||
this._hiddenDatasets.delete(index);
|
||||
if (this.externalHidden) {
|
||||
fireEvent(this, "dataset-unhidden", {
|
||||
index,
|
||||
});
|
||||
}
|
||||
}
|
||||
this.chart.update("none");
|
||||
this.requestUpdate("_hiddenDatasets");
|
||||
@@ -433,14 +475,6 @@ export class HaChartBase extends LitElement {
|
||||
.chartTooltip .bullet {
|
||||
align-self: baseline;
|
||||
}
|
||||
:host([rtl]) .chartLegend .bullet,
|
||||
:host([rtl]) .chartTooltip .bullet {
|
||||
margin-right: inherit;
|
||||
margin-left: 6px;
|
||||
margin-inline-end: inherit;
|
||||
margin-inline-start: 6px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.chartTooltip {
|
||||
padding: 8px;
|
||||
font-size: 90%;
|
||||
@@ -449,12 +483,13 @@ export class HaChartBase extends LitElement {
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
z-index: 1;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
width: 200px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
:host([rtl]) .chartTooltip {
|
||||
direction: rtl;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.chartLegend ul,
|
||||
.chartTooltip ul {
|
||||
@@ -496,4 +531,8 @@ declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-chart-base": HaChartBase;
|
||||
}
|
||||
interface HASSDomEvents {
|
||||
"dataset-hidden": { index: number };
|
||||
"dataset-unhidden": { index: number };
|
||||
}
|
||||
}
|
||||
|
@@ -220,7 +220,12 @@ export class StateHistoryChartLine extends LitElement {
|
||||
// @ts-expect-error
|
||||
locale: numberFormatToLocale(this.hass.locale),
|
||||
onClick: (e: any) => {
|
||||
if (!this.clickForMoreInfo) {
|
||||
if (
|
||||
!this.clickForMoreInfo ||
|
||||
!(e.native instanceof MouseEvent) ||
|
||||
(e.native instanceof PointerEvent &&
|
||||
e.native.pointerType !== "mouse")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -224,7 +224,11 @@ export class StateHistoryChartTimeline extends LitElement {
|
||||
// @ts-expect-error
|
||||
locale: numberFormatToLocale(this.hass.locale),
|
||||
onClick: (e: any) => {
|
||||
if (!this.clickForMoreInfo) {
|
||||
if (
|
||||
!this.clickForMoreInfo ||
|
||||
!(e.native instanceof MouseEvent) ||
|
||||
(e.native instanceof PointerEvent && e.native.pointerType !== "mouse")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -32,7 +32,11 @@ import {
|
||||
} from "../../data/recorder";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import "./ha-chart-base";
|
||||
import type { ChartResizeOptions, HaChartBase } from "./ha-chart-base";
|
||||
import type {
|
||||
ChartResizeOptions,
|
||||
ChartDatasetExtra,
|
||||
HaChartBase,
|
||||
} from "./ha-chart-base";
|
||||
|
||||
export const supportedStatTypeMap: Record<StatisticType, StatisticType> = {
|
||||
mean: "mean",
|
||||
@@ -79,10 +83,14 @@ export class StatisticsChart extends LitElement {
|
||||
|
||||
@state() private _chartData: ChartData = { datasets: [] };
|
||||
|
||||
@state() private _chartDatasetExtra: ChartDatasetExtra[] = [];
|
||||
|
||||
@state() private _statisticIds: string[] = [];
|
||||
|
||||
@state() private _chartOptions?: ChartOptions;
|
||||
|
||||
@state() private _hiddenStats = new Set<string>();
|
||||
|
||||
@query("ha-chart-base") private _chart?: HaChartBase;
|
||||
|
||||
private _computedStyle?: CSSStyleDeclaration;
|
||||
@@ -96,6 +104,9 @@ export class StatisticsChart extends LitElement {
|
||||
}
|
||||
|
||||
public willUpdate(changedProps: PropertyValues) {
|
||||
if (changedProps.has("legendMode")) {
|
||||
this._hiddenStats.clear();
|
||||
}
|
||||
if (
|
||||
!this.hasUpdated ||
|
||||
changedProps.has("unit") ||
|
||||
@@ -110,7 +121,8 @@ export class StatisticsChart extends LitElement {
|
||||
changedProps.has("statisticsData") ||
|
||||
changedProps.has("statTypes") ||
|
||||
changedProps.has("chartType") ||
|
||||
changedProps.has("hideLegend")
|
||||
changedProps.has("hideLegend") ||
|
||||
changedProps.has("_hiddenStats")
|
||||
) {
|
||||
this._generateData();
|
||||
}
|
||||
@@ -145,14 +157,30 @@ export class StatisticsChart extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-chart-base
|
||||
externalHidden
|
||||
.hass=${this.hass}
|
||||
.data=${this._chartData}
|
||||
.extraData=${this._chartDatasetExtra}
|
||||
.options=${this._chartOptions}
|
||||
.chartType=${this.chartType}
|
||||
@dataset-hidden=${this._datasetHidden}
|
||||
@dataset-unhidden=${this._datasetUnhidden}
|
||||
></ha-chart-base>
|
||||
`;
|
||||
}
|
||||
|
||||
private _datasetHidden(ev) {
|
||||
ev.stopPropagation();
|
||||
this._hiddenStats.add(this._statisticIds[ev.detail.index]);
|
||||
this.requestUpdate("_hiddenStats");
|
||||
}
|
||||
|
||||
private _datasetUnhidden(ev) {
|
||||
ev.stopPropagation();
|
||||
this._hiddenStats.delete(this._statisticIds[ev.detail.index]);
|
||||
this.requestUpdate("_hiddenStats");
|
||||
}
|
||||
|
||||
private _createOptions(unit?: string) {
|
||||
this._chartOptions = {
|
||||
parsing: false,
|
||||
@@ -274,6 +302,7 @@ export class StatisticsChart extends LitElement {
|
||||
let colorIndex = 0;
|
||||
const statisticsData = Object.entries(this.statisticsData);
|
||||
const totalDataSets: ChartDataset<"line">[] = [];
|
||||
const totalDatasetExtras: ChartDatasetExtra[] = [];
|
||||
const statisticIds: string[] = [];
|
||||
let endTime: Date;
|
||||
|
||||
@@ -324,6 +353,7 @@ export class StatisticsChart extends LitElement {
|
||||
|
||||
// The datasets for the current statistic
|
||||
const statDataSets: ChartDataset<"line">[] = [];
|
||||
const statDatasetExtras: ChartDatasetExtra[] = [];
|
||||
|
||||
const pushData = (
|
||||
start: Date,
|
||||
@@ -384,9 +414,20 @@ export class StatisticsChart extends LitElement {
|
||||
})
|
||||
: this.statTypes;
|
||||
|
||||
let displayed_legend = false;
|
||||
sortedTypes.forEach((type) => {
|
||||
if (statisticsHaveType(stats, type)) {
|
||||
const band = drawBands && (type === "min" || type === "max");
|
||||
if (!this.hideLegend) {
|
||||
const show_legend = hasMean
|
||||
? type === "mean"
|
||||
: displayed_legend === false;
|
||||
statDatasetExtras.push({
|
||||
legend_label: name,
|
||||
show_legend,
|
||||
});
|
||||
displayed_legend = displayed_legend || show_legend;
|
||||
}
|
||||
statTypes.push(type);
|
||||
statDataSets.push({
|
||||
label: name
|
||||
@@ -408,6 +449,9 @@ export class StatisticsChart extends LitElement {
|
||||
band && hasMean ? color + (this.hideLegend ? "00" : "7F") : color,
|
||||
backgroundColor: band ? color + "3F" : color + "7F",
|
||||
pointRadius: 0,
|
||||
hidden: !this.hideLegend
|
||||
? this._hiddenStats.has(statistic_id)
|
||||
: false,
|
||||
data: [],
|
||||
// @ts-ignore
|
||||
unit: meta?.unit_of_measurement,
|
||||
@@ -446,6 +490,7 @@ export class StatisticsChart extends LitElement {
|
||||
|
||||
// Concat two arrays
|
||||
Array.prototype.push.apply(totalDataSets, statDataSets);
|
||||
Array.prototype.push.apply(totalDatasetExtras, statDatasetExtras);
|
||||
});
|
||||
|
||||
if (unit) {
|
||||
@@ -455,6 +500,7 @@ export class StatisticsChart extends LitElement {
|
||||
this._chartData = {
|
||||
datasets: totalDataSets,
|
||||
};
|
||||
this._chartDatasetExtra = totalDatasetExtras;
|
||||
this._statisticIds = statisticIds;
|
||||
}
|
||||
|
||||
|
@@ -688,15 +688,12 @@ export class HaDataTable extends LitElement {
|
||||
padding-left: 16px;
|
||||
/* @noflip */
|
||||
padding-right: 0;
|
||||
/* @noflip */
|
||||
padding-inline-start: 16px;
|
||||
/* @noflip */
|
||||
padding-inline-end: initial;
|
||||
width: 60px;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell--checkbox,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--checkbox {
|
||||
/* @noflip */
|
||||
padding-left: 0;
|
||||
/* @noflip */
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.mdc-data-table__table {
|
||||
height: 100%;
|
||||
@@ -723,11 +720,7 @@ export class HaDataTable extends LitElement {
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--numeric {
|
||||
text-align: right;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--numeric {
|
||||
/* @noflip */
|
||||
text-align: left;
|
||||
text-align: var(--float-end);
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--icon {
|
||||
@@ -753,15 +746,7 @@ export class HaDataTable extends LitElement {
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(
|
||||
.not-sorted
|
||||
) {
|
||||
text-align: left;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:hover,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(
|
||||
.not-sorted
|
||||
) {
|
||||
text-align: right;
|
||||
text-align: var(--float-start);
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--icon:first-child img,
|
||||
@@ -771,27 +756,14 @@ export class HaDataTable extends LitElement {
|
||||
.mdc-data-table__cell--icon:first-child ha-domain-icon,
|
||||
.mdc-data-table__cell--icon:first-child ha-service-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--icon:first-child ha-icon,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__cell--icon:first-child
|
||||
ha-state-icon,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__cell--icon:first-child
|
||||
ha-svg-icon
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__cell--icon:first-child
|
||||
img {
|
||||
margin-left: auto;
|
||||
margin-right: 8px;
|
||||
margin-inline-start: 8px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--icon:first-child state-badge {
|
||||
margin-right: -8px;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--icon:first-child state-badge {
|
||||
margin-right: auto;
|
||||
margin-left: -8px;
|
||||
margin-inline-end: -8px;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--overflow-menu,
|
||||
@@ -824,15 +796,8 @@ export class HaDataTable extends LitElement {
|
||||
.mdc-data-table__header-cell--icon-button:first-child,
|
||||
.mdc-data-table__cell--icon-button:first-child {
|
||||
padding-left: 16px;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell--overflow-menu:first-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--overflow-menu:first-child,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell--overflow-menu:first-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--overflow-menu:first-child {
|
||||
padding-left: 8px;
|
||||
padding-right: 16px;
|
||||
padding-inline-start: 16px;
|
||||
padding-inline-end: initial;
|
||||
}
|
||||
|
||||
.mdc-data-table__cell--overflow-menu:last-child,
|
||||
@@ -840,14 +805,8 @@ export class HaDataTable extends LitElement {
|
||||
.mdc-data-table__header-cell--icon-button:last-child,
|
||||
.mdc-data-table__cell--icon-button:last-child {
|
||||
padding-right: 16px;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell--overflow-menu:last-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--overflow-menu:last-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell--icon-button:last-child,
|
||||
:host([dir="rtl"]) .mdc-data-table__cell--icon-button:last-child {
|
||||
padding-right: 8px;
|
||||
padding-left: 16px;
|
||||
padding-inline-end: 16px;
|
||||
padding-inline-start: initial;
|
||||
}
|
||||
.mdc-data-table__cell--overflow-menu,
|
||||
.mdc-data-table__header-cell--overflow-menu {
|
||||
@@ -867,28 +826,15 @@ export class HaDataTable extends LitElement {
|
||||
letter-spacing: 0.0071428571em;
|
||||
text-decoration: inherit;
|
||||
text-transform: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell {
|
||||
/* @noflip */
|
||||
text-align: right;
|
||||
text-align: var(--float-start);
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell--numeric {
|
||||
text-align: right;
|
||||
text-align: var(--float-end);
|
||||
}
|
||||
.mdc-data-table__header-cell--numeric.sortable:hover,
|
||||
.mdc-data-table__header-cell--numeric.sortable:not(.not-sorted) {
|
||||
text-align: left;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell--numeric {
|
||||
/* @noflip */
|
||||
text-align: left;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell--numeric.sortable:hover,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell--numeric.sortable:not(.not-sorted) {
|
||||
text-align: right;
|
||||
text-align: var(--float-start);
|
||||
}
|
||||
|
||||
/* custom from here */
|
||||
@@ -909,20 +855,15 @@ export class HaDataTable extends LitElement {
|
||||
.mdc-data-table__header-cell span {
|
||||
position: relative;
|
||||
left: 0px;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell span {
|
||||
left: auto;
|
||||
right: 0px;
|
||||
inset-inline-start: 0px;
|
||||
inset-inline-end: initial;
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell.sortable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.mdc-data-table__header-cell > * {
|
||||
transition: left 0.2s ease;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell > * {
|
||||
transition: right 0.2s ease;
|
||||
transition: var(--float-start) 0.2s ease;
|
||||
}
|
||||
.mdc-data-table__header-cell ha-svg-icon {
|
||||
top: -3px;
|
||||
@@ -930,35 +871,20 @@ export class HaDataTable extends LitElement {
|
||||
}
|
||||
.mdc-data-table__header-cell.not-sorted ha-svg-icon {
|
||||
left: -20px;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-data-table__header-cell.not-sorted ha-svg-icon {
|
||||
right: -20px;
|
||||
inset-inline-start: -20px;
|
||||
inset-inline-end: initial;
|
||||
}
|
||||
.mdc-data-table__header-cell.sortable:not(.not-sorted) span,
|
||||
.mdc-data-table__header-cell.sortable.not-sorted:hover span {
|
||||
left: 24px;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell.sortable:not(.not-sorted)
|
||||
span,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell.sortable.not-sorted:hover
|
||||
span {
|
||||
left: auto;
|
||||
right: 24px;
|
||||
inset-inline-start: 24px;
|
||||
inset-inline-end: initial;
|
||||
}
|
||||
.mdc-data-table__header-cell.sortable:not(.not-sorted) ha-svg-icon,
|
||||
.mdc-data-table__header-cell.sortable:hover.not-sorted ha-svg-icon {
|
||||
left: 12px;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell.sortable:not(.not-sorted)
|
||||
ha-svg-icon,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell.sortable:hover.not-sorted
|
||||
ha-svg-icon {
|
||||
left: auto;
|
||||
right: 12px;
|
||||
inset-inline-start: 12px;
|
||||
inset-inline-end: initial;
|
||||
}
|
||||
.table-header {
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
@@ -966,6 +892,8 @@ export class HaDataTable extends LitElement {
|
||||
search-input {
|
||||
display: block;
|
||||
flex: 1;
|
||||
--mdc-text-field-fill-color: var(--sidebar-background-color);
|
||||
--mdc-text-field-idle-line-color: transparent;
|
||||
}
|
||||
slot[name="header"] {
|
||||
display: block;
|
||||
|
@@ -9,6 +9,7 @@ import {
|
||||
localizeWeekdays,
|
||||
localizeMonths,
|
||||
} from "../common/datetime/localize_date";
|
||||
import { mainWindow } from "../common/dom/get_main_window";
|
||||
|
||||
// Set the current date to the left picker instead of the right picker because the right is hidden
|
||||
const CustomDateRangePicker = Vue.extend({
|
||||
@@ -157,7 +158,7 @@ class DateRangePickerElement extends WrappedElement {
|
||||
min-width: initial !important;
|
||||
max-height: var(--date-range-picker-max-height);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
.daterangepicker:before {
|
||||
display: none;
|
||||
}
|
||||
@@ -267,15 +268,37 @@ class DateRangePickerElement extends WrappedElement {
|
||||
.calendar-table {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.daterangepicker.ltr {
|
||||
.calendar-time {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
.daterangepicker.ltr {
|
||||
direction: var(--direction);
|
||||
text-align: var(--float-start);
|
||||
}
|
||||
.vue-daterange-picker{
|
||||
min-width: unset !important;
|
||||
display: block !important;
|
||||
}
|
||||
`;
|
||||
if (mainWindow.document.dir === "rtl") {
|
||||
style.innerHTML += `
|
||||
.daterangepicker .calendar-table .next span {
|
||||
transform: rotate(135deg);
|
||||
-webkit-transform: rotate(135deg);
|
||||
}
|
||||
.daterangepicker .calendar-table .prev span {
|
||||
transform: rotate(-45deg);
|
||||
-webkit-transform: rotate(-45deg);
|
||||
}
|
||||
.daterangepicker td.start-date {
|
||||
border-radius: 0 50% 50% 0;
|
||||
}
|
||||
.daterangepicker td.end-date {
|
||||
border-radius: 50% 0 0 50%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
const shadowRoot = this.shadowRoot!;
|
||||
shadowRoot.appendChild(style);
|
||||
// Stop click events from reaching the document, otherwise it will close the picker immediately.
|
||||
|
@@ -133,9 +133,9 @@ export class HaStateLabelBadge extends LitElement {
|
||||
entityState,
|
||||
this._timerTimeRemaining
|
||||
)}
|
||||
.description=${this.showName === false
|
||||
? undefined
|
||||
: this.name ?? computeStateName(entityState)}
|
||||
.description=${this.showName
|
||||
? this.name ?? computeStateName(entityState)
|
||||
: undefined}
|
||||
>
|
||||
${!image && showIcon
|
||||
? html`<ha-state-icon
|
||||
|
@@ -3,7 +3,6 @@ import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { computeRTL } from "../../common/util/compute_rtl";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import "../ha-relative-time";
|
||||
import "./state-badge";
|
||||
@@ -16,9 +15,6 @@ class StateInfo extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public inDialog = false;
|
||||
|
||||
// property used only in CSS
|
||||
@property({ type: Boolean, reflect: true }) public rtl = false;
|
||||
|
||||
@property() public color?: string;
|
||||
|
||||
protected render() {
|
||||
@@ -79,18 +75,6 @@ class StateInfo extends LitElement {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
protected updated(changedProps) {
|
||||
super.updated(changedProps);
|
||||
if (!changedProps.has("hass")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || oldHass.locale !== this.hass.locale) {
|
||||
this.rtl = computeRTL(this.hass);
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
:host {
|
||||
@@ -106,17 +90,14 @@ class StateInfo extends LitElement {
|
||||
|
||||
.info {
|
||||
margin-left: 8px;
|
||||
margin-inline-start: 8px;
|
||||
margin-inline-end: initial;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
:host([rtl]) .info {
|
||||
margin-right: 8px;
|
||||
margin-left: 0;
|
||||
text-align: right;
|
||||
text-align: var(--float-start);
|
||||
}
|
||||
|
||||
.name {
|
||||
|
@@ -69,6 +69,7 @@ export class HaButtonToggleGroup extends LitElement {
|
||||
display: flex;
|
||||
--mdc-icon-button-size: var(--button-toggle-size, 36px);
|
||||
--mdc-icon-size: var(--button-toggle-icon-size, 20px);
|
||||
direction: ltr;
|
||||
}
|
||||
mwc-button {
|
||||
--mdc-shape-small: 0;
|
||||
@@ -119,19 +120,6 @@ export class HaButtonToggleGroup extends LitElement {
|
||||
--mdc-shape-small: 4px;
|
||||
border-right-width: 1px;
|
||||
}
|
||||
|
||||
:host([dir="rtl"]) ha-icon-button:first-child,
|
||||
:host([dir="rtl"]) mwc-button:first-child {
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-right-width: 1px;
|
||||
--mdc-shape-small: 0 4px 4px 0;
|
||||
--mdc-button-outline-width: 1px;
|
||||
}
|
||||
:host([dir="rtl"]) ha-icon-button:last-child,
|
||||
:host([dir="rtl"]) mwc-button:last-child {
|
||||
--mdc-shape-small: 4px 0 0 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@@ -32,7 +32,6 @@ import { firstWeekdayIndex } from "../common/datetime/first_weekday";
|
||||
import { formatDate } from "../common/datetime/format_date";
|
||||
import { formatDateTime } from "../common/datetime/format_date_time";
|
||||
import { useAmPm } from "../common/datetime/use_am_pm";
|
||||
import { computeRTLDirection } from "../common/util/compute_rtl";
|
||||
import { HomeAssistant } from "../types";
|
||||
import "./date-range-picker";
|
||||
import "./ha-icon-button";
|
||||
@@ -65,8 +64,6 @@ export class HaDateRangePicker extends LitElement {
|
||||
|
||||
@state() private _hour24format = false;
|
||||
|
||||
@state() private _rtlDirection = "ltr";
|
||||
|
||||
@property({ type: Boolean }) public extendedPresets = false;
|
||||
|
||||
@property() public openingDirection?: "right" | "left" | "center" | "inline";
|
||||
@@ -236,7 +233,6 @@ export class HaDateRangePicker extends LitElement {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || oldHass.locale !== this.hass.locale) {
|
||||
this._hour24format = !useAmPm(this.hass.locale);
|
||||
this._rtlDirection = computeRTLDirection(this.hass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,11 +302,7 @@ export class HaDateRangePicker extends LitElement {
|
||||
></ha-icon-button>`}
|
||||
</div>
|
||||
${this.ranges !== false && (this.ranges || this._ranges)
|
||||
? html`<div
|
||||
slot="ranges"
|
||||
class="date-range-ranges"
|
||||
.dir=${this._rtlDirection}
|
||||
>
|
||||
? html`<div slot="ranges" class="date-range-ranges">
|
||||
<mwc-list @action=${this._setDateRange} activatable>
|
||||
${Object.keys(this.ranges || this._ranges!).map(
|
||||
(name) => html`<mwc-list-item>${name}</mwc-list-item>`
|
||||
|
@@ -12,6 +12,8 @@ export class HaDrawer extends DrawerBase {
|
||||
|
||||
private _mc?: HammerManager;
|
||||
|
||||
private _rtlStyle?: HTMLElement;
|
||||
|
||||
protected createAdapter() {
|
||||
return {
|
||||
...super.createAdapter(),
|
||||
@@ -32,7 +34,26 @@ export class HaDrawer extends DrawerBase {
|
||||
super.updated(changedProps);
|
||||
if (changedProps.has("direction")) {
|
||||
this.mdcRoot.dir = this.direction;
|
||||
if (this.direction === "rtl") {
|
||||
this._rtlStyle = document.createElement("style");
|
||||
this._rtlStyle.innerHTML = `
|
||||
.mdc-drawer--animate {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
.mdc-drawer--opening {
|
||||
transform: translateX(0);
|
||||
}
|
||||
.mdc-drawer--closing {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
`;
|
||||
|
||||
this.shadowRoot!.appendChild(this._rtlStyle);
|
||||
} else if (this._rtlStyle) {
|
||||
this.shadowRoot!.removeChild(this._rtlStyle);
|
||||
}
|
||||
}
|
||||
|
||||
if (changedProps.has("open") && this.open && this.type === "modal") {
|
||||
this._setupSwipe();
|
||||
} else if (this._mc) {
|
||||
@@ -66,6 +87,8 @@ export class HaDrawer extends DrawerBase {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
border-color: var(--divider-color, rgba(0, 0, 0, 0.12));
|
||||
inset-inline-start: 0 !important;
|
||||
inset-inline-end: initial !important;
|
||||
}
|
||||
.mdc-drawer.mdc-drawer--modal.mdc-drawer--open {
|
||||
z-index: 200;
|
||||
|
@@ -54,7 +54,8 @@ export const computeInitialHaFormData = (
|
||||
"icon" in selector ||
|
||||
"template" in selector ||
|
||||
"text" in selector ||
|
||||
"theme" in selector
|
||||
"theme" in selector ||
|
||||
"object" in selector
|
||||
) {
|
||||
data[field.name] = "";
|
||||
} else if ("number" in selector) {
|
||||
|
@@ -2,6 +2,7 @@ import { LitElement, PropertyValues, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import QRCode from "qrcode";
|
||||
import "./ha-alert";
|
||||
import { rgb2hex } from "../common/color/convert-color";
|
||||
|
||||
@customElement("ha-qr-code")
|
||||
export class HaQrCode extends LitElement {
|
||||
@@ -65,6 +66,26 @@ export class HaQrCode extends LitElement {
|
||||
changedProperties.has("centerImage"))
|
||||
) {
|
||||
const computedStyles = getComputedStyle(this);
|
||||
const textRgb = computedStyles.getPropertyValue(
|
||||
"--rgb-primary-text-color"
|
||||
);
|
||||
const backgroundRgb = computedStyles.getPropertyValue(
|
||||
"--rgb-card-background-color"
|
||||
);
|
||||
const textHex = rgb2hex(
|
||||
textRgb.split(",").map((a) => parseInt(a, 10)) as [
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
]
|
||||
);
|
||||
const backgroundHex = rgb2hex(
|
||||
backgroundRgb.split(",").map((a) => parseInt(a, 10)) as [
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
]
|
||||
);
|
||||
|
||||
QRCode.toCanvas(canvas, this.data, {
|
||||
errorCorrectionLevel:
|
||||
@@ -74,8 +95,8 @@ export class HaQrCode extends LitElement {
|
||||
margin: this.margin,
|
||||
maskPattern: this.maskPattern,
|
||||
color: {
|
||||
light: computedStyles.getPropertyValue("--card-background-color"),
|
||||
dark: computedStyles.getPropertyValue("--primary-text-color"),
|
||||
light: backgroundHex,
|
||||
dark: textHex,
|
||||
},
|
||||
}).catch((err) => {
|
||||
this._error = err.message;
|
||||
|
@@ -38,7 +38,6 @@ import { storage } from "../common/decorators/storage";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { toggleAttribute } from "../common/dom/toggle_attribute";
|
||||
import { stringCompare } from "../common/string/compare";
|
||||
import { computeRTL } from "../common/util/compute_rtl";
|
||||
import { throttle } from "../common/util/throttle";
|
||||
import { ActionHandlerDetail } from "../data/lovelace/action_handler";
|
||||
import {
|
||||
@@ -307,16 +306,12 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || oldHass.locale !== this.hass.locale) {
|
||||
toggleAttribute(this, "rtl", computeRTL(this.hass));
|
||||
}
|
||||
|
||||
this._calculateCounts();
|
||||
|
||||
if (!SUPPORT_SCROLL_IF_NEEDED) {
|
||||
return;
|
||||
}
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || oldHass.panelUrl !== this.hass.panelUrl) {
|
||||
const selectedEl = this.shadowRoot!.querySelector(".iron-selected");
|
||||
if (selectedEl) {
|
||||
@@ -851,29 +846,22 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
font-size: 20px;
|
||||
align-items: center;
|
||||
padding-left: calc(4px + env(safe-area-inset-left));
|
||||
}
|
||||
:host([rtl]) .menu {
|
||||
padding-left: 4px;
|
||||
padding-right: calc(4px + env(safe-area-inset-right));
|
||||
padding-inline-start: calc(4px + env(safe-area-inset-left));
|
||||
padding-inline-end: initial;
|
||||
}
|
||||
:host([expanded]) .menu {
|
||||
width: calc(256px + env(safe-area-inset-left));
|
||||
}
|
||||
:host([rtl][expanded]) .menu {
|
||||
width: calc(256px + env(safe-area-inset-right));
|
||||
}
|
||||
.menu ha-icon-button {
|
||||
color: var(--sidebar-icon-color);
|
||||
}
|
||||
.title {
|
||||
margin-left: 19px;
|
||||
margin-inline-start: 19px;
|
||||
margin-inline-end: initial;
|
||||
width: 100%;
|
||||
display: none;
|
||||
}
|
||||
:host([rtl]) .title {
|
||||
margin-left: 0;
|
||||
margin-right: 19px;
|
||||
}
|
||||
:host([narrow]) .title {
|
||||
margin: 0;
|
||||
padding: 0 16px;
|
||||
@@ -904,11 +892,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
overflow-x: hidden;
|
||||
background: none;
|
||||
margin-left: env(safe-area-inset-left);
|
||||
}
|
||||
|
||||
:host([rtl]) paper-listbox {
|
||||
margin-left: initial;
|
||||
margin-right: env(safe-area-inset-right);
|
||||
margin-inline-start: env(safe-area-inset-left);
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -925,6 +910,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
box-sizing: border-box;
|
||||
margin: 4px;
|
||||
padding-left: 12px;
|
||||
padding-inline-start: 12px;
|
||||
padding-inline-end: initial;
|
||||
border-radius: 4px;
|
||||
--paper-item-min-height: 40px;
|
||||
width: 48px;
|
||||
@@ -932,10 +919,6 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
:host([expanded]) paper-icon-item {
|
||||
width: 248px;
|
||||
}
|
||||
:host([rtl]) paper-icon-item {
|
||||
padding-left: auto;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
ha-icon[slot="item-icon"],
|
||||
ha-svg-icon[slot="item-icon"] {
|
||||
@@ -1010,11 +993,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
.configuration-container {
|
||||
display: flex;
|
||||
margin-left: env(safe-area-inset-left);
|
||||
}
|
||||
:host([rtl]) .notifications-container,
|
||||
:host([rtl]) .configuration-container {
|
||||
margin-left: initial;
|
||||
margin-right: env(safe-area-inset-right);
|
||||
margin-inline-start: env(safe-area-inset-left);
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
.notifications {
|
||||
cursor: pointer;
|
||||
@@ -1025,23 +1005,18 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
.profile {
|
||||
margin-left: env(safe-area-inset-left);
|
||||
}
|
||||
:host([rtl]) .profile {
|
||||
margin-left: initial;
|
||||
margin-right: env(safe-area-inset-right);
|
||||
margin-inline-start: env(safe-area-inset-left);
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
.profile paper-icon-item {
|
||||
padding-left: 4px;
|
||||
}
|
||||
:host([rtl]) .profile paper-icon-item {
|
||||
padding-left: auto;
|
||||
padding-right: 4px;
|
||||
margin-inline-start: 4px;
|
||||
margin-inline-end: auto;
|
||||
}
|
||||
.profile .item-text {
|
||||
margin-left: 8px;
|
||||
}
|
||||
:host([rtl]) .profile .item-text {
|
||||
margin-right: 8px;
|
||||
margin-inline-start: 8px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
|
||||
.notification-badge,
|
||||
@@ -1106,9 +1081,9 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:host([rtl]) .menu ha-icon-button {
|
||||
-webkit-transform: scaleX(-1);
|
||||
transform: scaleX(-1);
|
||||
.menu ha-icon-button {
|
||||
-webkit-transform: scaleX(var(--scale-direction));
|
||||
transform: scaleX(var(--scale-direction));
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
@@ -2,9 +2,15 @@ import { customElement } from "lit/decorators";
|
||||
import "element-internals-polyfill";
|
||||
import { MdSlider } from "@material/web/slider/slider";
|
||||
import { CSSResult, css } from "lit";
|
||||
import { mainWindow } from "../common/dom/get_main_window";
|
||||
|
||||
@customElement("ha-slider")
|
||||
export class HaSlider extends MdSlider {
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.dir = mainWindow.document.dir;
|
||||
}
|
||||
|
||||
static override styles: CSSResult[] = [
|
||||
...MdSlider.styles,
|
||||
css`
|
||||
|
@@ -39,6 +39,12 @@ export class HaSortable extends LitElement {
|
||||
@property({ type: String, attribute: "group" })
|
||||
public group?: string;
|
||||
|
||||
@property({ type: Number, attribute: "swap-threshold" })
|
||||
public swapThreshold?: number;
|
||||
|
||||
@property({ type: Boolean, attribute: "invert-swap" })
|
||||
public invertSwap?: boolean;
|
||||
|
||||
protected updated(changedProperties: PropertyValues<this>) {
|
||||
if (changedProperties.has("disabled")) {
|
||||
if (this.disabled) {
|
||||
@@ -81,7 +87,7 @@ export class HaSortable extends LitElement {
|
||||
}
|
||||
|
||||
.sortable-ghost {
|
||||
border: 2px solid var(--primary-color);
|
||||
box-shadow: 0 0 0 2px var(--primary-color);
|
||||
background: rgba(var(--rgb-primary-color), 0.25);
|
||||
border-radius: 4px;
|
||||
opacity: 0.4;
|
||||
@@ -108,7 +114,7 @@ export class HaSortable extends LitElement {
|
||||
|
||||
const options: SortableInstance.Options = {
|
||||
animation: 150,
|
||||
swapThreshold: 0.75,
|
||||
swapThreshold: 1,
|
||||
onChoose: this._handleChoose,
|
||||
onEnd: this._handleEnd,
|
||||
};
|
||||
@@ -116,6 +122,13 @@ export class HaSortable extends LitElement {
|
||||
if (this.draggableSelector) {
|
||||
options.draggable = this.draggableSelector;
|
||||
}
|
||||
|
||||
if (this.swapThreshold !== undefined) {
|
||||
options.swapThreshold = this.swapThreshold;
|
||||
}
|
||||
if (this.invertSwap !== undefined) {
|
||||
options.invertSwap = this.invertSwap;
|
||||
}
|
||||
if (this.handleSelector) {
|
||||
options.handle = this.handleSelector;
|
||||
}
|
||||
|
@@ -3,18 +3,11 @@ import { styles as textfieldStyles } from "@material/mwc-textfield/mwc-textfield
|
||||
import { styles as textareaStyles } from "@material/mwc-textarea/mwc-textarea.css";
|
||||
import { css, PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { mainWindow } from "../common/dom/get_main_window";
|
||||
|
||||
@customElement("ha-textarea")
|
||||
export class HaTextArea extends TextAreaBase {
|
||||
@property({ type: Boolean, reflect: true }) autogrow = false;
|
||||
|
||||
firstUpdated() {
|
||||
super.firstUpdated();
|
||||
|
||||
this.setAttribute("dir", mainWindow.document.dir);
|
||||
}
|
||||
|
||||
updated(changedProperties: PropertyValues) {
|
||||
super.updated(changedProperties);
|
||||
if (this.autogrow && changedProperties.has("value")) {
|
||||
@@ -54,9 +47,10 @@ export class HaTextArea extends TextAreaBase {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
:host([dir="rtl"]) .mdc-floating-label {
|
||||
right: 16px;
|
||||
left: initial;
|
||||
.mdc-floating-label {
|
||||
inset-inline-start: 16px !important;
|
||||
inset-inline-end: initial !important;
|
||||
transform-origin: var(--float-start) top;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
@@ -8,12 +8,18 @@ import type {
|
||||
Marker,
|
||||
Polyline,
|
||||
} from "leaflet";
|
||||
import { isToday } from "date-fns";
|
||||
import { css, CSSResultGroup, PropertyValues, ReactiveElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import {
|
||||
LeafletModuleType,
|
||||
setupLeafletMap,
|
||||
} from "../../common/dom/setup-leaflet-map";
|
||||
import {
|
||||
formatTimeWithSeconds,
|
||||
formatTimeWeekday,
|
||||
} from "../../common/datetime/format_time";
|
||||
import { formatDateTime } from "../../common/datetime/format_date_time";
|
||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
import { loadPolyfillIfNeeded } from "../../resources/resize-observer.polyfill";
|
||||
@@ -27,12 +33,14 @@ const getEntityId = (entity: string | HaMapEntity): string =>
|
||||
|
||||
export interface HaMapPathPoint {
|
||||
point: LatLngTuple;
|
||||
tooltip: string;
|
||||
timestamp: Date;
|
||||
}
|
||||
export interface HaMapPaths {
|
||||
points: HaMapPathPoint[];
|
||||
color?: string;
|
||||
name?: string;
|
||||
gradualOpacity?: number;
|
||||
fullDatetime?: boolean;
|
||||
}
|
||||
|
||||
export interface HaMapEntity {
|
||||
@@ -242,6 +250,30 @@ export class HaMap extends ReactiveElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _computePathTooltip(path: HaMapPaths, point: HaMapPathPoint): string {
|
||||
let formattedTime: string;
|
||||
if (path.fullDatetime) {
|
||||
formattedTime = formatDateTime(
|
||||
point.timestamp,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
} else if (isToday(point.timestamp)) {
|
||||
formattedTime = formatTimeWithSeconds(
|
||||
point.timestamp,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
} else {
|
||||
formattedTime = formatTimeWeekday(
|
||||
point.timestamp,
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
}
|
||||
return `${path.name}<br>${formattedTime}`;
|
||||
}
|
||||
|
||||
private _drawPaths(): void {
|
||||
const hass = this.hass;
|
||||
const map = this.leafletMap;
|
||||
@@ -289,7 +321,10 @@ export class HaMap extends ReactiveElement {
|
||||
fillOpacity: opacity,
|
||||
interactive: true,
|
||||
})
|
||||
.bindTooltip(path.points[pointIndex].tooltip, { direction: "top" })
|
||||
.bindTooltip(
|
||||
this._computePathTooltip(path, path.points[pointIndex]),
|
||||
{ direction: "top" }
|
||||
)
|
||||
);
|
||||
|
||||
// DRAW line between this and next point
|
||||
@@ -319,7 +354,10 @@ export class HaMap extends ReactiveElement {
|
||||
fillOpacity: opacity,
|
||||
interactive: true,
|
||||
})
|
||||
.bindTooltip(path.points[pointIndex].tooltip, { direction: "top" })
|
||||
.bindTooltip(
|
||||
this._computePathTooltip(path, path.points[pointIndex]),
|
||||
{ direction: "top" }
|
||||
)
|
||||
);
|
||||
}
|
||||
this._mapPaths.forEach((marker) => map.addLayer(marker));
|
||||
@@ -556,6 +594,7 @@ export class HaMap extends ReactiveElement {
|
||||
color: white !important;
|
||||
border-radius: 4px;
|
||||
box-shadow: none !important;
|
||||
text-align: center;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@@ -25,7 +25,6 @@ import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { until } from "lit/directives/until";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeRTLDirection } from "../../common/util/compute_rtl";
|
||||
import { debounce } from "../../common/util/debounce";
|
||||
import { isUnavailableState } from "../../data/entity";
|
||||
import type { MediaPlayerItem } from "../../data/media-player";
|
||||
@@ -539,7 +538,6 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
.graphic=${mediaClass.show_list_images
|
||||
? "medium"
|
||||
: "avatar"}
|
||||
dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<span class="title">
|
||||
${this.hass.localize(
|
||||
@@ -637,7 +635,6 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
@click=${this._childClicked}
|
||||
.item=${child}
|
||||
.graphic=${mediaClass.show_list_images ? "medium" : "avatar"}
|
||||
dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
${backgroundImage === "none" && !child.can_play
|
||||
? html`<ha-svg-icon
|
||||
@@ -1198,10 +1195,8 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
|
||||
mwc-list-item .title {
|
||||
margin-left: 16px;
|
||||
}
|
||||
mwc-list-item[dir="rtl"] .title {
|
||||
margin-right: 16px;
|
||||
margin-left: 0;
|
||||
margin-inline-start: 16px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
|
||||
/* ============= Narrow ============= */
|
||||
@@ -1332,6 +1327,10 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
lit-virtualizer.not_shown {
|
||||
height: calc(100% - 36px);
|
||||
}
|
||||
|
||||
ha-browse-media-tts {
|
||||
direction: var(--direction);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import {
|
||||
html,
|
||||
TemplateResult,
|
||||
svg,
|
||||
nothing,
|
||||
} from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { NODE_SIZE, SPACING } from "./hat-graph-const";
|
||||
@@ -51,7 +52,7 @@ export class HatGraphNode extends LitElement {
|
||||
: Math.ceil((NODE_SIZE + SPACING * 2) / 2)} ${width} ${height}"
|
||||
>
|
||||
${this.graphStart
|
||||
? ``
|
||||
? nothing
|
||||
: svg`
|
||||
<path
|
||||
class="connector"
|
||||
@@ -64,7 +65,6 @@ export class HatGraphNode extends LitElement {
|
||||
`}
|
||||
<g class="node">
|
||||
<circle cx="0" cy="0" r=${NODE_SIZE / 2} />
|
||||
}
|
||||
${this.badge
|
||||
? svg`
|
||||
<g class="number">
|
||||
@@ -81,9 +81,11 @@ export class HatGraphNode extends LitElement {
|
||||
>${this.badge > 9 ? "9+" : this.badge}</text>
|
||||
</g>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
<g style="pointer-events: none" transform="translate(${-12} ${-12})">
|
||||
${this.iconPath ? svg`<path class="icon" d=${this.iconPath}/>` : ""}
|
||||
${this.iconPath
|
||||
? svg`<path class="icon" d=${this.iconPath}/>`
|
||||
: svg`<foreignObject><span class="icon"><slot name="icon"></slot></span></foreignObject>`}
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
@@ -152,6 +154,13 @@ export class HatGraphNode extends LitElement {
|
||||
path.icon {
|
||||
fill: var(--icon-clr);
|
||||
}
|
||||
foreignObject {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
.icon {
|
||||
color: var(--icon-clr);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@@ -17,11 +17,10 @@ import {
|
||||
mdiRoomService,
|
||||
mdiShuffleDisabled,
|
||||
} from "@mdi/js";
|
||||
import { LitElement, PropertyValues, css, html } from "lit";
|
||||
import { LitElement, PropertyValues, css, html, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { ensureArray } from "../../common/array/ensure-array";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { ACTION_ICONS } from "../../data/action";
|
||||
import { Condition, Trigger } from "../../data/automation";
|
||||
import {
|
||||
Action,
|
||||
@@ -41,11 +40,14 @@ import {
|
||||
IfActionTraceStep,
|
||||
TraceExtended,
|
||||
} from "../../data/trace";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "../ha-icon-button";
|
||||
import "../ha-service-icon";
|
||||
import "./hat-graph-branch";
|
||||
import { BRANCH_HEIGHT, NODE_SIZE, SPACING } from "./hat-graph-const";
|
||||
import "./hat-graph-node";
|
||||
import "./hat-graph-spacer";
|
||||
import { ACTION_ICONS } from "../../data/action";
|
||||
|
||||
export interface NodeInfo {
|
||||
path: string;
|
||||
@@ -64,6 +66,8 @@ export class HatScriptGraph extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public selected?: string;
|
||||
|
||||
public hass!: HomeAssistant;
|
||||
|
||||
public renderedNodes: Record<string, NodeInfo> = {};
|
||||
|
||||
public trackedNodes: Record<string, NodeInfo> = {};
|
||||
@@ -415,13 +419,21 @@ export class HatScriptGraph extends LitElement {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiRoomService}
|
||||
.iconPath=${node.service ? undefined : mdiRoomService}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
>
|
||||
${node.service
|
||||
? html`<ha-service-icon
|
||||
slot="icon"
|
||||
.hass=${this.hass}
|
||||
.service=${node.service}
|
||||
></ha-service-icon>`
|
||||
: nothing}
|
||||
</hat-graph-node>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -667,8 +679,6 @@ export class HatScriptGraph extends LitElement {
|
||||
}
|
||||
.parent {
|
||||
margin-left: 8px;
|
||||
margin-inline-start: 8px;
|
||||
margin-inline-end: initial;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.error {
|
||||
|
@@ -18,6 +18,7 @@ export interface CloudPreferences {
|
||||
google_enabled: boolean;
|
||||
alexa_enabled: boolean;
|
||||
remote_enabled: boolean;
|
||||
remote_allow_remote_enable: boolean;
|
||||
google_secure_devices_pin: string | undefined;
|
||||
cloudhooks: { [webhookId: string]: CloudWebhook };
|
||||
alexa_report_state: boolean;
|
||||
@@ -139,6 +140,7 @@ export const updateCloudPref = (
|
||||
google_report_state?: CloudPreferences["google_report_state"];
|
||||
google_secure_devices_pin?: CloudPreferences["google_secure_devices_pin"];
|
||||
tts_default_voice?: CloudPreferences["tts_default_voice"];
|
||||
remote_allow_remote_enable?: CloudPreferences["remote_allow_remote_enable"];
|
||||
}
|
||||
) =>
|
||||
hass.callWS({
|
||||
|
@@ -8,37 +8,49 @@ import {
|
||||
EntityRegistryDisplayEntry,
|
||||
EntityRegistryEntry,
|
||||
} from "./entity_registry";
|
||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||
import { atLeastVersion } from "../common/config/version";
|
||||
|
||||
const resources: Record<IconCategory, any> = {
|
||||
const resources: {
|
||||
entity: Record<string, Promise<PlatformIcons>>;
|
||||
entity_component: {
|
||||
domains?: string[];
|
||||
resources?: Promise<Record<string, ComponentIcons>>;
|
||||
};
|
||||
services: {
|
||||
all?: Promise<Record<string, ServiceIcons>>;
|
||||
domains: { [domain: string]: ServiceIcons | Promise<ServiceIcons> };
|
||||
};
|
||||
} = {
|
||||
entity: {},
|
||||
entity_component: undefined,
|
||||
services: {},
|
||||
entity_component: {},
|
||||
services: { domains: {} },
|
||||
};
|
||||
|
||||
interface IconResources {
|
||||
resources: Record<string, string | Record<string, string>>;
|
||||
interface IconResources<
|
||||
T extends ComponentIcons | PlatformIcons | ServiceIcons,
|
||||
> {
|
||||
resources: Record<string, T>;
|
||||
}
|
||||
|
||||
interface PlatformIcons {
|
||||
[domain: string]: {
|
||||
[translation_key: string]: {
|
||||
state: Record<string, string>;
|
||||
state_attributes: Record<
|
||||
string,
|
||||
{
|
||||
state: Record<string, string>;
|
||||
default: string;
|
||||
}
|
||||
>;
|
||||
default: string;
|
||||
};
|
||||
[translation_key: string]: {
|
||||
state: Record<string, string>;
|
||||
state_attributes: Record<
|
||||
string,
|
||||
{
|
||||
state: Record<string, string>;
|
||||
default: string;
|
||||
}
|
||||
>;
|
||||
default: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface ComponentIcons {
|
||||
export interface ComponentIcons {
|
||||
[device_class: string]: {
|
||||
state: Record<string, string>;
|
||||
state_attributes: Record<
|
||||
state?: Record<string, string>;
|
||||
state_attributes?: Record<
|
||||
string,
|
||||
{
|
||||
state: Record<string, string>;
|
||||
@@ -55,12 +67,18 @@ interface ServiceIcons {
|
||||
|
||||
export type IconCategory = "entity" | "entity_component" | "services";
|
||||
|
||||
export const getHassIcons = async (
|
||||
type CategoryType = {
|
||||
entity: PlatformIcons;
|
||||
entity_component: ComponentIcons;
|
||||
services: ServiceIcons;
|
||||
};
|
||||
|
||||
export const getHassIcons = async <T extends IconCategory>(
|
||||
hass: HomeAssistant,
|
||||
category: IconCategory,
|
||||
category: T,
|
||||
integration?: string
|
||||
): Promise<IconResources> =>
|
||||
hass.callWS<{ resources: Record<string, string> }>({
|
||||
) =>
|
||||
hass.callWS<IconResources<CategoryType[T]>>({
|
||||
type: "frontend/get_icons",
|
||||
category,
|
||||
integration,
|
||||
@@ -70,14 +88,20 @@ export const getPlatformIcons = async (
|
||||
hass: HomeAssistant,
|
||||
integration: string,
|
||||
force = false
|
||||
): Promise<PlatformIcons> => {
|
||||
): Promise<PlatformIcons | undefined> => {
|
||||
if (!force && integration in resources.entity) {
|
||||
return resources.entity[integration];
|
||||
}
|
||||
const result = getHassIcons(hass, "entity", integration);
|
||||
resources.entity[integration] = result.then(
|
||||
if (
|
||||
!isComponentLoaded(hass, integration) ||
|
||||
!atLeastVersion(hass.connection.haVersion, 2024, 2)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
const result = getHassIcons(hass, "entity", integration).then(
|
||||
(res) => res?.resources[integration]
|
||||
);
|
||||
resources.entity[integration] = result;
|
||||
return resources.entity[integration];
|
||||
};
|
||||
|
||||
@@ -85,45 +109,70 @@ export const getComponentIcons = async (
|
||||
hass: HomeAssistant,
|
||||
domain: string,
|
||||
force = false
|
||||
): Promise<ComponentIcons> => {
|
||||
if (!force && resources.entity_component) {
|
||||
return resources.entity_component.then((res) => res[domain]);
|
||||
): Promise<ComponentIcons | undefined> => {
|
||||
// For Cast, old instances can connect to it.
|
||||
if (
|
||||
__BACKWARDS_COMPAT__ &&
|
||||
!atLeastVersion(hass.connection.haVersion, 2024, 2)
|
||||
) {
|
||||
return import("../fake_data/entity_component_icons")
|
||||
.then((mod) => mod.ENTITY_COMPONENT_ICONS)
|
||||
.then((res) => res[domain]);
|
||||
}
|
||||
resources.entity_component = getHassIcons(hass, "entity_component").then(
|
||||
(result) => result.resources
|
||||
);
|
||||
return resources.entity_component.then((res) => res[domain]);
|
||||
|
||||
if (
|
||||
!force &&
|
||||
resources.entity_component.resources &&
|
||||
resources.entity_component.domains?.includes(domain)
|
||||
) {
|
||||
return resources.entity_component.resources.then((res) => res[domain]);
|
||||
}
|
||||
|
||||
if (!isComponentLoaded(hass, domain)) {
|
||||
return undefined;
|
||||
}
|
||||
resources.entity_component.domains = [...hass.config.components];
|
||||
resources.entity_component.resources = getHassIcons(
|
||||
hass,
|
||||
"entity_component"
|
||||
).then((result) => result.resources);
|
||||
return resources.entity_component.resources.then((res) => res[domain]);
|
||||
};
|
||||
|
||||
export const getServiceIcons = async (
|
||||
hass: HomeAssistant,
|
||||
domain?: string,
|
||||
force = false
|
||||
): Promise<ServiceIcons> => {
|
||||
): Promise<ServiceIcons | Record<string, ServiceIcons> | undefined> => {
|
||||
if (!domain) {
|
||||
if (!force && resources.services.all) {
|
||||
return resources.services.all;
|
||||
}
|
||||
resources.services.all = getHassIcons(hass, "services", domain).then(
|
||||
(res) => {
|
||||
resources.services = res.resources;
|
||||
resources.services.domains = res.resources;
|
||||
return res?.resources;
|
||||
}
|
||||
);
|
||||
return resources.services.all;
|
||||
}
|
||||
if (!force && domain && domain in resources.services) {
|
||||
return resources.services[domain];
|
||||
if (!force && domain in resources.services.domains) {
|
||||
return resources.services.domains[domain];
|
||||
}
|
||||
if (resources.services.all && !force) {
|
||||
await resources.services.all;
|
||||
if (domain in resources.services) {
|
||||
return resources.services[domain];
|
||||
if (domain in resources.services.domains) {
|
||||
return resources.services.domains[domain];
|
||||
}
|
||||
}
|
||||
if (!isComponentLoaded(hass, domain)) {
|
||||
return undefined;
|
||||
}
|
||||
const result = getHassIcons(hass, "services", domain);
|
||||
resources.services[domain] = result.then((res) => res?.resources[domain]);
|
||||
return resources.services[domain];
|
||||
resources.services.domains[domain] = result.then(
|
||||
(res) => res?.resources[domain]
|
||||
);
|
||||
return resources.services.domains[domain];
|
||||
};
|
||||
|
||||
export const entityIcon = async (
|
||||
@@ -238,7 +287,7 @@ export const serviceIcon = async (
|
||||
const serviceName = computeObjectId(service);
|
||||
const serviceIcons = await getServiceIcons(hass, domain);
|
||||
if (serviceIcons) {
|
||||
icon = serviceIcons[serviceName];
|
||||
icon = serviceIcons[serviceName] as string;
|
||||
}
|
||||
if (!icon) {
|
||||
icon = await domainIcon(hass, domain);
|
||||
|
@@ -35,6 +35,7 @@ export interface MatterNodeDiagnostics {
|
||||
mac_address?: string;
|
||||
available: boolean;
|
||||
active_fabrics: MatterFabricData[];
|
||||
active_fabric_index: number;
|
||||
}
|
||||
|
||||
export interface MatterPingResult {
|
||||
|
@@ -2,7 +2,6 @@ import "@material/mwc-button/mwc-button";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeRTLDirection } from "../../common/util/compute_rtl";
|
||||
import "../../components/ha-dialog";
|
||||
import "../../components/ha-formfield";
|
||||
import "../../components/ha-switch";
|
||||
@@ -82,7 +81,6 @@ class DialogConfigEntrySystemOptions extends LitElement {
|
||||
}
|
||||
)}
|
||||
</p>`}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<ha-switch
|
||||
.checked=${!this._disableNewEntities}
|
||||
@@ -109,7 +107,6 @@ class DialogConfigEntrySystemOptions extends LitElement {
|
||||
}
|
||||
)}
|
||||
</p>`}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<ha-switch
|
||||
.checked=${!this._disablePolling}
|
||||
|
@@ -14,7 +14,6 @@ import { customElement, property } from "lit/decorators";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-select";
|
||||
import "../../../components/ha-slider";
|
||||
@@ -131,7 +130,6 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
<ha-slider
|
||||
labeled
|
||||
id="input"
|
||||
.dir=${computeRTLDirection(this.hass!)}
|
||||
.value=${Number(stateObj.attributes.volume_level) * 100}
|
||||
@change=${this._selectedValueChanged}
|
||||
></ha-slider>
|
||||
|
@@ -14,6 +14,7 @@ import "./notification-item";
|
||||
import "../../components/ha-header-bar";
|
||||
import "../../components/ha-drawer";
|
||||
import type { HaDrawer } from "../../components/ha-drawer";
|
||||
import { computeRTLDirection } from "../../common/util/compute_rtl";
|
||||
|
||||
@customElement("notification-drawer")
|
||||
export class HuiNotificationDrawer extends LitElement {
|
||||
@@ -92,7 +93,12 @@ export class HuiNotificationDrawer extends LitElement {
|
||||
});
|
||||
|
||||
return html`
|
||||
<ha-drawer type="modal" open @MDCDrawer:closed=${this._dialogClosed}>
|
||||
<ha-drawer
|
||||
type="modal"
|
||||
open
|
||||
@MDCDrawer:closed=${this._dialogClosed}
|
||||
.direction=${computeRTLDirection(this.hass)}
|
||||
>
|
||||
<ha-header-bar>
|
||||
<div slot="title">
|
||||
${this.hass.localize("ui.notification_drawer.title")}
|
||||
|
@@ -35,13 +35,22 @@ interface EMOutgoingMessageConfigGet extends EMMessage {
|
||||
type: "config/get";
|
||||
}
|
||||
|
||||
interface EMOutgoingMessageScanQRCode extends EMMessage {
|
||||
type: "qr_code/scan";
|
||||
interface EMOutgoingMessageBarCodeScan extends EMMessage {
|
||||
type: "bar_code/scan";
|
||||
title: string;
|
||||
description: string;
|
||||
alternative_option_label?: string;
|
||||
}
|
||||
|
||||
interface EMOutgoingMessageBarCodeClose extends EMMessage {
|
||||
type: "bar_code/close";
|
||||
}
|
||||
|
||||
interface EMOutgoingMessageBarCodeNotify extends EMMessage {
|
||||
type: "bar_code/notify";
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface EMOutgoingMessageMatterCommission extends EMMessage {
|
||||
type: "matter/commission";
|
||||
}
|
||||
@@ -55,13 +64,6 @@ type EMOutgoingMessageWithAnswer = {
|
||||
request: EMOutgoingMessageConfigGet;
|
||||
response: ExternalConfig;
|
||||
};
|
||||
"qr_code/scan": {
|
||||
request: EMOutgoingMessageScanQRCode;
|
||||
response:
|
||||
| EMIncomingMessageQRCodeResponseCanceled
|
||||
| EMIncomingMessageQRCodeResponseAlternativeOptions
|
||||
| EMIncomingMessageQRCodeResponseScanResult;
|
||||
};
|
||||
};
|
||||
|
||||
interface EMOutgoingMessageExoplayerPlayHLS extends EMMessage {
|
||||
@@ -124,20 +126,23 @@ interface EMOutgoingMessageAssistShow extends EMMessage {
|
||||
}
|
||||
|
||||
type EMOutgoingMessageWithoutAnswer =
|
||||
| EMOutgoingMessageHaptic
|
||||
| EMOutgoingMessageConnectionStatus
|
||||
| EMMessageResultError
|
||||
| EMMessageResultSuccess
|
||||
| EMOutgoingMessageAppConfiguration
|
||||
| EMOutgoingMessageTagWrite
|
||||
| EMOutgoingMessageSidebarShow
|
||||
| EMOutgoingMessageAssistShow
|
||||
| EMOutgoingMessageBarCodeClose
|
||||
| EMOutgoingMessageBarCodeNotify
|
||||
| EMOutgoingMessageBarCodeScan
|
||||
| EMOutgoingMessageConnectionStatus
|
||||
| EMOutgoingMessageExoplayerPlayHLS
|
||||
| EMOutgoingMessageExoplayerResize
|
||||
| EMOutgoingMessageExoplayerStop
|
||||
| EMOutgoingMessageThemeUpdate
|
||||
| EMMessageResultSuccess
|
||||
| EMMessageResultError
|
||||
| EMOutgoingMessageHaptic
|
||||
| EMOutgoingMessageImportThreadCredentials
|
||||
| EMOutgoingMessageMatterCommission
|
||||
| EMOutgoingMessageImportThreadCredentials;
|
||||
| EMOutgoingMessageSidebarShow
|
||||
| EMOutgoingMessageTagWrite
|
||||
| EMOutgoingMessageThemeUpdate;
|
||||
|
||||
interface EMIncomingMessageRestart {
|
||||
id: number;
|
||||
@@ -172,17 +177,39 @@ interface EMIncomingMessageShowAutomationEditor {
|
||||
};
|
||||
}
|
||||
|
||||
export interface EMIncomingMessageQRCodeResponseCanceled {
|
||||
action: "canceled";
|
||||
export interface EMIncomingMessageBarCodeScanResult {
|
||||
id: number;
|
||||
type: "command";
|
||||
command: "bar_code/scan_result";
|
||||
payload: {
|
||||
// A string decoded from the barcode data.
|
||||
rawValue: string;
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API#supported_barcode_formats
|
||||
format:
|
||||
| "aztec"
|
||||
| "code_128"
|
||||
| "code_39"
|
||||
| "code_93"
|
||||
| "codabar"
|
||||
| "data_matrix"
|
||||
| "ean_13"
|
||||
| "ean_8"
|
||||
| "itf"
|
||||
| "pdf417"
|
||||
| "qr_code"
|
||||
| "upc_a"
|
||||
| "upc_e"
|
||||
| "unknown";
|
||||
};
|
||||
}
|
||||
|
||||
export interface EMIncomingMessageQRCodeResponseAlternativeOptions {
|
||||
action: "alternative_options";
|
||||
}
|
||||
|
||||
export interface EMIncomingMessageQRCodeResponseScanResult {
|
||||
action: "scan_result";
|
||||
result: string;
|
||||
export interface EMIncomingMessageBarCodeScanAborted {
|
||||
id: number;
|
||||
type: "command";
|
||||
command: "bar_code/aborted";
|
||||
payload: {
|
||||
reason: "canceled" | "alternative_options";
|
||||
};
|
||||
}
|
||||
|
||||
export type EMIncomingMessageCommands =
|
||||
@@ -190,7 +217,9 @@ export type EMIncomingMessageCommands =
|
||||
| EMIncomingMessageShowNotifications
|
||||
| EMIncomingMessageToggleSidebar
|
||||
| EMIncomingMessageShowSidebar
|
||||
| EMIncomingMessageShowAutomationEditor;
|
||||
| EMIncomingMessageShowAutomationEditor
|
||||
| EMIncomingMessageBarCodeScanResult
|
||||
| EMIncomingMessageBarCodeScanAborted;
|
||||
|
||||
type EMIncomingMessage =
|
||||
| EMMessageResultSuccess
|
||||
@@ -207,7 +236,7 @@ export interface ExternalConfig {
|
||||
canCommissionMatter: boolean;
|
||||
canImportThreadCredentials: boolean;
|
||||
hasAssist: boolean;
|
||||
hasQRScanner: number;
|
||||
hasBarCodeScanner: number;
|
||||
}
|
||||
|
||||
export class ExternalMessaging {
|
||||
|
@@ -14,7 +14,53 @@ export const demoConfig: HassConfig = {
|
||||
wind_speed: "m/s",
|
||||
accumulated_precipitation: "mm",
|
||||
},
|
||||
components: ["notify.html5", "history", "todo", "forecast_solar", "energy"],
|
||||
components: [
|
||||
"notify.html5",
|
||||
"history",
|
||||
"forecast_solar",
|
||||
"energy",
|
||||
"person",
|
||||
"number",
|
||||
"select",
|
||||
"tts",
|
||||
"datetime",
|
||||
"vacuum",
|
||||
"wake_word",
|
||||
"light",
|
||||
"alarm_control_panel",
|
||||
"text",
|
||||
"lawn_mower",
|
||||
"siren",
|
||||
"input_boolean",
|
||||
"lock",
|
||||
"calendar",
|
||||
"image",
|
||||
"device_tracker",
|
||||
"scene",
|
||||
"script",
|
||||
"todo",
|
||||
"cover",
|
||||
"switch",
|
||||
"button",
|
||||
"water_heater",
|
||||
"binary_sensor",
|
||||
"sensor",
|
||||
"humidifier",
|
||||
"valve",
|
||||
"time",
|
||||
"media_player",
|
||||
"air_quality",
|
||||
"camera",
|
||||
"date",
|
||||
"fan",
|
||||
"automation",
|
||||
"weather",
|
||||
"climate",
|
||||
"stt",
|
||||
"update",
|
||||
"event",
|
||||
"demo",
|
||||
],
|
||||
time_zone: "America/Los_Angeles",
|
||||
config_dir: "/config",
|
||||
version: "DEMO",
|
||||
|
962
src/fake_data/entity_component_icons.ts
Normal file
962
src/fake_data/entity_component_icons.ts
Normal file
@@ -0,0 +1,962 @@
|
||||
import { ComponentIcons } from "../data/icons";
|
||||
|
||||
export const ENTITY_COMPONENT_ICONS: Record<string, ComponentIcons> = {
|
||||
person: {
|
||||
_: {
|
||||
default: "mdi:account",
|
||||
state: {
|
||||
not_home: "mdi:account-arrow-right",
|
||||
},
|
||||
},
|
||||
},
|
||||
number: {
|
||||
_: {
|
||||
default: "mdi:ray-vertex",
|
||||
},
|
||||
apparent_power: {
|
||||
default: "mdi:flash",
|
||||
},
|
||||
aqi: {
|
||||
default: "mdi:air-filter",
|
||||
},
|
||||
atmospheric_pressure: {
|
||||
default: "mdi:thermometer-lines",
|
||||
},
|
||||
battery: {
|
||||
default: "mdi:battery",
|
||||
},
|
||||
carbon_dioxide: {
|
||||
default: "mdi:molecule-co2",
|
||||
},
|
||||
carbon_monoxide: {
|
||||
default: "mdi:molecule-co",
|
||||
},
|
||||
current: {
|
||||
default: "mdi:current-ac",
|
||||
},
|
||||
data_rate: {
|
||||
default: "mdi:transmission-tower",
|
||||
},
|
||||
data_size: {
|
||||
default: "mdi:database",
|
||||
},
|
||||
distance: {
|
||||
default: "mdi:arrow-left-right",
|
||||
},
|
||||
duration: {
|
||||
default: "mdi:progress-clock",
|
||||
},
|
||||
energy: {
|
||||
default: "mdi:lightning-bolt",
|
||||
},
|
||||
energy_storage: {
|
||||
default: "mdi:car-battery",
|
||||
},
|
||||
frequency: {
|
||||
default: "mdi:sine-wave",
|
||||
},
|
||||
gas: {
|
||||
default: "mdi:meter-gas",
|
||||
},
|
||||
humidity: {
|
||||
default: "mdi:water-percent",
|
||||
},
|
||||
illuminance: {
|
||||
default: "mdi:brightness-5",
|
||||
},
|
||||
irradiance: {
|
||||
default: "mdi:sun-wireless",
|
||||
},
|
||||
moisture: {
|
||||
default: "mdi:water-percent",
|
||||
},
|
||||
monetary: {
|
||||
default: "mdi:cash",
|
||||
},
|
||||
nitrogen_dioxide: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
nitrogen_monoxide: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
nitrous_oxide: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
ozone: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
ph: {
|
||||
default: "mdi:ph",
|
||||
},
|
||||
pm1: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
pm10: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
pm25: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
power: {
|
||||
default: "mdi:flash",
|
||||
},
|
||||
power_factor: {
|
||||
default: "mdi:angle-acute",
|
||||
},
|
||||
precipitation: {
|
||||
default: "mdi:weather-rainy",
|
||||
},
|
||||
precipitation_intensity: {
|
||||
default: "mdi:weather-pouring",
|
||||
},
|
||||
pressure: {
|
||||
default: "mdi:gauge",
|
||||
},
|
||||
reactive_power: {
|
||||
default: "mdi:flash",
|
||||
},
|
||||
signal_strength: {
|
||||
default: "mdi:wifi",
|
||||
},
|
||||
sound_pressure: {
|
||||
default: "mdi:ear-hearing",
|
||||
},
|
||||
speed: {
|
||||
default: "mdi:speedometer",
|
||||
},
|
||||
sulfur_dioxide: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
temperature: {
|
||||
default: "mdi:thermometer",
|
||||
},
|
||||
volatile_organic_compounds: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
volatile_organic_compounds_parts: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
voltage: {
|
||||
default: "mdi:sine-wave",
|
||||
},
|
||||
volume: {
|
||||
default: "mdi:car-coolant-level",
|
||||
},
|
||||
volume_storage: {
|
||||
default: "mdi:storage-tank",
|
||||
},
|
||||
water: {
|
||||
default: "mdi:water",
|
||||
},
|
||||
weight: {
|
||||
default: "mdi:weight",
|
||||
},
|
||||
wind_speed: {
|
||||
default: "mdi:weather-windy",
|
||||
},
|
||||
},
|
||||
select: {
|
||||
_: {
|
||||
default: "mdi:format-list-bulleted",
|
||||
},
|
||||
},
|
||||
tts: {
|
||||
_: {
|
||||
default: "mdi:speaker-message",
|
||||
},
|
||||
},
|
||||
datetime: {
|
||||
_: {
|
||||
default: "mdi:calendar-clock",
|
||||
},
|
||||
},
|
||||
vacuum: {
|
||||
_: {
|
||||
default: "mdi:robot-vacuum",
|
||||
},
|
||||
},
|
||||
wake_word: {
|
||||
_: {
|
||||
default: "mdi:chat-sleep",
|
||||
},
|
||||
},
|
||||
light: {
|
||||
_: {
|
||||
default: "mdi:lightbulb",
|
||||
},
|
||||
},
|
||||
alarm_control_panel: {
|
||||
_: {
|
||||
default: "mdi:shield",
|
||||
state: {
|
||||
armed_away: "mdi:shield-lock",
|
||||
armed_custom_bypass: "mdi:security",
|
||||
armed_home: "mdi:shield-home",
|
||||
armed_night: "mdi:shield-moon",
|
||||
armed_vacation: "mdi:shield-airplane",
|
||||
disarmed: "mdi:shield-off",
|
||||
pending: "mdi:shield-outline",
|
||||
triggered: "mdi:bell-ring",
|
||||
},
|
||||
},
|
||||
},
|
||||
text: {
|
||||
_: {
|
||||
default: "mdi:form-textbox",
|
||||
},
|
||||
},
|
||||
lawn_mower: {
|
||||
_: {
|
||||
default: "mdi:robot-mower",
|
||||
},
|
||||
},
|
||||
siren: {
|
||||
_: {
|
||||
default: "mdi:bullhorn",
|
||||
},
|
||||
},
|
||||
input_boolean: {
|
||||
_: {
|
||||
default: "mdi:check-circle-outline",
|
||||
state: {
|
||||
off: "mdi:close-circle-outline",
|
||||
},
|
||||
},
|
||||
},
|
||||
lock: {
|
||||
_: {
|
||||
default: "mdi:lock",
|
||||
state: {
|
||||
jammed: "mdi:lock-alert",
|
||||
locking: "mdi:lock-clock",
|
||||
unlocked: "mdi:lock-open",
|
||||
unlocking: "mdi:lock-clock",
|
||||
},
|
||||
},
|
||||
},
|
||||
calendar: {
|
||||
_: {
|
||||
default: "mdi:calendar",
|
||||
state: {
|
||||
on: "mdi:calendar-check",
|
||||
off: "mdi:calendar-blank",
|
||||
},
|
||||
},
|
||||
},
|
||||
image: {
|
||||
_: {
|
||||
default: "mdi:image",
|
||||
},
|
||||
},
|
||||
device_tracker: {
|
||||
_: {
|
||||
default: "mdi:account",
|
||||
state: {
|
||||
not_home: "mdi:account-arrow-right",
|
||||
},
|
||||
},
|
||||
},
|
||||
scene: {
|
||||
_: {
|
||||
default: "mdi:palette",
|
||||
},
|
||||
},
|
||||
script: {
|
||||
_: {
|
||||
default: "mdi:script-text",
|
||||
state: {
|
||||
on: "mdi:script-text-play",
|
||||
},
|
||||
},
|
||||
},
|
||||
todo: {
|
||||
_: {
|
||||
default: "mdi:clipboard-list",
|
||||
},
|
||||
},
|
||||
cover: {
|
||||
_: {
|
||||
default: "mdi:window-open",
|
||||
state: {
|
||||
closed: "mdi:window-closed",
|
||||
closing: "mdi:arrow-down-box",
|
||||
opening: "mdi:arrow-up-box",
|
||||
},
|
||||
},
|
||||
blind: {
|
||||
default: "mdi:blinds-horizontal",
|
||||
state: {
|
||||
closed: "mdi:blinds-horizontal-closed",
|
||||
closing: "mdi:arrow-down-box",
|
||||
opening: "mdi:arrow-up-box",
|
||||
},
|
||||
},
|
||||
curtain: {
|
||||
default: "mdi:curtains",
|
||||
state: {
|
||||
closed: "mdi:curtains-closed",
|
||||
closing: "mdi:arrow-collapse-horizontal",
|
||||
opening: "mdi:arrow-split-vertical",
|
||||
},
|
||||
},
|
||||
damper: {
|
||||
default: "mdi:circle",
|
||||
state: {
|
||||
closed: "mdi:circle-slice-8",
|
||||
},
|
||||
},
|
||||
door: {
|
||||
default: "mdi:door-open",
|
||||
state: {
|
||||
closed: "mdi:door-closed",
|
||||
},
|
||||
},
|
||||
garage: {
|
||||
default: "mdi:garage-open",
|
||||
state: {
|
||||
closed: "mdi:garage",
|
||||
closing: "mdi:arrow-down-box",
|
||||
opening: "mdi:arrow-up-box",
|
||||
},
|
||||
},
|
||||
gate: {
|
||||
default: "mdi:gate-open",
|
||||
state: {
|
||||
closed: "mdi:gate",
|
||||
closing: "mdi:arrow-right",
|
||||
opening: "mdi:arrow-right",
|
||||
},
|
||||
},
|
||||
shade: {
|
||||
default: "mdi:roller-shade",
|
||||
state: {
|
||||
closed: "mdi:roller-shade-closed",
|
||||
closing: "mdi:arrow-down-box",
|
||||
opening: "mdi:arrow-up-box",
|
||||
},
|
||||
},
|
||||
shutter: {
|
||||
default: "mdi:window-shutter-open",
|
||||
state: {
|
||||
closed: "mdi:window-shutter",
|
||||
closing: "mdi:arrow-down-box",
|
||||
opening: "mdi:arrow-up-box",
|
||||
},
|
||||
},
|
||||
window: {
|
||||
default: "mdi:window-open",
|
||||
state: {
|
||||
closed: "mdi:window-closed",
|
||||
closing: "mdi:arrow-down-box",
|
||||
opening: "mdi:arrow-up-box",
|
||||
},
|
||||
},
|
||||
},
|
||||
switch: {
|
||||
_: {
|
||||
default: "mdi:toggle-switch-variant",
|
||||
},
|
||||
switch: {
|
||||
default: "mdi:toggle-switch-variant",
|
||||
state: {
|
||||
off: "mdi:toggle-switch-variant-off",
|
||||
},
|
||||
},
|
||||
outlet: {
|
||||
default: "mdi:power-plug",
|
||||
state: {
|
||||
off: "mdi:power-plug-off",
|
||||
},
|
||||
},
|
||||
},
|
||||
button: {
|
||||
_: {
|
||||
default: "mdi:button-pointer",
|
||||
},
|
||||
restart: {
|
||||
default: "mdi:restart",
|
||||
},
|
||||
identify: {
|
||||
default: "mdi:crosshairs-question",
|
||||
},
|
||||
update: {
|
||||
default: "mdi:package-up",
|
||||
},
|
||||
},
|
||||
water_heater: {
|
||||
_: {
|
||||
default: "mdi:water-boiler",
|
||||
state: {
|
||||
off: "mdi:water-boiler-off",
|
||||
},
|
||||
state_attributes: {
|
||||
operation_mode: {
|
||||
default: "mdi:circle-medium",
|
||||
state: {
|
||||
eco: "mdi:leaf",
|
||||
electric: "mdi:lightning-bolt",
|
||||
gas: "mdi:fire-circle",
|
||||
heat_pump: "mdi:heat-wave",
|
||||
high_demand: "mdi:finance",
|
||||
off: "mdi:power",
|
||||
performance: "mdi:rocket-launch",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
binary_sensor: {
|
||||
_: {
|
||||
default: "mdi:radiobox-blank",
|
||||
state: {
|
||||
on: "mdi:checkbox-marked-circle",
|
||||
},
|
||||
},
|
||||
battery: {
|
||||
default: "mdi:battery",
|
||||
state: {
|
||||
on: "mdi:battery-outline",
|
||||
},
|
||||
},
|
||||
battery_charging: {
|
||||
default: "mdi:battery",
|
||||
state: {
|
||||
on: "mdi:battery-charging",
|
||||
},
|
||||
},
|
||||
carbon_monoxide: {
|
||||
default: "mdi:smoke-detector",
|
||||
state: {
|
||||
on: "mdi:smoke-detector-alert",
|
||||
},
|
||||
},
|
||||
cold: {
|
||||
default: "mdi:thermometer",
|
||||
state: {
|
||||
on: "mdi:snowflake",
|
||||
},
|
||||
},
|
||||
connectivity: {
|
||||
default: "mdi:close-network-outline",
|
||||
state: {
|
||||
on: "mdi:check-network-outline",
|
||||
},
|
||||
},
|
||||
door: {
|
||||
default: "mdi:door-closed",
|
||||
state: {
|
||||
on: "mdi:door-open",
|
||||
},
|
||||
},
|
||||
garage_door: {
|
||||
default: "mdi:garage",
|
||||
state: {
|
||||
on: "mdi:garage-open",
|
||||
},
|
||||
},
|
||||
gas: {
|
||||
default: "mdi:check-circle",
|
||||
state: {
|
||||
on: "mdi:alert-circle",
|
||||
},
|
||||
},
|
||||
heat: {
|
||||
default: "mdi:thermometer",
|
||||
state: {
|
||||
on: "mdi:fire",
|
||||
},
|
||||
},
|
||||
light: {
|
||||
default: "mdi:brightness-5",
|
||||
state: {
|
||||
on: "mdi:brightness-7",
|
||||
},
|
||||
},
|
||||
lock: {
|
||||
default: "mdi:lock",
|
||||
state: {
|
||||
on: "mdi:lock-open",
|
||||
},
|
||||
},
|
||||
moisture: {
|
||||
default: "mdi:water-off",
|
||||
state: {
|
||||
on: "mdi:water",
|
||||
},
|
||||
},
|
||||
motion: {
|
||||
default: "mdi:motion-sensor-off",
|
||||
state: {
|
||||
on: "mdi:motion-sensor",
|
||||
},
|
||||
},
|
||||
moving: {
|
||||
default: "mdi:arrow-right",
|
||||
state: {
|
||||
on: "mdi:octagon",
|
||||
},
|
||||
},
|
||||
occupancy: {
|
||||
default: "mdi:home-outline",
|
||||
state: {
|
||||
on: "mdi:home",
|
||||
},
|
||||
},
|
||||
opening: {
|
||||
default: "mdi:square",
|
||||
state: {
|
||||
on: "mdi:square-outline",
|
||||
},
|
||||
},
|
||||
plug: {
|
||||
default: "mdi:power-plug-off",
|
||||
state: {
|
||||
on: "mdi:power-plug",
|
||||
},
|
||||
},
|
||||
power: {
|
||||
default: "mdi:power-plug-off",
|
||||
state: {
|
||||
on: "mdi:power-plug",
|
||||
},
|
||||
},
|
||||
presence: {
|
||||
default: "mdi:home-outline",
|
||||
state: {
|
||||
on: "mdi:home",
|
||||
},
|
||||
},
|
||||
problem: {
|
||||
default: "mdi:check-circle",
|
||||
state: {
|
||||
on: "mdi:alert-circle",
|
||||
},
|
||||
},
|
||||
running: {
|
||||
default: "mdi:stop",
|
||||
state: {
|
||||
on: "mdi:play",
|
||||
},
|
||||
},
|
||||
safety: {
|
||||
default: "mdi:check-circle",
|
||||
state: {
|
||||
on: "mdi:alert-circle",
|
||||
},
|
||||
},
|
||||
smoke: {
|
||||
default: "mdi:smoke-detector-variant",
|
||||
state: {
|
||||
on: "mdi:smoke-detector-variant-alert",
|
||||
},
|
||||
},
|
||||
sound: {
|
||||
default: "mdi:music-note-off",
|
||||
state: {
|
||||
on: "mdi:music-note",
|
||||
},
|
||||
},
|
||||
tamper: {
|
||||
default: "mdi:check-circle",
|
||||
state: {
|
||||
on: "mdi:alert-circle",
|
||||
},
|
||||
},
|
||||
update: {
|
||||
default: "mdi:package",
|
||||
state: {
|
||||
on: "mdi:package-up",
|
||||
},
|
||||
},
|
||||
vibration: {
|
||||
default: "mdi:crop-portrait",
|
||||
state: {
|
||||
on: "mdi:vibrate",
|
||||
},
|
||||
},
|
||||
window: {
|
||||
default: "mdi:window-closed",
|
||||
state: {
|
||||
on: "mdi:window-open",
|
||||
},
|
||||
},
|
||||
},
|
||||
sensor: {
|
||||
_: {
|
||||
default: "mdi:eye",
|
||||
},
|
||||
apparent_power: {
|
||||
default: "mdi:flash",
|
||||
},
|
||||
aqi: {
|
||||
default: "mdi:air-filter",
|
||||
},
|
||||
atmospheric_pressure: {
|
||||
default: "mdi:thermometer-lines",
|
||||
},
|
||||
carbon_dioxide: {
|
||||
default: "mdi:molecule-co2",
|
||||
},
|
||||
carbon_monoxide: {
|
||||
default: "mdi:molecule-co",
|
||||
},
|
||||
current: {
|
||||
default: "mdi:current-ac",
|
||||
},
|
||||
data_rate: {
|
||||
default: "mdi:transmission-tower",
|
||||
},
|
||||
data_size: {
|
||||
default: "mdi:database",
|
||||
},
|
||||
date: {
|
||||
default: "mdi:calendar",
|
||||
},
|
||||
distance: {
|
||||
default: "mdi:arrow-left-right",
|
||||
},
|
||||
duration: {
|
||||
default: "mdi:progress-clock",
|
||||
},
|
||||
energy: {
|
||||
default: "mdi:lightning-bolt",
|
||||
},
|
||||
energy_storage: {
|
||||
default: "mdi:car-battery",
|
||||
},
|
||||
enum: {
|
||||
default: "mdi:eye",
|
||||
},
|
||||
frequency: {
|
||||
default: "mdi:sine-wave",
|
||||
},
|
||||
gas: {
|
||||
default: "mdi:meter-gas",
|
||||
},
|
||||
humidity: {
|
||||
default: "mdi:water-percent",
|
||||
},
|
||||
illuminance: {
|
||||
default: "mdi:brightness-5",
|
||||
},
|
||||
irradiance: {
|
||||
default: "mdi:sun-wireless",
|
||||
},
|
||||
moisture: {
|
||||
default: "mdi:water-percent",
|
||||
},
|
||||
monetary: {
|
||||
default: "mdi:cash",
|
||||
},
|
||||
nitrogen_dioxide: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
nitrogen_monoxide: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
nitrous_oxide: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
ozone: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
ph: {
|
||||
default: "mdi:ph",
|
||||
},
|
||||
pm1: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
pm10: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
pm25: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
power: {
|
||||
default: "mdi:flash",
|
||||
},
|
||||
power_factor: {
|
||||
default: "mdi:angle-acute",
|
||||
},
|
||||
precipitation: {
|
||||
default: "mdi:weather-rainy",
|
||||
},
|
||||
precipitation_intensity: {
|
||||
default: "mdi:weather-pouring",
|
||||
},
|
||||
pressure: {
|
||||
default: "mdi:gauge",
|
||||
},
|
||||
reactive_power: {
|
||||
default: "mdi:flash",
|
||||
},
|
||||
signal_strength: {
|
||||
default: "mdi:wifi",
|
||||
},
|
||||
sound_pressure: {
|
||||
default: "mdi:ear-hearing",
|
||||
},
|
||||
speed: {
|
||||
default: "mdi:speedometer",
|
||||
},
|
||||
sulfur_dioxide: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
temperature: {
|
||||
default: "mdi:thermometer",
|
||||
},
|
||||
timestamp: {
|
||||
default: "mdi:clock",
|
||||
},
|
||||
volatile_organic_compounds: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
volatile_organic_compounds_parts: {
|
||||
default: "mdi:molecule",
|
||||
},
|
||||
voltage: {
|
||||
default: "mdi:sine-wave",
|
||||
},
|
||||
volume: {
|
||||
default: "mdi:car-coolant-level",
|
||||
},
|
||||
volume_storage: {
|
||||
default: "mdi:storage-tank",
|
||||
},
|
||||
water: {
|
||||
default: "mdi:water",
|
||||
},
|
||||
weight: {
|
||||
default: "mdi:weight",
|
||||
},
|
||||
wind_speed: {
|
||||
default: "mdi:weather-windy",
|
||||
},
|
||||
},
|
||||
humidifier: {
|
||||
_: {
|
||||
default: "mdi:air-humidifier",
|
||||
state: {
|
||||
off: "mdi:air-humidifier-off",
|
||||
},
|
||||
state_attributes: {
|
||||
action: {
|
||||
default: "mdi:circle-medium",
|
||||
state: {
|
||||
drying: "mdi:arrow-down-bold",
|
||||
humidifying: "mdi:arrow-up-bold",
|
||||
idle: "mdi:clock-outline",
|
||||
off: "mdi:power",
|
||||
},
|
||||
},
|
||||
mode: {
|
||||
default: "mdi:circle-medium",
|
||||
state: {
|
||||
auto: "mdi:refresh-auto",
|
||||
away: "mdi:account-arrow-right",
|
||||
baby: "mdi:baby-carriage",
|
||||
boost: "mdi:rocket-launch",
|
||||
comfort: "mdi:sofa",
|
||||
eco: "mdi:leaf",
|
||||
home: "mdi:home",
|
||||
normal: "mdi:water-percent",
|
||||
sleep: "mdi:power-sleep",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
valve: {
|
||||
_: {
|
||||
default: "mdi:pipe-valve",
|
||||
},
|
||||
gas: {
|
||||
default: "mdi:meter-gas",
|
||||
},
|
||||
water: {
|
||||
default: "mdi:pipe-valve",
|
||||
},
|
||||
},
|
||||
time: {
|
||||
_: {
|
||||
default: "mdi:clock",
|
||||
},
|
||||
},
|
||||
media_player: {
|
||||
_: {
|
||||
default: "mdi:cast",
|
||||
state: {
|
||||
off: "mdi:cast-off",
|
||||
paused: "mdi:cast-connected",
|
||||
playing: "mdi:cast-connected",
|
||||
},
|
||||
},
|
||||
receiver: {
|
||||
default: "mdi:audio-video",
|
||||
state: {
|
||||
off: "mdi:audio-video-off",
|
||||
},
|
||||
},
|
||||
speaker: {
|
||||
default: "mdi:speaker",
|
||||
state: {
|
||||
off: "mdi:speaker-off",
|
||||
paused: "mdi:speaker-pause",
|
||||
playing: "mdi:speaker-play",
|
||||
},
|
||||
},
|
||||
tv: {
|
||||
default: "mdi:television",
|
||||
state: {
|
||||
off: "mdi:television-off",
|
||||
paused: "mdi:television-pause",
|
||||
playing: "mdi:television-play",
|
||||
},
|
||||
},
|
||||
},
|
||||
air_quality: {
|
||||
_: {
|
||||
default: "mdi:air-filter",
|
||||
},
|
||||
},
|
||||
camera: {
|
||||
_: {
|
||||
default: "mdi:video",
|
||||
state: {
|
||||
off: "mdi:video-off",
|
||||
},
|
||||
},
|
||||
},
|
||||
date: {
|
||||
_: {
|
||||
default: "mdi:calendar",
|
||||
},
|
||||
},
|
||||
fan: {
|
||||
_: {
|
||||
default: "mdi:fan",
|
||||
state: {
|
||||
off: "mdi:fan-off",
|
||||
},
|
||||
state_attributes: {
|
||||
direction: {
|
||||
default: "mdi:rotate-right",
|
||||
state: {
|
||||
reverse: "mdi:rotate-left",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
automation: {
|
||||
_: {
|
||||
default: "mdi:robot",
|
||||
state: {
|
||||
off: "mdi:robot-off",
|
||||
unavailable: "mdi:robot-confused",
|
||||
},
|
||||
},
|
||||
},
|
||||
weather: {
|
||||
_: {
|
||||
default: "mdi:weather-partly-cloudy",
|
||||
state: {
|
||||
"clear-night": "mdi:weather-night",
|
||||
cloudy: "mdi:weather-cloudy",
|
||||
exceptional: "mdi:alert-circle-outline",
|
||||
fog: "mdi:weather-fog",
|
||||
hail: "mdi:weather-hail",
|
||||
lightning: "mdi:weather-lightning",
|
||||
"lightning-rainy": "mdi:weather-lightning-rainy",
|
||||
pouring: "mdi:weather-pouring",
|
||||
rainy: "mdi:weather-rainy",
|
||||
snowy: "mdi:weather-snowy",
|
||||
"snowy-rainy": "mdi:weather-snowy-rainy",
|
||||
sunny: "mdi:weather-sunny",
|
||||
windy: "mdi:weather-windy",
|
||||
"windy-variant": "mdi:weather-windy-variant",
|
||||
},
|
||||
},
|
||||
},
|
||||
climate: {
|
||||
_: {
|
||||
default: "mdi:thermostat",
|
||||
state_attributes: {
|
||||
fan_mode: {
|
||||
default: "mdi:circle-medium",
|
||||
state: {
|
||||
diffuse: "mdi:weather-windy",
|
||||
focus: "mdi:target",
|
||||
high: "mdi:speedometer",
|
||||
low: "mdi:speedometer-slow",
|
||||
medium: "mdi:speedometer-medium",
|
||||
middle: "mdi:speedometer-medium",
|
||||
off: "mdi:fan-off",
|
||||
on: "mdi:fan",
|
||||
},
|
||||
},
|
||||
hvac_action: {
|
||||
default: "mdi:circle-medium",
|
||||
state: {
|
||||
cooling: "mdi:snowflake",
|
||||
drying: "mdi:water-percent",
|
||||
fan: "mdi:fan",
|
||||
heating: "mdi:fire",
|
||||
idle: "mdi:clock-outline",
|
||||
off: "mdi:power",
|
||||
preheating: "mdi:heat-wave",
|
||||
},
|
||||
},
|
||||
preset_mode: {
|
||||
default: "mdi:circle-medium",
|
||||
state: {
|
||||
activity: "mdi:motion-sensor",
|
||||
away: "mdi:account-arrow-right",
|
||||
boost: "mdi:rocket-launch",
|
||||
comfort: "mdi:sofa",
|
||||
eco: "mdi:leaf",
|
||||
home: "mdi:home",
|
||||
sleep: "mdi:bed",
|
||||
},
|
||||
},
|
||||
swing_mode: {
|
||||
default: "mdi:circle-medium",
|
||||
state: {
|
||||
both: "mdi:arrow-all",
|
||||
horizontal: "mdi:arrow-left-right",
|
||||
off: "mdi:arrow-oscillating-off",
|
||||
on: "mdi:arrow-oscillating",
|
||||
vertical: "mdi:arrow-up-down",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
stt: {
|
||||
_: {
|
||||
default: "mdi:microphone-message",
|
||||
},
|
||||
},
|
||||
update: {
|
||||
_: {
|
||||
default: "mdi:package-up",
|
||||
state: {
|
||||
off: "mdi:package",
|
||||
},
|
||||
},
|
||||
},
|
||||
event: {
|
||||
_: {
|
||||
default: "mdi:eye-check",
|
||||
},
|
||||
button: {
|
||||
default: "mdi:gesture-tap-button",
|
||||
},
|
||||
doorbell: {
|
||||
default: "mdi:doorbell",
|
||||
},
|
||||
motion: {
|
||||
default: "mdi:motion-sensor",
|
||||
},
|
||||
},
|
||||
};
|
@@ -1,15 +1,6 @@
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, eventOptions, property } from "lit/decorators";
|
||||
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||
import { toggleAttribute } from "../common/dom/toggle_attribute";
|
||||
import { computeRTL } from "../common/util/compute_rtl";
|
||||
import "../components/ha-icon-button-arrow-prev";
|
||||
import "../components/ha-menu-button";
|
||||
import { HomeAssistant } from "../types";
|
||||
@@ -34,17 +25,6 @@ class HassSubpage extends LitElement {
|
||||
// @ts-ignore
|
||||
@restoreScroll(".content") private _savedScrollPos?: number;
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues): void {
|
||||
super.willUpdate(changedProps);
|
||||
if (!changedProps.has("hass")) {
|
||||
return;
|
||||
}
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || oldHass.locale !== this.hass.locale) {
|
||||
toggleAttribute(this, "rtl", computeRTL(this.hass));
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div class="toolbar">
|
||||
@@ -160,6 +140,9 @@ class HassSubpage extends LitElement {
|
||||
#fab {
|
||||
position: absolute;
|
||||
right: calc(16px + env(safe-area-inset-right));
|
||||
inset-inline-end: calc(16px + env(safe-area-inset-right));
|
||||
inset-inline-start: initial;
|
||||
|
||||
bottom: calc(16px + env(safe-area-inset-bottom));
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -169,15 +152,8 @@ class HassSubpage extends LitElement {
|
||||
#fab[is-wide] {
|
||||
bottom: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
:host([rtl]) #fab {
|
||||
right: auto;
|
||||
left: calc(16px + env(safe-area-inset-left));
|
||||
}
|
||||
:host([rtl][is-wide]) #fab {
|
||||
bottom: 24px;
|
||||
left: 24px;
|
||||
right: auto;
|
||||
inset-inline-end: 24px;
|
||||
inset-inline-start: initial;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
@@ -4,7 +4,6 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
import { computeRTLDirection } from "../common/util/compute_rtl";
|
||||
import "../components/data-table/ha-data-table";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
@@ -244,7 +243,6 @@ export class HaTabsSubpageDataTable extends LitElement {
|
||||
.selectable=${this.selectable}
|
||||
.hasFab=${this.hasFab}
|
||||
.id=${this.id}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
.clickable=${this.clickable}
|
||||
.appendRow=${this.appendRow}
|
||||
>
|
||||
|
@@ -13,7 +13,6 @@ import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
import { computeRTL } from "../common/util/compute_rtl";
|
||||
import "../components/ha-icon-button-arrow-prev";
|
||||
import "../components/ha-menu-button";
|
||||
import "../components/ha-svg-icon";
|
||||
@@ -58,8 +57,6 @@ class HassTabsSubpage extends LitElement {
|
||||
@property({ type: Boolean, reflect: true, attribute: "is-wide" })
|
||||
public isWide = false;
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public rtl = false;
|
||||
|
||||
@state() private _activeTab?: PageNavigation;
|
||||
|
||||
// @ts-ignore
|
||||
@@ -123,14 +120,6 @@ class HassTabsSubpage extends LitElement {
|
||||
`${this.route.prefix}${this.route.path}`.includes(tab.path)
|
||||
);
|
||||
}
|
||||
if (changedProperties.has("hass")) {
|
||||
const oldHass = changedProperties.get("hass") as
|
||||
| HomeAssistant
|
||||
| undefined;
|
||||
if (!oldHass || oldHass.language !== this.hass.language) {
|
||||
this.rtl = computeRTL(this.hass);
|
||||
}
|
||||
}
|
||||
super.willUpdate(changedProperties);
|
||||
}
|
||||
|
||||
@@ -334,6 +323,8 @@ class HassTabsSubpage extends LitElement {
|
||||
#fab {
|
||||
position: fixed;
|
||||
right: calc(16px + env(safe-area-inset-right));
|
||||
inset-inline-end: calc(16px + env(safe-area-inset-right));
|
||||
inset-inline-start: initial;
|
||||
bottom: calc(16px + env(safe-area-inset-bottom));
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -343,15 +334,8 @@ class HassTabsSubpage extends LitElement {
|
||||
#fab[is-wide] {
|
||||
bottom: 24px;
|
||||
right: 24px;
|
||||
}
|
||||
:host([rtl]) #fab {
|
||||
right: auto;
|
||||
left: calc(16px + env(safe-area-inset-left));
|
||||
}
|
||||
:host([rtl][is-wide]) #fab {
|
||||
bottom: 24px;
|
||||
left: 24px;
|
||||
right: auto;
|
||||
inset-inline-end: 24px;
|
||||
inset-inline-start: initial;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
@@ -11,11 +11,11 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent, HASSDomEvent } from "../common/dom/fire_event";
|
||||
import { listenMediaQuery } from "../common/dom/media_query";
|
||||
import { toggleAttribute } from "../common/dom/toggle_attribute";
|
||||
import { computeRTLDirection } from "../common/util/compute_rtl";
|
||||
import "../components/ha-drawer";
|
||||
import { showNotificationDrawer } from "../dialogs/notifications/show-notification-drawer";
|
||||
import type { HomeAssistant, Route } from "../types";
|
||||
import "./partial-panel-resolver";
|
||||
import { computeRTLDirection } from "../common/util/compute_rtl";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
|
@@ -28,7 +28,6 @@ import { useAmPm } from "../../common/datetime/use_am_pm";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { supportsFeature } from "../../common/entity/supports-feature";
|
||||
import { LocalizeFunc } from "../../common/translations/localize";
|
||||
import { computeRTLDirection } from "../../common/util/compute_rtl";
|
||||
import "../../components/ha-button-toggle-group";
|
||||
import "../../components/ha-fab";
|
||||
import "../../components/ha-icon-button-next";
|
||||
@@ -169,7 +168,6 @@ export class HAFullCalendar extends LitElement {
|
||||
.buttons=${viewToggleButtons}
|
||||
.active=${this._activeView}
|
||||
@value-changed=${this._handleView}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
></ha-button-toggle-group>
|
||||
`
|
||||
: html`
|
||||
@@ -203,7 +201,6 @@ export class HAFullCalendar extends LitElement {
|
||||
.buttons=${viewToggleButtons}
|
||||
.active=${this._activeView}
|
||||
@value-changed=${this._handleView}
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
></ha-button-toggle-group>
|
||||
</div>
|
||||
`}
|
||||
@@ -503,6 +500,8 @@ export class HAFullCalendar extends LitElement {
|
||||
position: absolute;
|
||||
bottom: 32px;
|
||||
right: 32px;
|
||||
inset-inline-end: 32px;
|
||||
inset-inline-start: initial;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
|
@@ -77,10 +77,12 @@ export default class HaAutomationAction extends LitElement {
|
||||
return html`
|
||||
<ha-sortable
|
||||
handle-selector=".handle"
|
||||
draggable-selector="ha-automation-action-row"
|
||||
.disabled=${!this._showReorder || this.disabled}
|
||||
@item-moved=${this._actionMoved}
|
||||
group="actions"
|
||||
.path=${this.path}
|
||||
invert-swap
|
||||
>
|
||||
<div class="actions">
|
||||
${repeat(
|
||||
@@ -111,30 +113,29 @@ export default class HaAutomationAction extends LitElement {
|
||||
</ha-automation-action-row>
|
||||
`
|
||||
)}
|
||||
<div class="buttons">
|
||||
<ha-button
|
||||
outlined
|
||||
.disabled=${this.disabled}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.add"
|
||||
)}
|
||||
@click=${this._addActionDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
<ha-button
|
||||
.disabled=${this.disabled}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.add_building_block"
|
||||
)}
|
||||
@click=${this._addActionBuildingBlockDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</ha-sortable>
|
||||
<div class="buttons">
|
||||
<ha-button
|
||||
outlined
|
||||
.disabled=${this.disabled}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.add"
|
||||
)}
|
||||
@click=${this._addActionDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
<ha-button
|
||||
.disabled=${this.disabled}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.add_building_block"
|
||||
)}
|
||||
@click=${this._addActionBuildingBlockDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -202,12 +203,14 @@ export default class HaAutomationAction extends LitElement {
|
||||
}
|
||||
|
||||
private _moveUp(ev) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
const newIndex = index - 1;
|
||||
this._move(index, newIndex);
|
||||
}
|
||||
|
||||
private _moveDown(ev) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
const newIndex = index + 1;
|
||||
this._move(index, newIndex);
|
||||
@@ -266,22 +269,29 @@ export default class HaAutomationAction extends LitElement {
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
.actions {
|
||||
padding: 16px;
|
||||
margin: -16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
.sortable-ghost {
|
||||
background: none;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
}
|
||||
.sortable-drag {
|
||||
background: none;
|
||||
}
|
||||
ha-automation-action-row {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
scroll-margin-top: 48px;
|
||||
}
|
||||
ha-svg-icon {
|
||||
height: 20px;
|
||||
}
|
||||
ha-alert {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
overflow: hidden;
|
||||
}
|
||||
.handle {
|
||||
padding: 12px 4px;
|
||||
padding: 12px;
|
||||
cursor: move; /* fallback if grab cursor is unsupported */
|
||||
cursor: grab;
|
||||
}
|
||||
@@ -293,6 +303,7 @@ export default class HaAutomationAction extends LitElement {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
order: 1;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@@ -122,9 +122,11 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
||||
return html`
|
||||
<ha-sortable
|
||||
handle-selector=".handle"
|
||||
draggable-selector=".option"
|
||||
.disabled=${!this._showReorder || this.disabled}
|
||||
group="choose-options"
|
||||
.path=${[...(this.path ?? []), "choose"]}
|
||||
invert-swap
|
||||
>
|
||||
<div class="options">
|
||||
${repeat(
|
||||
@@ -276,18 +278,21 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
<div class="buttons">
|
||||
<ha-button
|
||||
outlined
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.choose.add_option"
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@click=${this._addOption}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</ha-sortable>
|
||||
<ha-button
|
||||
outlined
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.choose.add_option"
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@click=${this._addOption}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
|
||||
${this._showDefault || action.default
|
||||
? html`
|
||||
<h2>
|
||||
@@ -296,7 +301,7 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
||||
)}:
|
||||
</h2>
|
||||
<ha-automation-action
|
||||
.path=${[...(this.path ?? []), "choose", "default"]}
|
||||
.path=${[...(this.path ?? []), "default"]}
|
||||
.actions=${ensureArray(action.default) || []}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._defaultChanged}
|
||||
@@ -502,8 +507,19 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.option {
|
||||
margin: 0 0 16px 0;
|
||||
.options {
|
||||
padding: 16px;
|
||||
margin: -16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
.sortable-ghost {
|
||||
background: none;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
}
|
||||
.sortable-drag {
|
||||
background: none;
|
||||
}
|
||||
.add-card mwc-button {
|
||||
display: block;
|
||||
@@ -539,7 +555,7 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
||||
padding: 0 16px 16px 16px;
|
||||
}
|
||||
.handle {
|
||||
padding: 12px 4px;
|
||||
padding: 12px;
|
||||
cursor: move; /* fallback if grab cursor is unsupported */
|
||||
cursor: grab;
|
||||
}
|
||||
@@ -547,6 +563,12 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
||||
pointer-events: none;
|
||||
height: 24px;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
order: 1;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -117,10 +117,12 @@ export default class HaAutomationCondition extends LitElement {
|
||||
return html`
|
||||
<ha-sortable
|
||||
handle-selector=".handle"
|
||||
draggable-selector="ha-automation-condition-row"
|
||||
.disabled=${!this._showReorder || this.disabled}
|
||||
@item-moved=${this._conditionMoved}
|
||||
group="conditions"
|
||||
.path=${this.path}
|
||||
invert-swap
|
||||
>
|
||||
<div class="conditions">
|
||||
${repeat(
|
||||
@@ -151,29 +153,29 @@ export default class HaAutomationCondition extends LitElement {
|
||||
</ha-automation-condition-row>
|
||||
`
|
||||
)}
|
||||
<div class="buttons">
|
||||
<ha-button
|
||||
outlined
|
||||
.disabled=${this.disabled}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.add"
|
||||
)}
|
||||
@click=${this._addConditionDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
<ha-button
|
||||
.disabled=${this.disabled}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.add_building_block"
|
||||
)}
|
||||
@click=${this._addConditionBuildingBlockDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</ha-sortable>
|
||||
<div class="buttons">
|
||||
<ha-button
|
||||
outlined
|
||||
.disabled=${this.disabled}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.add"
|
||||
)}
|
||||
@click=${this._addConditionDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
<ha-button
|
||||
.disabled=${this.disabled}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.add_building_block"
|
||||
)}
|
||||
@click=${this._addConditionBuildingBlockDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -225,12 +227,14 @@ export default class HaAutomationCondition extends LitElement {
|
||||
}
|
||||
|
||||
private _moveUp(ev) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
const newIndex = index - 1;
|
||||
this._move(index, newIndex);
|
||||
}
|
||||
|
||||
private _moveDown(ev) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
const newIndex = index + 1;
|
||||
this._move(index, newIndex);
|
||||
@@ -291,22 +295,32 @@ export default class HaAutomationCondition extends LitElement {
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
.conditions {
|
||||
padding: 16px;
|
||||
margin: -16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
.sortable-ghost {
|
||||
background: none;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
}
|
||||
.sortable-drag {
|
||||
background: none;
|
||||
}
|
||||
ha-automation-condition-row {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
scroll-margin-top: 48px;
|
||||
}
|
||||
.buttons {
|
||||
order: 1;
|
||||
}
|
||||
ha-svg-icon {
|
||||
height: 20px;
|
||||
}
|
||||
ha-alert {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
overflow: hidden;
|
||||
}
|
||||
.handle {
|
||||
padding: 12px 4px;
|
||||
padding: 12px;
|
||||
cursor: move; /* fallback if grab cursor is unsupported */
|
||||
cursor: grab;
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import "@material/mwc-button";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import {
|
||||
mdiCheck,
|
||||
mdiContentDuplicate,
|
||||
@@ -35,6 +34,7 @@ import "../../../components/ha-fab";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import "../../../components/ha-yaml-editor";
|
||||
import "../../../components/ha-list-item";
|
||||
import {
|
||||
AutomationConfig,
|
||||
AutomationEntity,
|
||||
@@ -150,7 +150,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.disabled=${!stateObj}
|
||||
@click=${this._showInfo}
|
||||
@@ -160,20 +160,20 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
slot="graphic"
|
||||
.path=${mdiInformationOutline}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.disabled=${!stateObj}
|
||||
@click=${this._runActions}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.run")}
|
||||
<ha-svg-icon slot="graphic" .path=${mdiPlay}></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
${stateObj && this._config && this.narrow
|
||||
? html`<a href="/config/automation/trace/${this._config.id}">
|
||||
<mwc-list-item graphic="icon">
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.show_trace"
|
||||
)}
|
||||
@@ -181,22 +181,22 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
slot="graphic"
|
||||
.path=${mdiTransitConnection}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
</a>`
|
||||
: ""}
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@click=${this._promptAutomationAlias}
|
||||
.disabled=${!this.automationId || this._mode === "yaml"}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.rename")}
|
||||
<ha-svg-icon slot="graphic" .path=${mdiRenameBox}></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
${this._config && !("use_blueprint" in this._config)
|
||||
? html`
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@click=${this._promptAutomationMode}
|
||||
.disabled=${this._readOnly || this._mode === "yaml"}
|
||||
@@ -208,11 +208,11 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
slot="graphic"
|
||||
.path=${mdiDebugStepOver}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
`
|
||||
: ""}
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
.disabled=${!this._readOnly && !this.automationId}
|
||||
graphic="icon"
|
||||
@click=${this._duplicate}
|
||||
@@ -226,11 +226,11 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
slot="graphic"
|
||||
.path=${mdiContentDuplicate}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
<li divider role="separator"></li>
|
||||
|
||||
<mwc-list-item graphic="icon" @click=${this._switchUiMode}>
|
||||
<ha-list-item graphic="icon" @click=${this._switchUiMode}>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.edit_ui")}
|
||||
${this._mode === "gui"
|
||||
? html`<ha-svg-icon
|
||||
@@ -239,8 +239,8 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
.path=${mdiCheck}
|
||||
></ha-svg-icon>`
|
||||
: ``}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item graphic="icon" @click=${this._switchYamlMode}>
|
||||
</ha-list-item>
|
||||
<ha-list-item graphic="icon" @click=${this._switchYamlMode}>
|
||||
${this.hass.localize("ui.panel.config.automation.editor.edit_yaml")}
|
||||
${this._mode === "yaml"
|
||||
? html`<ha-svg-icon
|
||||
@@ -249,11 +249,11 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
.path=${mdiCheck}
|
||||
></ha-svg-icon>`
|
||||
: ``}
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
<li divider role="separator"></li>
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.disabled=${!stateObj}
|
||||
@click=${this._toggle}
|
||||
@@ -267,9 +267,9 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
? mdiPlayCircleOutline
|
||||
: mdiStopCircleOutline}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
|
||||
<mwc-list-item
|
||||
<ha-list-item
|
||||
.disabled=${!this.automationId}
|
||||
class=${classMap({ warning: Boolean(this.automationId) })}
|
||||
graphic="icon"
|
||||
@@ -282,7 +282,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
.path=${mdiDelete}
|
||||
>
|
||||
</ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
|
||||
${this._config
|
||||
|
@@ -232,6 +232,7 @@ export class HaAutomationTrace extends LitElement {
|
||||
<div class="main">
|
||||
<div class="graph">
|
||||
<hat-script-graph
|
||||
.hass=${this.hass}
|
||||
.trace=${this._trace}
|
||||
.selected=${this._selected?.path}
|
||||
@graph-node-selected=${this._pickNode}
|
||||
|
@@ -74,10 +74,12 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
return html`
|
||||
<ha-sortable
|
||||
handle-selector=".handle"
|
||||
draggable-selector="ha-automation-trigger-row"
|
||||
.disabled=${!this._showReorder || this.disabled}
|
||||
@item-moved=${this._triggerMoved}
|
||||
group="triggers"
|
||||
.path=${this.path}
|
||||
invert-swap
|
||||
>
|
||||
<div class="triggers">
|
||||
${repeat(
|
||||
@@ -107,18 +109,20 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
</ha-automation-trigger-row>
|
||||
`
|
||||
)}
|
||||
<div class="buttons">
|
||||
<ha-button
|
||||
outlined
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.add"
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@click=${this._addTriggerDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
</div>
|
||||
</div>
|
||||
</ha-sortable>
|
||||
<ha-button
|
||||
outlined
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.add"
|
||||
)}
|
||||
.disabled=${this.disabled}
|
||||
@click=${this._addTriggerDialog}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -176,12 +180,14 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
}
|
||||
|
||||
private _moveUp(ev) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
const newIndex = index - 1;
|
||||
this._move(index, newIndex);
|
||||
}
|
||||
|
||||
private _moveDown(ev) {
|
||||
ev.stopPropagation();
|
||||
const index = (ev.target as any).index;
|
||||
const newIndex = index + 1;
|
||||
this._move(index, newIndex);
|
||||
@@ -240,22 +246,29 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
.triggers {
|
||||
padding: 16px;
|
||||
margin: -16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
.sortable-ghost {
|
||||
background: none;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
}
|
||||
.sortable-drag {
|
||||
background: none;
|
||||
}
|
||||
ha-automation-trigger-row {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
scroll-margin-top: 48px;
|
||||
}
|
||||
ha-svg-icon {
|
||||
height: 20px;
|
||||
}
|
||||
ha-alert {
|
||||
display: block;
|
||||
margin-bottom: 16px;
|
||||
border-radius: var(--ha-card-border-radius, 16px);
|
||||
overflow: hidden;
|
||||
}
|
||||
.handle {
|
||||
padding: 12px 4px;
|
||||
padding: 12px;
|
||||
cursor: move; /* fallback if grab cursor is unsupported */
|
||||
cursor: grab;
|
||||
}
|
||||
@@ -263,6 +276,12 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
pointer-events: none;
|
||||
height: 24px;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
order: 1;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import "@material/mwc-button";
|
||||
import { css, html, LitElement, PropertyValues } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { formatDateTime } from "../../../../common/datetime/format_date_time";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import { debounce } from "../../../../common/util/debounce";
|
||||
import "../../../../components/ha-alert";
|
||||
import "../../../../components/ha-card";
|
||||
@@ -37,8 +36,6 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _subscription?: SubscriptionInfo;
|
||||
|
||||
@state() private _rtlDirection: "rtl" | "ltr" = "rtl";
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<hass-subpage
|
||||
@@ -172,13 +169,11 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
<cloud-remote-pref
|
||||
.hass=${this.hass}
|
||||
.cloudStatus=${this.cloudStatus}
|
||||
dir=${this._rtlDirection}
|
||||
></cloud-remote-pref>
|
||||
|
||||
<cloud-tts-pref
|
||||
.hass=${this.hass}
|
||||
.cloudStatus=${this.cloudStatus}
|
||||
dir=${this._rtlDirection}
|
||||
></cloud-tts-pref>
|
||||
|
||||
<ha-tip .hass=${this.hass}>
|
||||
@@ -193,7 +188,6 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.cloudStatus=${this.cloudStatus}
|
||||
dir=${this._rtlDirection}
|
||||
></cloud-webhooks>
|
||||
</ha-config-section>
|
||||
</div>
|
||||
@@ -205,15 +199,6 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
this._fetchSubscriptionInfo();
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
if (changedProps.has("hass")) {
|
||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||
if (!oldHass || oldHass.locale !== this.hass.locale) {
|
||||
this._rtlDirection = computeRTLDirection(this.hass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override hassSubscribe() {
|
||||
const googleCheck = debounce(
|
||||
() => {
|
||||
@@ -272,10 +257,6 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
fireEvent(this, "ha-refresh-cloud-status");
|
||||
}
|
||||
|
||||
_computeRTLDirection(hass) {
|
||||
return computeRTLDirection(hass);
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return [
|
||||
haStyle,
|
||||
|
@@ -13,6 +13,7 @@ import {
|
||||
CloudStatusLoggedIn,
|
||||
connectCloudRemote,
|
||||
disconnectCloudRemote,
|
||||
updateCloudPref,
|
||||
} from "../../../../data/cloud";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { showToast } from "../../../../util/toast";
|
||||
@@ -29,7 +30,8 @@ export class CloudRemotePref extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const { remote_enabled } = this.cloudStatus.prefs;
|
||||
const { remote_enabled, remote_allow_remote_enable } =
|
||||
this.cloudStatus.prefs;
|
||||
|
||||
const {
|
||||
remote_connected,
|
||||
@@ -126,6 +128,12 @@ export class CloudRemotePref extends LitElement {
|
||||
.path=${mdiContentCopy}
|
||||
@click=${this._copyURL}
|
||||
></ha-svg-icon>
|
||||
<ha-formfield .label=${"Allow external activation"}>
|
||||
<ha-switch
|
||||
.checked=${remote_allow_remote_enable}
|
||||
@change=${this._toggleAllowRemoteEnabledChanged}
|
||||
></ha-switch>
|
||||
</ha-formfield>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._openCertInfo}>
|
||||
@@ -160,6 +168,20 @@ export class CloudRemotePref extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _toggleAllowRemoteEnabledChanged(ev) {
|
||||
const toggle = ev.target as HaSwitch;
|
||||
|
||||
try {
|
||||
await updateCloudPref(this.hass, {
|
||||
remote_allow_remote_enable: toggle.checked,
|
||||
});
|
||||
fireEvent(this, "ha-refresh-cloud-status");
|
||||
} catch (err: any) {
|
||||
alert(err.message);
|
||||
toggle.checked = !toggle.checked;
|
||||
}
|
||||
}
|
||||
|
||||
private async _copyURL(ev): Promise<void> {
|
||||
const url = ev.currentTarget.url;
|
||||
await copyToClipboard(url);
|
||||
@@ -179,14 +201,12 @@ export class CloudRemotePref extends LitElement {
|
||||
.header-actions {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
inset-inline-end: 24px;
|
||||
inset-inline-start: initial;
|
||||
top: 24px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
:host([dir="rtl"]) .header-actions {
|
||||
right: auto;
|
||||
left: 24px;
|
||||
}
|
||||
.header-actions .icon-link {
|
||||
margin-top: -16px;
|
||||
margin-right: 8px;
|
||||
@@ -218,6 +238,9 @@ export class CloudRemotePref extends LitElement {
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
ha-formfield {
|
||||
margin-top: 8px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@@ -177,12 +177,10 @@ export class CloudTTSPref extends LitElement {
|
||||
.example {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
inset-inline-end: 16px;
|
||||
inset-inline-start: initial;
|
||||
top: 16px;
|
||||
}
|
||||
:host([dir="rtl"]) .example {
|
||||
right: auto;
|
||||
left: 24px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
}
|
||||
|
@@ -144,15 +144,6 @@ export class CloudLogin extends LitElement {
|
||||
"ui.panel.config.cloud.login.password_error_msg"
|
||||
)}
|
||||
></ha-textfield>
|
||||
<button
|
||||
class="link pwd-forgot-link"
|
||||
.disabled=${this._requestInProgress}
|
||||
@click=${this._handleForgotPassword}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.cloud.login.forgot_password"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<ha-progress-button
|
||||
@@ -162,6 +153,15 @@ export class CloudLogin extends LitElement {
|
||||
"ui.panel.config.cloud.login.sign_in"
|
||||
)}</ha-progress-button
|
||||
>
|
||||
<button
|
||||
class="link pwd-forgot-link"
|
||||
.disabled=${this._requestInProgress}
|
||||
@click=${this._handleForgotPassword}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.cloud.login.forgot_password"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</ha-card>
|
||||
|
||||
@@ -311,11 +311,6 @@ export class CloudLogin extends LitElement {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.pwd-forgot-link {
|
||||
color: var(--secondary-text-color) !important;
|
||||
text-align: right !important;
|
||||
align-self: flex-end;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@ import {
|
||||
} from "lit";
|
||||
import { customElement, state } from "lit/decorators";
|
||||
import { computeStateName } from "../../../../../../common/entity/compute_state_name";
|
||||
import { computeRTLDirection } from "../../../../../../common/util/compute_rtl";
|
||||
import "../../../../../../components/ha-dialog";
|
||||
import "../../../../../../components/ha-formfield";
|
||||
import "../../../../../../components/ha-switch";
|
||||
@@ -51,8 +50,6 @@ class DialogMQTTDeviceDebugInfo extends LitElement {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const dir = computeRTLDirection(this.hass!);
|
||||
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
@@ -72,7 +69,6 @@ class DialogMQTTDeviceDebugInfo extends LitElement {
|
||||
.label=${this.hass!.localize(
|
||||
"ui.dialogs.mqtt_device_debug_info.deserialize"
|
||||
)}
|
||||
.dir=${dir}
|
||||
>
|
||||
<ha-switch
|
||||
.checked=${this._showDeserialized}
|
||||
@@ -87,7 +83,6 @@ class DialogMQTTDeviceDebugInfo extends LitElement {
|
||||
.label=${this.hass!.localize(
|
||||
"ui.dialogs.mqtt_device_debug_info.show_as_yaml"
|
||||
)}
|
||||
.dir=${dir}
|
||||
>
|
||||
<ha-switch
|
||||
.checked=${this._showAsYaml}
|
||||
|
@@ -20,7 +20,6 @@ import {
|
||||
} from "../../../common/integrations/protocolIntegrationPicked";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
@@ -488,7 +487,6 @@ export class HaConfigDeviceDashboard extends LitElement {
|
||||
.label=${this.hass.localize("ui.panel.config.devices.add_device")}
|
||||
extended
|
||||
@click=${this._addDevice}
|
||||
?rtl=${computeRTL(this.hass)}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||
</ha-fab>
|
||||
|
@@ -31,11 +31,11 @@ import "../../../components/ha-area-picker";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-button-next";
|
||||
import "../../../components/ha-icon-picker";
|
||||
import "../../../components/ha-state-icon";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-radio";
|
||||
import "../../../components/ha-select";
|
||||
import "../../../components/ha-settings-row";
|
||||
import "../../../components/ha-state-icon";
|
||||
import "../../../components/ha-switch";
|
||||
import type { HaSwitch } from "../../../components/ha-switch";
|
||||
import "../../../components/ha-textfield";
|
||||
@@ -52,10 +52,6 @@ import {
|
||||
createConfigFlow,
|
||||
handleConfigFlowStep,
|
||||
} from "../../../data/config_flow";
|
||||
import {
|
||||
createOptionsFlow,
|
||||
handleOptionsFlowStep,
|
||||
} from "../../../data/options_flow";
|
||||
import { DataEntryFlowStepCreateEntry } from "../../../data/data_entry_flow";
|
||||
import {
|
||||
DeviceRegistryEntry,
|
||||
@@ -70,9 +66,13 @@ import {
|
||||
subscribeEntityRegistry,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../data/entity_registry";
|
||||
import { entityIcon } from "../../../data/icons";
|
||||
import { entityIcon, entryIcon } from "../../../data/icons";
|
||||
import { domainToName } from "../../../data/integration";
|
||||
import { getNumberDeviceClassConvertibleUnits } from "../../../data/number";
|
||||
import {
|
||||
createOptionsFlow,
|
||||
handleOptionsFlowStep,
|
||||
} from "../../../data/options_flow";
|
||||
import {
|
||||
getSensorDeviceClassConvertibleUnits,
|
||||
getSensorNumericDeviceClasses,
|
||||
@@ -392,7 +392,8 @@ export class EntityRegistrySettingsEditor extends LitElement {
|
||||
)}
|
||||
.placeholder=${this.entry.original_icon ||
|
||||
stateObj?.attributes.icon ||
|
||||
(stateObj && until(entityIcon(this.hass, stateObj)))}
|
||||
(stateObj && until(entityIcon(this.hass, stateObj))) ||
|
||||
until(entryIcon(this.hass, this.entry))}
|
||||
.disabled=${this.disabled}
|
||||
>
|
||||
${!this._icon && !stateObj?.attributes.icon && stateObj
|
||||
|
@@ -25,6 +25,7 @@ import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { until } from "lit/directives/until";
|
||||
import memoize from "memoize-one";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
@@ -35,7 +36,6 @@ import {
|
||||
} from "../../../common/integrations/protocolIntegrationPicked";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
@@ -43,6 +43,7 @@ import type {
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-check-list-item";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { ConfigEntry, getConfigEntries } from "../../../data/config_entries";
|
||||
@@ -54,6 +55,7 @@ import {
|
||||
removeEntityRegistryEntry,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../data/entity_registry";
|
||||
import { entryIcon } from "../../../data/icons";
|
||||
import { domainToName } from "../../../data/integration";
|
||||
import {
|
||||
showAlertDialog,
|
||||
@@ -208,14 +210,23 @@ export class HaConfigEntities extends LitElement {
|
||||
title: "",
|
||||
label: localize("ui.panel.config.entities.picker.headers.state_icon"),
|
||||
type: "icon",
|
||||
template: (entry) => html`
|
||||
<ha-state-icon
|
||||
title=${ifDefined(entry.entity?.state)}
|
||||
slot="item-icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${entry.entity}
|
||||
></ha-state-icon>
|
||||
`,
|
||||
template: (entry) =>
|
||||
entry.icon
|
||||
? html`
|
||||
<ha-state-icon
|
||||
title=${ifDefined(entry.entity?.state)}
|
||||
slot="item-icon"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${entry.entity}
|
||||
></ha-state-icon>
|
||||
`
|
||||
: html`
|
||||
<ha-icon
|
||||
icon=${until(
|
||||
entryIcon(this.hass, entry as EntityRegistryEntry)
|
||||
)}
|
||||
></ha-icon>
|
||||
`,
|
||||
},
|
||||
name: {
|
||||
main: true,
|
||||
@@ -680,7 +691,6 @@ export class HaConfigEntities extends LitElement {
|
||||
extended
|
||||
@click=${this._addDevice}
|
||||
slot="fab"
|
||||
?rtl=${computeRTL(this.hass)}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||
</ha-fab>`
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { mdiClose } from "@mdi/js";
|
||||
import { mdiDelete } from "@mdi/js";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
@@ -20,8 +20,6 @@ import { haStyleDialog } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { MatterManageFabricsDialogParams } from "./show-dialog-matter-manage-fabrics";
|
||||
|
||||
const NABUCASA_FABRIC = 4939;
|
||||
|
||||
@customElement("dialog-matter-manage-fabrics")
|
||||
class DialogMatterManageFabrics extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@@ -61,8 +59,9 @@ class DialogMatterManageFabrics extends LitElement {
|
||||
(fabric) =>
|
||||
html`<ha-list-item
|
||||
noninteractive
|
||||
.hasMeta=${this._nodeDiagnostics?.available &&
|
||||
fabric.vendor_id !== NABUCASA_FABRIC}
|
||||
.hasMeta=${this._nodeDiagnostics!.available &&
|
||||
fabric.fabric_index !==
|
||||
this._nodeDiagnostics!.active_fabric_index}
|
||||
>${fabric.vendor_name ||
|
||||
fabric.fabric_label ||
|
||||
fabric.vendor_id}
|
||||
@@ -70,7 +69,7 @@ class DialogMatterManageFabrics extends LitElement {
|
||||
@click=${this._removeFabric}
|
||||
slot="meta"
|
||||
.fabric=${fabric}
|
||||
.path=${mdiClose}
|
||||
.path=${mdiDelete}
|
||||
></ha-icon-button>
|
||||
</ha-list-item>`
|
||||
)}
|
||||
@@ -99,6 +98,9 @@ class DialogMatterManageFabrics extends LitElement {
|
||||
|
||||
private async _removeFabric(ev) {
|
||||
const fabric: MatterFabricData = ev.target.fabric;
|
||||
if (this._nodeDiagnostics!.active_fabric_index === fabric.fabric_index) {
|
||||
return;
|
||||
}
|
||||
const fabricName =
|
||||
fabric.vendor_name || fabric.fabric_label || fabric.vendor_id.toString();
|
||||
const confirm = await showConfirmationDialog(this, {
|
||||
|
@@ -1,18 +1,21 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { mdiCheckCircle, mdiCloseCircle } from "@mdi/js";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { mdiCloseCircle } from "@mdi/js";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-circular-progress";
|
||||
import "../../../../../components/ha-qr-code";
|
||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||
import "../../../../../components/ha-qr-code";
|
||||
import { domainToName } from "../../../../../data/integration";
|
||||
import {
|
||||
openMatterCommissioningWindow,
|
||||
MatterCommissioningParameters,
|
||||
openMatterCommissioningWindow,
|
||||
} from "../../../../../data/matter";
|
||||
import { haStyleDialog } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { brandsUrl } from "../../../../../util/brands-url";
|
||||
import { MatterOpenCommissioningWindowDialogParams } from "./show-dialog-matter-open-commissioning-window";
|
||||
import { copyToClipboard } from "../../../../../common/util/copy-clipboard";
|
||||
|
||||
@customElement("dialog-matter-open-commissioning-window")
|
||||
class DialogMatterOpenCommissioningWindow extends LitElement {
|
||||
@@ -48,27 +51,50 @@ class DialogMatterOpenCommissioningWindow extends LitElement {
|
||||
>
|
||||
${this._commissionParams
|
||||
? html`
|
||||
<div class="flex-container">
|
||||
<ha-svg-icon
|
||||
.path=${mdiCheckCircle}
|
||||
class="success"
|
||||
></ha-svg-icon>
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.open_commissioning_window.sharing_code"
|
||||
)}: <b>${this._commissionParams.setup_manual_code}</b>
|
||||
</p>
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.open_commissioning_window.success"
|
||||
)}
|
||||
<br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.open_commissioning_window.scan_code"
|
||||
)}
|
||||
</p>
|
||||
<div class="sharing-code-container">
|
||||
<div class="sharing-code">
|
||||
<img
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
alt=${domainToName(this.hass.localize, "matter")}
|
||||
src=${brandsUrl({
|
||||
domain: "matter",
|
||||
type: "logo",
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
})}
|
||||
/>
|
||||
<ha-qr-code
|
||||
.data=${this._commissionParams.setup_qr_code}
|
||||
errorCorrectionLevel="quartile"
|
||||
scale="6"
|
||||
margin="1"
|
||||
></ha-qr-code>
|
||||
<span class="code"
|
||||
>${this._commissionParams.setup_manual_code.substring(
|
||||
0,
|
||||
4
|
||||
)}-${this._commissionParams.setup_manual_code.substring(
|
||||
4,
|
||||
7
|
||||
)}-${this._commissionParams.setup_manual_code.substring(
|
||||
7
|
||||
)}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<ha-qr-code
|
||||
.data=${this._commissionParams.setup_qr_code}
|
||||
errorCorrectionLevel="quartile"
|
||||
scale="6"
|
||||
></ha-qr-code>
|
||||
<div></div>
|
||||
<mwc-button slot="primaryAction" @click=${this.closeDialog}>
|
||||
${this.hass.localize("ui.common.close")}
|
||||
<mwc-button slot="primaryAction" @click=${this._copyCode}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.open_commissioning_window.copy_code"
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
: this._status === "started"
|
||||
@@ -140,9 +166,18 @@ class DialogMatterOpenCommissioningWindow extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _copyCode() {
|
||||
if (!this._commissionParams) {
|
||||
return;
|
||||
}
|
||||
await copyToClipboard(this._commissionParams.setup_manual_code);
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this.device_id = undefined;
|
||||
this._status = undefined;
|
||||
this._commissionParams = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
@@ -188,6 +223,30 @@ class DialogMatterOpenCommissioningWindow extends LitElement {
|
||||
.flex-container ha-svg-icon {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.sharing-code-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.sharing-code {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border: 2px solid;
|
||||
border-radius: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.sharing-code img {
|
||||
width: 160px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.code {
|
||||
font-family: monospace;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { mdiCheckCircle, mdiCloseCircle } from "@mdi/js";
|
||||
import { mdiAlertCircle, mdiCheckCircle, mdiCloseCircle } from "@mdi/js";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-circular-progress";
|
||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||
import { pingMatterNode, MatterPingResult } from "../../../../../data/matter";
|
||||
import { haStyleDialog } from "../../../../../resources/styles";
|
||||
import { haStyle, haStyleDialog } from "../../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import { MatterPingNodeDialogParams } from "./show-dialog-matter-ping-node";
|
||||
|
||||
@@ -40,33 +40,24 @@ class DialogMatterPingNode extends LitElement {
|
||||
>
|
||||
${this._pingResult
|
||||
? html`
|
||||
<div class="flex-container">
|
||||
<ha-svg-icon
|
||||
.path=${mdiCheckCircle}
|
||||
class="success"
|
||||
></ha-svg-icon>
|
||||
<div class="status">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.ping_node.ping_complete"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<mwc-list>
|
||||
${Object.entries(this._pingResult).map(
|
||||
([ip, success]) =>
|
||||
html`<ha-list-item hasMeta
|
||||
>${ip}
|
||||
<ha-icon
|
||||
slot="meta"
|
||||
icon=${success ? "mdi:check" : "mdi:close"}
|
||||
></ha-icon>
|
||||
</ha-list-item>`
|
||||
)}
|
||||
</mwc-list>
|
||||
</div>
|
||||
<h2>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.matter.ping_node.ping_complete"
|
||||
)}
|
||||
</h2>
|
||||
<mwc-list>
|
||||
${Object.entries(this._pingResult).map(
|
||||
([ip, success]) =>
|
||||
html`<ha-list-item hasMeta noninteractive
|
||||
>${ip}
|
||||
<ha-svg-icon
|
||||
slot="meta"
|
||||
.path=${success ? mdiCheckCircle : mdiAlertCircle}
|
||||
class=${success ? "success" : "failed"}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>`
|
||||
)}
|
||||
</mwc-list>
|
||||
<mwc-button slot="primaryAction" @click=${this.closeDialog}>
|
||||
${this.hass.localize("ui.common.close")}
|
||||
</mwc-button>
|
||||
@@ -151,6 +142,7 @@ class DialogMatterPingNode extends LitElement {
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
.success {
|
||||
@@ -170,23 +162,22 @@ class DialogMatterPingNode extends LitElement {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.stage ha-svg-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.stage {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
ha-svg-icon {
|
||||
width: 68px;
|
||||
height: 48px;
|
||||
mwc-list {
|
||||
--mdc-list-side-padding: 0;
|
||||
}
|
||||
|
||||
.flex-container ha-circular-progress,
|
||||
.flex-container ha-svg-icon {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.flex-container ha-svg-icon {
|
||||
width: 68px;
|
||||
height: 48px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { computeRTLDirection } from "../../../../../common/util/compute_rtl";
|
||||
import "../../../../../components/data-table/ha-data-table";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
@@ -82,7 +81,6 @@ export class ZHAClustersDataTable extends LitElement {
|
||||
.id=${"cluster_id"}
|
||||
selectable
|
||||
auto-height
|
||||
.dir=${computeRTLDirection(this.hass)}
|
||||
.searchLabel=${this.hass.localize("ui.components.data-table.search")}
|
||||
.noDataText=${this.hass.localize("ui.components.data-table.no-data")}
|
||||
></ha-data-table>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user