Compare commits

..

28 Commits

Author SHA1 Message Date
Paul Bottein
0b065799bf Add column option to grid section config
Add column density option to the grid section

Fix translations

Rename to grid density

Limit card size with the grid size

Rename function

Fix types
2024-10-14 19:40:42 +02:00
Wendelin
ca94267c44 Fix tooltip firefox bug in persistent-notification-item (#22363) 2024-10-14 15:47:12 +02:00
renovate[bot]
df1f26cee7 Update dependency magic-string to v0.30.12 (#22362)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 12:00:18 +02:00
renovate[bot]
24a4e075e6 Update babel monorepo to v7.25.8 (#22355)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 11:48:23 +02:00
dependabot[bot]
43fcc6238e Bump actions/upload-artifact from 4.4.0 to 4.4.3 (#22359)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-14 09:29:29 +02:00
dependabot[bot]
b40b96248b Bump actions/cache from 4.1.0 to 4.1.1 (#22358)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-14 09:17:16 +02:00
dependabot[bot]
c7ac4c7490 Bump actions/checkout from 4.2.0 to 4.2.1 (#22360)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-14 09:17:03 +02:00
Abdulrasheed Abdulsalam
6cd8471b91 Fix: correct some typos in translation file (#22353) 2024-10-13 10:11:27 +00:00
Marc Mueller
940eaa26e0 Update build-system (#22348) 2024-10-13 07:41:03 +02:00
renovate[bot]
79e68ce125 Update dependency typescript to v5.6.3 (#22340)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 11:13:22 +02:00
renovate[bot]
e581d35432 Update formatjs monorepo (#22342)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-12 09:14:19 +02:00
Paul Bottein
d3d578e0f4 Hide fields section when all fields inside are filtered (#22277)
Hide field section when all fields inside are filtered
2024-10-11 21:52:44 +02:00
karwosts
79c71cbe48 Add sensor offset to time trigger UI (#21957)
* Add sensor offset to time trigger UI

* refactor long expression

* memoize data

* fix for trigger platform migration
2024-10-11 21:36:44 +02:00
karwosts
82b50a1c5d Refine automation action search with ignoreLocation (#22332) 2024-10-11 21:34:43 +02:00
karwosts
6cfda78aa1 Fix a case where developer-tools/action can get stuck in an error loop (#22334) 2024-10-11 20:37:49 +02:00
renovate[bot]
f9ff938775 Update dependency @formatjs/intl-datetimeformat to v6.12.6 (#22335)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-11 20:24:26 +02:00
Bram Kragten
778fcab90d Fix entity id setting on newly created scripts, handle update of enti… (#22272)
Fix entity id setting on newly created scripts, handle update of entity id
2024-10-11 13:13:17 +02:00
Wendelin
07e5aa30c6 Add hide completed option to hui-todo-list-card (#22323) 2024-10-11 08:58:40 +02:00
Paul Bottein
3f0ec03a14 Improve zigbee remove device dialog (#22276)
* Improve zigbee remove device dialog

* Fix translations
2024-10-11 06:40:15 +02:00
Alex Jurkiewicz
1bb871b9ac fix(script/bootstrap): Improve missing Yarn error (#22308) 2024-10-10 18:27:22 +03:00
Paul Bottein
0e8783fb01 Use default font for heading card (#22322) 2024-10-10 15:19:14 +00:00
Bram Kragten
1d88c4465b Bumped version to 20241010.0 2024-10-10 17:14:04 +02:00
Wendelin
af2d575bf0 Fix ha-selector-action drag and drop (#22273)
* Fix ha-selector-action with removing memoize-one

* Fix array-move to update parent reference.

* Fix array-move if item is no array
2024-10-10 16:53:35 +02:00
Stefan Agner
92165d776a Fix command selection for OTBRs without dataset (#22318)
Typically, the Home Assistant OTBR integration makes sure that we
either setup or read the current dataset. However, in some cases,
e.g. when reinstalling the add-on, deleting the dataset, and starting
the add-on while keeping the OTBR config entry, the dataset is not
available and a new one is not being created (since the config entry
is not recreated).

Just support this particular case as well.

Fixes: #22306
2024-10-10 16:50:44 +02:00
renovate[bot]
a8bbd8ab90 Update dependency @codemirror/commands to v6.7.0 (#22316)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-10 10:21:29 +00:00
renovate[bot]
43ac9dbea7 Update vaadinWebComponents monorepo to v24.4.11 (#22315)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-10 10:20:33 +00:00
renovate[bot]
bba9eca4e9 Update dependency eslint-plugin-wc to v2.2.0 (#22310)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-10 10:04:10 +02:00
renovate[bot]
40f65b1980 Update dependency del to v8 (#22311)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-10 10:03:29 +02:00
39 changed files with 719 additions and 757 deletions

View File

@@ -21,7 +21,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
with:
ref: dev
@@ -57,7 +57,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
with:
ref: master

View File

@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
- name: Setup Node
uses: actions/setup-node@v4.0.4
with:
@@ -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.1.0
uses: actions/cache@v4.1.1
with:
path: |
node_modules/.cache/prettier
@@ -58,7 +58,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
- name: Setup Node
uses: actions/setup-node@v4.0.4
with:
@@ -76,7 +76,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
- name: Setup Node
uses: actions/setup-node@v4.0.4
with:
@@ -89,7 +89,7 @@ jobs:
env:
IS_TEST: "true"
- name: Upload bundle stats
uses: actions/upload-artifact@v4.4.0
uses: actions/upload-artifact@v4.4.3
with:
name: frontend-bundle-stats
path: build/stats/*.json
@@ -100,7 +100,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
- name: Setup Node
uses: actions/setup-node@v4.0.4
with:
@@ -113,7 +113,7 @@ jobs:
env:
IS_TEST: "true"
- name: Upload bundle stats
uses: actions/upload-artifact@v4.4.0
uses: actions/upload-artifact@v4.4.3
with:
name: supervisor-bundle-stats
path: build/stats/*.json

View File

@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.

View File

@@ -22,7 +22,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
with:
ref: dev
@@ -58,7 +58,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
with:
ref: master

View File

@@ -16,7 +16,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
- name: Setup Node
uses: actions/setup-node@v4.0.4

View File

@@ -21,7 +21,7 @@ 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.2.0
uses: actions/checkout@v4.2.1
- name: Setup Node
uses: actions/setup-node@v4.0.4

View File

@@ -20,7 +20,7 @@ jobs:
contents: write
steps:
- name: Checkout the repository
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
@@ -57,14 +57,14 @@ jobs:
run: tar -czvf translations.tar.gz translations
- name: Upload build artifacts
uses: actions/upload-artifact@v4.4.0
uses: actions/upload-artifact@v4.4.3
with:
name: wheels
path: dist/home_assistant_frontend*.whl
if-no-files-found: error
- name: Upload translations
uses: actions/upload-artifact@v4.4.0
uses: actions/upload-artifact@v4.4.3
with:
name: translations
path: translations.tar.gz

View File

@@ -23,7 +23,7 @@ jobs:
contents: write # Required to upload release assets
steps:
- name: Checkout the repository
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
- name: Verify version
uses: home-assistant/actions/helpers/verify-version@master

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4.2.0
uses: actions/checkout@v4.2.1
- name: Upload Translations
run: |

View File

@@ -28,21 +28,21 @@
"@babel/runtime": "7.25.7",
"@braintree/sanitize-url": "7.1.0",
"@codemirror/autocomplete": "6.18.1",
"@codemirror/commands": "6.6.2",
"@codemirror/commands": "6.7.0",
"@codemirror/language": "6.10.3",
"@codemirror/legacy-modes": "6.4.1",
"@codemirror/search": "6.5.6",
"@codemirror/state": "6.4.1",
"@codemirror/view": "6.34.1",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.12.5",
"@formatjs/intl-displaynames": "6.6.8",
"@formatjs/intl-datetimeformat": "6.13.0",
"@formatjs/intl-displaynames": "6.6.9",
"@formatjs/intl-getcanonicallocales": "2.3.0",
"@formatjs/intl-listformat": "7.5.7",
"@formatjs/intl-locale": "4.0.0",
"@formatjs/intl-numberformat": "8.10.3",
"@formatjs/intl-pluralrules": "5.2.14",
"@formatjs/intl-relativetimeformat": "11.2.14",
"@formatjs/intl-listformat": "7.5.8",
"@formatjs/intl-locale": "4.0.1",
"@formatjs/intl-numberformat": "8.11.0",
"@formatjs/intl-pluralrules": "5.2.15",
"@formatjs/intl-relativetimeformat": "11.2.15",
"@fullcalendar/core": "6.1.15",
"@fullcalendar/daygrid": "6.1.15",
"@fullcalendar/interaction": "6.1.15",
@@ -89,8 +89,8 @@
"@polymer/polymer": "3.5.1",
"@replit/codemirror-indentation-markers": "6.5.3",
"@thomasloven/round-slider": "0.6.0",
"@vaadin/combo-box": "24.4.10",
"@vaadin/vaadin-themable-mixin": "24.4.10",
"@vaadin/combo-box": "24.4.11",
"@vaadin/vaadin-themable-mixin": "24.4.11",
"@vibrant/color": "3.2.1-alpha.1",
"@vibrant/core": "3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
@@ -114,7 +114,7 @@
"hls.js": "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch",
"home-assistant-js-websocket": "9.4.0",
"idb-keyval": "6.2.1",
"intl-messageformat": "10.5.14",
"intl-messageformat": "10.6.0",
"js-yaml": "4.1.0",
"leaflet": "1.9.4",
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
@@ -151,11 +151,11 @@
"xss": "1.0.15"
},
"devDependencies": {
"@babel/core": "7.25.7",
"@babel/core": "7.25.8",
"@babel/helper-define-polyfill-provider": "0.6.2",
"@babel/plugin-proposal-decorators": "7.25.7",
"@babel/plugin-transform-runtime": "7.25.7",
"@babel/preset-env": "7.25.7",
"@babel/preset-env": "7.25.8",
"@babel/preset-typescript": "7.25.7",
"@bundle-stats/plugin-webpack-filter": "4.15.1",
"@koa/cors": "5.0.0",
@@ -195,7 +195,7 @@
"babel-plugin-template-html-minifier": "4.1.0",
"browserslist-useragent-regexp": "4.1.3",
"chai": "5.1.1",
"del": "7.1.0",
"del": "8.0.0",
"eslint": "8.57.1",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-airbnb-typescript": "18.0.0",
@@ -205,7 +205,7 @@
"eslint-plugin-lit": "1.15.0",
"eslint-plugin-lit-a11y": "4.1.4",
"eslint-plugin-unused-imports": "4.1.4",
"eslint-plugin-wc": "2.1.1",
"eslint-plugin-wc": "2.2.0",
"fancy-log": "2.0.0",
"fs-extra": "11.2.0",
"glob": "11.0.0",
@@ -222,7 +222,7 @@
"lit-analyzer": "2.0.3",
"lodash.merge": "4.6.2",
"lodash.template": "4.5.0",
"magic-string": "0.30.11",
"magic-string": "0.30.12",
"map-stream": "0.0.7",
"mocha": "10.5.0",
"object-hash": "3.0.0",
@@ -240,7 +240,7 @@
"terser-webpack-plugin": "5.3.10",
"transform-async-modules-webpack-plugin": "1.1.1",
"ts-lit-plugin": "2.0.2",
"typescript": "5.6.2",
"typescript": "5.6.3",
"webpack": "5.95.0",
"webpack-cli": "5.1.4",
"webpack-dev-server": "5.1.0",

View File

@@ -1,10 +1,10 @@
[build-system]
requires = ["setuptools~=68.0", "wheel~=0.40.0"]
requires = ["setuptools~=75.1"]
build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20241002.2"
version = "20241010.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"

View File

@@ -18,5 +18,9 @@ if [[ -n "$DEVCONTAINER" ]]; then
fi
fi
if ! command -v yarn &> /dev/null; then
echo "Error: yarn not found. Please install it following the official instructions: https://yarnpkg.com/getting-started/install" >&2
exit 1
fi
# Install node modules
yarn install
yarn install

View File

@@ -20,6 +20,15 @@ function findNestedItem(
}, obj);
}
function updateNestedItem(obj: any, path: ItemPath): any {
const lastKey = path.pop()!;
const parent = findNestedItem(obj, path);
parent[lastKey] = Array.isArray(parent[lastKey])
? [...parent[lastKey]]
: [parent[lastKey]];
return obj;
}
export function nestedArrayMove<A>(
obj: A,
oldIndex: number,
@@ -27,14 +36,18 @@ export function nestedArrayMove<A>(
oldPath?: ItemPath,
newPath?: ItemPath
): A {
const newObj = (Array.isArray(obj) ? [...obj] : { ...obj }) as A;
let newObj = (Array.isArray(obj) ? [...obj] : { ...obj }) as A;
if (oldPath) {
newObj = updateNestedItem(newObj, [...oldPath]);
}
if (newPath) {
newObj = updateNestedItem(newObj, [...newPath]);
}
const from = oldPath ? findNestedItem(newObj, oldPath) : newObj;
const to = newPath ? findNestedItem(newObj, newPath, true) : newObj;
if (!Array.isArray(from) || !Array.isArray(to)) {
return obj;
}
const item = from.splice(oldIndex, 1)[0];
to.splice(newIndex, 0, item);

View File

@@ -3,7 +3,6 @@ import "@material/mwc-list/mwc-list-item";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { stopPropagation } from "../../common/dom/stop_propagation";
import { fullEntitiesContext } from "../../data/context";
import {
DeviceAutomation,
@@ -104,7 +103,6 @@ export abstract class HaDeviceAutomationPicker<
.label=${this.label}
.value=${value}
@selected=${this._automationChanged}
@closed=${stopPropagation}
.disabled=${this._automations.length === 0}
>
${value === NO_AUTOMATION_KEY

View File

@@ -174,7 +174,6 @@ export class HaServiceControl extends LitElement {
if (this._value && serviceData) {
const loadDefaults = this.value && !("data" in this.value);
// Set mandatory bools without a default value to false
this._value = { ...this._value };
if (!this._value.data) {
this._value.data = {};
}
@@ -500,8 +499,23 @@ export class HaServiceControl extends LitElement {
.defaultValue=${this._value?.data}
@value-changed=${this._dataChanged}
></ha-yaml-editor>`
: serviceData?.fields.map((dataField) =>
dataField.fields
: serviceData?.fields.map((dataField) => {
if (!dataField.fields) {
return this._renderField(
dataField,
hasOptional,
domain,
serviceName,
targetEntities
);
}
const fields = Object.entries(dataField.fields).map(
([key, field]) => ({ key, ...field })
);
return fields.length &&
this._hasFilteredFields(fields, targetEntities)
? html`<ha-expansion-panel
leftChevron
.expanded=${!dataField.collapsed}
@@ -532,14 +546,8 @@ export class HaServiceControl extends LitElement {
)
)}
</ha-expansion-panel>`
: this._renderField(
dataField,
hasOptional,
domain,
serviceName,
targetEntities
)
)} `;
: nothing;
})} `;
}
private _getSectionDescription(
@@ -552,6 +560,16 @@ export class HaServiceControl extends LitElement {
);
}
private _hasFilteredFields(
dataFields: ExtHassService["fields"],
targetEntities: string[]
) {
return dataFields.some(
(dataField) =>
!dataField.filter || this._filterField(dataField.filter, targetEntities)
);
}
private _renderField = (
dataField: ExtHassService["fields"][number],
hasOptional: boolean,

View File

@@ -167,7 +167,7 @@ export interface TagTrigger extends BaseTrigger {
export interface TimeTrigger extends BaseTrigger {
trigger: "time";
at: string;
at: string | { entity_id: string; offset?: string };
}
export interface TemplateTrigger extends BaseTrigger {

View File

@@ -8,6 +8,7 @@ import {
import secondsToDuration from "../common/datetime/seconds_to_duration";
import { computeAttributeNameDisplay } from "../common/entity/compute_attribute_display";
import { computeStateName } from "../common/entity/compute_state_name";
import { isValidEntityId } from "../common/entity/valid_entity_id";
import type { HomeAssistant } from "../types";
import { Condition, ForDict, Trigger } from "./automation";
import {
@@ -371,13 +372,22 @@ const tryDescribeTrigger = (
// Time Trigger
if (trigger.trigger === "time" && trigger.at) {
const result = ensureArray(trigger.at).map((at) =>
typeof at !== "string"
? at
: at.includes(".")
? `entity ${hass.states[at] ? computeStateName(hass.states[at]) : at}`
: localizeTimeString(at, hass.locale, hass.config)
);
const result = ensureArray(trigger.at).map((at) => {
if (typeof at === "string") {
if (isValidEntityId(at)) {
return `entity ${hass.states[at] ? computeStateName(hass.states[at]) : at}`;
}
return localizeTimeString(at, hass.locale, hass.config);
}
const entityStr = `entity ${hass.states[at.entity_id] ? computeStateName(hass.states[at.entity_id]) : at.entity_id}`;
const offsetStr = at.offset
? " " +
hass.localize(`${triggerTranslationBaseKey}.time.offset_by`, {
offset: describeDuration(hass.locale, at.offset),
})
: "";
return `${entityStr}${offsetStr}`;
});
return hass.localize(`${triggerTranslationBaseKey}.time.description.full`, {
time: formatListWithOrs(hass.locale, result),

View File

@@ -1,5 +1,4 @@
import type { HassServiceTarget } from "home-assistant-js-websocket";
import { Action } from "../../script";
export interface ToggleActionConfig extends BaseActionConfig {
action: "toggle";
@@ -32,11 +31,6 @@ export interface MoreInfoActionConfig extends BaseActionConfig {
entity_id?: string;
}
export interface SequenceActionConfig extends BaseActionConfig {
action: "sequence";
actions?: Action[];
}
export interface AssistActionConfig extends BaseActionConfig {
action: "assist";
pipeline_id?: string;
@@ -73,5 +67,4 @@ export type ActionConfig =
| MoreInfoActionConfig
| AssistActionConfig
| NoActionConfig
| CustomActionConfig
| SequenceActionConfig;
| CustomActionConfig;

View File

@@ -17,6 +17,10 @@ export interface LovelaceSectionConfig extends LovelaceBaseSectionConfig {
cards?: LovelaceCardConfig[];
}
export interface LovelaceGridSectionConfig extends LovelaceSectionConfig {
grid_base?: number;
}
export interface LovelaceStrategySectionConfig
extends LovelaceBaseSectionConfig {
strategy: LovelaceStrategyConfig;

View File

@@ -51,6 +51,7 @@ export class HuiPersistentNotificationItem extends LitElement {
static get styles(): CSSResultGroup {
return css`
.time {
position: relative;
display: flex;
justify-content: flex-end;
margin-top: 6px;

View File

@@ -208,6 +208,7 @@ class DialogAddAutomationElement extends LitElement implements HassDialog {
const options: IFuseOptions<ListItem> = {
keys: ["key", "name", "description"],
isCaseSensitive: false,
ignoreLocation: true,
minMatchCharLength: Math.min(filter.length, 2),
threshold: 0.2,
getFn: getStripDiacriticsFn,

View File

@@ -9,6 +9,9 @@ import type { TimeTrigger } from "../../../../../data/automation";
import type { HomeAssistant } from "../../../../../types";
import type { TriggerElement } from "../ha-automation-trigger-row";
const MODE_TIME = "time";
const MODE_ENTITY = "entity";
@customElement("ha-automation-trigger-time")
export class HaTimeTrigger extends LitElement implements TriggerElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -17,48 +20,60 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
@property({ type: Boolean }) public disabled = false;
@state() private _inputMode?: boolean;
@state() private _inputMode:
| undefined
| typeof MODE_TIME
| typeof MODE_ENTITY;
public static get defaultConfig(): TimeTrigger {
return { trigger: "time", at: "" };
}
private _schema = memoizeOne(
(localize: LocalizeFunc, inputMode?: boolean) => {
const atSelector = inputMode
? {
entity: {
filter: [
{ domain: "input_datetime" },
{ domain: "sensor", device_class: "timestamp" },
],
},
}
: { time: {} };
return [
(
localize: LocalizeFunc,
inputMode: typeof MODE_TIME | typeof MODE_ENTITY,
showOffset: boolean
) =>
[
{
name: "mode",
type: "select",
required: true,
options: [
[
"value",
MODE_TIME,
localize(
"ui.panel.config.automation.editor.triggers.type.time.type_value"
),
],
[
"input",
MODE_ENTITY,
localize(
"ui.panel.config.automation.editor.triggers.type.time.type_input"
),
],
],
},
{ name: "at", selector: atSelector },
] as const;
}
...(inputMode === MODE_TIME
? ([{ name: "time", selector: { time: {} } }] as const)
: ([
{
name: "entity",
selector: {
entity: {
filter: [
{ domain: "input_datetime" },
{ domain: "sensor", device_class: "timestamp" },
],
},
},
},
] as const)),
...(showOffset
? ([{ name: "offset", selector: { text: {} } }] as const)
: ([] as const)),
] as const
);
public willUpdate(changedProperties: PropertyValues) {
@@ -75,23 +90,46 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
}
}
private _data = memoizeOne(
(
inputMode: undefined | typeof MODE_ENTITY | typeof MODE_TIME,
at:
| string
| { entity_id: string | undefined; offset?: string | undefined }
): {
mode: typeof MODE_TIME | typeof MODE_ENTITY;
entity: string | undefined;
time: string | undefined;
offset: string | undefined;
} => {
const entity =
typeof at === "object"
? at.entity_id
: at?.startsWith("input_datetime.") || at?.startsWith("sensor.")
? at
: undefined;
const time = entity ? undefined : (at as string | undefined);
const offset = typeof at === "object" ? at.offset : undefined;
const mode = inputMode ?? (entity ? MODE_ENTITY : MODE_TIME);
return {
mode,
entity,
time,
offset,
};
}
);
protected render() {
const at = this.trigger.at;
if (Array.isArray(at)) {
return nothing;
}
const inputMode =
this._inputMode ??
(at?.startsWith("input_datetime.") || at?.startsWith("sensor."));
const schema = this._schema(this.hass.localize, inputMode);
const data = {
mode: inputMode ? "input" : "value",
...this.trigger,
};
const data = this._data(this._inputMode, at);
const showOffset =
data.mode === MODE_ENTITY && data.entity?.startsWith("sensor.");
const schema = this._schema(this.hass.localize, data.mode, !!showOffset);
return html`
<ha-form
@@ -107,26 +145,43 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
private _valueChanged(ev: CustomEvent): void {
ev.stopPropagation();
const newValue = ev.detail.value;
this._inputMode = newValue.mode === "input";
delete newValue.mode;
Object.keys(newValue).forEach((key) =>
newValue[key] === undefined || newValue[key] === ""
? delete newValue[key]
: {}
);
fireEvent(this, "value-changed", { value: newValue });
const newValue = { ...ev.detail.value };
this._inputMode = newValue.mode;
if (newValue.mode === MODE_TIME) {
delete newValue.entity;
delete newValue.offset;
} else {
delete newValue.time;
if (!newValue.entity?.startsWith("sensor.")) {
delete newValue.offset;
}
}
fireEvent(this, "value-changed", {
value: {
...this.trigger,
at: newValue.offset
? {
entity_id: newValue.entity,
offset: newValue.offset,
}
: newValue.entity || newValue.time,
},
});
}
private _computeLabelCallback = (
schema: SchemaUnion<ReturnType<typeof this._schema>>
): string =>
this.hass.localize(
): string => {
switch (schema.name) {
case "time":
return this.hass.localize(
`ui.panel.config.automation.editor.triggers.type.time.at`
);
}
return this.hass.localize(
`ui.panel.config.automation.editor.triggers.type.time.${schema.name}`
);
};
}
declare global {

View File

@@ -83,9 +83,15 @@ export const getZHADeviceActions = async (
classes: "warning",
action: async () => {
const confirmed = await showConfirmationDialog(el, {
text: hass.localize(
"ui.dialogs.zha_device_info.confirmations.remove"
title: hass.localize(
"ui.dialogs.zha_device_info.confirmations.remove_title"
),
text: hass.localize(
"ui.dialogs.zha_device_info.confirmations.remove_text"
),
confirmText: hass.localize("ui.common.remove"),
dismissText: hass.localize("ui.common.cancel"),
destructive: true,
});
if (!confirmed) {

View File

@@ -482,7 +482,9 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) {
const network = (ev.currentTarget as any).network as ThreadNetwork;
const router = (ev.currentTarget as any).router as ThreadRouter;
const otbr = (ev.currentTarget as any).otbr as OTBRInfo;
const index = Number(ev.detail.index);
const index = network.dataset
? Number(ev.detail.index)
: Number(ev.detail.index) + 1;
switch (index) {
case 0:
this._setPreferredBorderAgent(network.dataset!, router);

View File

@@ -83,8 +83,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@state() private _config?: ScriptConfig;
@state() private _idError = false;
@state() private _dirty = false;
@state() private _errors?: string;
@@ -414,6 +412,18 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
this._loadConfig();
}
if (
(changedProps.has("scriptId") || changedProps.has("entityRegistry")) &&
this.scriptId &&
this.entityRegistry
) {
// find entity for when script entity id changed
const entity = this.entityRegistry.find(
(ent) => ent.platform === "script" && ent.unique_id === this.scriptId
);
this._entityId = entity?.entity_id;
}
if (changedProps.has("scriptId") && !this.scriptId && this.hass) {
const initData = getScriptEditorInitData();
this._dirty = !!initData;
@@ -448,15 +458,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
}
}
private _setEntityId(id?: string) {
this._entityId = id;
if (this.hass.states[`script.${this._entityId}`]) {
this._idError = true;
} else {
this._idError = false;
}
}
private async _checkValidation() {
this._validationErrors = undefined;
if (!this._entityId || !this._config) {
@@ -766,28 +767,12 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
}
private async _saveScript(): Promise<void> {
if (this._idError) {
showToast(this, {
message: this.hass.localize(
"ui.panel.config.script.editor.id_already_exists_save_error"
),
dismissable: false,
duration: -1,
action: {
action: () => {},
text: this.hass.localize("ui.dialogs.generic.ok"),
},
});
return;
}
if (!this.scriptId) {
const saved = await this._promptScriptAlias();
if (!saved) {
return;
}
const entityId = this._computeEntityIdFromAlias(this._config!.alias);
this._setEntityId(entityId);
this._entityId = this._computeEntityIdFromAlias(this._config!.alias);
}
const id = this.scriptId || this._entityId || Date.now();

View File

@@ -68,6 +68,16 @@ class HaPanelDevAction extends LitElement {
@query("#yaml-editor") private _yamlEditor?: HaYamlEditor;
protected willUpdate() {
if (
!this.hasUpdated &&
this._serviceData?.action &&
typeof this._serviceData.action !== "string"
) {
this._serviceData.action = "";
}
}
protected firstUpdated(params) {
super.firstUpdated(params);
this.hass.loadBackendTranslation("services");

View File

@@ -187,7 +187,6 @@ export class HuiHeadingCard extends LitElement implements LovelaceCard {
}
.content p {
margin: 0;
font-family: Roboto;
font-style: normal;
white-space: nowrap;
overflow: hidden;

View File

@@ -275,7 +275,7 @@ export class HuiTodoListCard extends LitElement implements LovelaceCard {
"ui.panel.lovelace.cards.todo-list.no_unchecked_items"
)}
</p>`}
${checkedItems.length
${!this._config.hide_completed && checkedItems.length
? html`
<div role="separator">
<div class="divider"></div>

View File

@@ -453,6 +453,7 @@ export interface TodoListCardConfig extends LovelaceCardConfig {
title?: string;
theme?: string;
entity?: string;
hide_completed?: boolean;
}
export interface StackCardConfig extends LovelaceCardConfig {

View File

@@ -3,7 +3,6 @@ import { navigate } from "../../../common/navigate";
import { forwardHaptic } from "../../../data/haptics";
import { domainToName } from "../../../data/integration";
import { ActionConfig } from "../../../data/lovelace/config/action";
import { callExecuteScript } from "../../../data/service";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import { showVoiceCommandDialog } from "../../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
import { HomeAssistant } from "../../../types";
@@ -178,13 +177,6 @@ export const handleAction = async (
});
break;
}
case "sequence": {
if (!actionConfig.actions) {
return;
}
callExecuteScript(hass, actionConfig.actions);
break;
}
case "fire-dom-event": {
fireEvent(node, "ll-custom", actionConfig);
}

View File

@@ -1,5 +1,3 @@
import { ContextProvider } from "@lit-labs/context";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import {
css,
CSSResultGroup,
@@ -16,10 +14,7 @@ import "../../../components/ha-assist-pipeline-picker";
import { HaFormSchema, SchemaUnion } from "../../../components/ha-form/types";
import "../../../components/ha-help-tooltip";
import "../../../components/ha-navigation-picker";
import { HaSelect } from "../../../components/ha-select";
import "../../../components/ha-service-control";
import { fullEntitiesContext } from "../../../data/context";
import { subscribeEntityRegistry } from "../../../data/entity_registry";
import {
ActionConfig,
CallServiceActionConfig,
@@ -27,9 +22,9 @@ import {
UrlActionConfig,
} from "../../../data/lovelace/config/action";
import { ServiceAction } from "../../../data/script";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { HomeAssistant } from "../../../types";
import { EditorTarget } from "../editor/types";
import { HaSelect } from "../../../components/ha-select";
export type UiAction = Exclude<ActionConfig["action"], "fire-dom-event">;
@@ -39,7 +34,6 @@ const DEFAULT_ACTIONS: UiAction[] = [
"navigate",
"url",
"perform-action",
"sequence",
"assist",
"none",
];
@@ -76,17 +70,8 @@ const ASSIST_SCHEMA = [
},
] as const satisfies readonly HaFormSchema[];
const SEQUENCE_SCHEMA = [
{
name: "actions",
selector: {
action: {},
},
},
] as const satisfies readonly HaFormSchema[];
@customElement("hui-action-editor")
export class HuiActionEditor extends SubscribeMixin(LitElement) {
export class HuiActionEditor extends LitElement {
@property({ attribute: false }) public config?: ActionConfig;
@property() public label?: string;
@@ -101,19 +86,6 @@ export class HuiActionEditor extends SubscribeMixin(LitElement) {
@query("ha-select") private _select!: HaSelect;
private _entitiesContext = new ContextProvider(this, {
context: fullEntitiesContext,
initialValue: [],
});
public hassSubscribe(): UnsubscribeFunc[] {
return [
subscribeEntityRegistry(this.hass!.connection!, (entities) => {
this._entitiesContext.setValue(entities);
}),
];
}
get _navigation_path(): string {
const config = this.config as NavigateActionConfig | undefined;
return config?.navigation_path || "";
@@ -148,11 +120,6 @@ export class HuiActionEditor extends SubscribeMixin(LitElement) {
}
}
protected firstUpdated(_changedProperties: PropertyValues): void {
this.hass!.loadFragmentTranslation("config");
this.hass!.loadBackendTranslation("device_automation");
}
protected render() {
if (!this.hass) {
return nothing;
@@ -251,17 +218,6 @@ export class HuiActionEditor extends SubscribeMixin(LitElement) {
</ha-form>
`
: nothing}
${this.config?.action === "sequence"
? html`
<ha-form
.hass=${this.hass}
.schema=${SEQUENCE_SCHEMA}
.data=${this.config}
.computeLabel=${this._computeFormLabel}
@value-changed=${this._formValueChanged}
></ha-form>
`
: nothing}
`;
}
@@ -333,15 +289,7 @@ export class HuiActionEditor extends SubscribeMixin(LitElement) {
});
}
private _computeFormLabel(
schema:
| SchemaUnion<typeof ASSIST_SCHEMA>
| SchemaUnion<typeof NAVIGATE_SCHEMA>
| SchemaUnion<typeof SEQUENCE_SCHEMA>
) {
if (schema.name === "actions") {
return "";
}
private _computeFormLabel(schema: SchemaUnion<typeof ASSIST_SCHEMA>) {
return this.hass?.localize(
`ui.panel.lovelace.editor.action-editor.${schema.name}`
);

View File

@@ -3,12 +3,15 @@ import "@material/mwc-tab/mwc-tab";
import { CSSResultGroup, TemplateResult, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import {
LovelaceGridSectionConfig,
LovelaceSectionConfig,
} from "../../../../data/lovelace/config/section";
import { getCardElementClass } from "../../create-element/create-card-element";
import type { LovelaceCardEditor, LovelaceConfigForm } from "../../types";
import { HuiTypedElementEditor } from "../hui-typed-element-editor";
import "./hui-card-layout-editor";
import "./hui-card-visibility-editor";
import { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
const tabs = ["config", "visibility", "layout"] as const;
@@ -59,7 +62,7 @@ export class HuiCardElementEditor extends HuiTypedElementEditor<LovelaceCardConf
protected renderConfigElement(): TemplateResult {
const displayedTabs: string[] = ["config"];
if (this.showVisibilityTab) displayedTabs.push("visibility");
if (this._showLayoutTab) displayedTabs.push("layout");
if (this.sectionConfig?.type === "grid") displayedTabs.push("layout");
if (displayedTabs.length === 1) return super.renderConfigElement();
@@ -83,8 +86,8 @@ export class HuiCardElementEditor extends HuiTypedElementEditor<LovelaceCardConf
<hui-card-layout-editor
.hass=${this.hass}
.config=${this.value}
.sectionConfig=${this.sectionConfig!}
@value-changed=${this._configChanged}
.sectionConfig=${this.sectionConfig as LovelaceGridSectionConfig}
>
</hui-card-layout-editor>
`;

View File

@@ -19,7 +19,10 @@ import "../../../../components/ha-switch";
import "../../../../components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
import {
LovelaceGridSectionConfig,
LovelaceSectionConfig,
} from "../../../../data/lovelace/config/section";
import { haStyle } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
import { HuiCard } from "../../cards/hui-card";
@@ -27,6 +30,7 @@ import {
CardGridSize,
computeCardGridSize,
} from "../../common/compute-card-grid-size";
import { DEFAULT_GRID_BASE } from "../../sections/hui-grid-section";
import { LovelaceLayoutOptions } from "../../types";
@customElement("hui-card-layout-editor")
@@ -72,7 +76,10 @@ export class HuiCardLayoutEditor extends LitElement {
const value = this._computeCardGridSize(options);
const totalColumns = (this.sectionConfig.column_span ?? 1) * 4;
const totalColumns =
(this.sectionConfig.column_span ?? 1) *
((this.sectionConfig as LovelaceGridSectionConfig).grid_base ||
DEFAULT_GRID_BASE);
return html`
<div class="header">

View File

@@ -1,6 +1,6 @@
import { CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { assert, assign, object, optional, string } from "superstruct";
import { assert, assign, boolean, object, optional, string } from "superstruct";
import { isComponentLoaded } from "../../../../common/config/is_component_loaded";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-alert";
@@ -18,6 +18,7 @@ const cardConfigStruct = assign(
title: optional(string()),
theme: optional(string()),
entity: optional(string()),
hide_completed: optional(boolean()),
})
);
@@ -30,6 +31,7 @@ const SCHEMA = [
},
},
{ name: "theme", selector: { theme: {} } },
{ name: "hide_completed", selector: { boolean: {} } },
] as const;
@customElement("hui-todo-list-card-editor")
@@ -87,6 +89,10 @@ export class HuiTodoListEditor
)} (${this.hass!.localize(
"ui.panel.lovelace.editor.card.config.optional"
)})`;
case "hide_completed":
return this.hass!.localize(
"ui.panel.lovelace.editor.card.todo-list.hide_completed"
);
default:
return this.hass!.localize(
`ui.panel.lovelace.editor.card.generic.${schema.name}`

View File

@@ -1,4 +1,4 @@
import { LitElement, html } from "lit";
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../common/dom/fire_event";
@@ -6,12 +6,21 @@ import {
HaFormSchema,
SchemaUnion,
} from "../../../../components/ha-form/types";
import { LovelaceSectionRawConfig } from "../../../../data/lovelace/config/section";
import {
isStrategySection,
LovelaceGridSectionConfig,
LovelaceSectionRawConfig,
} from "../../../../data/lovelace/config/section";
import { LovelaceViewConfig } from "../../../../data/lovelace/config/view";
import { HomeAssistant } from "../../../../types";
import { LocalizeFunc } from "../../../../common/translations/localize";
import { DEFAULT_GRID_BASE } from "../../sections/hui-grid-section";
type GridDensity = "default" | "dense" | "custom";
type SettingsData = {
column_span?: number;
grid_density?: GridDensity;
};
@customElement("hui-section-settings-editor")
@@ -23,27 +32,89 @@ export class HuiDialogEditSection extends LitElement {
@property({ attribute: false }) public viewConfig!: LovelaceViewConfig;
private _schema = memoizeOne(
(maxColumns: number) =>
(
maxColumns: number,
localize: LocalizeFunc,
type?: string | undefined,
columnDensity?: GridDensity,
columnBase?: number
) =>
[
{
name: "column_span",
selector: {
number: {
min: 1,
max: maxColumns,
slider_ticks: true,
},
},
name: "title",
selector: { text: {} },
},
...(type === "grid"
? ([
{
name: "grid_density",
default: "default",
selector: {
select: {
mode: "list",
options: [
{
label: localize(
`ui.panel.lovelace.editor.edit_section.settings.grid_density_options.default`,
{ count: 4 }
),
value: "default",
},
{
label: localize(
`ui.panel.lovelace.editor.edit_section.settings.grid_density_options.dense`,
{ count: 6 }
),
value: "dense",
},
...(columnDensity === "custom" && columnBase
? [
{
label: localize(
`ui.panel.lovelace.editor.edit_section.settings.grid_density_options.custom`,
{ count: columnBase }
),
value: "custom",
},
]
: []),
],
},
},
},
] as const satisfies readonly HaFormSchema[])
: []),
] as const satisfies HaFormSchema[]
);
private _isGridSectionConfig(
config: LovelaceSectionRawConfig
): config is LovelaceGridSectionConfig {
return !isStrategySection(config) && config.type === "grid";
}
render() {
const gridBase = this._isGridSectionConfig(this.config)
? this.config.grid_base || DEFAULT_GRID_BASE
: undefined;
const columnDensity =
gridBase === 6 ? "dense" : gridBase === 4 ? "default" : "custom";
const data: SettingsData = {
column_span: this.config.column_span || 1,
grid_density: columnDensity,
};
const schema = this._schema(this.viewConfig.max_columns || 4);
const type = "type" in this.config ? this.config.type : undefined;
const schema = this._schema(
this.viewConfig.max_columns || 4,
this.hass.localize,
type,
columnDensity,
gridBase
);
return html`
<ha-form
@@ -75,11 +146,26 @@ export class HuiDialogEditSection extends LitElement {
ev.stopPropagation();
const newData = ev.detail.value as SettingsData;
const { column_span, grid_density } = newData;
const newConfig: LovelaceSectionRawConfig = {
...this.config,
column_span: newData.column_span,
column_span: column_span,
};
if (this._isGridSectionConfig(newConfig)) {
const gridBase =
grid_density === "default"
? 4
: grid_density === "dense"
? 6
: undefined;
if (gridBase) {
(newConfig as LovelaceGridSectionConfig).grid_base = gridBase;
}
}
fireEvent(this, "value-changed", { value: newConfig });
}
}

View File

@@ -48,12 +48,6 @@ const actionConfigStructService = object({
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigStructSequence = object({
action: literal("sequence"),
actions: optional(array(object())),
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigStructNavigate = object({
action: literal("navigate"),
navigation_path: string(),
@@ -107,9 +101,6 @@ export const actionConfigStruct = dynamic<any>((value) => {
case "more-info": {
return actionConfigStructMoreInfo;
}
case "sequence": {
return actionConfigStructSequence;
}
}
}

View File

@@ -8,7 +8,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
import type { HaSortableOptions } from "../../../components/ha-sortable";
import { LovelaceSectionElement } from "../../../data/lovelace";
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
import type { LovelaceGridSectionConfig } from "../../../data/lovelace/config/section";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { HuiCard } from "../cards/hui-card";
@@ -24,6 +24,8 @@ const CARD_SORTABLE_OPTIONS: HaSortableOptions = {
invertedSwapThreshold: 0.7,
} as HaSortableOptions;
export const DEFAULT_GRID_BASE = 4;
export class GridSection extends LitElement implements LovelaceSectionElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -37,11 +39,11 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
@property({ attribute: false }) public cards: HuiCard[] = [];
@state() _config?: LovelaceSectionConfig;
@state() _config?: LovelaceGridSectionConfig;
@state() _dragging = false;
public setConfig(config: LovelaceSectionConfig): void {
public setConfig(config: LovelaceGridSectionConfig): void {
this._config = config;
}
@@ -64,6 +66,8 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
const editMode = Boolean(this.lovelace?.editMode && !this.isStrategy);
const columnCount = this._config.grid_base ?? DEFAULT_GRID_BASE;
return html`
<ha-sortable
.disabled=${!editMode}
@@ -77,7 +81,10 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
.options=${CARD_SORTABLE_OPTIONS}
invert-swap
>
<div class="container ${classMap({ "edit-mode": editMode })}">
<div
class="container ${classMap({ "edit-mode": editMode })}"
style=${styleMap({ "--column-count": columnCount })}
>
${repeat(
cardsConfig,
(cardConfig) => this._getKey(cardConfig),
@@ -165,7 +172,6 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
haStyle,
css`
:host {
--base-column-count: 4;
--row-gap: var(--ha-section-grid-row-gap, 8px);
--column-gap: var(--ha-section-grid-column-gap, 8px);
--row-height: var(--ha-section-grid-row-height, 56px);
@@ -175,7 +181,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
}
.container {
--grid-column-count: calc(
var(--base-column-count) * var(--column-span, 1)
var(--column-count, 4) * var(--column-span, 1)
);
display: grid;
grid-template-columns: repeat(

View File

@@ -1635,7 +1635,8 @@
"zigbee_information": "View the Zigbee information for the device."
},
"confirmations": {
"remove": "Are you sure that you want to remove the device?"
"remove_title": "Remove device",
"remove_text": "This device will be permanently removed from the Zigbee network."
},
"quirk": "Quirk",
"last_seen": "Last seen",
@@ -2810,7 +2811,7 @@
"migrate": "Migrate",
"duplicate": "[%key:ui::common::duplicate%]",
"take_control": "Take control",
"confirm_take_control": "Your are viewing a preview of the automation config, do you want to take control?",
"confirm_take_control": "You are viewing a preview of the automation config, do you want to take control?",
"run": "[%key:ui::panel::config::automation::editor::actions::run%]",
"rename": "[%key:ui::panel::config::automation::editor::triggers::rename%]",
"show_trace": "Traces",
@@ -3053,6 +3054,9 @@
"type_input": "Value of a date/time helper or timestamp-class sensor",
"label": "Time",
"at": "At time",
"offset": "[%key:ui::panel::config::automation::editor::triggers::type::sun::offset%]",
"entity": "Entity with timestamp",
"offset_by": "offset by {offset}",
"mode": "Mode",
"description": {
"picker": "At a specific time, or on a specific date.",
@@ -3684,16 +3688,13 @@
"editor": {
"alias": "Name",
"icon": "Icon",
"id": "Entity ID",
"id_already_exists_save_error": "You can't save this script because the ID is not unique, pick another ID or leave it blank to automatically generate one.",
"id_already_exists": "This ID already exists",
"introduction": "Use scripts to run a sequence of actions.",
"show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]",
"show_info": "[%key:ui::panel::config::automation::editor::show_info%]",
"rename": "[%key:ui::panel::config::automation::editor::triggers::rename%]",
"change_mode": "[%key:ui::panel::config::automation::editor::change_mode%]",
"take_control": "[%key:ui::panel::config::automation::editor::take_control%]",
"confirm_take_control": "Your are viewing a preview of the script config, do you want to take control?",
"confirm_take_control": "You are viewing a preview of the script config, do you want to take control?",
"read_only": "This script cannot be edited from the UI, because it is not stored in the ''scripts.yaml'' file.",
"unavailable": "Script is unavailable",
"migrate": "Migrate",
@@ -5713,7 +5714,13 @@
"title": "Title",
"title_helper": "The title will appear at the top of section. Leave empty to hide the title.",
"column_span": "Width",
"column_span_helper": "Larger sections will be made smaller to fit the display. (e.g. on mobile devices)"
"column_span_helper": "Larger sections will be made smaller to fit the display. (e.g. on mobile devices)",
"grid_density": "Grid density",
"grid_density_options": {
"default": "Default ({count} columns)",
"dense": "Dense ({count} columns)",
"custom": "Custom ({count} {count, plural,\n one {column}\n other {columns}\n})"
}
},
"visibility": {
"explanation": "The section will be shown when ALL conditions below are fulfilled. If no conditions are set, the section will always be shown."
@@ -5752,12 +5759,10 @@
"more-info": "More info",
"toggle": "Toggle",
"navigate": "Navigate",
"sequence": "Sequence",
"assist": "Assist",
"url": "URL",
"none": "Nothing"
},
"sequence_actions": "Actions"
}
},
"condition-editor": {
"explanation": "The card will be shown when ALL conditions below are fulfilled.",
@@ -6133,7 +6138,8 @@
"todo-list": {
"name": "To-do list",
"description": "The to-do list card allows you to add, edit, check-off, and clear items from your to-do list.",
"integration_not_loaded": "This card requires the `todo` integration to be set up."
"integration_not_loaded": "This card requires the `todo` integration to be set up.",
"hide_completed": "Hide completed items"
},
"thermostat": {
"name": "Thermostat",

815
yarn.lock

File diff suppressed because it is too large Load Diff