mirror of
				https://github.com/home-assistant/frontend.git
				synced 2025-10-31 14:39:38 +00:00 
			
		
		
		
	Compare commits
	
		
			4 Commits
		
	
	
		
			fix-menu-o
			...
			fix-qr-col
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6c59a42dda | ||
|   | edd9cb769d | ||
|   | c567f20074 | ||
|   | 21b171245a | 
| @@ -1,5 +1,5 @@ | ||||
| # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/python-3/.devcontainer/base.Dockerfile | ||||
| FROM mcr.microsoft.com/devcontainers/python:3.12 | ||||
| FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.11 | ||||
|  | ||||
| ENV \ | ||||
|   DEBIAN_FRONTEND=noninteractive \ | ||||
|   | ||||
| @@ -2,13 +2,12 @@ | ||||
|   "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": { | ||||
| @@ -17,7 +16,7 @@ | ||||
|         "esbenp.prettier-vscode", | ||||
|         "runem.lit-plugin", | ||||
|         "github.vscode-pull-request-github", | ||||
|         "eamodio.gitlens" | ||||
|         "eamodio.gitlens", | ||||
|       ], | ||||
|       "settings": { | ||||
|         "files.eol": "\n", | ||||
| @@ -28,17 +27,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", | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
|   | ||||
							
								
								
									
										8
									
								
								.github/workflows/cast_deployment.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/cast_deployment.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -21,12 +21,12 @@ jobs: | ||||
|       url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|         with: | ||||
|           ref: dev | ||||
|  | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
| @@ -57,12 +57,12 @@ jobs: | ||||
|       url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|         with: | ||||
|           ref: master | ||||
|  | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
|   | ||||
							
								
								
									
										22
									
								
								.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								.github/workflows/ci.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -24,9 +24,9 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
| @@ -37,7 +37,7 @@ jobs: | ||||
|       - name: Build resources | ||||
|         run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages | ||||
|       - name: Setup lint cache | ||||
|         uses: actions/cache@v4.0.2 | ||||
|         uses: actions/cache@v4.0.0 | ||||
|         with: | ||||
|           path: | | ||||
|             node_modules/.cache/prettier | ||||
| @@ -58,9 +58,9 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
| @@ -76,9 +76,9 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         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.1 | ||||
|         uses: actions/upload-artifact@v4.3.0 | ||||
|         with: | ||||
|           name: frontend-bundle-stats | ||||
|           path: build/stats/*.json | ||||
| @@ -100,9 +100,9 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         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.1 | ||||
|         uses: actions/upload-artifact@v4.3.0 | ||||
|         with: | ||||
|           name: supervisor-bundle-stats | ||||
|           path: build/stats/*.json | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
								
							| @@ -23,7 +23,7 @@ jobs: | ||||
|  | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|         with: | ||||
|           # We must fetch at least the immediate parents so that if this is | ||||
|           # a pull request then we can checkout the head. | ||||
|   | ||||
							
								
								
									
										8
									
								
								.github/workflows/demo_deployment.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/demo_deployment.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -22,12 +22,12 @@ jobs: | ||||
|       url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|         with: | ||||
|           ref: dev | ||||
|  | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
| @@ -58,12 +58,12 @@ jobs: | ||||
|       url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|         with: | ||||
|           ref: master | ||||
|  | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/design_deployment.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/design_deployment.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -16,10 +16,10 @@ jobs: | ||||
|       url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }} | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|  | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
|   | ||||
							
								
								
									
										4
									
								
								.github/workflows/design_preview.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/design_preview.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -21,10 +21,10 @@ jobs: | ||||
|     if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview') | ||||
|     steps: | ||||
|       - name: Check out files from GitHub | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|  | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
|   | ||||
							
								
								
									
										10
									
								
								.github/workflows/nightly.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/nightly.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -6,7 +6,7 @@ on: | ||||
|     - cron: "0 1 * * *" | ||||
|  | ||||
| env: | ||||
|   PYTHON_VERSION: "3.12" | ||||
|   PYTHON_VERSION: "3.11" | ||||
|   NODE_OPTIONS: --max_old_space_size=6144 | ||||
|  | ||||
| permissions: | ||||
| @@ -20,7 +20,7 @@ jobs: | ||||
|       contents: write | ||||
|     steps: | ||||
|       - name: Checkout the repository | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|  | ||||
|       - name: Set up Python ${{ env.PYTHON_VERSION }} | ||||
|         uses: actions/setup-python@v5 | ||||
| @@ -28,7 +28,7 @@ jobs: | ||||
|           python-version: ${{ env.PYTHON_VERSION }} | ||||
|  | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         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.1 | ||||
|         uses: actions/upload-artifact@v4.3.0 | ||||
|         with: | ||||
|           name: wheels | ||||
|           path: dist/home_assistant_frontend*.whl | ||||
|           if-no-files-found: error | ||||
|  | ||||
|       - name: Upload translations | ||||
|         uses: actions/upload-artifact@v4.3.1 | ||||
|         uses: actions/upload-artifact@v4.3.0 | ||||
|         with: | ||||
|           name: translations | ||||
|           path: translations.tar.gz | ||||
|   | ||||
							
								
								
									
										8
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -6,7 +6,7 @@ on: | ||||
|       - published | ||||
|  | ||||
| env: | ||||
|   PYTHON_VERSION: "3.12" | ||||
|   PYTHON_VERSION: "3.11" | ||||
|   NODE_OPTIONS: --max_old_space_size=6144 | ||||
|  | ||||
| # Set default workflow permissions | ||||
| @@ -23,7 +23,7 @@ jobs: | ||||
|       contents: write # Required to upload release assets | ||||
|     steps: | ||||
|       - name: Checkout the repository | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|  | ||||
|       - name: Verify version | ||||
|         uses: home-assistant/actions/helpers/verify-version@master | ||||
| @@ -34,7 +34,7 @@ jobs: | ||||
|           python-version: ${{ env.PYTHON_VERSION }} | ||||
|  | ||||
|       - name: Setup Node | ||||
|         uses: actions/setup-node@v4.0.2 | ||||
|         uses: actions/setup-node@v4.0.1 | ||||
|         with: | ||||
|           node-version-file: ".nvmrc" | ||||
|           cache: yarn | ||||
| @@ -55,7 +55,7 @@ jobs: | ||||
|           script/release | ||||
|  | ||||
|       - name: Upload release assets | ||||
|         uses: softprops/action-gh-release@v2.0.4 | ||||
|         uses: softprops/action-gh-release@v0.1.15 | ||||
|         with: | ||||
|           files: | | ||||
|             dist/*.whl | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/translations.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/translations.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -13,7 +13,7 @@ jobs: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout the repository | ||||
|         uses: actions/checkout@v4.1.2 | ||||
|         uses: actions/checkout@v4.1.1 | ||||
|  | ||||
|       - name: Upload Translations | ||||
|         run: | | ||||
|   | ||||
| @@ -1,18 +0,0 @@ | ||||
| diff --git a/dist/hls.light.mjs b/dist/hls.light.mjs | ||||
| index eed9d788fafdb159975e1a2eb08ac88ba9c9ac33..ace881935e6665946f1c8110ebd2f739cde4427e 100644 | ||||
| --- a/dist/hls.light.mjs | ||||
| +++ b/dist/hls.light.mjs | ||||
| @@ -20523,9 +20523,9 @@ class Hls { | ||||
|  } | ||||
|  Hls.defaultConfig = void 0; | ||||
|   | ||||
| -var KeySystemFormats = empty.KeySystemFormats; | ||||
| -var KeySystems = empty.KeySystems; | ||||
| -var SubtitleStreamController = empty.SubtitleStreamController; | ||||
| -var TimelineController = empty.TimelineController; | ||||
| +var KeySystemFormats = empty; | ||||
| +var KeySystems = empty; | ||||
| +var SubtitleStreamController = empty; | ||||
| +var TimelineController = empty; | ||||
|  export { AbrController, AttrList, Cues as AudioStreamController, Cues as AudioTrackController, BasePlaylistController, BaseSegment, BaseStreamController, BufferController, Cues as CMCDController, CapLevelController, ChunkMetadata, ContentSteeringController, DateRange, Cues as EMEController, ErrorActionFlags, ErrorController, ErrorDetails, ErrorTypes, Events, FPSController, Fragment, Hls, HlsSkip, HlsUrlParameters, KeySystemFormats, KeySystems, Level, LevelDetails, LevelKey, LoadStats, MetadataSchema, NetworkErrorAction, Part, PlaylistLevelType, SubtitleStreamController, Cues as SubtitleTrackController, TimelineController, Hls as default, getMediaSource, isMSESupported, isSupported }; | ||||
|  //# sourceMappingURL=hls.light.mjs.map | ||||
										
											
												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.1.1.cjs | ||||
| yarnPath: .yarn/releases/yarn-4.1.0.cjs | ||||
|   | ||||
| @@ -115,9 +115,7 @@ gulp.task("webpack-prod-app", () => | ||||
|  | ||||
| gulp.task("webpack-dev-server-demo", () => | ||||
|   runDevServer({ | ||||
|     compiler: webpack( | ||||
|       createDemoConfig({ isProdBuild: false, latestBuild: true }) | ||||
|     ), | ||||
|     compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })), | ||||
|     contentBase: paths.demo_output_root, | ||||
|     port: 8090, | ||||
|   }) | ||||
| @@ -133,9 +131,7 @@ gulp.task("webpack-prod-demo", () => | ||||
|  | ||||
| gulp.task("webpack-dev-server-cast", () => | ||||
|   runDevServer({ | ||||
|     compiler: webpack( | ||||
|       createCastConfig({ isProdBuild: false, latestBuild: true }) | ||||
|     ), | ||||
|     compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })), | ||||
|     contentBase: paths.cast_output_root, | ||||
|     port: 8080, | ||||
|     // Accessible from the network, because that's how Cast hits it. | ||||
| @@ -178,9 +174,8 @@ gulp.task("webpack-prod-hassio", () => | ||||
|  | ||||
| gulp.task("webpack-dev-server-gallery", () => | ||||
|   runDevServer({ | ||||
|     compiler: webpack( | ||||
|       createGalleryConfig({ isProdBuild: false, latestBuild: true }) | ||||
|     ), | ||||
|     // 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 })), | ||||
|     contentBase: paths.gallery_output_root, | ||||
|     port: 8100, | ||||
|     listenHost: "0.0.0.0", | ||||
|   | ||||
| @@ -28,23 +28,25 @@ class HcLaunchScreen extends LitElement { | ||||
|       :host { | ||||
|         display: block; | ||||
|         height: 100vh; | ||||
|         background-color: #f2f4f9; | ||||
|         padding-top: 64px; | ||||
|         background-color: white; | ||||
|         font-size: 24px; | ||||
|       } | ||||
|       .container { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         text-align: center; | ||||
|         align-items: center; | ||||
|         height: 100%; | ||||
|         justify-content: space-evenly; | ||||
|       } | ||||
|       img { | ||||
|         max-width: 80%; | ||||
|         object-fit: cover; | ||||
|         width: 717px; | ||||
|         height: 376px; | ||||
|         display: block; | ||||
|         margin: 0 auto; | ||||
|       } | ||||
|       .status { | ||||
|         color: #1d2126; | ||||
|         padding-right: 54px; | ||||
|         padding-inline-end: 54px; | ||||
|         padding-inline-start: initial; | ||||
|       } | ||||
|     `; | ||||
|   } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ class HcLovelace extends LitElement { | ||||
|   @property({ attribute: false }) | ||||
|   public lovelaceConfig!: LovelaceConfig; | ||||
|  | ||||
|   @property() public viewPath?: string | number | null; | ||||
|   @property() public viewPath?: string | number; | ||||
|  | ||||
|   @property() public urlPath: string | null = null; | ||||
|  | ||||
| @@ -93,9 +93,6 @@ 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 _urlPath?: string | null; | ||||
|  | ||||
|   @state() private _error?: string; | ||||
|  | ||||
|   @state() private _urlPath?: string | null; | ||||
|  | ||||
|   private _hassUUID?: string; | ||||
|  | ||||
|   private _unsubLovelace?: UnsubscribeFunc; | ||||
| @@ -81,7 +81,7 @@ export class HcMain extends HassElement { | ||||
|  | ||||
|     if ( | ||||
|       !this._lovelaceConfig || | ||||
|       this._urlPath === undefined || | ||||
|       this._lovelacePath === null || | ||||
|       // 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} | ||||
|         .urlPath=${this._urlPath} | ||||
|         .viewPath=${this._lovelacePath} | ||||
|         .urlPath=${this._urlPath} | ||||
|         @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._lovelaceConfig = undefined; | ||||
|       this._urlPath = undefined; | ||||
|       this._lovelacePath = null; | ||||
|       this._urlPath = undefined; | ||||
|       this._lovelaceConfig = undefined; | ||||
|       if (this._unsubLovelace) { | ||||
|         this._unsubLovelace(); | ||||
|         this._unsubLovelace = undefined; | ||||
| @@ -270,7 +270,7 @@ export class HcMain extends HassElement { | ||||
|     } | ||||
|  | ||||
|     this._error = undefined; | ||||
|     if (msg.urlPath === "lovelace" || msg.urlPath === undefined) { | ||||
|     if (msg.urlPath === "lovelace") { | ||||
|       msg.urlPath = null; | ||||
|     } | ||||
|     this._lovelacePath = msg.viewPath; | ||||
| @@ -285,7 +285,7 @@ export class HcMain extends HassElement { | ||||
|         ], | ||||
|       }; | ||||
|       this._urlPath = "energy"; | ||||
|       this._lovelacePath = null; | ||||
|       this._lovelacePath = 0; | ||||
|       this._sendStatus(); | ||||
|       return; | ||||
|     } | ||||
|   | ||||
| @@ -4,7 +4,6 @@ import { energyEntities } from "../stubs/entities"; | ||||
| import { DemoConfig } from "./types"; | ||||
|  | ||||
| export const demoConfigs: Array<() => Promise<DemoConfig>> = [ | ||||
|   () => import("./sections").then((mod) => mod.demoSections), | ||||
|   () => import("./arsaboo").then((mod) => mod.demoArsaboo), | ||||
|   () => import("./teachingbirds").then((mod) => mod.demoTeachingbirds), | ||||
|   () => import("./kernehed").then((mod) => mod.demoKernehed), | ||||
|   | ||||
| @@ -1,16 +0,0 @@ | ||||
| import { html } from "lit"; | ||||
| import { DemoConfig } from "../types"; | ||||
|  | ||||
| export const demoLovelaceDescription: DemoConfig["description"] = ( | ||||
|   localize | ||||
| ) => html` | ||||
|   <p> | ||||
|     ${localize("ui.panel.page-demo.config.sections.description", { | ||||
|       blog_post: html`<a | ||||
|         href="https://www.home-assistant.io/blog/2024/03/04/dashboard-chapter-1/" | ||||
|         target="_blank" | ||||
|         >${localize("ui.panel.page-demo.config.sections.description_blog_post")} | ||||
|       </a>`, | ||||
|     })} | ||||
|   </p> | ||||
| `; | ||||
| @@ -1,474 +0,0 @@ | ||||
| import { convertEntities } from "../../../../src/fake_data/entity"; | ||||
| import { DemoConfig } from "../types"; | ||||
|  | ||||
| export const demoEntitiesSections: DemoConfig["entities"] = () => | ||||
|   convertEntities({ | ||||
|     "cover.living_room_garden_shutter": { | ||||
|       entity_id: "cover.living_room_garden_shutter", | ||||
|       state: "open", | ||||
|       attributes: { | ||||
|         current_position: 100, | ||||
|         device_class: "shutter", | ||||
|         friendly_name: "Living room garden shutter", | ||||
|         supported_features: 15, | ||||
|       }, | ||||
|     }, | ||||
|     "cover.living_room_graveyard_shutter": { | ||||
|       entity_id: "cover.living_room_graveyard_shutter", | ||||
|       state: "open", | ||||
|       attributes: { | ||||
|         current_position: 100, | ||||
|         device_class: "shutter", | ||||
|         friendly_name: "Living room graveyard shutter", | ||||
|         supported_features: 15, | ||||
|       }, | ||||
|     }, | ||||
|     "cover.living_room_left_shutter": { | ||||
|       entity_id: "cover.living_room_left_shutter", | ||||
|       state: "open", | ||||
|       attributes: { | ||||
|         current_position: 100, | ||||
|         device_class: "shutter", | ||||
|         friendly_name: "Living room left shutter", | ||||
|         supported_features: 15, | ||||
|       }, | ||||
|     }, | ||||
|     "cover.living_room_right_shutter": { | ||||
|       entity_id: "cover.living_room_right_shutter", | ||||
|       state: "open", | ||||
|       attributes: { | ||||
|         current_position: 100, | ||||
|         device_class: "shutter", | ||||
|         friendly_name: "Living room right shutter", | ||||
|         supported_features: 15, | ||||
|       }, | ||||
|     }, | ||||
|     "light.floor_lamp": { | ||||
|       entity_id: "light.floor_lamp", | ||||
|       state: "on", | ||||
|       attributes: { | ||||
|         min_color_temp_kelvin: 2000, | ||||
|         max_color_temp_kelvin: 6535, | ||||
|         min_mireds: 153, | ||||
|         max_mireds: 500, | ||||
|         supported_color_modes: ["color_temp", "xy"], | ||||
|         color_mode: "color_temp", | ||||
|         brightness: 178, | ||||
|         color_temp_kelvin: 2583, | ||||
|         color_temp: 387, | ||||
|         hs_color: [28.664, 69.597], | ||||
|         rgb_color: [255, 162, 77], | ||||
|         xy_color: [0.538, 0.389], | ||||
|         icon: "mdi:floor-lamp", | ||||
|         friendly_name: "Floor lamp", | ||||
|         supported_features: 44, | ||||
|       }, | ||||
|     }, | ||||
|     "light.living_room_spotlights": { | ||||
|       entity_id: "light.living_room_spotlights", | ||||
|       state: "on", | ||||
|       attributes: { | ||||
|         supported_color_modes: ["brightness"], | ||||
|         color_mode: "brightness", | ||||
|         brightness: 126, | ||||
|         icon: "mdi:ceiling-light-multiple", | ||||
|         friendly_name: "Living room spotlights", | ||||
|         supported_features: 32, | ||||
|       }, | ||||
|     }, | ||||
|     "light.bar_lamp": { | ||||
|       entity_id: "light.bar_lamp", | ||||
|       state: "on", | ||||
|       attributes: { | ||||
|         min_color_temp_kelvin: 2202, | ||||
|         max_color_temp_kelvin: 4504, | ||||
|         min_mireds: 222, | ||||
|         max_mireds: 454, | ||||
|         effect_list: ["None", "candle"], | ||||
|         supported_color_modes: ["color_temp"], | ||||
|         effect: null, | ||||
|         color_mode: null, | ||||
|         brightness: null, | ||||
|         color_temp_kelvin: null, | ||||
|         color_temp: null, | ||||
|         hs_color: null, | ||||
|         rgb_color: null, | ||||
|         xy_color: null, | ||||
|         mode: "normal", | ||||
|         dynamics: "none", | ||||
|         icon: "mdi:lightbulb-variant", | ||||
|         friendly_name: "Bar lamp", | ||||
|         supported_features: 44, | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.living_room_temperature": { | ||||
|       entity_id: "sensor.living_room_temperature", | ||||
|       state: "22.8", | ||||
|       attributes: { | ||||
|         state_class: "measurement", | ||||
|         unit_of_measurement: "°C", | ||||
|         device_class: "temperature", | ||||
|         friendly_name: "Living room Temperature", | ||||
|       }, | ||||
|     }, | ||||
|     "media_player.living_room_nest_mini": { | ||||
|       entity_id: "media_player.living_room_nest_mini", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         device_class: "speaker", | ||||
|         friendly_name: "Living room Nest Mini", | ||||
|         supported_features: 152461, | ||||
|       }, | ||||
|     }, | ||||
|     "cover.kitchen_shutter": { | ||||
|       entity_id: "cover.kitchen_shutter", | ||||
|       state: "open", | ||||
|       attributes: { | ||||
|         current_position: 100, | ||||
|         device_class: "shutter", | ||||
|         friendly_name: "Kitchen shutter ", | ||||
|         supported_features: 15, | ||||
|       }, | ||||
|     }, | ||||
|     "light.kitchen_spotlights": { | ||||
|       entity_id: "light.kitchen_spotlights", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         supported_color_modes: ["brightness"], | ||||
|         color_mode: null, | ||||
|         brightness: null, | ||||
|         icon: "mdi:ceiling-light-multiple", | ||||
|         friendly_name: "Kitchen spotlights ", | ||||
|         supported_features: 32, | ||||
|       }, | ||||
|     }, | ||||
|     "light.worktop_spotlights": { | ||||
|       entity_id: "light.worktop_spotlights", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         supported_color_modes: ["brightness"], | ||||
|         color_mode: null, | ||||
|         brightness: null, | ||||
|         icon: "mdi:ceiling-light-multiple", | ||||
|         friendly_name: "Worktop spotlights ", | ||||
|         supported_features: 32, | ||||
|       }, | ||||
|     }, | ||||
|     "binary_sensor.fridge_door": { | ||||
|       entity_id: "binary_sensor.fridge_door", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         device_class: "door", | ||||
|         icon: "mdi:fridge", | ||||
|         friendly_name: "Fridge door", | ||||
|       }, | ||||
|     }, | ||||
|     "media_player.kitchen_nest_audio": { | ||||
|       entity_id: "media_player.kitchen_nest_audio", | ||||
|       state: "on", | ||||
|       attributes: { | ||||
|         device_class: "speaker", | ||||
|         friendly_name: "Kitchen Nest Audio", | ||||
|         supported_features: 152461, | ||||
|       }, | ||||
|     }, | ||||
|     "binary_sensor.tesla_wall_connector_vehicle_connected": { | ||||
|       entity_id: "binary_sensor.tesla_wall_connector_vehicle_connected", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         device_class: "plug", | ||||
|         friendly_name: "Wall Connector Vehicle connected", | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.tesla_wall_connector_session_energy": { | ||||
|       entity_id: "sensor.tesla_wall_connector_session_energy", | ||||
|       state: "16.3", | ||||
|       attributes: { | ||||
|         state_class: "total_increasing", | ||||
|         unit_of_measurement: "kWh", | ||||
|         device_class: "energy", | ||||
|         friendly_name: "Tesla Wall Connector Session energy", | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.electric_meter_power": { | ||||
|       entity_id: "sensor.electric_meter_power", | ||||
|       state: "797.86", | ||||
|       attributes: { | ||||
|         state_class: "measurement", | ||||
|         unit_of_measurement: "W", | ||||
|         device_class: "power", | ||||
|         icon: "mdi:meter-electric", | ||||
|         friendly_name: "Electric meter Power", | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.eletric_meter_voltage": { | ||||
|       entity_id: "sensor.eletric_meter_voltage", | ||||
|       state: "232.19", | ||||
|       attributes: { | ||||
|         state_class: "measurement", | ||||
|         unit_of_measurement: "V", | ||||
|         device_class: "voltage", | ||||
|         friendly_name: "Electric meter voltage", | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.electricity_maps_grid_fossil_fuel_percentage": { | ||||
|       entity_id: "sensor.electricity_maps_grid_fossil_fuel_percentage", | ||||
|       state: "9.84", | ||||
|       attributes: { | ||||
|         state_class: "measurement", | ||||
|         country_code: "FR", | ||||
|         unit_of_measurement: "%", | ||||
|         attribution: "Data provided by Electricity Maps", | ||||
|         icon: "mdi:barrel", | ||||
|         friendly_name: "Electricity Maps Grid fossil fuel percentage", | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.electricity_maps_co2_intensity": { | ||||
|       entity_id: "sensor.electricity_maps_co2_intensity", | ||||
|       state: "62.0", | ||||
|       attributes: { | ||||
|         state_class: "measurement", | ||||
|         country_code: "FR", | ||||
|         unit_of_measurement: "gCO2eq/kWh", | ||||
|         attribution: "Data provided by Electricity Maps", | ||||
|         friendly_name: "Electricity Maps CO2 intensity", | ||||
|         icon: "mdi:molecule-co2", | ||||
|       }, | ||||
|     }, | ||||
|     "sun.sun": { | ||||
|       entity_id: "sun.sun", | ||||
|       state: "above_horizon", | ||||
|       attributes: { | ||||
|         next_dawn: "2024-03-05T05:50:21.964405+00:00", | ||||
|         next_dusk: "2024-03-04T18:08:54.311334+00:00", | ||||
|         next_midnight: "2024-03-05T00:00:00+00:00", | ||||
|         next_noon: "2024-03-05T12:00:05+00:00", | ||||
|         next_rising: "2024-03-05T06:23:42.739159+00:00", | ||||
|         next_setting: "2024-03-04T17:35:26.271171+00:00", | ||||
|         elevation: 30.38, | ||||
|         azimuth: 204.42, | ||||
|         rising: false, | ||||
|         friendly_name: "Sun", | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.rain": { | ||||
|       entity_id: "sensor.moon_phase", | ||||
|       state: "7.2", | ||||
|       attributes: { | ||||
|         state_class: "total_increasing", | ||||
|         unit_of_measurement: "mm", | ||||
|         device_class: "precipitation", | ||||
|         friendly_name: "Rain", | ||||
|       }, | ||||
|     }, | ||||
|     "climate.ground_floor": { | ||||
|       entity_id: "climate.ground_floor", | ||||
|       state: "heat", | ||||
|       attributes: { | ||||
|         hvac_modes: ["auto", "heat", "off"], | ||||
|         min_temp: 7, | ||||
|         max_temp: 35, | ||||
|         preset_modes: [ | ||||
|           "comfort", | ||||
|           "away", | ||||
|           "eco", | ||||
|           "frost_protection", | ||||
|           "external", | ||||
|           "home", | ||||
|         ], | ||||
|         current_temperature: 20.8, | ||||
|         temperature: 21, | ||||
|         preset_mode: "comfort", | ||||
|         icon: "mdi:home-floor-0", | ||||
|         friendly_name: "Ground floor Thermostat", | ||||
|         supported_features: 401, | ||||
|       }, | ||||
|     }, | ||||
|     "climate.first_floor": { | ||||
|       entity_id: "climate.first_floor", | ||||
|       state: "heat", | ||||
|       attributes: { | ||||
|         hvac_modes: ["auto", "heat", "off"], | ||||
|         min_temp: 7, | ||||
|         max_temp: 35, | ||||
|         preset_modes: [ | ||||
|           "comfort", | ||||
|           "away", | ||||
|           "eco", | ||||
|           "frost_protection", | ||||
|           "external", | ||||
|           "home", | ||||
|         ], | ||||
|         current_temperature: 21.7, | ||||
|         temperature: 21, | ||||
|         preset_mode: "comfort", | ||||
|         icon: "mdi:home-floor-1", | ||||
|         friendly_name: "First floor Thermostat", | ||||
|         supported_features: 401, | ||||
|       }, | ||||
|     }, | ||||
|     "cover.study_shutter": { | ||||
|       entity_id: "cover.study_shutter", | ||||
|       state: "open", | ||||
|       attributes: { | ||||
|         current_position: 100, | ||||
|         device_class: "shutter", | ||||
|         friendly_name: "Study shutter", | ||||
|         supported_features: 15, | ||||
|       }, | ||||
|     }, | ||||
|     "light.study_spotlights": { | ||||
|       entity_id: "light.study_spotlights", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         supported_color_modes: ["brightness"], | ||||
|         color_mode: null, | ||||
|         brightness: null, | ||||
|         icon: "mdi:ceiling-light-multiple", | ||||
|         friendly_name: "Study spotlights", | ||||
|         supported_features: 32, | ||||
|       }, | ||||
|     }, | ||||
|     "media_player.study_nest_hub": { | ||||
|       entity_id: "media_player.study_nest_hub", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         friendly_name: "Study Nest Hub", | ||||
|         supported_features: 152461, | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.standing_desk_height": { | ||||
|       entity_id: "sensor.standing_desk_height", | ||||
|       state: "72", | ||||
|       attributes: { | ||||
|         unit_of_measurement: "cm", | ||||
|         icon: "mdi:tape-measure", | ||||
|         friendly_name: "Standing desk Height", | ||||
|       }, | ||||
|     }, | ||||
|     "light.outdoor_light": { | ||||
|       entity_id: "light.outdoor_light", | ||||
|       state: "on", | ||||
|       attributes: { | ||||
|         supported_color_modes: ["brightness"], | ||||
|         color_mode: null, | ||||
|         brightness: 255, | ||||
|         icon: "mdi:outdoor-lamp", | ||||
|         friendly_name: "Outdoor light", | ||||
|         supported_features: 32, | ||||
|       }, | ||||
|     }, | ||||
|     "light.flood_light": { | ||||
|       entity_id: "light.flood_light", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         effect_list: ["None", "candle"], | ||||
|         supported_color_modes: ["brightness"], | ||||
|         effect: null, | ||||
|         color_mode: null, | ||||
|         brightness: null, | ||||
|         mode: "normal", | ||||
|         dynamics: "none", | ||||
|         icon: "mdi:light-flood-down", | ||||
|         friendly_name: "Flood light", | ||||
|         supported_features: 44, | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.outdoor_motion_sensor_temperature": { | ||||
|       entity_id: "sensor.outdoor_motion_sensor_temperature", | ||||
|       state: "10.2", | ||||
|       attributes: { | ||||
|         state_class: "measurement", | ||||
|         unit_of_measurement: "°C", | ||||
|         device_class: "temperature", | ||||
|         friendly_name: "Outdoor motion sensor Temperature", | ||||
|       }, | ||||
|     }, | ||||
|     "binary_sensor.outdoor_motion_sensor_motion": { | ||||
|       entity_id: "binary_sensor.outdoor_motion_sensor_motion", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         device_class: "motion", | ||||
|         friendly_name: "Outdoor motion sensor Motion", | ||||
|       }, | ||||
|     }, | ||||
|     "sensor.outdoor_motion_sensor_illuminance": { | ||||
|       entity_id: "sensor.outdoor_motion_sensor_illuminance", | ||||
|       state: "555", | ||||
|       attributes: { | ||||
|         state_class: "measurement", | ||||
|         light_level: 27444, | ||||
|         unit_of_measurement: "lx", | ||||
|         device_class: "illuminance", | ||||
|         friendly_name: "Outdoor motion sensor Illuminance", | ||||
|       }, | ||||
|     }, | ||||
|     "automation.home_assistant_auto_update": { | ||||
|       entity_id: "automation.home_assistant_auto_update", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         id: "1700669321947", | ||||
|         last_triggered: "2024-02-29T18:02:05.343139+00:00", | ||||
|         mode: "queued", | ||||
|         current: 0, | ||||
|         max: 50, | ||||
|         icon: "mdi:auto-mode", | ||||
|         friendly_name: "Home Assistant Auto-update", | ||||
|       }, | ||||
|     }, | ||||
|     "update.home_assistant_operating_system_update": { | ||||
|       entity_id: "update.home_assistant_operating_system_update", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         auto_update: false, | ||||
|         installed_version: "12.1", | ||||
|         in_progress: false, | ||||
|         latest_version: "12.1", | ||||
|         release_summary: null, | ||||
|         release_url: | ||||
|           "https://github.com/home-assistant/operating-system/commits/dev", | ||||
|         skipped_version: null, | ||||
|         title: "Home Assistant Operating System", | ||||
|         entity_picture: | ||||
|           "https://brands.home-assistant.io/homeassistant/icon.png", | ||||
|         friendly_name: "Home Assistant Operating System Update", | ||||
|         supported_features: 3, | ||||
|       }, | ||||
|     }, | ||||
|     "update.home_assistant_supervisor_update": { | ||||
|       entity_id: "update.home_assistant_supervisor_update", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         auto_update: true, | ||||
|         installed_version: "2024.02.2", | ||||
|         in_progress: false, | ||||
|         latest_version: "2024.02.2", | ||||
|         release_summary: null, | ||||
|         release_url: | ||||
|           "https://github.com/home-assistant/supervisor/commits/main", | ||||
|         skipped_version: null, | ||||
|         title: "Home Assistant Supervisor", | ||||
|         entity_picture: "https://brands.home-assistant.io/hassio/icon.png", | ||||
|         friendly_name: "Home Assistant Supervisor Update", | ||||
|         supported_features: 1, | ||||
|       }, | ||||
|     }, | ||||
|     "update.home_assistant_core_update": { | ||||
|       entity_id: "update.home_assistant_supervisor_update", | ||||
|       state: "off", | ||||
|       attributes: { | ||||
|         auto_update: false, | ||||
|         installed_version: "2024.4.0", | ||||
|         in_progress: false, | ||||
|         latest_version: "2024.4.0", | ||||
|         release_summary: null, | ||||
|         release_url: "https://github.com/home-assistant/core/commits/dev", | ||||
|         skipped_version: null, | ||||
|         title: "Home Assistant Core", | ||||
|         entity_picture: | ||||
|           "https://brands.home-assistant.io/homeassistant/icon.png", | ||||
|         friendly_name: "Home Assistant Core Update", | ||||
|         supported_features: 11, | ||||
|       }, | ||||
|     }, | ||||
|   }); | ||||
| @@ -1,14 +0,0 @@ | ||||
| import { DemoConfig } from "../types"; | ||||
| import { demoLovelaceDescription } from "./description"; | ||||
| import { demoEntitiesSections } from "./entities"; | ||||
| import { demoLovelaceSections } from "./lovelace"; | ||||
|  | ||||
| export const demoSections: DemoConfig = { | ||||
|   authorName: "Home Assistant", | ||||
|   authorUrl: "https://github.com/home-assistant/frontend/", | ||||
|   name: "Home Demo", | ||||
|   description: demoLovelaceDescription, | ||||
|   lovelace: demoLovelaceSections, | ||||
|   entities: demoEntitiesSections, | ||||
|   theme: () => ({}), | ||||
| }; | ||||
| @@ -1,281 +0,0 @@ | ||||
| import { DemoConfig } from "../types"; | ||||
|  | ||||
| export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({ | ||||
|   title: "Home Assistant Demo", | ||||
|   views: [ | ||||
|     { | ||||
|       type: "sections", | ||||
|       title: "Demo", | ||||
|       path: "home", | ||||
|       icon: "mdi:home-assistant", | ||||
|       sections: [ | ||||
|         { | ||||
|           title: "Welcome 👋", | ||||
|           cards: [{ type: "custom:ha-demo-card" }], | ||||
|         }, | ||||
|         { | ||||
|           cards: [ | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "cover.living_room_garden_shutter", | ||||
|               name: "Garden", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "cover.living_room_graveyard_shutter", | ||||
|               name: "Rear", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "cover.living_room_left_shutter", | ||||
|               name: "Left", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "cover.living_room_right_shutter", | ||||
|               name: "Right", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "light.floor_lamp", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "light.living_room_spotlights", | ||||
|               name: "Spotlights", | ||||
|               features: [ | ||||
|                 { | ||||
|                   type: "light-brightness", | ||||
|                 }, | ||||
|               ], | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "light.bar_lamp", | ||||
|             }, | ||||
|             { | ||||
|               graph: "line", | ||||
|               type: "sensor", | ||||
|               entity: "sensor.living_room_temperature", | ||||
|               detail: 1, | ||||
|               name: "Temperature", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "media_player.living_room_nest_mini", | ||||
|               name: "Nest Mini", | ||||
|             }, | ||||
|           ], | ||||
|           title: "🛋️ Living room ", | ||||
|         }, | ||||
|         { | ||||
|           type: "grid", | ||||
|           cards: [ | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "cover.kitchen_shutter", | ||||
|               name: "Shutter", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "light.kitchen_spotlights", | ||||
|               name: "Spotlights", | ||||
|               features: [ | ||||
|                 { | ||||
|                   type: "light-brightness", | ||||
|                 }, | ||||
|               ], | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "light.worktop_spotlights", | ||||
|               name: "Worktop", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "binary_sensor.fridge_door", | ||||
|               name: "Fridge", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "media_player.kitchen_nest_audio", | ||||
|               name: "Nest Audio", | ||||
|             }, | ||||
|           ], | ||||
|           title: "👩🍳 Kitchen", | ||||
|         }, | ||||
|         { | ||||
|           type: "grid", | ||||
|           cards: [ | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "binary_sensor.tesla_wall_connector_vehicle_connected", | ||||
|               name: "EV", | ||||
|               icon: "mdi:car", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sensor.tesla_wall_connector_session_energy", | ||||
|               name: "Last charge", | ||||
|               color: "green", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sensor.electric_meter_power", | ||||
|               color: "deep-orange", | ||||
|               name: "Home power", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sensor.eletric_meter_voltage", | ||||
|               name: "Voltage", | ||||
|               color: "deep-orange", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sensor.electricity_maps_grid_fossil_fuel_percentage", | ||||
|               name: "Fossil fuel", | ||||
|               color: "brown", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sensor.electricity_maps_co2_intensity", | ||||
|               name: "CO2 Intensity", | ||||
|               color: "dark-grey", | ||||
|             }, | ||||
|           ], | ||||
|           title: "⚡️ Energy", | ||||
|         }, | ||||
|         { | ||||
|           type: "grid", | ||||
|           cards: [ | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sun.sun", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sensor.rain", | ||||
|               color: "blue", | ||||
|             }, | ||||
|             { | ||||
|               features: [ | ||||
|                 { | ||||
|                   type: "target-temperature", | ||||
|                 }, | ||||
|               ], | ||||
|               type: "tile", | ||||
|               name: "Downstairs", | ||||
|               entity: "climate.ground_floor", | ||||
|               state_content: ["preset_mode", "current_temperature"], | ||||
|             }, | ||||
|             { | ||||
|               features: [ | ||||
|                 { | ||||
|                   type: "target-temperature", | ||||
|                 }, | ||||
|               ], | ||||
|               type: "tile", | ||||
|               name: "Upstairs", | ||||
|               entity: "climate.first_floor", | ||||
|               state_content: ["preset_mode", "current_temperature"], | ||||
|             }, | ||||
|           ], | ||||
|           title: "🌤️ Climate", | ||||
|         }, | ||||
|         { | ||||
|           type: "grid", | ||||
|           cards: [ | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "cover.study_shutter", | ||||
|               name: "Shutter", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "light.study_spotlights", | ||||
|               name: "Spotlights", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "media_player.study_nest_hub", | ||||
|               name: "Nest Hub", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sensor.standing_desk_height", | ||||
|               name: "Desk", | ||||
|               color: "brown", | ||||
|               icon: "mdi:desk", | ||||
|             }, | ||||
|           ], | ||||
|           title: "🧑💻 Study", | ||||
|         }, | ||||
|         { | ||||
|           type: "grid", | ||||
|           cards: [ | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "light.outdoor_light", | ||||
|               name: "Door light", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "light.flood_light", | ||||
|             }, | ||||
|             { | ||||
|               graph: "line", | ||||
|               type: "sensor", | ||||
|               entity: "sensor.outdoor_motion_sensor_temperature", | ||||
|               detail: 1, | ||||
|               name: "Temperature", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "binary_sensor.outdoor_motion_sensor_motion", | ||||
|               name: "Motion", | ||||
|               color: "blue", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "sensor.outdoor_motion_sensor_illuminance", | ||||
|               color: "amber", | ||||
|               name: "Illuminance", | ||||
|             }, | ||||
|           ], | ||||
|           title: "🌳 Outdoor", | ||||
|         }, | ||||
|         { | ||||
|           type: "grid", | ||||
|           cards: [ | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "automation.home_assistant_auto_update", | ||||
|               name: "Auto-update", | ||||
|               color: "green", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "update.home_assistant_operating_system_update", | ||||
|               name: "OS", | ||||
|               icon: "mdi:home-assistant", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "update.home_assistant_supervisor_update", | ||||
|               icon: "mdi:home-assistant", | ||||
|               name: "Supervisor", | ||||
|             }, | ||||
|             { | ||||
|               type: "tile", | ||||
|               entity: "update.home_assistant_core_update", | ||||
|               name: "Core", | ||||
|               icon: "mdi:home-assistant", | ||||
|             }, | ||||
|           ], | ||||
|           title: "🎉 Updates", | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| @@ -1,4 +1,3 @@ | ||||
| import { TemplateResult } from "lit"; | ||||
| import { LocalizeFunc } from "../../../src/common/translations/localize"; | ||||
| import { LovelaceConfig } from "../../../src/data/lovelace/config/types"; | ||||
| import { Entity } from "../../../src/fake_data/entity"; | ||||
| @@ -8,9 +7,6 @@ export interface DemoConfig { | ||||
|   name: string; | ||||
|   authorName: string; | ||||
|   authorUrl: string; | ||||
|   description?: | ||||
|     | string | ||||
|     | ((localize: LocalizeFunc) => string | TemplateResult<1>); | ||||
|   lovelace: (localize: LocalizeFunc) => LovelaceConfig; | ||||
|   entities: (localize: LocalizeFunc) => Entity[]; | ||||
|   theme: () => Record<string, string> | null; | ||||
|   | ||||
| @@ -39,51 +39,32 @@ export class HADemoCard extends LitElement implements LovelaceCard { | ||||
|         <div class="picker"> | ||||
|           <div class="label"> | ||||
|             ${this._switching | ||||
|               ? html` | ||||
|                   <ha-circular-progress indeterminate></ha-circular-progress> | ||||
|                 ` | ||||
|               ? html`<ha-circular-progress | ||||
|                   indeterminate | ||||
|                 ></ha-circular-progress>` | ||||
|               : until( | ||||
|                   selectedDemoConfig.then( | ||||
|                     (conf) => html` | ||||
|                       ${conf.name} | ||||
|                       <small> | ||||
|                         <a target="_blank" href=${conf.authorUrl}> | ||||
|                           ${this.hass.localize( | ||||
|                             "ui.panel.page-demo.cards.demo.demo_by", | ||||
|                           { | ||||
|                             name: html` | ||||
|                               <a target="_blank" href=${conf.authorUrl}> | ||||
|                                 ${conf.authorName} | ||||
|                               </a> | ||||
|                             `, | ||||
|                           } | ||||
|                             { name: conf.authorName } | ||||
|                           )} | ||||
|                         </a> | ||||
|                       </small> | ||||
|                     ` | ||||
|                   ), | ||||
|                   "" | ||||
|                 )} | ||||
|           </div> | ||||
|  | ||||
|           <mwc-button @click=${this._nextConfig} .disabled=${this._switching}> | ||||
|             ${this.hass.localize("ui.panel.page-demo.cards.demo.next_demo")} | ||||
|           </mwc-button> | ||||
|         </div> | ||||
|         <div class="content"> | ||||
|           <p class="small-hidden"> | ||||
|         <div class="content small-hidden"> | ||||
|           ${this.hass.localize("ui.panel.page-demo.cards.demo.introduction")} | ||||
|           </p> | ||||
|           ${until( | ||||
|             selectedDemoConfig.then((conf) => { | ||||
|               if (typeof conf.description === "function") { | ||||
|                 return conf.description(this.hass.localize); | ||||
|               } | ||||
|               if (conf.description) { | ||||
|                 return html`<p>${conf.description}</p>`; | ||||
|               } | ||||
|               return nothing; | ||||
|             }), | ||||
|             nothing | ||||
|           )} | ||||
|         </div> | ||||
|         <div class="actions small-hidden"> | ||||
|           <a href="https://www.home-assistant.io" target="_blank"> | ||||
| @@ -127,7 +108,6 @@ export class HADemoCard extends LitElement implements LovelaceCard { | ||||
|       css` | ||||
|         a { | ||||
|           color: var(--primary-color); | ||||
|           display: inline-block; | ||||
|         } | ||||
|  | ||||
|         .actions a { | ||||
| @@ -135,11 +115,7 @@ export class HADemoCard extends LitElement implements LovelaceCard { | ||||
|         } | ||||
|  | ||||
|         .content { | ||||
|           padding: 0 16px; | ||||
|         } | ||||
|  | ||||
|         .content p { | ||||
|           margin: 16px 0; | ||||
|           padding: 16px; | ||||
|         } | ||||
|  | ||||
|         .picker { | ||||
| @@ -162,8 +138,9 @@ export class HADemoCard extends LitElement implements LovelaceCard { | ||||
|         } | ||||
|  | ||||
|         .actions { | ||||
|           padding: 0px 8px 4px 8px; | ||||
|           padding-left: 8px; | ||||
|         } | ||||
|  | ||||
|         @media only screen and (max-width: 500px) { | ||||
|           .small-hidden { | ||||
|             display: none; | ||||
|   | ||||
| @@ -17,14 +17,12 @@ 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"; | ||||
| @@ -52,13 +50,11 @@ 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); | ||||
| @@ -72,8 +68,6 @@ export class HaDemo extends HomeAssistantAppEl { | ||||
|         id: "sensor.co2_intensity", | ||||
|         name: null, | ||||
|         icon: null, | ||||
|         labels: [], | ||||
|         categories: {}, | ||||
|         platform: "co2signal", | ||||
|         hidden_by: null, | ||||
|         entity_category: null, | ||||
| @@ -90,8 +84,6 @@ export class HaDemo extends HomeAssistantAppEl { | ||||
|         id: "sensor.co2_intensity", | ||||
|         name: null, | ||||
|         icon: null, | ||||
|         labels: [], | ||||
|         categories: {}, | ||||
|         platform: "co2signal", | ||||
|         hidden_by: null, | ||||
|         entity_category: null, | ||||
|   | ||||
| @@ -4,11 +4,4 @@ import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; | ||||
| export const mockAreaRegistry = ( | ||||
|   hass: MockHomeAssistant, | ||||
|   data: AreaRegistryEntry[] = [] | ||||
| ) => { | ||||
|   hass.mockWS("config/area_registry/list", () => data); | ||||
|   const areas = {}; | ||||
|   data.forEach((area) => { | ||||
|     areas[area.area_id] = area; | ||||
|   }); | ||||
|   hass.updateHass({ areas }); | ||||
| }; | ||||
| ) => hass.mockWS("config/area_registry/list", () => data); | ||||
|   | ||||
| @@ -10,7 +10,6 @@ export const mockConfigEntries = (hass: MockHomeAssistant) => { | ||||
|     supports_options: false, | ||||
|     supports_remove_device: false, | ||||
|     supports_unload: true, | ||||
|     supports_reconfigure: true, | ||||
|     pref_disable_new_entities: false, | ||||
|     pref_disable_polling: false, | ||||
|     disabled_by: null, | ||||
|   | ||||
| @@ -4,11 +4,4 @@ import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; | ||||
| export const mockDeviceRegistry = ( | ||||
|   hass: MockHomeAssistant, | ||||
|   data: DeviceRegistryEntry[] = [] | ||||
| ) => { | ||||
|   hass.mockWS("config/device_registry/list", () => data); | ||||
|   const devices = {}; | ||||
|   data.forEach((device) => { | ||||
|     devices[device.id] = device; | ||||
|   }); | ||||
|   hass.updateHass({ devices }); | ||||
| }; | ||||
| ) => hass.mockWS("config/device_registry/list", () => data); | ||||
|   | ||||
| @@ -1,7 +0,0 @@ | ||||
| import { FloorRegistryEntry } from "../../../src/data/floor_registry"; | ||||
| import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; | ||||
|  | ||||
| export const mockFloorRegistry = ( | ||||
|   hass: MockHomeAssistant, | ||||
|   data: FloorRegistryEntry[] = [] | ||||
| ) => hass.mockWS("config/floor_registry/list", () => data); | ||||
| @@ -1,33 +0,0 @@ | ||||
| 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: {} }; | ||||
|     } | ||||
|   ); | ||||
| }; | ||||
| @@ -1,7 +0,0 @@ | ||||
| import { LabelRegistryEntry } from "../../../src/data/label_registry"; | ||||
| import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; | ||||
|  | ||||
| export const mockLabelRegistry = ( | ||||
|   hass: MockHomeAssistant, | ||||
|   data: LabelRegistryEntry[] = [] | ||||
| ) => hass.mockWS("config/label_registry/list", () => data); | ||||
| @@ -1,58 +0,0 @@ | ||||
| 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,5 +21,4 @@ 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, nothing } from "lit"; | ||||
| import { html, LitElement, css, TemplateResult } 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,9 +45,7 @@ class DemoBlackWhiteRow extends LitElement { | ||||
|               </mwc-button> | ||||
|             </div> | ||||
|           </ha-card> | ||||
|           ${this.value | ||||
|             ? html`<pre>${JSON.stringify(this.value, undefined, 2)}</pre>` | ||||
|             : nothing} | ||||
|           <pre>${JSON.stringify(this.value, undefined, 2)}</pre> | ||||
|         </div> | ||||
|       </div> | ||||
|     `; | ||||
|   | ||||
| @@ -17,7 +17,6 @@ export const basicTrace: DemoTrace = { | ||||
|         { | ||||
|           path: "trigger/0", | ||||
|           timestamp: "2021-03-25T04:36:51.223693+00:00", | ||||
|           changed_variables: {}, | ||||
|         }, | ||||
|       ], | ||||
|       "condition/0": [ | ||||
|   | ||||
| @@ -17,7 +17,6 @@ export const motionLightTrace: DemoTrace = { | ||||
|         { | ||||
|           path: "trigger/0", | ||||
|           timestamp: "2021-03-25T04:36:51.223693+00:00", | ||||
|           changed_variables: {}, | ||||
|         }, | ||||
|       ], | ||||
|       "action/0": [ | ||||
|   | ||||
| @@ -21,10 +21,10 @@ const ENTITIES = [ | ||||
|   }), | ||||
| ]; | ||||
|  | ||||
| const conditions: Condition[] = [ | ||||
|   { condition: "and", conditions: [] }, | ||||
|   { condition: "not", conditions: [] }, | ||||
|   { condition: "or", conditions: [] }, | ||||
| const conditions = [ | ||||
|   { condition: "and" }, | ||||
|   { condition: "not" }, | ||||
|   { condition: "or" }, | ||||
|   { condition: "state", entity_id: "light.kitchen", state: "on" }, | ||||
|   { | ||||
|     condition: "numeric_state", | ||||
| @@ -34,11 +34,11 @@ const conditions: Condition[] = [ | ||||
|     above: 20, | ||||
|   }, | ||||
|   { condition: "sun", after: "sunset" }, | ||||
|   { condition: "sun", after: "sunrise", before_offset: 3600 }, | ||||
|   { condition: "sun", after: "sunrise", offset: "-01:00" }, | ||||
|   { condition: "zone", entity_id: "device_tracker.person", zone: "zone.home" }, | ||||
|   { condition: "trigger", id: "motion" }, | ||||
|   { condition: "time" }, | ||||
|   { condition: "template", value_template: "" }, | ||||
|   { condition: "template" }, | ||||
| ]; | ||||
|  | ||||
| const initialCondition: Condition = { | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| 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"; | ||||
| @@ -55,7 +56,6 @@ export class DemoAutomationTraceTimeline extends LitElement { | ||||
|     super.firstUpdated(changedProps); | ||||
|     const hass = provideHass(this); | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("config", "en"); | ||||
|   } | ||||
|  | ||||
|   static get styles() { | ||||
|   | ||||
| @@ -60,7 +60,6 @@ export class DemoAutomationTrace extends LitElement { | ||||
|     super.firstUpdated(changedProps); | ||||
|     const hass = provideHass(this); | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("config", "en"); | ||||
|   } | ||||
|  | ||||
|   static get styles() { | ||||
|   | ||||
| @@ -162,7 +162,7 @@ export class DemoHaBarButton extends LitElement { | ||||
|       } | ||||
|       .custom-group { | ||||
|         --control-button-group-thickness: 100px; | ||||
|         --control-button-group-border-radius: 36px; | ||||
|         --control-button-group-border-radius: 18px; | ||||
|         --control-button-group-spacing: 20px; | ||||
|       } | ||||
|       .custom-group ha-control-button { | ||||
|   | ||||
| @@ -94,7 +94,7 @@ export class DemoHarControlNumberButtons extends LitElement { | ||||
|         --control-number-buttons-background-color: #2196f3; | ||||
|         --control-number-buttons-background-opacity: 0.1; | ||||
|         --control-number-buttons-thickness: 100px; | ||||
|         --control-number-buttons-border-radius: 36px; | ||||
|         --control-number-buttons-border-radius: 24px; | ||||
|       } | ||||
|     `; | ||||
|   } | ||||
|   | ||||
| @@ -186,8 +186,8 @@ export class DemoHaControlSelect extends LitElement { | ||||
|       .custom { | ||||
|         --mdc-icon-size: 24px; | ||||
|         --control-select-color: var(--state-fan-active-color); | ||||
|         --control-select-thickness: 130px; | ||||
|         --control-select-border-radius: 48px; | ||||
|         --control-select-thickness: 100px; | ||||
|         --control-select-border-radius: 24px; | ||||
|       } | ||||
|       .vertical-selects { | ||||
|         height: 300px; | ||||
|   | ||||
| @@ -150,8 +150,8 @@ export class DemoHaBarSlider extends LitElement { | ||||
|         --control-slider-color: #ffcf4c; | ||||
|         --control-slider-background: #ffcf4c; | ||||
|         --control-slider-background-opacity: 0.2; | ||||
|         --control-slider-thickness: 130px; | ||||
|         --control-slider-border-radius: 48px; | ||||
|         --control-slider-thickness: 100px; | ||||
|         --control-slider-border-radius: 24px; | ||||
|       } | ||||
|       .vertical-sliders { | ||||
|         height: 300px; | ||||
|   | ||||
| @@ -117,8 +117,8 @@ export class DemoHaControlSwitch extends LitElement { | ||||
|       .custom { | ||||
|         --control-switch-on-color: var(--green-color); | ||||
|         --control-switch-off-color: var(--red-color); | ||||
|         --control-switch-thickness: 130px; | ||||
|         --control-switch-border-radius: 48px; | ||||
|         --control-switch-thickness: 100px; | ||||
|         --control-switch-border-radius: 24px; | ||||
|         --control-switch-padding: 6px; | ||||
|         --mdc-icon-size: 24px; | ||||
|       } | ||||
|   | ||||
| @@ -59,7 +59,6 @@ const DEVICES = [ | ||||
|     hw_version: null, | ||||
|     via_device_id: null, | ||||
|     serial_number: null, | ||||
|     labels: [], | ||||
|   }, | ||||
|   { | ||||
|     area_id: "backyard", | ||||
| @@ -78,7 +77,6 @@ const DEVICES = [ | ||||
|     hw_version: null, | ||||
|     via_device_id: null, | ||||
|     serial_number: null, | ||||
|     labels: [], | ||||
|   }, | ||||
|   { | ||||
|     area_id: null, | ||||
| @@ -97,37 +95,30 @@ const DEVICES = [ | ||||
|     hw_version: null, | ||||
|     via_device_id: null, | ||||
|     serial_number: null, | ||||
|     labels: [], | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| const AREAS: AreaRegistryEntry[] = [ | ||||
|   { | ||||
|     area_id: "backyard", | ||||
|     floor_id: null, | ||||
|     name: "Backyard", | ||||
|     icon: null, | ||||
|     picture: null, | ||||
|     aliases: [], | ||||
|     labels: [], | ||||
|   }, | ||||
|   { | ||||
|     area_id: "bedroom", | ||||
|     floor_id: null, | ||||
|     name: "Bedroom", | ||||
|     icon: "mdi:bed", | ||||
|     picture: null, | ||||
|     aliases: [], | ||||
|     labels: [], | ||||
|   }, | ||||
|   { | ||||
|     area_id: "livingroom", | ||||
|     floor_id: null, | ||||
|     name: "Livingroom", | ||||
|     icon: "mdi:sofa", | ||||
|     picture: null, | ||||
|     aliases: [], | ||||
|     labels: [], | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
|   | ||||
| @@ -17,10 +17,6 @@ import { provideHass } from "../../../../src/fake_data/provide_hass"; | ||||
| import { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin"; | ||||
| import type { HomeAssistant } from "../../../../src/types"; | ||||
| import "../../components/demo-black-white-row"; | ||||
| import { FloorRegistryEntry } from "../../../../src/data/floor_registry"; | ||||
| import { LabelRegistryEntry } from "../../../../src/data/label_registry"; | ||||
| import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry"; | ||||
| import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry"; | ||||
|  | ||||
| const ENTITIES = [ | ||||
|   getEntity("alarm_control_panel", "alarm", "disarmed", { | ||||
| @@ -59,7 +55,6 @@ const DEVICES = [ | ||||
|     hw_version: null, | ||||
|     via_device_id: null, | ||||
|     serial_number: null, | ||||
|     labels: [], | ||||
|   }, | ||||
|   { | ||||
|     area_id: "backyard", | ||||
| @@ -78,7 +73,6 @@ const DEVICES = [ | ||||
|     hw_version: null, | ||||
|     via_device_id: null, | ||||
|     serial_number: null, | ||||
|     labels: [], | ||||
|   }, | ||||
|   { | ||||
|     area_id: null, | ||||
| @@ -97,76 +91,30 @@ const DEVICES = [ | ||||
|     hw_version: null, | ||||
|     via_device_id: null, | ||||
|     serial_number: null, | ||||
|     labels: [], | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| const AREAS: AreaRegistryEntry[] = [ | ||||
|   { | ||||
|     area_id: "backyard", | ||||
|     floor_id: "ground", | ||||
|     name: "Backyard", | ||||
|     icon: null, | ||||
|     picture: null, | ||||
|     aliases: [], | ||||
|     labels: [], | ||||
|   }, | ||||
|   { | ||||
|     area_id: "bedroom", | ||||
|     floor_id: "first", | ||||
|     name: "Bedroom", | ||||
|     icon: "mdi:bed", | ||||
|     picture: null, | ||||
|     aliases: [], | ||||
|     labels: [], | ||||
|   }, | ||||
|   { | ||||
|     area_id: "livingroom", | ||||
|     floor_id: "ground", | ||||
|     name: "Livingroom", | ||||
|     icon: "mdi:sofa", | ||||
|     picture: null, | ||||
|     aliases: [], | ||||
|     labels: [], | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| const FLOORS: FloorRegistryEntry[] = [ | ||||
|   { | ||||
|     floor_id: "ground", | ||||
|     name: "Ground floor", | ||||
|     level: 0, | ||||
|     icon: null, | ||||
|     aliases: [], | ||||
|   }, | ||||
|   { | ||||
|     floor_id: "first", | ||||
|     name: "First floor", | ||||
|     level: 1, | ||||
|     icon: "mdi:numeric-1", | ||||
|     aliases: [], | ||||
|   }, | ||||
|   { | ||||
|     floor_id: "second", | ||||
|     name: "Second floor", | ||||
|     level: 2, | ||||
|     icon: "mdi:numeric-2", | ||||
|     aliases: [], | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| const LABELS: LabelRegistryEntry[] = [ | ||||
|   { | ||||
|     label_id: "energy", | ||||
|     name: "Energy", | ||||
|     icon: null, | ||||
|     color: "yellow", | ||||
|   }, | ||||
|   { | ||||
|     label_id: "entertainment", | ||||
|     name: "Entertainment", | ||||
|     icon: "mdi:popcorn", | ||||
|     color: "blue", | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| @@ -177,12 +125,7 @@ const SCHEMAS: { | ||||
|   { | ||||
|     name: "One of each", | ||||
|     input: { | ||||
|       label: { name: "Label", selector: { label: {} } }, | ||||
|       floor: { name: "Floor", selector: { floor: {} } }, | ||||
|       area: { name: "Area", selector: { area: {} } }, | ||||
|       device: { name: "Device", selector: { device: {} } }, | ||||
|       entity: { name: "Entity", selector: { entity: {} } }, | ||||
|       target: { name: "Target", selector: { target: {} } }, | ||||
|       state: { | ||||
|         name: "State", | ||||
|         selector: { state: { entity_id: "alarm_control_panel.alarm" } }, | ||||
| @@ -191,12 +134,15 @@ const SCHEMAS: { | ||||
|         name: "Attribute", | ||||
|         selector: { attribute: { entity_id: "" } }, | ||||
|       }, | ||||
|       device: { name: "Device", selector: { device: {} } }, | ||||
|       config_entry: { | ||||
|         name: "Integration", | ||||
|         selector: { config_entry: {} }, | ||||
|       }, | ||||
|       duration: { name: "Duration", selector: { duration: {} } }, | ||||
|       addon: { name: "Addon", selector: { addon: {} } }, | ||||
|       area: { name: "Area", selector: { area: {} } }, | ||||
|       target: { name: "Target", selector: { target: {} } }, | ||||
|       number_box: { | ||||
|         name: "Number Box", | ||||
|         selector: { | ||||
| @@ -329,14 +275,6 @@ 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!" } }, | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   { | ||||
| @@ -345,8 +283,6 @@ const SCHEMAS: { | ||||
|       entity: { name: "Entity", selector: { entity: { multiple: true } } }, | ||||
|       device: { name: "Device", selector: { device: { multiple: true } } }, | ||||
|       area: { name: "Area", selector: { area: { multiple: true } } }, | ||||
|       floor: { name: "Floor", selector: { floor: { multiple: true } } }, | ||||
|       label: { name: "Label", selector: { label: { multiple: true } } }, | ||||
|       select: { | ||||
|         name: "Select Multiple", | ||||
|         selector: { | ||||
| @@ -403,8 +339,6 @@ class DemoHaSelector extends LitElement implements ProvideHassElement { | ||||
|     mockDeviceRegistry(hass, DEVICES); | ||||
|     mockConfigEntries(hass); | ||||
|     mockAreaRegistry(hass, AREAS); | ||||
|     mockFloorRegistry(hass, FLOORS); | ||||
|     mockLabelRegistry(hass, LABELS); | ||||
|     mockHassioSupervisor(hass); | ||||
|     hass.mockWS("auth/sign_path", (params) => params); | ||||
|     hass.mockWS("media_player/browse_media", this._browseMedia); | ||||
| @@ -567,7 +501,7 @@ class DemoHaSelector extends LitElement implements ProvideHassElement { | ||||
|           this.requestUpdate(); | ||||
|         }; | ||||
|         return html` | ||||
|           <demo-black-white-row .title=${info.name}> | ||||
|           <demo-black-white-row .title=${info.name} .value=${this.data[idx]}> | ||||
|             ${["light", "dark"].map((slot) => | ||||
|               Object.entries(info.input).map( | ||||
|                 ([key, value]) => html` | ||||
| @@ -600,8 +534,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement { | ||||
|   } | ||||
|  | ||||
|   static styles = css` | ||||
|     ha-settings-row { | ||||
|       --paper-item-body-two-line-min-height: 0; | ||||
|     ha-selector { | ||||
|       width: 60; | ||||
|     } | ||||
|     .options { | ||||
|       max-width: 800px; | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -85,7 +84,6 @@ class DemoAlarmPanelEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -147,7 +146,6 @@ class DemoArea extends LitElement { | ||||
|         entity_id: "binary_sensor.kitchen_door", | ||||
|       }, | ||||
|     ]); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -67,7 +66,6 @@ class DemoConditional extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -324,7 +323,6 @@ class DemoEntities extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -83,7 +82,6 @@ class DemoButtonEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -11,7 +10,7 @@ const ENTITIES = [ | ||||
|     latitude: 32.877105, | ||||
|     longitude: 117.232185, | ||||
|     gps_accuracy: 91, | ||||
|     battery: 25, | ||||
|     battery: 71, | ||||
|     friendly_name: "Paulus", | ||||
|   }), | ||||
|   getEntity("device_tracker", "demo_anne_therese", "school", { | ||||
| @@ -19,7 +18,7 @@ const ENTITIES = [ | ||||
|     latitude: 32.877105, | ||||
|     longitude: 117.232185, | ||||
|     gps_accuracy: 91, | ||||
|     battery: 50, | ||||
|     battery: 71, | ||||
|     friendly_name: "Anne Therese", | ||||
|   }), | ||||
|   getEntity("device_tracker", "demo_home_boy", "home", { | ||||
| @@ -27,7 +26,7 @@ const ENTITIES = [ | ||||
|     latitude: 32.877105, | ||||
|     longitude: 117.232185, | ||||
|     gps_accuracy: 91, | ||||
|     battery: 75, | ||||
|     battery: 71, | ||||
|     friendly_name: "Home Boy", | ||||
|   }), | ||||
|   getEntity("light", "bed_light", "on", { | ||||
| @@ -39,53 +38,21 @@ const ENTITIES = [ | ||||
|   getEntity("light", "ceiling_lights", "off", { | ||||
|     friendly_name: "Ceiling Lights", | ||||
|   }), | ||||
|   getEntity("sensor", "battery_1", 20, { | ||||
|     device_class: "battery", | ||||
|     friendly_name: "Battery 1", | ||||
|     unit_of_measurement: "%", | ||||
|   }), | ||||
|   getEntity("sensor", "battery_2", 35, { | ||||
|     device_class: "battery", | ||||
|     friendly_name: "Battery 2", | ||||
|     unit_of_measurement: "%", | ||||
|   }), | ||||
|   getEntity("sensor", "battery_3", 40, { | ||||
|     device_class: "battery", | ||||
|     friendly_name: "Battery 3", | ||||
|     unit_of_measurement: "%", | ||||
|   }), | ||||
|   getEntity("sensor", "battery_4", 80, { | ||||
|     device_class: "battery", | ||||
|     friendly_name: "Battery 4", | ||||
|     unit_of_measurement: "%", | ||||
|   }), | ||||
|   getEntity("input_number", "min_battery_level", 30, { | ||||
|     mode: "slider", | ||||
|     step: 10, | ||||
|     min: 0, | ||||
|     max: 100, | ||||
|     icon: "mdi:battery-alert-variant", | ||||
|     friendly_name: "Minimum Battery Level", | ||||
|     unit_of_measurement: "%", | ||||
|   }), | ||||
| ]; | ||||
|  | ||||
| const CONFIGS = [ | ||||
|   { | ||||
|     heading: "Unfiltered entities", | ||||
|     heading: "Unfiltered controller", | ||||
|     config: ` | ||||
| - type: entities | ||||
|   entities: | ||||
|     - device_tracker.demo_anne_therese | ||||
|     - device_tracker.demo_home_boy | ||||
|     - device_tracker.demo_paulus | ||||
|   - light.bed_light | ||||
|   - light.ceiling_lights | ||||
|   - light.kitchen_lights | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "On and home entities", | ||||
|     heading: "Filtered entities card", | ||||
|     config: ` | ||||
| - type: entity-filter | ||||
|   entities: | ||||
| @@ -95,30 +62,11 @@ const CONFIGS = [ | ||||
|     - light.bed_light | ||||
|     - light.ceiling_lights | ||||
|     - light.kitchen_lights | ||||
|   conditions: | ||||
|     - condition: state | ||||
|       state: | ||||
|   state_filter: | ||||
|     - "on" | ||||
|     - home | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Same state as Bed Light", | ||||
|     config: ` | ||||
| - type: entity-filter | ||||
|   entities: | ||||
|     - device_tracker.demo_anne_therese | ||||
|     - device_tracker.demo_home_boy | ||||
|     - device_tracker.demo_paulus | ||||
|     - light.bed_light | ||||
|     - light.ceiling_lights | ||||
|     - light.kitchen_lights | ||||
|   conditions: | ||||
|     - condition: state | ||||
|       state: | ||||
|         - light.bed_light | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: 'With "entities" card config', | ||||
|     config: ` | ||||
| @@ -130,11 +78,9 @@ const CONFIGS = [ | ||||
|     - light.bed_light | ||||
|     - light.ceiling_lights | ||||
|     - light.kitchen_lights | ||||
|   conditions: | ||||
|     - condition: state | ||||
|       state: | ||||
|   state_filter: | ||||
|     - "on" | ||||
|         - home | ||||
|     - not_home | ||||
|   card: | ||||
|     type: entities | ||||
|     title: Custom Title | ||||
| @@ -152,101 +98,15 @@ const CONFIGS = [ | ||||
|     - light.bed_light | ||||
|     - light.ceiling_lights | ||||
|     - light.kitchen_lights | ||||
|   conditions: | ||||
|     - condition: state | ||||
|       state: | ||||
|   state_filter: | ||||
|     - "on" | ||||
|         - home | ||||
|     - not_home | ||||
|   card: | ||||
|     type: glance | ||||
|     show_state: true | ||||
|     title: Custom Title | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: | ||||
|       "Filtered entities by battery attribute (< '30') using state filter", | ||||
|     config: ` | ||||
| - type: entity-filter | ||||
|   entities: | ||||
|     - device_tracker.demo_anne_therese | ||||
|     - device_tracker.demo_home_boy | ||||
|     - device_tracker.demo_paulus | ||||
|   state_filter: | ||||
|     - operator: < | ||||
|       attribute: battery | ||||
|       value: "30" | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Unfiltered number entities", | ||||
|     config: ` | ||||
| - type: entities | ||||
|   entities: | ||||
|     - input_number.min_battery_level | ||||
|     - sensor.battery_1 | ||||
|     - sensor.battery_3 | ||||
|     - sensor.battery_2 | ||||
|     - sensor.battery_4 | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Battery lower than 50%", | ||||
|     config: ` | ||||
| - type: entity-filter | ||||
|   entities: | ||||
|     - sensor.battery_1 | ||||
|     - sensor.battery_3 | ||||
|     - sensor.battery_2 | ||||
|     - sensor.battery_4 | ||||
|   conditions: | ||||
|     - condition: numeric_state | ||||
|       below: 50 | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Battery lower than min battery level", | ||||
|     config: ` | ||||
| - type: entity-filter | ||||
|   entities: | ||||
|     - sensor.battery_1 | ||||
|     - sensor.battery_3 | ||||
|     - sensor.battery_2 | ||||
|     - sensor.battery_4 | ||||
|   conditions: | ||||
|     - condition: numeric_state | ||||
|       below: input_number.min_battery_level | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Battery between min battery level and 70%", | ||||
|     config: ` | ||||
| - type: entity-filter | ||||
|   entities: | ||||
|     - sensor.battery_1 | ||||
|     - sensor.battery_3 | ||||
|     - sensor.battery_2 | ||||
|     - sensor.battery_4 | ||||
|   conditions: | ||||
|     - condition: numeric_state | ||||
|       above: input_number.min_battery_level | ||||
|       below: 70 | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Error: Entities must be specified", | ||||
|     config: ` | ||||
| - type: entity-filter | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Error: Incorrect filter config", | ||||
|     config: ` | ||||
| - type: entity-filter | ||||
|   entities: | ||||
|     - sensor.gas_station_lowest_price | ||||
|     `, | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| @customElement("demo-lovelace-entity-filter-card") | ||||
| @@ -263,7 +123,6 @@ class DemoEntityFilter extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", {}), | ||||
| @@ -129,7 +128,6 @@ class DemoGaugeEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -239,7 +238,6 @@ class DemoGlanceEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -4,7 +4,6 @@ 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", { | ||||
| @@ -215,7 +214,6 @@ class DemoStack extends LitElement { | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockHistory(hass); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -77,7 +76,6 @@ class DemoLightEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -139,7 +138,6 @@ class DemoPictureElements extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -94,7 +93,6 @@ class DemoPictureEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -135,7 +134,6 @@ class DemoPictureGlance extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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 = [ | ||||
|   { | ||||
| @@ -44,7 +43,6 @@ export class DemoPlantEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(createPlantEntities()); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,6 @@ 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", { | ||||
| @@ -36,45 +35,6 @@ const ENTITIES = [ | ||||
|     friendly_name: "Nest", | ||||
|     supported_features: 43, | ||||
|   }), | ||||
|   getEntity("climate", "overkiz_radiator", "heat", { | ||||
|     current_temperature: 18, | ||||
|     min_temp: 7, | ||||
|     max_temp: 35, | ||||
|     temperature: 20, | ||||
|     hvac_modes: ["heat", "auto", "off"], | ||||
|     friendly_name: "Overkiz radiator", | ||||
|     supported_features: 17, | ||||
|     preset_mode: "comfort", | ||||
|     preset_modes: [ | ||||
|       "none", | ||||
|       "frost_protection", | ||||
|       "eco", | ||||
|       "comfort", | ||||
|       "comfort-1", | ||||
|       "comfort-2", | ||||
|       "auto", | ||||
|       "boost", | ||||
|       "external", | ||||
|       "prog", | ||||
|     ], | ||||
|   }), | ||||
|   getEntity("climate", "overkiz_towel_dryer", "heat", { | ||||
|     current_temperature: null, | ||||
|     min_temp: 7, | ||||
|     max_temp: 35, | ||||
|     hvac_modes: ["heat", "off"], | ||||
|     friendly_name: "Overkiz towel dryer", | ||||
|     supported_features: 16, | ||||
|     preset_mode: "eco", | ||||
|     preset_modes: [ | ||||
|       "none", | ||||
|       "frost_protection", | ||||
|       "eco", | ||||
|       "comfort", | ||||
|       "comfort-1", | ||||
|       "comfort-2", | ||||
|     ], | ||||
|   }), | ||||
|   getEntity("climate", "sensibo", "fan_only", { | ||||
|     current_temperature: null, | ||||
|     temperature: null, | ||||
| @@ -85,9 +45,7 @@ const ENTITIES = [ | ||||
|     friendly_name: "Sensibo purifier", | ||||
|     fan_modes: ["low", "high"], | ||||
|     fan_mode: "low", | ||||
|     swing_modes: ["on", "off", "both", "vertical", "horizontal"], | ||||
|     swing_mode: "vertical", | ||||
|     supported_features: 41, | ||||
|     supported_features: 9, | ||||
|   }), | ||||
|   getEntity("climate", "unavailable", "unavailable", { | ||||
|     supported_features: 43, | ||||
| @@ -100,6 +58,8 @@ const CONFIGS = [ | ||||
|     config: ` | ||||
| - type: thermostat | ||||
|   entity: climate.ecobee | ||||
| - type: thermostat | ||||
|   entity: climate.nest | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
| @@ -109,66 +69,6 @@ const CONFIGS = [ | ||||
|   entity: climate.nest | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Feature example", | ||||
|     config: ` | ||||
| - type: thermostat | ||||
|   entity: climate.overkiz_radiator | ||||
|   features: | ||||
|     - type: climate-hvac-modes | ||||
|       hvac_modes: | ||||
|         - heat | ||||
|         - 'off' | ||||
|         - auto | ||||
|     - type: climate-preset-modes | ||||
|       style: icons | ||||
|       preset_modes: | ||||
|         - none | ||||
|         - frost_protection | ||||
|         - eco | ||||
|         - comfort | ||||
|         - comfort-1 | ||||
|         - comfort-2 | ||||
|         - auto | ||||
|         - boost | ||||
|         - external | ||||
|         - prog | ||||
|     - type: climate-preset-modes | ||||
|       style: dropdown | ||||
|       preset_modes: | ||||
|         - none | ||||
|         - frost_protection | ||||
|         - eco | ||||
|         - comfort | ||||
|         - comfort-1 | ||||
|         - comfort-2 | ||||
|         - auto | ||||
|         - boost | ||||
|         - external | ||||
|         - prog | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Preset only example", | ||||
|     config: ` | ||||
| - type: thermostat | ||||
|   entity: climate.overkiz_towel_dryer | ||||
|   features: | ||||
|     - type: climate-hvac-modes | ||||
|       hvac_modes: | ||||
|         - heat | ||||
|         - 'off' | ||||
|     - type: climate-preset-modes | ||||
|       style: icons | ||||
|       preset_modes: | ||||
|         - none | ||||
|         - frost_protection | ||||
|         - eco | ||||
|         - comfort | ||||
|         - comfort-1 | ||||
|         - comfort-2 | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
|     heading: "Fan only example", | ||||
|     config: ` | ||||
| @@ -184,14 +84,6 @@ const CONFIGS = [ | ||||
|       fan_modes: | ||||
|         - low | ||||
|         - high | ||||
|     - type: climate-swing-modes | ||||
|       style: icons | ||||
|       swing_modes: | ||||
|         - 'on' | ||||
|         - 'off' | ||||
|         - 'both' | ||||
|         - 'vertical' | ||||
|         - 'horizontal' | ||||
|     `, | ||||
|   }, | ||||
|   { | ||||
| @@ -224,7 +116,6 @@ class DemoThermostatEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,6 @@ 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", { | ||||
| @@ -185,7 +184,6 @@ class DemoTile extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -4,7 +4,6 @@ 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", { | ||||
| @@ -48,7 +47,6 @@ class DemoTodoListEntity extends LitElement { | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("lovelace", "en"); | ||||
|     hass.addEntities(ENTITIES); | ||||
|     mockIcons(hass); | ||||
|  | ||||
|     mockTodo(hass); | ||||
|   } | ||||
|   | ||||
| @@ -11,7 +11,6 @@ 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 = [ | ||||
| @@ -292,7 +291,6 @@ 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( | ||||
| @@ -399,17 +397,6 @@ 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", | ||||
|           labels: [], | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
|     hass.updateTranslations(null, "en"); | ||||
|     hass.updateTranslations("config", "en"); | ||||
|   } | ||||
|   | ||||
| @@ -31,7 +31,6 @@ const createConfigEntry = ( | ||||
|   supports_options: false, | ||||
|   supports_remove_device: false, | ||||
|   supports_unload: true, | ||||
|   supports_reconfigure: true, | ||||
|   disabled_by: null, | ||||
|   pref_disable_new_entities: false, | ||||
|   pref_disable_polling: false, | ||||
| @@ -199,8 +198,6 @@ const createEntityRegistryEntries = ( | ||||
|     has_entity_name: false, | ||||
|     unique_id: "updater", | ||||
|     options: null, | ||||
|     labels: [], | ||||
|     categories: {}, | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| @@ -224,7 +221,6 @@ const createDeviceRegistryEntries = ( | ||||
|     name_by_user: null, | ||||
|     disabled_by: null, | ||||
|     configuration_url: null, | ||||
|     labels: [], | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import "../../components/demo-more-infos"; | ||||
| import { ClimateEntityFeature } from "../../../../src/data/climate"; | ||||
|  | ||||
| const ENTITIES = [ | ||||
|   getEntity("climate", "radiator", "heat", { | ||||
|   getEntity("climate", "thermostat", "heat", { | ||||
|     friendly_name: "Basic heater", | ||||
|     hvac_modes: ["heat", "off"], | ||||
|     hvac_mode: "heat", | ||||
| @@ -80,24 +80,6 @@ const ENTITIES = [ | ||||
|     max_humidity: 100, | ||||
|     humidity: 50, | ||||
|   }), | ||||
|   getEntity("climate", "towel_dryer", "heat", { | ||||
|     friendly_name: "Preset only heater", | ||||
|     hvac_modes: ["heat", "off"], | ||||
|     hvac_mode: "heat", | ||||
|     preset_modes: [ | ||||
|       "none", | ||||
|       "frost_protection", | ||||
|       "eco", | ||||
|       "comfort", | ||||
|       "comfort-1", | ||||
|       "comfort-2", | ||||
|     ], | ||||
|     preset_mode: "eco", | ||||
|     current_temperature: null, | ||||
|     min_temp: 7, | ||||
|     max_temp: 35, | ||||
|     supported_features: ClimateEntityFeature.PRESET_MODE, | ||||
|   }), | ||||
|   getEntity("climate", "unavailable", "unavailable", { | ||||
|     friendly_name: "Unavailable heater", | ||||
|     hvac_modes: ["heat", "off"], | ||||
|   | ||||
| @@ -1263,7 +1263,6 @@ class HassioAddonInfo extends LitElement { | ||||
|         .card-actions { | ||||
|           justify-content: space-between; | ||||
|           display: flex; | ||||
|           direction: var(--direction); | ||||
|         } | ||||
|         .changelog { | ||||
|           display: contents; | ||||
|   | ||||
| @@ -154,16 +154,12 @@ class HassioHardwareDialog extends LitElement { | ||||
|         ha-icon-button { | ||||
|           position: absolute; | ||||
|           right: 16px; | ||||
|           inset-inline-end: 16px; | ||||
|           inset-inline-start: initial; | ||||
|           top: 10px; | ||||
|           text-decoration: none; | ||||
|           color: var(--primary-text-color); | ||||
|         } | ||||
|         h2 { | ||||
|           margin: 18px 42px 0 18px; | ||||
|           margin-inline-start: 18px; | ||||
|           margin-inline-end: 42px; | ||||
|           color: var(--primary-text-color); | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| import "@material/mwc-button/mwc-button"; | ||||
| import { mdiDelete, mdiDeleteOff } from "@mdi/js"; | ||||
| import "@polymer/paper-item/paper-item"; | ||||
| import "@polymer/paper-item/paper-item-body"; | ||||
| import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; | ||||
| import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; | ||||
| import { customElement, property, query, state } from "lit/decorators"; | ||||
| @@ -25,8 +27,6 @@ import type { HomeAssistant } from "../../../../src/types"; | ||||
| import { HassioRepositoryDialogParams } from "./show-dialog-repositories"; | ||||
| import type { HaTextField } from "../../../../src/components/ha-textfield"; | ||||
| import "../../../../src/components/ha-textfield"; | ||||
| import "../../../../src/components/ha-list-new"; | ||||
| import "../../../../src/components/ha-list-item-new"; | ||||
|  | ||||
| @customElement("dialog-hassio-repositories") | ||||
| class HassioRepositoriesDialog extends LitElement { | ||||
| @@ -106,17 +106,16 @@ class HassioRepositoriesDialog extends LitElement { | ||||
|           ? html`<ha-alert alert-type="error">${this._error}</ha-alert>` | ||||
|           : ""} | ||||
|         <div class="form"> | ||||
|           <ha-list-new> | ||||
|           ${repositories.length | ||||
|             ? repositories.map( | ||||
|                 (repo) => html` | ||||
|                     <ha-list-item-new class="option"> | ||||
|                       ${repo.name} | ||||
|                       <div slot="supporting-text"> | ||||
|                         <div>${repo.maintainer}</div> | ||||
|                         <div>${repo.url}</div> | ||||
|                       </div> | ||||
|                       <div class="delete" slot="end"> | ||||
|                   <paper-item class="option"> | ||||
|                     <paper-item-body three-line> | ||||
|                       <div>${repo.name}</div> | ||||
|                       <div secondary>${repo.maintainer}</div> | ||||
|                       <div secondary>${repo.url}</div> | ||||
|                     </paper-item-body> | ||||
|                     <div class="delete"> | ||||
|                       <ha-icon-button | ||||
|                         .label=${this._dialogParams!.supervisor.localize( | ||||
|                           "dialog.repositories.remove" | ||||
| @@ -141,11 +140,10 @@ class HassioRepositoriesDialog extends LitElement { | ||||
|                         )} | ||||
|                       </simple-tooltip> | ||||
|                     </div> | ||||
|                     </ha-list-item-new> | ||||
|                   </paper-item> | ||||
|                 ` | ||||
|               ) | ||||
|               : html`<ha-list-item-new> No repositories </ha-list-item-new>`} | ||||
|           </ha-list-new> | ||||
|             : html`<paper-item> No repositories </paper-item>`} | ||||
|           <div class="layout horizontal bottom"> | ||||
|             <ha-textfield | ||||
|               class="flex-auto" | ||||
| @@ -208,9 +206,6 @@ class HassioRepositoriesDialog extends LitElement { | ||||
|         div.delete ha-icon-button { | ||||
|           color: var(--error-color); | ||||
|         } | ||||
|         ha-list-item-new { | ||||
|           position: relative; | ||||
|         } | ||||
|       `, | ||||
|     ]; | ||||
|   } | ||||
|   | ||||
							
								
								
									
										122
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								package.json
									
									
									
									
									
								
							| @@ -25,36 +25,36 @@ | ||||
|   "license": "Apache-2.0", | ||||
|   "type": "module", | ||||
|   "dependencies": { | ||||
|     "@babel/runtime": "7.24.1", | ||||
|     "@braintree/sanitize-url": "7.0.1", | ||||
|     "@codemirror/autocomplete": "6.15.0", | ||||
|     "@babel/runtime": "7.23.9", | ||||
|     "@braintree/sanitize-url": "7.0.0", | ||||
|     "@codemirror/autocomplete": "6.12.0", | ||||
|     "@codemirror/commands": "6.3.3", | ||||
|     "@codemirror/language": "6.10.1", | ||||
|     "@codemirror/legacy-modes": "6.3.3", | ||||
|     "@codemirror/search": "6.5.6", | ||||
|     "@codemirror/state": "6.4.1", | ||||
|     "@codemirror/view": "6.26.1", | ||||
|     "@codemirror/search": "6.5.5", | ||||
|     "@codemirror/state": "6.4.0", | ||||
|     "@codemirror/view": "6.23.1", | ||||
|     "@egjs/hammerjs": "2.0.17", | ||||
|     "@formatjs/intl-datetimeformat": "6.12.3", | ||||
|     "@formatjs/intl-datetimeformat": "6.12.2", | ||||
|     "@formatjs/intl-displaynames": "6.6.6", | ||||
|     "@formatjs/intl-getcanonicallocales": "2.3.0", | ||||
|     "@formatjs/intl-listformat": "7.5.5", | ||||
|     "@formatjs/intl-locale": "3.4.5", | ||||
|     "@formatjs/intl-numberformat": "8.10.1", | ||||
|     "@formatjs/intl-numberformat": "8.10.0", | ||||
|     "@formatjs/intl-pluralrules": "5.2.12", | ||||
|     "@formatjs/intl-relativetimeformat": "11.2.12", | ||||
|     "@fullcalendar/core": "6.1.11", | ||||
|     "@fullcalendar/daygrid": "6.1.11", | ||||
|     "@fullcalendar/interaction": "6.1.11", | ||||
|     "@fullcalendar/list": "6.1.11", | ||||
|     "@fullcalendar/luxon3": "6.1.11", | ||||
|     "@fullcalendar/timegrid": "6.1.11", | ||||
|     "@fullcalendar/core": "6.1.10", | ||||
|     "@fullcalendar/daygrid": "6.1.10", | ||||
|     "@fullcalendar/interaction": "6.1.10", | ||||
|     "@fullcalendar/list": "6.1.10", | ||||
|     "@fullcalendar/luxon3": "6.1.10", | ||||
|     "@fullcalendar/timegrid": "6.1.10", | ||||
|     "@lezer/highlight": "1.2.0", | ||||
|     "@lit-labs/context": "0.4.1", | ||||
|     "@lit-labs/motion": "1.0.7", | ||||
|     "@lit-labs/observers": "2.0.2", | ||||
|     "@lit-labs/virtualizer": "2.0.12", | ||||
|     "@lrnwebcomponents/simple-tooltip": "8.0.2", | ||||
|     "@lrnwebcomponents/simple-tooltip": "8.0.0", | ||||
|     "@material/chips": "=14.0.0-canary.53b3cad2f.0", | ||||
|     "@material/data-table": "=14.0.0-canary.53b3cad2f.0", | ||||
|     "@material/mwc-base": "0.27.0", | ||||
| @@ -72,7 +72,6 @@ | ||||
|     "@material/mwc-radio": "0.27.0", | ||||
|     "@material/mwc-ripple": "0.27.0", | ||||
|     "@material/mwc-select": "0.27.0", | ||||
|     "@material/mwc-snackbar": "0.27.0", | ||||
|     "@material/mwc-switch": "0.27.0", | ||||
|     "@material/mwc-tab": "0.27.0", | ||||
|     "@material/mwc-tab-bar": "0.27.0", | ||||
| @@ -81,16 +80,17 @@ | ||||
|     "@material/mwc-top-app-bar": "0.27.0", | ||||
|     "@material/mwc-top-app-bar-fixed": "0.27.0", | ||||
|     "@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0", | ||||
|     "@material/web": "=1.3.0", | ||||
|     "@material/web": "=1.2.0", | ||||
|     "@mdi/js": "7.4.47", | ||||
|     "@mdi/svg": "7.4.47", | ||||
|     "@polymer/paper-item": "3.0.1", | ||||
|     "@polymer/paper-listbox": "3.0.1", | ||||
|     "@polymer/paper-tabs": "3.1.0", | ||||
|     "@polymer/paper-toast": "3.0.1", | ||||
|     "@polymer/polymer": "3.5.1", | ||||
|     "@thomasloven/round-slider": "0.6.0", | ||||
|     "@vaadin/combo-box": "24.3.10", | ||||
|     "@vaadin/vaadin-themable-mixin": "24.3.10", | ||||
|     "@vaadin/combo-box": "24.3.5", | ||||
|     "@vaadin/vaadin-themable-mixin": "24.3.5", | ||||
|     "@vibrant/color": "3.2.1-alpha.1", | ||||
|     "@vibrant/core": "3.2.1-alpha.1", | ||||
|     "@vibrant/quantizer-mmcq": "3.2.1-alpha.1", | ||||
| @@ -98,20 +98,19 @@ | ||||
|     "@webcomponents/scoped-custom-element-registry": "0.0.9", | ||||
|     "@webcomponents/webcomponentsjs": "2.8.0", | ||||
|     "app-datepicker": "5.1.1", | ||||
|     "chart.js": "4.4.2", | ||||
|     "color-name": "2.0.0", | ||||
|     "chart.js": "4.4.1", | ||||
|     "comlink": "4.4.1", | ||||
|     "core-js": "3.36.1", | ||||
|     "core-js": "3.35.1", | ||||
|     "cropperjs": "1.6.1", | ||||
|     "date-fns": "2.30.0", | ||||
|     "date-fns-tz": "2.0.1", | ||||
|     "date-fns-tz": "2.0.0", | ||||
|     "deep-clone-simple": "1.1.1", | ||||
|     "deep-freeze": "0.0.1", | ||||
|     "element-internals-polyfill": "1.3.10", | ||||
|     "fuse.js": "7.0.0", | ||||
|     "google-timezones-json": "1.2.0", | ||||
|     "hls.js": "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch", | ||||
|     "home-assistant-js-websocket": "9.2.1", | ||||
|     "hls.js": "1.5.3", | ||||
|     "home-assistant-js-websocket": "9.1.0", | ||||
|     "idb-keyval": "6.2.1", | ||||
|     "intl-messageformat": "10.5.11", | ||||
|     "js-yaml": "4.1.0", | ||||
| @@ -119,7 +118,7 @@ | ||||
|     "leaflet-draw": "1.0.4", | ||||
|     "lit": "2.8.0", | ||||
|     "luxon": "3.4.4", | ||||
|     "marked": "12.0.1", | ||||
|     "marked": "11.2.0", | ||||
|     "memoize-one": "6.0.0", | ||||
|     "node-vibrant": "3.2.1-alpha.1", | ||||
|     "proxy-polyfill": "0.3.2", | ||||
| @@ -130,7 +129,7 @@ | ||||
|     "rrule": "2.8.1", | ||||
|     "sortablejs": "1.15.2", | ||||
|     "stacktrace-js": "2.0.2", | ||||
|     "superstruct": "1.0.4", | ||||
|     "superstruct": "1.0.3", | ||||
|     "tinykeys": "2.1.0", | ||||
|     "tsparticles-engine": "2.12.0", | ||||
|     "tsparticles-preset-links": "2.12.0", | ||||
| @@ -147,20 +146,20 @@ | ||||
|     "workbox-precaching": "7.0.0", | ||||
|     "workbox-routing": "7.0.0", | ||||
|     "workbox-strategies": "7.0.0", | ||||
|     "xss": "1.0.15" | ||||
|     "xss": "1.0.14" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@babel/core": "7.24.3", | ||||
|     "@babel/helper-define-polyfill-provider": "0.6.1", | ||||
|     "@babel/plugin-proposal-decorators": "7.24.1", | ||||
|     "@babel/plugin-transform-runtime": "7.24.3", | ||||
|     "@babel/preset-env": "7.24.3", | ||||
|     "@babel/preset-typescript": "7.24.1", | ||||
|     "@bundle-stats/plugin-webpack-filter": "4.12.2", | ||||
|     "@babel/core": "7.23.9", | ||||
|     "@babel/helper-define-polyfill-provider": "0.5.0", | ||||
|     "@babel/plugin-proposal-decorators": "7.23.9", | ||||
|     "@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", | ||||
|     "@koa/cors": "5.0.0", | ||||
|     "@lokalise/node-api": "12.3.0", | ||||
|     "@octokit/auth-oauth-device": "7.0.1", | ||||
|     "@octokit/plugin-retry": "7.0.3", | ||||
|     "@lokalise/node-api": "12.1.0", | ||||
|     "@octokit/auth-oauth-device": "6.0.1", | ||||
|     "@octokit/plugin-retry": "6.0.1", | ||||
|     "@octokit/rest": "20.0.2", | ||||
|     "@open-wc/dev-server-hmr": "0.1.4", | ||||
|     "@rollup/plugin-babel": "6.0.4", | ||||
| @@ -170,8 +169,7 @@ | ||||
|     "@rollup/plugin-replace": "5.0.5", | ||||
|     "@types/babel__plugin-transform-runtime": "7.9.5", | ||||
|     "@types/chromecast-caf-receiver": "6.0.13", | ||||
|     "@types/chromecast-caf-sender": "1.0.9", | ||||
|     "@types/color-name": "1.1.3", | ||||
|     "@types/chromecast-caf-sender": "1.0.8", | ||||
|     "@types/glob": "8.1.0", | ||||
|     "@types/html-minifier-terser": "7.0.2", | ||||
|     "@types/js-yaml": "4.0.9", | ||||
| @@ -181,52 +179,52 @@ | ||||
|     "@types/mocha": "10.0.6", | ||||
|     "@types/qrcode": "1.5.5", | ||||
|     "@types/serve-handler": "6.1.4", | ||||
|     "@types/sortablejs": "1.15.8", | ||||
|     "@types/sortablejs": "1.15.7", | ||||
|     "@types/tar": "6.1.11", | ||||
|     "@types/ua-parser-js": "0.7.39", | ||||
|     "@types/webspeechapi": "0.0.29", | ||||
|     "@typescript-eslint/eslint-plugin": "7.4.0", | ||||
|     "@typescript-eslint/parser": "7.4.0", | ||||
|     "@typescript-eslint/eslint-plugin": "6.20.0", | ||||
|     "@typescript-eslint/parser": "6.20.0", | ||||
|     "@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.1.0", | ||||
|     "chai": "5.0.3", | ||||
|     "del": "7.1.0", | ||||
|     "eslint": "8.57.0", | ||||
|     "eslint": "8.56.0", | ||||
|     "eslint-config-airbnb-base": "15.0.0", | ||||
|     "eslint-config-airbnb-typescript": "18.0.0", | ||||
|     "eslint-config-airbnb-typescript": "17.1.0", | ||||
|     "eslint-config-prettier": "9.1.0", | ||||
|     "eslint-import-resolver-webpack": "0.13.8", | ||||
|     "eslint-plugin-disable": "2.0.3", | ||||
|     "eslint-plugin-import": "2.29.1", | ||||
|     "eslint-plugin-lit": "1.11.0", | ||||
|     "eslint-plugin-lit-a11y": "4.1.2", | ||||
|     "eslint-plugin-unused-imports": "3.1.0", | ||||
|     "eslint-plugin-unused-imports": "3.0.0", | ||||
|     "eslint-plugin-wc": "2.0.4", | ||||
|     "fancy-log": "2.0.0", | ||||
|     "fs-extra": "11.2.0", | ||||
|     "glob": "10.3.10", | ||||
|     "gulp": "4.0.2", | ||||
|     "gulp-flatmap": "1.0.2", | ||||
|     "gulp-json-transform": "0.5.0", | ||||
|     "gulp-merge-json": "2.2.1", | ||||
|     "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.11", | ||||
|     "husky": "9.0.10", | ||||
|     "instant-mocha": "1.5.2", | ||||
|     "jszip": "3.10.1", | ||||
|     "lint-staged": "15.2.2", | ||||
|     "lint-staged": "15.2.1", | ||||
|     "lit-analyzer": "2.0.3", | ||||
|     "lodash.template": "4.5.0", | ||||
|     "magic-string": "0.30.8", | ||||
|     "magic-string": "0.30.6", | ||||
|     "map-stream": "0.0.7", | ||||
|     "mocha": "10.3.0", | ||||
|     "mocha": "10.2.0", | ||||
|     "object-hash": "3.0.0", | ||||
|     "open": "10.1.0", | ||||
|     "open": "10.0.3", | ||||
|     "pinst": "3.0.0", | ||||
|     "prettier": "3.2.5", | ||||
|     "prettier": "3.2.4", | ||||
|     "rollup": "2.79.1", | ||||
|     "rollup-plugin-string": "3.0.0", | ||||
|     "rollup-plugin-terser": "7.0.2", | ||||
| @@ -235,19 +233,19 @@ | ||||
|     "sinon": "17.0.1", | ||||
|     "source-map-url": "0.4.1", | ||||
|     "systemjs": "6.14.3", | ||||
|     "tar": "6.2.1", | ||||
|     "tar": "6.2.0", | ||||
|     "terser-webpack-plugin": "5.3.10", | ||||
|     "transform-async-modules-webpack-plugin": "1.0.4", | ||||
|     "transform-async-modules-webpack-plugin": "1.0.2", | ||||
|     "ts-lit-plugin": "2.0.2", | ||||
|     "typescript": "5.4.3", | ||||
|     "typescript": "5.3.3", | ||||
|     "vinyl-buffer": "1.0.1", | ||||
|     "vinyl-source-stream": "2.0.0", | ||||
|     "webpack": "5.91.0", | ||||
|     "webpack": "5.90.1", | ||||
|     "webpack-cli": "5.1.4", | ||||
|     "webpack-dev-server": "5.0.4", | ||||
|     "webpack-dev-server": "4.15.1", | ||||
|     "webpack-manifest-plugin": "5.0.0", | ||||
|     "webpack-stats-plugin": "1.1.3", | ||||
|     "webpackbar": "6.0.1", | ||||
|     "webpackbar": "6.0.0", | ||||
|     "workbox-build": "7.0.0" | ||||
|   }, | ||||
|   "_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch", | ||||
| @@ -260,5 +258,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.1.1" | ||||
|   "packageManager": "yarn@4.1.0" | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| Before Width: | Height: | Size: 7.1 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 19 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 8.6 KiB | 
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| Before Width: | Height: | Size: 6.2 KiB | 
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| Before Width: | Height: | Size: 52 KiB | 
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| Before Width: | Height: | Size: 69 KiB | 
| @@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta" | ||||
|  | ||||
| [project] | ||||
| name         = "home-assistant-frontend" | ||||
| version      = "20240402.0" | ||||
| version      = "20240207.0" | ||||
| license      = {text = "Apache-2.0"} | ||||
| description  = "The Home Assistant frontend" | ||||
| readme       = "README.md" | ||||
| authors      = [ | ||||
|     {name = "The Home Assistant Authors", email = "hello@home-assistant.io"} | ||||
| ] | ||||
| requires-python = ">=3.11.0" | ||||
| requires-python = ">=3.10.0" | ||||
|  | ||||
| [project.urls] | ||||
| "Homepage" = "https://github.com/home-assistant/frontend" | ||||
|   | ||||
| @@ -40,7 +40,6 @@ 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 | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| import { theme2hex } from "./convert-color"; | ||||
|  | ||||
| export const COLORS = [ | ||||
|   "#44739e", | ||||
|   "#984ea3", | ||||
| @@ -67,10 +65,10 @@ export function getColorByIndex(index: number) { | ||||
| export function getGraphColorByIndex( | ||||
|   index: number, | ||||
|   style: CSSStyleDeclaration | ||||
| ): string { | ||||
| ) { | ||||
|   // The CSS vars for the colors use range 1..n, so we need to adjust the index from the internal 0..n color index range. | ||||
|   const themeColor = | ||||
|   return ( | ||||
|     style.getPropertyValue(`--graph-color-${index + 1}`) || | ||||
|     getColorByIndex(index); | ||||
|   return theme2hex(themeColor); | ||||
|     getColorByIndex(index) | ||||
|   ); | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import colors from "color-name"; | ||||
| import { expandHex } from "./hex"; | ||||
|  | ||||
| const rgb_hex = (component: number): string => { | ||||
| @@ -127,18 +126,3 @@ export const rgb2hs = (rgb: [number, number, number]): [number, number] => | ||||
|  | ||||
| export const hs2rgb = (hs: [number, number]): [number, number, number] => | ||||
|   hsv2rgb([hs[0], hs[1], 255]); | ||||
|  | ||||
| export function theme2hex(themeColor: string): string { | ||||
|   if (themeColor.startsWith("#")) { | ||||
|     return themeColor; | ||||
|   } | ||||
|  | ||||
|   const rgbFromColorName = colors[themeColor]; | ||||
|   if (!rgbFromColorName) { | ||||
|     // We have a named color, and there's nothing in the table, | ||||
|     // so nothing further we can do with it. | ||||
|     // Compare/border/background color will all be the same. | ||||
|     return themeColor; | ||||
|   } | ||||
|   return rgb2hex(rgbFromColorName); | ||||
| } | ||||
|   | ||||
| @@ -1,25 +1,19 @@ | ||||
| import { PageNavigation } from "../../layouts/hass-tabs-subpage"; | ||||
| import { HomeAssistant } from "../../types"; | ||||
| import { ensureArray } from "../array/ensure-array"; | ||||
| import { isComponentLoaded } from "./is_component_loaded"; | ||||
|  | ||||
| export const canShowPage = (hass: HomeAssistant, page: PageNavigation) => | ||||
|   (isCore(page) || isLoadedIntegration(hass, page)) && | ||||
|   !hideAdvancedPage(hass, page) && | ||||
|   isNotLoadedIntegration(hass, page); | ||||
|   !hideAdvancedPage(hass, page); | ||||
|  | ||||
| const isLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) => | ||||
|   !page.component || | ||||
|   ensureArray(page.component).some((integration) => | ||||
|   page.component | ||||
|     ? isComponentLoaded(hass, page.component) | ||||
|     : page.components | ||||
|       ? page.components.some((integration) => | ||||
|           isComponentLoaded(hass, integration) | ||||
|   ); | ||||
|  | ||||
| const isNotLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) => | ||||
|   !page.not_component || | ||||
|   !ensureArray(page.not_component).some((integration) => | ||||
|     isComponentLoaded(hass, integration) | ||||
|   ); | ||||
|  | ||||
|         ) | ||||
|       : true; | ||||
| const isCore = (page: PageNavigation) => page.core; | ||||
| const isAdvancedPage = (page: PageNavigation) => page.advancedOnly; | ||||
| const userWantsAdvanced = (hass: HomeAssistant) => hass.userData?.showAdvanced; | ||||
|   | ||||
| @@ -231,7 +231,6 @@ export const SENSOR_ENTITIES = [ | ||||
|   "calendar", | ||||
|   "camera", | ||||
|   "device_tracker", | ||||
|   "image", | ||||
|   "weather", | ||||
| ]; | ||||
|  | ||||
|   | ||||
| @@ -37,20 +37,3 @@ export const calcDateProperty = ( | ||||
|   locale.time_zone === TimeZone.server | ||||
|     ? (calcZonedDate(date, config.time_zone, fn, options) as number | boolean) | ||||
|     : fn(date, options); | ||||
|  | ||||
| export const calcDateDifferenceProperty = ( | ||||
|   endDate: Date, | ||||
|   startDate: Date, | ||||
|   fn: (date: Date, options?: any) => boolean | number, | ||||
|   locale: FrontendLocaleData, | ||||
|   config: HassConfig | ||||
| ) => | ||||
|   calcDateProperty( | ||||
|     endDate, | ||||
|     fn, | ||||
|     locale, | ||||
|     config, | ||||
|     locale.time_zone === TimeZone.server | ||||
|       ? utcToZonedTime(startDate, config.time_zone) | ||||
|       : startDate | ||||
|   ); | ||||
|   | ||||
| @@ -1,13 +1,8 @@ | ||||
| import { MAIN_WINDOW_NAME } from "../../data/main_window"; | ||||
|  | ||||
| export const mainWindow = (() => { | ||||
|   try { | ||||
|     return window.name === MAIN_WINDOW_NAME | ||||
| export const mainWindow = | ||||
|   window.name === MAIN_WINDOW_NAME | ||||
|     ? window | ||||
|     : parent.name === MAIN_WINDOW_NAME | ||||
|       ? parent | ||||
|       : top!; | ||||
|   } catch { | ||||
|     return window; | ||||
|   } | ||||
| })(); | ||||
|   | ||||
| @@ -53,7 +53,9 @@ export const computeAttributeValueDisplay = ( | ||||
|  | ||||
|     if (domain === "weather") { | ||||
|       unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute); | ||||
|     } else if (TEMPERATURE_ATTRIBUTES.has(attribute)) { | ||||
|     } | ||||
|  | ||||
|     if (TEMPERATURE_ATTRIBUTES.has(attribute)) { | ||||
|       unit = config.unit_system.temperature; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -20,14 +20,14 @@ function findNestedItem( | ||||
|   }, obj); | ||||
| } | ||||
|  | ||||
| export function nestedArrayMove<A>( | ||||
|   obj: A, | ||||
| export function nestedArrayMove<T>( | ||||
|   obj: T | T[], | ||||
|   oldIndex: number, | ||||
|   newIndex: number, | ||||
|   oldPath?: ItemPath, | ||||
|   newPath?: ItemPath | ||||
| ): A { | ||||
|   const newObj = (Array.isArray(obj) ? [...obj] : { ...obj }) as A; | ||||
| ): T | T[] { | ||||
|   const newObj = Array.isArray(obj) ? [...obj] : { ...obj }; | ||||
|   const from = oldPath ? findNestedItem(newObj, oldPath) : newObj; | ||||
|   const to = newPath ? findNestedItem(newObj, newPath, true) : newObj; | ||||
|  | ||||
|   | ||||
| @@ -5,18 +5,10 @@ import type { | ||||
|   ChartOptions, | ||||
|   TooltipModel, | ||||
| } from "chart.js"; | ||||
| import { | ||||
|   css, | ||||
|   CSSResultGroup, | ||||
|   html, | ||||
|   nothing, | ||||
|   LitElement, | ||||
|   PropertyValues, | ||||
| } from "lit"; | ||||
| import { css, CSSResultGroup, html, 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 { HomeAssistant } from "../../types"; | ||||
| import { debounce } from "../../common/util/debounce"; | ||||
| @@ -35,11 +27,6 @@ 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; | ||||
| @@ -51,8 +38,6 @@ 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[]; | ||||
| @@ -61,8 +46,6 @@ 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; | ||||
| @@ -75,8 +58,6 @@ export class HaChartBase extends LitElement { | ||||
|  | ||||
|   private _paddingYAxisInternal = 0; | ||||
|  | ||||
|   private _datasetOrder: number[] = []; | ||||
|  | ||||
|   public disconnectedCallback() { | ||||
|     super.disconnectedCallback(); | ||||
|     this._releaseCanvas(); | ||||
| @@ -167,29 +148,6 @@ export class HaChartBase extends LitElement { | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // put the legend labels in sorted order if provided | ||||
|     if (changedProps.has("data")) { | ||||
|       this._datasetOrder = this.data.datasets.map((_, index) => index); | ||||
|       if (this.data?.datasets.some((dataset) => dataset.order)) { | ||||
|         this._datasetOrder.sort( | ||||
|           (a, b) => | ||||
|             (this.data.datasets[a].order || 0) - | ||||
|             (this.data.datasets[b].order || 0) | ||||
|         ); | ||||
|       } | ||||
|  | ||||
|       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; | ||||
|     } | ||||
| @@ -199,7 +157,7 @@ export class HaChartBase extends LitElement { | ||||
|       return; | ||||
|     } | ||||
|     if (changedProps.has("data")) { | ||||
|       if (this._hiddenDatasets.size && !this.externalHidden) { | ||||
|       if (this._hiddenDatasets.size) { | ||||
|         this.data.datasets.forEach((dataset, index) => { | ||||
|           dataset.hidden = this._hiddenDatasets.has(index); | ||||
|         }); | ||||
| @@ -217,18 +175,15 @@ export class HaChartBase extends LitElement { | ||||
|       ${this.options?.plugins?.legend?.display === true | ||||
|         ? html`<div class="chartLegend"> | ||||
|             <ul> | ||||
|               ${this._datasetOrder.map((index) => { | ||||
|                 const dataset = this.data.datasets[index]; | ||||
|                 return this.extraData?.[index]?.show_legend === false | ||||
|                   ? nothing | ||||
|                   : html`<li | ||||
|               ${this.data.datasets.map( | ||||
|                 (dataset, index) => | ||||
|                   html`<li | ||||
|                     .datasetIndex=${index} | ||||
|                     @click=${this._legendClick} | ||||
|                     class=${classMap({ | ||||
|                       hidden: this._hiddenDatasets.has(index), | ||||
|                     })} | ||||
|                       .title=${this.extraData?.[index]?.legend_label ?? | ||||
|                       dataset.label} | ||||
|                     .title=${dataset.label} | ||||
|                   > | ||||
|                     <div | ||||
|                       class="bullet" | ||||
| @@ -237,12 +192,9 @@ export class HaChartBase extends LitElement { | ||||
|                         borderColor: dataset.borderColor as string, | ||||
|                       })} | ||||
|                     ></div> | ||||
|                       <div class="label"> | ||||
|                         ${this.extraData?.[index]?.legend_label ?? | ||||
|                         dataset.label} | ||||
|                       </div> | ||||
|                     </li>`; | ||||
|               })} | ||||
|                     <div class="label">${dataset.label}</div> | ||||
|                   </li>` | ||||
|               )} | ||||
|             </ul> | ||||
|           </div>` | ||||
|         : ""} | ||||
| @@ -259,9 +211,9 @@ export class HaChartBase extends LitElement { | ||||
|             height: `${ | ||||
|               this.height ?? this._chartHeight ?? this.clientWidth / 2 | ||||
|             }px`, | ||||
|             "padding-left": `${this._paddingYAxisInternal}px`, | ||||
|             "padding-left": `${this._paddingYAxisInternal}`, | ||||
|             "padding-right": 0, | ||||
|             "padding-inline-start": `${this._paddingYAxisInternal}px`, | ||||
|             "padding-inline-start": `${this._paddingYAxisInternal}`, | ||||
|             "padding-inline-end": 0, | ||||
|           })} | ||||
|         > | ||||
| @@ -387,19 +339,9 @@ 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"); | ||||
| @@ -544,8 +486,4 @@ declare global { | ||||
|   interface HTMLElementTagNameMap { | ||||
|     "ha-chart-base": HaChartBase; | ||||
|   } | ||||
|   interface HASSDomEvents { | ||||
|     "dataset-hidden": { index: number }; | ||||
|     "dataset-unhidden": { index: number }; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -111,7 +111,7 @@ export class StateHistoryChartLine extends LitElement { | ||||
|                 config: this.hass.config, | ||||
|               }, | ||||
|             }, | ||||
|             min: this.startTime, | ||||
|             suggestedMin: this.startTime, | ||||
|             suggestedMax: this.endTime, | ||||
|             ticks: { | ||||
|               maxRotation: 0, | ||||
|   | ||||
| @@ -114,7 +114,7 @@ export class StateHistoryChartTimeline extends LitElement { | ||||
|               config: this.hass.config, | ||||
|             }, | ||||
|           }, | ||||
|           min: this.startTime, | ||||
|           suggestedMin: this.startTime, | ||||
|           suggestedMax: this.endTime, | ||||
|           ticks: { | ||||
|             autoSkip: true, | ||||
|   | ||||
| @@ -233,32 +233,16 @@ export class StateHistoryCharts extends LitElement { | ||||
|           new Date().getTime() - 60 * 60 * this.hoursToShow * 1000 | ||||
|         ); | ||||
|       } else { | ||||
|         let minTimeAll = (this.historyData?.timeline ?? []).reduce( | ||||
|         this._computedStartTime = new Date( | ||||
|           (this.historyData?.timeline ?? []).reduce( | ||||
|             (minTime, stateInfo) => | ||||
|               Math.min( | ||||
|                 minTime, | ||||
|                 new Date(stateInfo.data[0].last_changed).getTime() | ||||
|               ), | ||||
|             new Date().getTime() | ||||
|         ); | ||||
|  | ||||
|         minTimeAll = (this.historyData?.line ?? []).reduce( | ||||
|           (minTimeLine, line) => | ||||
|             Math.min( | ||||
|               minTimeLine, | ||||
|               line.data.reduce( | ||||
|                 (minTimeData, data) => | ||||
|                   Math.min( | ||||
|                     minTimeData, | ||||
|                     new Date(data.states[0].last_changed).getTime() | ||||
|                   ), | ||||
|                 minTimeLine | ||||
|           ) | ||||
|             ), | ||||
|           minTimeAll | ||||
|         ); | ||||
|  | ||||
|         this._computedStartTime = new Date(minTimeAll); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -16,7 +16,6 @@ import { customElement, property, state, query } from "lit/decorators"; | ||||
| import memoizeOne from "memoize-one"; | ||||
| import { getGraphColorByIndex } from "../../common/color/colors"; | ||||
| import { isComponentLoaded } from "../../common/config/is_component_loaded"; | ||||
| import { fireEvent } from "../../common/dom/fire_event"; | ||||
| import { | ||||
|   formatNumber, | ||||
|   numberFormatToLocale, | ||||
| @@ -26,7 +25,6 @@ import { | ||||
|   getDisplayUnit, | ||||
|   getStatisticLabel, | ||||
|   getStatisticMetadata, | ||||
|   isExternalStatistic, | ||||
|   Statistics, | ||||
|   statisticsHaveType, | ||||
|   StatisticsMetaData, | ||||
| @@ -34,11 +32,7 @@ import { | ||||
| } from "../../data/recorder"; | ||||
| import type { HomeAssistant } from "../../types"; | ||||
| import "./ha-chart-base"; | ||||
| import type { | ||||
|   ChartResizeOptions, | ||||
|   ChartDatasetExtra, | ||||
|   HaChartBase, | ||||
| } from "./ha-chart-base"; | ||||
| import type { ChartResizeOptions, HaChartBase } from "./ha-chart-base"; | ||||
|  | ||||
| export const supportedStatTypeMap: Record<StatisticType, StatisticType> = { | ||||
|   mean: "mean", | ||||
| @@ -81,20 +75,14 @@ export class StatisticsChart extends LitElement { | ||||
|  | ||||
|   @property({ type: Boolean }) public isLoadingData = false; | ||||
|  | ||||
|   @property({ type: Boolean }) public clickForMoreInfo = true; | ||||
|  | ||||
|   @property() public period?: string; | ||||
|  | ||||
|   @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; | ||||
| @@ -108,9 +96,6 @@ export class StatisticsChart extends LitElement { | ||||
|   } | ||||
|  | ||||
|   public willUpdate(changedProps: PropertyValues) { | ||||
|     if (changedProps.has("legendMode")) { | ||||
|       this._hiddenStats.clear(); | ||||
|     } | ||||
|     if ( | ||||
|       !this.hasUpdated || | ||||
|       changedProps.has("unit") || | ||||
| @@ -125,8 +110,7 @@ export class StatisticsChart extends LitElement { | ||||
|       changedProps.has("statisticsData") || | ||||
|       changedProps.has("statTypes") || | ||||
|       changedProps.has("chartType") || | ||||
|       changedProps.has("hideLegend") || | ||||
|       changedProps.has("_hiddenStats") | ||||
|       changedProps.has("hideLegend") | ||||
|     ) { | ||||
|       this._generateData(); | ||||
|     } | ||||
| @@ -161,30 +145,14 @@ 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, | ||||
| @@ -277,33 +245,6 @@ export class StatisticsChart extends LitElement { | ||||
|       }, | ||||
|       // @ts-expect-error | ||||
|       locale: numberFormatToLocale(this.hass.locale), | ||||
|       onClick: (e: any) => { | ||||
|         if ( | ||||
|           !this.clickForMoreInfo || | ||||
|           !(e.native instanceof MouseEvent) || | ||||
|           (e.native instanceof PointerEvent && e.native.pointerType !== "mouse") | ||||
|         ) { | ||||
|           return; | ||||
|         } | ||||
|  | ||||
|         const chart = e.chart; | ||||
|  | ||||
|         const points = chart.getElementsAtEventForMode( | ||||
|           e, | ||||
|           "nearest", | ||||
|           { intersect: true }, | ||||
|           true | ||||
|         ); | ||||
|  | ||||
|         if (points.length) { | ||||
|           const firstPoint = points[0]; | ||||
|           const statisticId = this._statisticIds[firstPoint.datasetIndex]; | ||||
|           if (!isExternalStatistic(statisticId)) { | ||||
|             fireEvent(this, "hass-more-info", { entityId: statisticId }); | ||||
|             chart.canvas.dispatchEvent(new Event("mouseout")); // to hide tooltip | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|     }; | ||||
|   } | ||||
|  | ||||
| @@ -333,7 +274,6 @@ 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; | ||||
|  | ||||
| @@ -384,7 +324,6 @@ export class StatisticsChart extends LitElement { | ||||
|  | ||||
|       // The datasets for the current statistic | ||||
|       const statDataSets: ChartDataset<"line">[] = []; | ||||
|       const statDatasetExtras: ChartDatasetExtra[] = []; | ||||
|  | ||||
|       const pushData = ( | ||||
|         start: Date, | ||||
| @@ -445,20 +384,9 @@ 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 | ||||
| @@ -480,9 +408,6 @@ 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, | ||||
| @@ -521,7 +446,6 @@ export class StatisticsChart extends LitElement { | ||||
|  | ||||
|       // Concat two arrays | ||||
|       Array.prototype.push.apply(totalDataSets, statDataSets); | ||||
|       Array.prototype.push.apply(totalDatasetExtras, statDatasetExtras); | ||||
|     }); | ||||
|  | ||||
|     if (unit) { | ||||
| @@ -531,7 +455,6 @@ export class StatisticsChart extends LitElement { | ||||
|     this._chartData = { | ||||
|       datasets: totalDataSets, | ||||
|     }; | ||||
|     this._chartDatasetExtra = totalDatasetExtras; | ||||
|     this._statisticIds = statisticIds; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -205,9 +205,7 @@ export class TimelineController extends BarController { | ||||
|  | ||||
|       const y = vScale.getPixelForValue(this.index); | ||||
|  | ||||
|       const xStart = iScale.getPixelForValue( | ||||
|         Math.max(iScale.min, data.start.getTime()) | ||||
|       ); | ||||
|       const xStart = iScale.getPixelForValue(data.start.getTime()); | ||||
|       const xEnd = iScale.getPixelForValue(data.end.getTime()); | ||||
|       const width = xEnd - xStart; | ||||
|  | ||||
|   | ||||
| @@ -49,7 +49,7 @@ export class TimeLineScale extends TimeScale { | ||||
|     max = isFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit); | ||||
|  | ||||
|     // Make sure that max is strictly higher than min (required by the lookup table) | ||||
|     this.min = adapter.parse(options.min, this) ?? Math.min(min, max - 1); | ||||
|     this.max = adapter.parse(options.max, this) ?? Math.max(min + 1, max); | ||||
|     this.min = Math.min(min, max - 1); | ||||
|     this.max = Math.max(min + 1, max); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,24 +4,22 @@ import { css, html } from "lit"; | ||||
| import { customElement, property } from "lit/decorators"; | ||||
|  | ||||
| @customElement("ha-assist-chip") | ||||
| // @ts-ignore | ||||
| export class HaAssistChip extends MdAssistChip { | ||||
|   @property({ type: Boolean, reflect: true }) filled = false; | ||||
|  | ||||
|   @property({ type: Boolean }) active = false; | ||||
|  | ||||
|   static override styles = [ | ||||
|     ...super.styles, | ||||
|     css` | ||||
|       :host { | ||||
|         --md-sys-color-primary: var(--primary-text-color); | ||||
|         --md-sys-color-on-surface: var(--primary-text-color); | ||||
|         --md-assist-chip-container-shape: var( | ||||
|           --ha-assist-chip-container-shape, | ||||
|           16px | ||||
|         ); | ||||
|         --md-assist-chip-container-shape: 16px; | ||||
|         --md-assist-chip-outline-color: var(--outline-color); | ||||
|         --md-assist-chip-label-text-weight: 400; | ||||
|         --ha-assist-chip-filled-container-color: rgba( | ||||
|           var(--rgb-primary-text-color), | ||||
|           0.15 | ||||
|         ); | ||||
|       } | ||||
|       /** Material 3 doesn't have a filled chip, so we have to make our own **/ | ||||
|       .filled { | ||||
| @@ -33,28 +31,10 @@ export class HaAssistChip extends MdAssistChip { | ||||
|         background-color: var(--ha-assist-chip-filled-container-color); | ||||
|       } | ||||
|       /** Set the size of mdc icons **/ | ||||
|       ::slotted([slot="icon"]), | ||||
|       ::slotted([slot="trailingIcon"]) { | ||||
|       ::slotted([slot="icon"]) { | ||||
|         display: flex; | ||||
|         --mdc-icon-size: var(--md-input-chip-icon-size, 18px); | ||||
|       } | ||||
|  | ||||
|       .trailing.icon ::slotted(*), | ||||
|       .trailing.icon svg { | ||||
|         margin-inline-end: unset; | ||||
|         margin-inline-start: var(--_icon-label-space); | ||||
|       } | ||||
|       ::before { | ||||
|         background: var(--ha-assist-chip-container-color); | ||||
|         opacity: var(--ha-assist-chip-container-opacity); | ||||
|       } | ||||
|       :where(.active)::before { | ||||
|         background: var(--ha-assist-chip-active-container-color); | ||||
|         opacity: var(--ha-assist-chip-active-container-opacity); | ||||
|       } | ||||
|       .label { | ||||
|         font-family: Roboto, sans-serif; | ||||
|       } | ||||
|     `, | ||||
|   ]; | ||||
|  | ||||
| @@ -65,30 +45,6 @@ export class HaAssistChip extends MdAssistChip { | ||||
|  | ||||
|     return super.renderOutline(); | ||||
|   } | ||||
|  | ||||
|   protected override getContainerClasses() { | ||||
|     return { | ||||
|       ...super.getContainerClasses(), | ||||
|       active: this.active, | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   protected override renderPrimaryContent() { | ||||
|     return html` | ||||
|       <span class="leading icon" aria-hidden="true"> | ||||
|         ${this.renderLeadingIcon()} | ||||
|       </span> | ||||
|       <span class="label">${this.label}</span> | ||||
|       <span class="touch"></span> | ||||
|       <span class="trailing leading icon" aria-hidden="true"> | ||||
|         ${this.renderTrailingIcon()} | ||||
|       </span> | ||||
|     `; | ||||
|   } | ||||
|  | ||||
|   protected renderTrailingIcon() { | ||||
|     return html`<slot name="trailing-icon"></slot>`; | ||||
|   } | ||||
| } | ||||
|  | ||||
| declare global { | ||||
|   | ||||
| @@ -19,16 +19,12 @@ export class HaInputChip extends MdInputChip { | ||||
|           var(--rgb-primary-text-color), | ||||
|           0.15 | ||||
|         ); | ||||
|         --ha-input-chip-selected-container-opacity: 1; | ||||
|       } | ||||
|       /** Set the size of mdc icons **/ | ||||
|       ::slotted([slot="icon"]) { | ||||
|         display: flex; | ||||
|         --mdc-icon-size: var(--md-input-chip-icon-size, 18px); | ||||
|       } | ||||
|       .selected::before { | ||||
|         opacity: var(--ha-input-chip-selected-container-opacity); | ||||
|       } | ||||
|     `, | ||||
|   ]; | ||||
| } | ||||
|   | ||||
| @@ -44,8 +44,6 @@ class HaDataTableIcon extends LitElement { | ||||
|       div { | ||||
|         position: absolute; | ||||
|         right: 28px; | ||||
|         inset-inline-end: 28px; | ||||
|         inset-inline-start: initial; | ||||
|         z-index: 1002; | ||||
|         outline: none; | ||||
|         font-size: 10px; | ||||
|   | ||||
| @@ -1,130 +0,0 @@ | ||||
| import { css, html, LitElement, nothing, TemplateResult } from "lit"; | ||||
| import { customElement, property } from "lit/decorators"; | ||||
| import { repeat } from "lit/directives/repeat"; | ||||
| import { LabelRegistryEntry } from "../../data/label_registry"; | ||||
| import { computeCssColor } from "../../common/color/compute-color"; | ||||
| import { fireEvent } from "../../common/dom/fire_event"; | ||||
| import "../ha-label"; | ||||
| import { stringCompare } from "../../common/string/compare"; | ||||
|  | ||||
| @customElement("ha-data-table-labels") | ||||
| class HaDataTableLabels extends LitElement { | ||||
|   @property({ attribute: false }) public labels!: LabelRegistryEntry[]; | ||||
|  | ||||
|   protected render(): TemplateResult { | ||||
|     const labels = this.labels.sort((a, b) => stringCompare(a.name, b.name)); | ||||
|     return html` | ||||
|       <ha-chip-set> | ||||
|         ${repeat( | ||||
|           labels.slice(0, 2), | ||||
|           (label) => label.label_id, | ||||
|           (label) => this._renderLabel(label, true) | ||||
|         )} | ||||
|         ${labels.length > 2 | ||||
|           ? html`<ha-button-menu | ||||
|               absolute | ||||
|               role="button" | ||||
|               tabindex="0" | ||||
|               @click=${this._handleIconOverflowMenuOpened} | ||||
|               @closed=${this._handleIconOverflowMenuClosed} | ||||
|             > | ||||
|               <ha-label slot="trigger" class="plus" dense> | ||||
|                 +${labels.length - 2} | ||||
|               </ha-label> | ||||
|               ${repeat( | ||||
|                 labels.slice(2), | ||||
|                 (label) => label.label_id, | ||||
|                 (label) => html` | ||||
|                   <ha-list-item @click=${this._labelClicked} .item=${label}> | ||||
|                     ${this._renderLabel(label, false)} | ||||
|                   </ha-list-item> | ||||
|                 ` | ||||
|               )} | ||||
|             </ha-button-menu>` | ||||
|           : nothing} | ||||
|       </ha-chip-set> | ||||
|     `; | ||||
|   } | ||||
|  | ||||
|   private _renderLabel(label: LabelRegistryEntry, clickAction: boolean) { | ||||
|     const color = label?.color ? computeCssColor(label.color) : undefined; | ||||
|     return html` | ||||
|       <ha-label | ||||
|         dense | ||||
|         role="button" | ||||
|         tabindex="0" | ||||
|         .item=${label} | ||||
|         @click=${clickAction ? this._labelClicked : undefined} | ||||
|         @keydown=${clickAction ? this._labelClicked : undefined} | ||||
|         style=${color ? `--color: ${color}` : ""} | ||||
|       > | ||||
|         ${label?.icon | ||||
|           ? html`<ha-icon slot="icon" .icon=${label.icon}></ha-icon>` | ||||
|           : nothing} | ||||
|         ${label.name} | ||||
|       </ha-label> | ||||
|     `; | ||||
|   } | ||||
|  | ||||
|   private _labelClicked(ev) { | ||||
|     ev.stopPropagation(); | ||||
|     if (ev.type === "keydown" && ev.key !== "Enter" && ev.key !== " ") { | ||||
|       return; | ||||
|     } | ||||
|     const label = (ev.currentTarget as any).item as LabelRegistryEntry; | ||||
|     fireEvent(this, "label-clicked", { label }); | ||||
|   } | ||||
|  | ||||
|   protected _handleIconOverflowMenuOpened(e) { | ||||
|     e.stopPropagation(); | ||||
|     // If this component is used inside a data table, the z-index of the row | ||||
|     // needs to be increased. Otherwise the ha-button-menu would be displayed | ||||
|     // underneath the next row in the table. | ||||
|     const row = this.closest(".mdc-data-table__row") as HTMLDivElement | null; | ||||
|     if (row) { | ||||
|       row.style.zIndex = "1"; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   protected _handleIconOverflowMenuClosed() { | ||||
|     const row = this.closest(".mdc-data-table__row") as HTMLDivElement | null; | ||||
|     if (row) { | ||||
|       row.style.zIndex = ""; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static get styles() { | ||||
|     return css` | ||||
|       :host { | ||||
|         display: block; | ||||
|         flex-grow: 1; | ||||
|         margin-top: 4px; | ||||
|         height: 22px; | ||||
|       } | ||||
|       ha-chip-set { | ||||
|         position: fixed; | ||||
|         flex-wrap: nowrap; | ||||
|       } | ||||
|       ha-label { | ||||
|         --ha-label-background-color: var(--color, var(--grey-color)); | ||||
|         --ha-label-background-opacity: 0.5; | ||||
|       } | ||||
|       ha-button-menu { | ||||
|         border-radius: 10px; | ||||
|       } | ||||
|       .plus { | ||||
|         --ha-label-background-color: transparent; | ||||
|         border: 1px solid var(--divider-color); | ||||
|       } | ||||
|     `; | ||||
|   } | ||||
| } | ||||
|  | ||||
| declare global { | ||||
|   interface HTMLElementTagNameMap { | ||||
|     "ha-data-table-labels": HaDataTableLabels; | ||||
|   } | ||||
|   interface HASSDomEvents { | ||||
|     "label-clicked": { label: LabelRegistryEntry }; | ||||
|   } | ||||
| } | ||||
| @@ -32,7 +32,6 @@ import type { HaCheckbox } from "../ha-checkbox"; | ||||
| import "../ha-svg-icon"; | ||||
| import "../search-input"; | ||||
| import { filterData, sortData } from "./sort-filter"; | ||||
| import { groupBy } from "../../common/util/group-by"; | ||||
|  | ||||
| declare global { | ||||
|   // for fire event | ||||
| @@ -68,20 +67,13 @@ export interface DataTableSortColumnData { | ||||
|   filterKey?: string; | ||||
|   valueColumn?: string; | ||||
|   direction?: SortingDirection; | ||||
|   groupable?: boolean; | ||||
| } | ||||
|  | ||||
| export interface DataTableColumnData<T = any> extends DataTableSortColumnData { | ||||
|   main?: boolean; | ||||
|   title: TemplateResult | string; | ||||
|   label?: TemplateResult | string; | ||||
|   type?: | ||||
|     | "numeric" | ||||
|     | "icon" | ||||
|     | "icon-button" | ||||
|     | "overflow" | ||||
|     | "overflow-menu" | ||||
|     | "flex"; | ||||
|   type?: "numeric" | "icon" | "icon-button" | "overflow-menu" | "flex"; | ||||
|   template?: (row: T) => TemplateResult | string | typeof nothing; | ||||
|   width?: string; | ||||
|   maxWidth?: string; | ||||
| @@ -103,8 +95,6 @@ export interface SortableColumnContainer { | ||||
|   [key: string]: ClonedDataTableColumnData; | ||||
| } | ||||
|  | ||||
| const UNDEFINED_GROUP_KEY = "zzzzz_undefined"; | ||||
|  | ||||
| @customElement("ha-data-table") | ||||
| export class HaDataTable extends LitElement { | ||||
|   @property({ attribute: false }) public hass!: HomeAssistant; | ||||
| @@ -139,16 +129,14 @@ export class HaDataTable extends LitElement { | ||||
|  | ||||
|   @property({ type: String }) public filter = ""; | ||||
|  | ||||
|   @property() public groupColumn?: string; | ||||
|  | ||||
|   @property() public sortColumn?: string; | ||||
|  | ||||
|   @property() public sortDirection: SortingDirection = null; | ||||
|  | ||||
|   @state() private _filterable = false; | ||||
|  | ||||
|   @state() private _filter = ""; | ||||
|  | ||||
|   @state() private _sortColumn?: string; | ||||
|  | ||||
|   @state() private _sortDirection: SortingDirection = null; | ||||
|  | ||||
|   @state() private _filteredData: DataTableRowData[] = []; | ||||
|  | ||||
|   @state() private _headerHeight = 0; | ||||
| @@ -181,13 +169,6 @@ export class HaDataTable extends LitElement { | ||||
|     this._checkedRowsChanged(); | ||||
|   } | ||||
|  | ||||
|   public selectAll(): void { | ||||
|     this._checkedRows = this._filteredData | ||||
|       .filter((data) => data.selectable !== false) | ||||
|       .map((data) => data[this.id]); | ||||
|     this._checkedRowsChanged(); | ||||
|   } | ||||
|  | ||||
|   public connectedCallback() { | ||||
|     super.connectedCallback(); | ||||
|     if (this._items.length) { | ||||
| @@ -214,14 +195,8 @@ export class HaDataTable extends LitElement { | ||||
|  | ||||
|       for (const columnId in this.columns) { | ||||
|         if (this.columns[columnId].direction) { | ||||
|           this.sortDirection = this.columns[columnId].direction!; | ||||
|           this.sortColumn = columnId; | ||||
|  | ||||
|           fireEvent(this, "sorting-changed", { | ||||
|             column: columnId, | ||||
|             direction: this.sortDirection, | ||||
|           }); | ||||
|  | ||||
|           this._sortDirection = this.columns[columnId].direction!; | ||||
|           this._sortColumn = columnId; | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
| @@ -251,16 +226,11 @@ export class HaDataTable extends LitElement { | ||||
|       properties.has("data") || | ||||
|       properties.has("columns") || | ||||
|       properties.has("_filter") || | ||||
|       properties.has("sortColumn") || | ||||
|       properties.has("sortDirection") || | ||||
|       properties.has("groupColumn") | ||||
|       properties.has("_sortColumn") || | ||||
|       properties.has("_sortDirection") | ||||
|     ) { | ||||
|       this._sortFilterData(); | ||||
|     } | ||||
|  | ||||
|     if (properties.has("selectable")) { | ||||
|       this._items = [...this._items]; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   protected render() { | ||||
| @@ -293,7 +263,6 @@ export class HaDataTable extends LitElement { | ||||
|           })} | ||||
|         > | ||||
|           <div class="mdc-data-table__header-row" role="row" aria-rowindex="1"> | ||||
|             <slot name="header-row"> | ||||
|             ${this.selectable | ||||
|               ? html` | ||||
|                   <div | ||||
| @@ -316,7 +285,7 @@ export class HaDataTable extends LitElement { | ||||
|               if (column.hidden) { | ||||
|                 return ""; | ||||
|               } | ||||
|                 const sorted = key === this.sortColumn; | ||||
|               const sorted = key === this._sortColumn; | ||||
|               const classes = { | ||||
|                 "mdc-data-table__header-cell--numeric": | ||||
|                   column.type === "numeric", | ||||
| @@ -325,8 +294,6 @@ export class HaDataTable extends LitElement { | ||||
|                   column.type === "icon-button", | ||||
|                 "mdc-data-table__header-cell--overflow-menu": | ||||
|                   column.type === "overflow-menu", | ||||
|                   "mdc-data-table__header-cell--overflow": | ||||
|                     column.type === "overflow", | ||||
|                 sortable: Boolean(column.sortable), | ||||
|                 "not-sorted": Boolean(column.sortable && !sorted), | ||||
|                 grows: Boolean(column.grows), | ||||
| @@ -344,7 +311,7 @@ export class HaDataTable extends LitElement { | ||||
|                   role="columnheader" | ||||
|                   aria-sort=${ifDefined( | ||||
|                     sorted | ||||
|                         ? this.sortDirection === "desc" | ||||
|                       ? this._sortDirection === "desc" | ||||
|                         ? "descending" | ||||
|                         : "ascending" | ||||
|                       : undefined | ||||
| @@ -355,7 +322,7 @@ export class HaDataTable extends LitElement { | ||||
|                   ${column.sortable | ||||
|                     ? html` | ||||
|                         <ha-svg-icon | ||||
|                             .path=${sorted && this.sortDirection === "desc" | ||||
|                           .path=${sorted && this._sortDirection === "desc" | ||||
|                             ? mdiArrowDown | ||||
|                             : mdiArrowUp} | ||||
|                         ></ha-svg-icon> | ||||
| @@ -365,7 +332,6 @@ export class HaDataTable extends LitElement { | ||||
|                 </div> | ||||
|               `; | ||||
|             })} | ||||
|             </slot> | ||||
|           </div> | ||||
|           ${!this._filteredData.length | ||||
|             ? html` | ||||
| @@ -393,7 +359,7 @@ export class HaDataTable extends LitElement { | ||||
|     `; | ||||
|   } | ||||
|  | ||||
|   private _keyFunction = (row: DataTableRowData) => row?.[this.id] || row; | ||||
|   private _keyFunction = (row: DataTableRowData) => row[this.id] || row; | ||||
|  | ||||
|   private _renderRow = (row: DataTableRowData, index: number) => { | ||||
|     // not sure how this happens... | ||||
| @@ -442,7 +408,7 @@ export class HaDataTable extends LitElement { | ||||
|           : ""} | ||||
|         ${Object.entries(this.columns).map(([key, column]) => { | ||||
|           if (column.hidden) { | ||||
|             return nothing; | ||||
|             return ""; | ||||
|           } | ||||
|           return html` | ||||
|             <div | ||||
| @@ -455,7 +421,6 @@ export class HaDataTable extends LitElement { | ||||
|                   column.type === "icon-button", | ||||
|                 "mdc-data-table__cell--overflow-menu": | ||||
|                   column.type === "overflow-menu", | ||||
|                 "mdc-data-table__cell--overflow": column.type === "overflow", | ||||
|                 grows: Boolean(column.grows), | ||||
|                 forceLTR: Boolean(column.forceLTR), | ||||
|               })}" | ||||
| @@ -488,12 +453,12 @@ export class HaDataTable extends LitElement { | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     const prom = this.sortColumn | ||||
|     const prom = this._sortColumn | ||||
|       ? sortData( | ||||
|           filteredData, | ||||
|           this._sortColumns[this.sortColumn], | ||||
|           this.sortDirection, | ||||
|           this.sortColumn, | ||||
|           this._sortColumns[this._sortColumn], | ||||
|           this._sortDirection, | ||||
|           this._sortColumn, | ||||
|           this.hass.locale.language | ||||
|         ) | ||||
|       : filteredData; | ||||
| @@ -512,56 +477,17 @@ export class HaDataTable extends LitElement { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (this.appendRow || this.hasFab || this.groupColumn) { | ||||
|     if (this.appendRow || this.hasFab) { | ||||
|       const items = [...data]; | ||||
|  | ||||
|       if (this.appendRow) { | ||||
|         items.push({ append: true, content: this.appendRow }); | ||||
|       } | ||||
|  | ||||
|       if (this.groupColumn) { | ||||
|         const grouped = groupBy(items, (item) => item[this.groupColumn!]); | ||||
|         if (grouped.undefined) { | ||||
|           // make sure ungrouped items are at the bottom | ||||
|           grouped[UNDEFINED_GROUP_KEY] = grouped.undefined; | ||||
|           delete grouped.undefined; | ||||
|         } | ||||
|         const sorted: { | ||||
|           [key: string]: DataTableRowData[]; | ||||
|         } = Object.keys(grouped) | ||||
|           .sort() | ||||
|           .reduce((obj, key) => { | ||||
|             obj[key] = grouped[key]; | ||||
|             return obj; | ||||
|           }, {}); | ||||
|         const groupedItems: DataTableRowData[] = []; | ||||
|         Object.entries(sorted).forEach(([groupName, rows]) => { | ||||
|           if ( | ||||
|             groupName !== UNDEFINED_GROUP_KEY || | ||||
|             Object.keys(sorted).length > 1 | ||||
|           ) { | ||||
|             groupedItems.push({ | ||||
|               append: true, | ||||
|               content: html`<div | ||||
|                 class="mdc-data-table__cell group-header" | ||||
|                 role="cell" | ||||
|               > | ||||
|                 ${groupName === UNDEFINED_GROUP_KEY ? "" : groupName || ""} | ||||
|               </div>`, | ||||
|             }); | ||||
|           } | ||||
|  | ||||
|           groupedItems.push(...rows); | ||||
|         }); | ||||
|  | ||||
|         this._items = groupedItems; | ||||
|       } else { | ||||
|         this._items = items; | ||||
|       } | ||||
|  | ||||
|       if (this.hasFab) { | ||||
|         this._items = [...this._items, { empty: true }]; | ||||
|         items.push({ empty: true }); | ||||
|       } | ||||
|       this._items = items; | ||||
|     } else { | ||||
|       this._items = data; | ||||
|     } | ||||
| @@ -581,26 +507,29 @@ export class HaDataTable extends LitElement { | ||||
|     if (!this.columns[columnId].sortable) { | ||||
|       return; | ||||
|     } | ||||
|     if (!this.sortDirection || this.sortColumn !== columnId) { | ||||
|       this.sortDirection = "asc"; | ||||
|     } else if (this.sortDirection === "asc") { | ||||
|       this.sortDirection = "desc"; | ||||
|     if (!this._sortDirection || this._sortColumn !== columnId) { | ||||
|       this._sortDirection = "asc"; | ||||
|     } else if (this._sortDirection === "asc") { | ||||
|       this._sortDirection = "desc"; | ||||
|     } else { | ||||
|       this.sortDirection = null; | ||||
|       this._sortDirection = null; | ||||
|     } | ||||
|  | ||||
|     this.sortColumn = this.sortDirection === null ? undefined : columnId; | ||||
|     this._sortColumn = this._sortDirection === null ? undefined : columnId; | ||||
|  | ||||
|     fireEvent(this, "sorting-changed", { | ||||
|       column: columnId, | ||||
|       direction: this.sortDirection, | ||||
|       direction: this._sortDirection, | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   private _handleHeaderRowCheckboxClick(ev: Event) { | ||||
|     const checkbox = ev.target as HaCheckbox; | ||||
|     if (checkbox.checked) { | ||||
|       this.selectAll(); | ||||
|       this._checkedRows = this._filteredData | ||||
|         .filter((data) => data.selectable !== false) | ||||
|         .map((data) => data[this.id]); | ||||
|       this._checkedRowsChanged(); | ||||
|     } else { | ||||
|       this._checkedRows = []; | ||||
|       this._checkedRowsChanged(); | ||||
| @@ -623,19 +552,8 @@ export class HaDataTable extends LitElement { | ||||
|   }; | ||||
|  | ||||
|   private _handleRowClick = (ev: Event) => { | ||||
|     if ( | ||||
|       ev | ||||
|         .composedPath() | ||||
|         .find((el) => | ||||
|           [ | ||||
|             "ha-checkbox", | ||||
|             "mwc-button", | ||||
|             "ha-button", | ||||
|             "ha-icon-button", | ||||
|             "ha-assist-chip", | ||||
|           ].includes((el as HTMLElement).localName) | ||||
|         ) | ||||
|     ) { | ||||
|     const target = ev.target as HTMLElement; | ||||
|     if (["HA-CHECKBOX", "MWC-BUTTON"].includes(target.tagName)) { | ||||
|       return; | ||||
|     } | ||||
|     const rowId = (ev.currentTarget as any).rowId; | ||||
| @@ -711,7 +629,7 @@ export class HaDataTable extends LitElement { | ||||
|         .mdc-data-table__row { | ||||
|           display: flex; | ||||
|           width: 100%; | ||||
|           height: var(--data-table-row-height, 52px); | ||||
|           height: 52px; | ||||
|         } | ||||
|  | ||||
|         .mdc-data-table__row ~ .mdc-data-table__row { | ||||
| @@ -737,6 +655,7 @@ export class HaDataTable extends LitElement { | ||||
|           display: flex; | ||||
|           width: 100%; | ||||
|           border-bottom: 1px solid var(--divider-color); | ||||
|           overflow-x: auto; | ||||
|         } | ||||
|  | ||||
|         .mdc-data-table__header-row::-webkit-scrollbar { | ||||
| @@ -890,9 +809,7 @@ export class HaDataTable extends LitElement { | ||||
|           padding-inline-start: initial; | ||||
|         } | ||||
|         .mdc-data-table__cell--overflow-menu, | ||||
|         .mdc-data-table__cell--overflow, | ||||
|         .mdc-data-table__header-cell--overflow-menu, | ||||
|         .mdc-data-table__header-cell--overflow { | ||||
|         .mdc-data-table__header-cell--overflow-menu { | ||||
|           overflow: initial; | ||||
|         } | ||||
|         .mdc-data-table__cell--icon-button a { | ||||
| @@ -922,12 +839,6 @@ export class HaDataTable extends LitElement { | ||||
|  | ||||
|         /* custom from here */ | ||||
|  | ||||
|         .group-header { | ||||
|           padding-top: 12px; | ||||
|           width: 100%; | ||||
|           font-weight: 500; | ||||
|         } | ||||
|  | ||||
|         :host { | ||||
|           display: block; | ||||
|         } | ||||
|   | ||||
| @@ -32,9 +32,7 @@ export class StateBadge extends LitElement { | ||||
|  | ||||
|   @property() public overrideImage?: string; | ||||
|  | ||||
|   // Cannot be a boolean attribute because undefined is treated different than | ||||
|   // false.  When it is undefined, state is still colored for light entities. | ||||
|   @property({ attribute: false }) public stateColor?: boolean; | ||||
|   @property({ type: Boolean }) public stateColor = false; | ||||
|  | ||||
|   @property() public color?: string; | ||||
|  | ||||
| @@ -72,7 +70,7 @@ export class StateBadge extends LitElement { | ||||
|     const domain = this.stateObj | ||||
|       ? computeStateDomain(this.stateObj) | ||||
|       : undefined; | ||||
|     return this.stateColor ?? domain === "light"; | ||||
|     return this.stateColor || (domain === "light" && this.stateColor !== false); | ||||
|   } | ||||
|  | ||||
|   protected render() { | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user