mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
20221213.0 (#14757)
This commit is contained in:
commit
d8b4611c24
2
.github/workflows/demo_deployment.yaml
vendored
2
.github/workflows/demo_deployment.yaml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: Demo
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL }}
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@v3
|
||||
|
2
.github/workflows/design_deployment.yaml
vendored
2
.github/workflows/design_deployment.yaml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: Design
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL }}
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@v3
|
||||
|
54
.github/workflows/design_preview.yaml
vendored
Normal file
54
.github/workflows/design_preview.yaml
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
name: Design preview
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- labeled
|
||||
branches:
|
||||
- dev
|
||||
|
||||
env:
|
||||
NODE_VERSION: 16
|
||||
NODE_OPTIONS: --max_old_space_size=6144
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
runs-on: ubuntu-latest
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
# Skip running PRs without 'needs design preview' label
|
||||
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@v3
|
||||
|
||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: yarn
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Build Gallery
|
||||
run: ./node_modules/.bin/gulp build-gallery
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Deploy preview to Netlify
|
||||
id: deploy
|
||||
uses: netlify/actions/cli@master
|
||||
with:
|
||||
args: deploy --dir=gallery/dist --alias "deploy-preview-${{ github.event.number }}"
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}
|
||||
|
||||
- name: Generate summary
|
||||
run: |
|
||||
echo "${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}" >> "$GITHUB_STEP_SUMMARY"
|
@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
TARGET_LABEL="needs design preview"
|
||||
export SKIP_FETCH_NIGHTLY_TRANSLATIONS="true"
|
||||
|
||||
if [[ "$NETLIFY" != "true" ]]; then
|
||||
echo "This script can only be run on Netlify"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function createStatus() {
|
||||
state="$1"
|
||||
description="$2"
|
||||
target_url="$3"
|
||||
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/home-assistant/frontend/statuses/$COMMIT_REF" \
|
||||
-d '{"state": "'"${state}"'", "context": "Netlify/Design Preview Build", "description": "'"$description"'", "target_url": "'"$target_url"'"}'
|
||||
}
|
||||
|
||||
|
||||
if [[ "${PULL_REQUEST}" == "true" ]]; then
|
||||
if [[ "$(curl -sSLf -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/home-assistant/frontend/pulls/${REVIEW_ID}" | jq '.labels[].name' -r)" =~ "$TARGET_LABEL" ]]; then
|
||||
createStatus "pending" "Building design preview" "https://app.netlify.com/sites/home-assistant-gallery/deploys/$BUILD_ID"
|
||||
gulp build-gallery
|
||||
if [ $? -eq 0 ]; then
|
||||
createStatus "success" "Build complete" "$DEPLOY_PRIME_URL"
|
||||
else
|
||||
createStatus "error" "Build failed" "https://app.netlify.com/sites/home-assistant-gallery/deploys/$BUILD_ID"
|
||||
fi
|
||||
else
|
||||
createStatus "success" "Build was not requested by PR label"
|
||||
fi
|
||||
fi
|
@ -130,6 +130,17 @@ const ENTITIES: HassEntity[] = [
|
||||
createEntity("climate.auto", "auto"),
|
||||
createEntity("climate.dry", "dry"),
|
||||
createEntity("climate.fan_only", "fan_only"),
|
||||
createEntity("climate.auto_idle", "auto", undefined, { hvac_action: "idle" }),
|
||||
createEntity("climate.auto_off", "auto", undefined, { hvac_action: "off" }),
|
||||
createEntity("climate.auto_heating", "auto", undefined, {
|
||||
hvac_action: "heating",
|
||||
}),
|
||||
createEntity("climate.auto_cooling", "auto", undefined, {
|
||||
hvac_action: "cooling",
|
||||
}),
|
||||
createEntity("climate.auto_dry", "auto", undefined, {
|
||||
hvac_action: "drying",
|
||||
}),
|
||||
// Cover
|
||||
createEntity("cover.closing", "closing"),
|
||||
createEntity("cover.closed", "closed"),
|
||||
|
@ -193,12 +193,11 @@
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-config-airbnb-typescript": "^14.0.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-webpack": "^0.13.1",
|
||||
"eslint-plugin-disable": "^2.0.1",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-lit": "^1.6.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-unused-imports": "^1.1.5",
|
||||
"eslint-plugin-wc": "^1.3.2",
|
||||
"fancy-log": "^1.3.3",
|
||||
@ -224,7 +223,7 @@
|
||||
"object-hash": "^2.0.3",
|
||||
"open": "^7.0.4",
|
||||
"pinst": "^3.0.0",
|
||||
"prettier": "^2.4.1",
|
||||
"prettier": "^2.8.1",
|
||||
"require-dir": "^1.2.0",
|
||||
"rollup": "^2.8.2",
|
||||
"rollup-plugin-string": "^3.0.0",
|
||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20221212.0"
|
||||
version = "20221213.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "The Home Assistant frontend"
|
||||
readme = "README.md"
|
||||
|
@ -1,7 +1,7 @@
|
||||
export const batteryStateColor = (state: string) => {
|
||||
const value = Number(state);
|
||||
if (isNaN(value)) {
|
||||
return "sensor-battery-unknown";
|
||||
return undefined;
|
||||
}
|
||||
if (value >= 70) {
|
||||
return "sensor-battery-high";
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { stateActive } from "../state_active";
|
||||
|
||||
const ALERTING_DEVICE_CLASSES = new Set([
|
||||
"battery",
|
||||
@ -12,9 +13,15 @@ const ALERTING_DEVICE_CLASSES = new Set([
|
||||
"tamper",
|
||||
]);
|
||||
|
||||
export const binarySensorColor = (stateObj: HassEntity): string | undefined => {
|
||||
export const binarySensorColor = (
|
||||
stateObj: HassEntity,
|
||||
state: string
|
||||
): string | undefined => {
|
||||
const deviceClass = stateObj?.attributes.device_class;
|
||||
|
||||
if (!stateActive(stateObj, state)) {
|
||||
return undefined;
|
||||
}
|
||||
return deviceClass && ALERTING_DEVICE_CLASSES.has(deviceClass)
|
||||
? "binary-sensor-alerting"
|
||||
: "binary-sensor";
|
||||
|
@ -1,3 +1,13 @@
|
||||
import { HvacAction } from "../../../data/climate";
|
||||
|
||||
export const CLIMATE_HVAC_ACTION_COLORS: Record<HvacAction, string> = {
|
||||
cooling: "var(--rgb-state-climate-cool-color)",
|
||||
drying: "var(--rgb-state-climate-dry-color)",
|
||||
heating: "var(--rgb-state-climate-heat-color)",
|
||||
idle: "var(--rgb-state-climate-idle-color)",
|
||||
off: "var(--rgb-state-climate-off-color)",
|
||||
};
|
||||
|
||||
export const climateColor = (state: string): string | undefined => {
|
||||
switch (state) {
|
||||
case "auto":
|
||||
|
15
src/common/entity/color/update_color.ts
Normal file
15
src/common/entity/color/update_color.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UpdateEntity, updateIsInstalling } from "../../../data/update";
|
||||
import { stateActive } from "../state_active";
|
||||
|
||||
export const updateColor = (
|
||||
stateObj: HassEntity,
|
||||
state: string
|
||||
): string | undefined => {
|
||||
if (!stateActive(stateObj, state)) {
|
||||
return undefined;
|
||||
}
|
||||
return updateIsInstalling(stateObj as UpdateEntity)
|
||||
? "update-installing"
|
||||
: "update";
|
||||
};
|
@ -180,6 +180,9 @@ export const domainIconWithoutDefault = (
|
||||
}
|
||||
}
|
||||
|
||||
case "person":
|
||||
return compareState === "not_home" ? mdiAccountArrowRight : mdiAccount;
|
||||
|
||||
case "switch":
|
||||
switch (stateObj?.attributes.device_class) {
|
||||
case "outlet":
|
||||
|
@ -1,13 +1,13 @@
|
||||
/** Return an color representing a state. */
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { UNAVAILABLE } from "../../data/entity";
|
||||
import { UpdateEntity, updateIsInstalling } from "../../data/update";
|
||||
import { alarmControlPanelColor } from "./color/alarm_control_panel_color";
|
||||
import { binarySensorColor } from "./color/binary_sensor_color";
|
||||
import { climateColor } from "./color/climate_color";
|
||||
import { lockColor } from "./color/lock_color";
|
||||
import { personColor } from "./color/person_color";
|
||||
import { sensorColor } from "./color/sensor_color";
|
||||
import { updateColor } from "./color/update_color";
|
||||
import { computeDomain } from "./compute_domain";
|
||||
import { stateActive } from "./state_active";
|
||||
|
||||
@ -66,7 +66,7 @@ export const stateColor = (stateObj: HassEntity, state?: string) => {
|
||||
return alarmControlPanelColor(compareState);
|
||||
|
||||
case "binary_sensor":
|
||||
return binarySensorColor(stateObj);
|
||||
return binarySensorColor(stateObj, compareState);
|
||||
|
||||
case "climate":
|
||||
return climateColor(compareState);
|
||||
@ -85,9 +85,7 @@ export const stateColor = (stateObj: HassEntity, state?: string) => {
|
||||
return compareState === "above_horizon" ? "sun-day" : "sun-night";
|
||||
|
||||
case "update":
|
||||
return updateIsInstalling(stateObj as UpdateEntity)
|
||||
? "update-installing"
|
||||
: "update";
|
||||
return updateColor(stateObj, compareState);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
@ -627,7 +627,9 @@ export class HaDataTable extends LitElement {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
|
||||
.mdc-data-table__row.clickable:not(.mdc-data-table__row--selected):hover {
|
||||
.mdc-data-table__row.clickable:not(
|
||||
.mdc-data-table__row--selected
|
||||
):hover {
|
||||
background-color: rgba(var(--rgb-primary-text-color), 0.04);
|
||||
}
|
||||
|
||||
@ -734,13 +736,17 @@ export class HaDataTable extends LitElement {
|
||||
}
|
||||
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:hover,
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(.not-sorted) {
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(
|
||||
.not-sorted
|
||||
) {
|
||||
text-align: left;
|
||||
}
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:hover,
|
||||
:host([dir="rtl"])
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(.not-sorted) {
|
||||
.mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(
|
||||
.not-sorted
|
||||
) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
import { property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { CLIMATE_HVAC_ACTION_COLORS } from "../../common/entity/color/climate_color";
|
||||
import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||
import { stateActive } from "../../common/entity/state_active";
|
||||
@ -34,7 +35,7 @@ export class StateBadge extends LitElement {
|
||||
@property({ type: Boolean, reflect: true, attribute: "icon" })
|
||||
private _showIcon = true;
|
||||
|
||||
@state() private _iconStyle: { [name: string]: string } = {};
|
||||
@state() private _iconStyle: { [name: string]: string | undefined } = {};
|
||||
|
||||
private get _stateColor() {
|
||||
const domain = this.stateObj
|
||||
@ -127,6 +128,14 @@ export class StateBadge extends LitElement {
|
||||
// lowest brightness will be around 50% (that's pretty dark)
|
||||
iconStyle.filter = `brightness(${(brightness + 245) / 5}%)`;
|
||||
}
|
||||
if (stateObj.attributes.hvac_action) {
|
||||
const hvacAction = stateObj.attributes.hvac_action;
|
||||
if (["heating", "cooling", "drying"].includes(hvacAction)) {
|
||||
iconStyle.color = `rgb(${CLIMATE_HVAC_ACTION_COLORS[hvacAction]})`;
|
||||
} else {
|
||||
delete iconStyle.color;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this.overrideImage) {
|
||||
let imageUrl = this.overrideImage;
|
||||
|
@ -25,6 +25,7 @@ import { SYMBOL_TO_ISO } from "../../../data/currency";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import "../../../components/ha-alert";
|
||||
|
||||
@customElement("ha-config-section-general")
|
||||
class HaConfigSectionGeneral extends LitElement {
|
||||
@ -52,6 +53,8 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
|
||||
@state() private _languages?: { value: string; label: string }[];
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const canEdit = ["storage", "default"].includes(
|
||||
this.hass.config.config_source
|
||||
@ -65,6 +68,9 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
.header=${this.hass.localize("ui.panel.config.core.caption")}
|
||||
>
|
||||
<div class="content">
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
${!canEdit
|
||||
@ -289,7 +295,7 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
this._country = this.hass.config.country;
|
||||
this._language = this.hass.config.language;
|
||||
this._elevation = this.hass.config.elevation;
|
||||
this._timeZone = this.hass.config.time_zone;
|
||||
this._timeZone = this.hass.config.time_zone || "Etc/GMT";
|
||||
this._name = this.hass.config.location_name;
|
||||
this._computeLanguages();
|
||||
}
|
||||
@ -347,6 +353,8 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
this._error = undefined;
|
||||
|
||||
try {
|
||||
await saveCoreConfig(this.hass, {
|
||||
currency: this._currency,
|
||||
@ -361,7 +369,7 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
button.actionSuccess();
|
||||
} catch (err: any) {
|
||||
button.actionError();
|
||||
alert(`Error saving config: ${err.message}`);
|
||||
this._error = err.message;
|
||||
} finally {
|
||||
button.progress = false;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { CLIMATE_HVAC_ACTION_COLORS } from "../../../common/entity/color/climate_color";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
@ -192,8 +193,10 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||
.icon=${this._config.icon}
|
||||
.state=${stateObj}
|
||||
style=${styleMap({
|
||||
color: colored ? this._computeColor(stateObj) : "",
|
||||
filter: colored ? this._computeBrightness(stateObj) : "",
|
||||
color: colored ? this._computeColor(stateObj) : undefined,
|
||||
filter: colored
|
||||
? this._computeBrightness(stateObj)
|
||||
: undefined,
|
||||
height: this._config.icon_height
|
||||
? this._config.icon_height
|
||||
: "",
|
||||
@ -309,19 +312,24 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
private _computeBrightness(stateObj: HassEntity | LightEntity): string {
|
||||
if (!stateObj.attributes.brightness && stateActive(stateObj)) {
|
||||
if (stateObj.attributes.brightness) {
|
||||
const brightness = stateObj.attributes.brightness;
|
||||
return `brightness(${(brightness + 245) / 5}%)`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private _computeColor(
|
||||
stateObj: HassEntity | LightEntity
|
||||
): string | undefined {
|
||||
if (stateObj.attributes.rgb_color && stateActive(stateObj)) {
|
||||
private _computeColor(stateObj: HassEntity): string | undefined {
|
||||
if (stateObj.attributes.rgb_color) {
|
||||
return `rgb(${stateObj.attributes.rgb_color.join(",")})`;
|
||||
}
|
||||
if (stateObj.attributes.hvac_action) {
|
||||
const hvacAction = stateObj.attributes.hvac_action;
|
||||
if (["heating", "cooling", "drying"].includes(hvacAction)) {
|
||||
return `rgb(${CLIMATE_HVAC_ACTION_COLORS[hvacAction]})`;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
const iconColor = stateColorCss(stateObj);
|
||||
if (iconColor) {
|
||||
return `rgb(${iconColor})`;
|
||||
|
@ -12,6 +12,7 @@ import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { CLIMATE_HVAC_ACTION_COLORS } from "../../../common/entity/color/climate_color";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
@ -149,6 +150,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
data-state=${stateObj.state}
|
||||
style=${styleMap({
|
||||
color: colored ? this._computeColor(stateObj) : undefined,
|
||||
filter: colored ? this._computeBrightness(stateObj) : undefined,
|
||||
height: this._config.icon_height
|
||||
? this._config.icon_height
|
||||
: "",
|
||||
@ -193,9 +195,17 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
`;
|
||||
}
|
||||
|
||||
private _computeColor(
|
||||
stateObj: HassEntity | LightEntity
|
||||
): string | undefined {
|
||||
private _computeColor(stateObj: HassEntity): string | undefined {
|
||||
if (stateObj.attributes.hvac_action) {
|
||||
const hvacAction = stateObj.attributes.hvac_action;
|
||||
if (["heating", "cooling", "drying"].includes(hvacAction)) {
|
||||
return `rgb(${CLIMATE_HVAC_ACTION_COLORS[hvacAction]})`;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
if (stateObj.attributes.rgb_color && stateActive(stateObj)) {
|
||||
return `rgb(${stateObj.attributes.rgb_color.join(",")})`;
|
||||
}
|
||||
const iconColor = stateColorCss(stateObj);
|
||||
if (iconColor) {
|
||||
return `rgb(${iconColor})`;
|
||||
@ -203,6 +213,14 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _computeBrightness(stateObj: HassEntity | LightEntity): string {
|
||||
if (stateObj.attributes.brightness && stateActive(stateObj)) {
|
||||
const brightness = stateObj.attributes.brightness;
|
||||
return `brightness(${(brightness + 245) / 5}%)`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||
// Side Effect used to update footer hass while keeping optimizations
|
||||
if (this._footerElement) {
|
||||
|
@ -9,6 +9,7 @@ import { hsv2rgb, rgb2hsv } from "../../../common/color/convert-color";
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { stateActive } from "../../../common/entity/state_active";
|
||||
import { stateColorCss } from "../../../common/entity/state_color";
|
||||
import { stateIconPath } from "../../../common/entity/state_icon_path";
|
||||
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||
@ -128,9 +129,9 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
private _computeStateColor = memoize((entity: HassEntity, color?: string) => {
|
||||
// Use custom color
|
||||
// Use custom color if active
|
||||
if (color) {
|
||||
return computeRgbColor(color);
|
||||
return stateActive(entity) ? computeRgbColor(color) : undefined;
|
||||
}
|
||||
|
||||
// Use default color for person/device_tracker because color is on the badge
|
||||
@ -363,7 +364,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
:host {
|
||||
--tile-color: var(--rgb-state-default-color);
|
||||
--tile-color: var(--rgb-state-inactive-color);
|
||||
--tile-tap-padding: 6px;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
@ -5,17 +5,10 @@ import {
|
||||
mdiSnowflake,
|
||||
mdiWaterPercent,
|
||||
} from "@mdi/js";
|
||||
import { CLIMATE_HVAC_ACTION_COLORS } from "../../../../../common/entity/color/climate_color";
|
||||
import { ClimateEntity, HvacAction } from "../../../../../data/climate";
|
||||
import { ComputeBadgeFunction } from "./tile-badge";
|
||||
|
||||
export const CLIMATE_HVAC_ACTION_COLORS: Record<HvacAction, string> = {
|
||||
cooling: "var(--rgb-state-climate-cool-color)",
|
||||
drying: "var(--rgb-state-climate-dry-color)",
|
||||
heating: "var(--rgb-state-climate-heat-color)",
|
||||
idle: "var(--rgb-state-climate-idle-color)",
|
||||
off: "var(--rgb-state-climate-off-color)",
|
||||
};
|
||||
|
||||
export const CLIMATE_HVAC_ACTION_ICONS: Record<HvacAction, string> = {
|
||||
cooling: mdiSnowflake,
|
||||
drying: mdiWaterPercent,
|
||||
|
@ -304,19 +304,13 @@ export const generateViewConfig = (
|
||||
path: string,
|
||||
title: string | undefined,
|
||||
icon: string | undefined,
|
||||
entities: HassEntities,
|
||||
groupOrders: { [entityId: string]: number }
|
||||
entities: HassEntities
|
||||
): LovelaceViewConfig => {
|
||||
const splitted = splitByGroups(entities);
|
||||
splitted.groups.sort(
|
||||
(gr1, gr2) => groupOrders[gr1.entity_id] - groupOrders[gr2.entity_id]
|
||||
);
|
||||
|
||||
const ungroupedEntitites: { [domain: string]: string[] } = {};
|
||||
|
||||
// Organize ungrouped entities in ungrouped things
|
||||
for (const entityId of Object.keys(splitted.ungrouped)) {
|
||||
const state = splitted.ungrouped[entityId];
|
||||
for (const entityId of Object.keys(entities)) {
|
||||
const state = entities[entityId];
|
||||
const domain = computeStateDomain(state);
|
||||
|
||||
if (!(domain in ungroupedEntitites)) {
|
||||
@ -384,15 +378,6 @@ export const generateViewConfig = (
|
||||
delete ungroupedEntitites.person;
|
||||
}
|
||||
|
||||
for (const groupEntity of splitted.groups) {
|
||||
cards.push(
|
||||
...computeCards(entities, groupEntity.attributes.entity_id, {
|
||||
title: computeStateName(groupEntity),
|
||||
show_header_toggle: groupEntity.attributes.control !== "hidden",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Group helper entities in a single card
|
||||
const helperEntities: string[] = [];
|
||||
|
||||
@ -480,13 +465,28 @@ export const generateDefaultViewConfig = (
|
||||
states
|
||||
);
|
||||
|
||||
const splittedByGroups = splitByGroups(splittedByAreaDevice.otherEntities);
|
||||
splittedByGroups.groups.sort(
|
||||
(gr1, gr2) => groupOrders[gr1.entity_id] - groupOrders[gr2.entity_id]
|
||||
);
|
||||
|
||||
const groupCards: LovelaceCardConfig[] = [];
|
||||
|
||||
for (const groupEntity of splittedByGroups.groups) {
|
||||
groupCards.push(
|
||||
...computeCards(entities, groupEntity.attributes.entity_id, {
|
||||
title: computeStateName(groupEntity),
|
||||
show_header_toggle: groupEntity.attributes.control !== "hidden",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const config = generateViewConfig(
|
||||
localize,
|
||||
path,
|
||||
title,
|
||||
icon,
|
||||
splittedByAreaDevice.otherEntities,
|
||||
groupOrders
|
||||
splittedByGroups.ungrouped
|
||||
);
|
||||
|
||||
const areaCards: LovelaceCardConfig[] = [];
|
||||
@ -568,9 +568,11 @@ export const generateDefaultViewConfig = (
|
||||
|
||||
config.cards!.unshift(
|
||||
...areaCards,
|
||||
...(energyCard ? [energyCard] : []),
|
||||
...deviceCards
|
||||
...groupCards,
|
||||
...(energyCard ? [energyCard] : [])
|
||||
);
|
||||
|
||||
config.cards!.push(...deviceCards);
|
||||
|
||||
return config;
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import "../../../components/ha-select";
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
@ -76,15 +77,14 @@ class HuiSelectEntityRow extends LitElement implements LovelaceRow {
|
||||
? stateObj.attributes.options.map(
|
||||
(option) =>
|
||||
html`
|
||||
<mwc-list-item .value=${option}
|
||||
>${(stateObj.attributes.device_class &&
|
||||
this.hass!.localize(
|
||||
`component.select.state.${stateObj.attributes.device_class}.${option}`
|
||||
)) ||
|
||||
this.hass!.localize(
|
||||
`component.select.state._.${option}`
|
||||
) ||
|
||||
option}
|
||||
<mwc-list-item .value=${option}>
|
||||
${computeStateDisplay(
|
||||
this.hass!.localize,
|
||||
stateObj,
|
||||
this.hass!.locale,
|
||||
this.hass!.entities,
|
||||
option
|
||||
)}
|
||||
</mwc-list-item>
|
||||
`
|
||||
)
|
||||
|
@ -156,7 +156,7 @@ documentContainer.innerHTML = `<custom-style>
|
||||
--rgb-state-climate-fan-only-color: var(--rgb-cyan-color);
|
||||
--rgb-state-climate-heat-color: var(--rgb-deep-orange-color);
|
||||
--rgb-state-climate-heat-cool-color: var(--rgb-amber-color);
|
||||
--rgb-state-climate-idle-color: var(--rgb-off-color);
|
||||
--rgb-state-climate-idle-color: var(--rgb-grey-color);
|
||||
--rgb-state-cover-color: var(--rgb-purple-color);
|
||||
--rgb-state-fan-color: var(--rgb-cyan-color);
|
||||
--rgb-state-group-color: var(--rgb-amber-color);
|
||||
@ -176,7 +176,6 @@ documentContainer.innerHTML = `<custom-style>
|
||||
--rgb-state-sensor-battery-high-color: var(--rgb-green-color);
|
||||
--rgb-state-sensor-battery-low-color: var(--rgb-red-color);
|
||||
--rgb-state-sensor-battery-medium-color: var(--rgb-orange-color);
|
||||
--rgb-state-sensor-battery-unknown-color: var(--rgb-off-color);
|
||||
--rgb-state-siren-color: var(--rgb-red-color);
|
||||
--rgb-state-sun-day-color: var(--rgb-amber-color);
|
||||
--rgb-state-sun-night-color: var(--rgb-deep-purple-color);
|
||||
|
@ -8,6 +8,7 @@ import "../components/entity/state-badge";
|
||||
import { UNAVAILABLE } from "../data/entity";
|
||||
import { SelectEntity, setSelectOption } from "../data/select";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||
|
||||
@customElement("state-card-select")
|
||||
class StateCardSelect extends LitElement {
|
||||
@ -31,12 +32,13 @@ class StateCardSelect extends LitElement {
|
||||
(option) =>
|
||||
html`
|
||||
<mwc-list-item .value=${option}>
|
||||
${(this.stateObj.attributes.device_class &&
|
||||
this.hass.localize(
|
||||
`component.select.state.${this.stateObj.attributes.device_class}.${option}`
|
||||
)) ||
|
||||
this.hass.localize(`component.select.state._.${option}`) ||
|
||||
option}
|
||||
${computeStateDisplay(
|
||||
this.hass.localize,
|
||||
this.stateObj,
|
||||
this.hass.locale,
|
||||
this.hass.entities,
|
||||
option
|
||||
)}
|
||||
</mwc-list-item>
|
||||
`
|
||||
)}
|
||||
|
52
yarn.lock
52
yarn.lock
@ -7662,14 +7662,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-config-prettier@npm:^8.3.0":
|
||||
version: 8.3.0
|
||||
resolution: "eslint-config-prettier@npm:8.3.0"
|
||||
"eslint-config-prettier@npm:^8.5.0":
|
||||
version: 8.5.0
|
||||
resolution: "eslint-config-prettier@npm:8.5.0"
|
||||
peerDependencies:
|
||||
eslint: ">=7.0.0"
|
||||
bin:
|
||||
eslint-config-prettier: bin/cli.js
|
||||
checksum: df4cea3032671995bb5ab07e016169072f7fa59f44a53251664d9ca60951b66cdc872683b5c6a3729c91497c11490ca44a79654b395dd6756beb0c3903a37196
|
||||
checksum: 0d0f5c32e7a0ad91249467ce71ca92394ccd343178277d318baf32063b79ea90216f4c81d1065d60f96366fdc60f151d4d68ae7811a58bd37228b84c2083f893
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -7765,21 +7765,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-prettier@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "eslint-plugin-prettier@npm:4.0.0"
|
||||
dependencies:
|
||||
prettier-linter-helpers: ^1.0.0
|
||||
peerDependencies:
|
||||
eslint: ">=7.28.0"
|
||||
prettier: ">=2.0.0"
|
||||
peerDependenciesMeta:
|
||||
eslint-config-prettier:
|
||||
optional: true
|
||||
checksum: 03d69177a3c21fa2229c7e427ce604429f0b20ab7f411e2e824912f572a207c7f5a41fd1f0a95b9b8afe121e291c1b1f1dc1d44c7aad4b0837487f9c19f5210d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-unused-imports@npm:^1.1.5":
|
||||
version: 1.1.5
|
||||
resolution: "eslint-plugin-unused-imports@npm:1.1.5"
|
||||
@ -8228,13 +8213,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fast-diff@npm:^1.1.2":
|
||||
version: 1.2.0
|
||||
resolution: "fast-diff@npm:1.2.0"
|
||||
checksum: 1b5306eaa9e826564d9e5ffcd6ebd881eb5f770b3f977fcbf38f05c824e42172b53c79920e8429c54eb742ce15a0caf268b0fdd5b38f6de52234c4a8368131ae
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fast-glob@npm:^2.2.6":
|
||||
version: 2.2.7
|
||||
resolution: "fast-glob@npm:2.2.7"
|
||||
@ -9401,12 +9379,11 @@ fsevents@^1.2.7:
|
||||
eslint: ^7.32.0
|
||||
eslint-config-airbnb-base: ^14.2.1
|
||||
eslint-config-airbnb-typescript: ^14.0.0
|
||||
eslint-config-prettier: ^8.3.0
|
||||
eslint-config-prettier: ^8.5.0
|
||||
eslint-import-resolver-webpack: ^0.13.1
|
||||
eslint-plugin-disable: ^2.0.1
|
||||
eslint-plugin-import: ^2.24.2
|
||||
eslint-plugin-lit: ^1.6.1
|
||||
eslint-plugin-prettier: ^4.0.0
|
||||
eslint-plugin-unused-imports: ^1.1.5
|
||||
eslint-plugin-wc: ^1.3.2
|
||||
fancy-log: ^1.3.3
|
||||
@ -9446,7 +9423,7 @@ fsevents@^1.2.7:
|
||||
object-hash: ^2.0.3
|
||||
open: ^7.0.4
|
||||
pinst: ^3.0.0
|
||||
prettier: ^2.4.1
|
||||
prettier: ^2.8.1
|
||||
proxy-polyfill: ^0.3.2
|
||||
punycode: ^2.1.1
|
||||
qr-scanner: ^1.3.0
|
||||
@ -13047,21 +13024,12 @@ fsevents@^1.2.7:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prettier-linter-helpers@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "prettier-linter-helpers@npm:1.0.0"
|
||||
dependencies:
|
||||
fast-diff: ^1.1.2
|
||||
checksum: 00ce8011cf6430158d27f9c92cfea0a7699405633f7f1d4a45f07e21bf78e99895911cbcdc3853db3a824201a7c745bd49bfea8abd5fb9883e765a90f74f8392
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prettier@npm:^2.4.1":
|
||||
version: 2.4.1
|
||||
resolution: "prettier@npm:2.4.1"
|
||||
"prettier@npm:^2.8.1":
|
||||
version: 2.8.1
|
||||
resolution: "prettier@npm:2.8.1"
|
||||
bin:
|
||||
prettier: bin-prettier.js
|
||||
checksum: cc6830588b401b0d742862fe9c46bc9118204fb307c3abe0e49e95b35ed23629573807ffdf9cdd65289c252a0bb51fc0171437f6626ee36378dea80f0ee80b91
|
||||
checksum: 4f21a0f1269f76fb36f54e9a8a1ea4c11e27478958bf860661fb4b6d7ac69aac1581f8724fa98ea3585e56d42a2ea317a17ff6e3324f40cb11ff9e20b73785cc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user