mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-19 15:47:05 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f75d3f887e | |||
| c05824c641 | |||
| 3abdffda9c | |||
| 67da851efc | |||
| 5463a27255 | |||
| ec0434c9b0 | |||
| 7d8cb5c863 | |||
| 4f01348ffb | |||
| 2af3400464 | |||
| b6e220a4c5 | |||
| d5d45f100e | |||
| 6b9ca60c47 | |||
| bc445a1e27 | |||
| a087b4c43e | |||
| 8f67ddf968 | |||
| 9ef07484dd |
@@ -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
|
||||
@@ -28,7 +28,7 @@ class HcLaunchScreen extends LitElement {
|
||||
:host {
|
||||
display: block;
|
||||
height: 100vh;
|
||||
background-color: #f2f4f9;
|
||||
background-color: white;
|
||||
font-size: 24px;
|
||||
}
|
||||
.container {
|
||||
@@ -43,9 +43,6 @@ class HcLaunchScreen extends LitElement {
|
||||
max-width: 80%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.status {
|
||||
color: #1d2126;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
${this.hass.localize(
|
||||
"ui.panel.page-demo.cards.demo.demo_by",
|
||||
{
|
||||
name: html`
|
||||
<a target="_blank" href=${conf.authorUrl}>
|
||||
${conf.authorName}
|
||||
</a>
|
||||
`,
|
||||
}
|
||||
)}
|
||||
<a target="_blank" href=${conf.authorUrl}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.page-demo.cards.demo.demo_by",
|
||||
{ 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">
|
||||
${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 class="content small-hidden">
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.introduction")}
|
||||
</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,6 +17,7 @@ export const basicTrace: DemoTrace = {
|
||||
{
|
||||
path: "trigger/0",
|
||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
||||
changed_variables: {},
|
||||
},
|
||||
],
|
||||
"condition/0": [
|
||||
|
||||
@@ -17,6 +17,7 @@ export const motionLightTrace: DemoTrace = {
|
||||
{
|
||||
path: "trigger/0",
|
||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
||||
changed_variables: {},
|
||||
},
|
||||
],
|
||||
"action/0": [
|
||||
|
||||
@@ -55,6 +55,7 @@ export class DemoAutomationTraceTimeline extends LitElement {
|
||||
super.firstUpdated(changedProps);
|
||||
const hass = provideHass(this);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("config", "en");
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
|
||||
@@ -60,6 +60,7 @@ export class DemoAutomationTrace extends LitElement {
|
||||
super.firstUpdated(changedProps);
|
||||
const hass = provideHass(this);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("config", "en");
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
|
||||
+9
-9
@@ -72,6 +72,7 @@
|
||||
"@material/mwc-radio": "0.27.0",
|
||||
"@material/mwc-ripple": "0.27.0",
|
||||
"@material/mwc-select": "0.27.0",
|
||||
"@material/mwc-snackbar": "0.27.0",
|
||||
"@material/mwc-switch": "0.27.0",
|
||||
"@material/mwc-tab": "0.27.0",
|
||||
"@material/mwc-tab-bar": "0.27.0",
|
||||
@@ -86,11 +87,10 @@
|
||||
"@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.6",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.6",
|
||||
"@vaadin/combo-box": "24.3.7",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.7",
|
||||
"@vibrant/color": "3.2.1-alpha.1",
|
||||
"@vibrant/core": "3.2.1-alpha.1",
|
||||
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
|
||||
@@ -110,7 +110,7 @@
|
||||
"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",
|
||||
"hls.js": "1.5.7",
|
||||
"home-assistant-js-websocket": "9.1.0",
|
||||
"idb-keyval": "6.2.1",
|
||||
"intl-messageformat": "10.5.11",
|
||||
@@ -159,8 +159,8 @@
|
||||
"@bundle-stats/plugin-webpack-filter": "4.10.1",
|
||||
"@koa/cors": "5.0.0",
|
||||
"@lokalise/node-api": "12.1.0",
|
||||
"@octokit/auth-oauth-device": "6.0.1",
|
||||
"@octokit/plugin-retry": "6.0.1",
|
||||
"@octokit/auth-oauth-device": "7.0.0",
|
||||
"@octokit/plugin-retry": "7.0.1",
|
||||
"@octokit/rest": "20.0.2",
|
||||
"@open-wc/dev-server-hmr": "0.1.4",
|
||||
"@rollup/plugin-babel": "6.0.4",
|
||||
@@ -185,8 +185,8 @@
|
||||
"@types/tar": "6.1.11",
|
||||
"@types/ua-parser-js": "0.7.39",
|
||||
"@types/webspeechapi": "0.0.29",
|
||||
"@typescript-eslint/eslint-plugin": "7.0.2",
|
||||
"@typescript-eslint/parser": "7.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "7.1.0",
|
||||
"@typescript-eslint/parser": "7.1.0",
|
||||
"@web/dev-server": "0.1.38",
|
||||
"@web/dev-server-rollup": "0.4.1",
|
||||
"babel-loader": "9.1.3",
|
||||
@@ -224,7 +224,7 @@
|
||||
"map-stream": "0.0.7",
|
||||
"mocha": "10.3.0",
|
||||
"object-hash": "3.0.0",
|
||||
"open": "10.0.3",
|
||||
"open": "10.0.4",
|
||||
"pinst": "3.0.0",
|
||||
"prettier": "3.2.5",
|
||||
"rollup": "2.79.1",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20240307.0"
|
||||
version = "20240228.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "The Home Assistant frontend"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -1,35 +1,8 @@
|
||||
import "@polymer/paper-toast/paper-toast";
|
||||
import type { PaperToastElement } from "@polymer/paper-toast/paper-toast";
|
||||
import { customElement } from "lit/decorators";
|
||||
import type { Constructor } from "../types";
|
||||
|
||||
const PaperToast = customElements.get(
|
||||
"paper-toast"
|
||||
) as Constructor<PaperToastElement>;
|
||||
import { Snackbar } from "@material/mwc-snackbar/mwc-snackbar";
|
||||
|
||||
@customElement("ha-toast")
|
||||
export class HaToast extends PaperToast {
|
||||
private _resizeListener?: (obj: { matches: boolean }) => unknown;
|
||||
|
||||
private _mediaq?: MediaQueryList;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
if (!this._resizeListener) {
|
||||
this._resizeListener = (ev) =>
|
||||
this.classList.toggle("fit-bottom", ev.matches);
|
||||
this._mediaq = window.matchMedia("(max-width: 599px");
|
||||
}
|
||||
this._mediaq!.addListener(this._resizeListener);
|
||||
this._resizeListener(this._mediaq!);
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._mediaq!.removeListener(this._resizeListener!);
|
||||
}
|
||||
}
|
||||
export class HaToast extends Snackbar {}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
|
||||
@@ -163,21 +163,22 @@ export class HaTracePathDetails extends LitElement {
|
||||
}
|
||||
)}
|
||||
<br />
|
||||
${error
|
||||
? html`<div class="error">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.automation.trace.path.error",
|
||||
{
|
||||
error: error,
|
||||
}
|
||||
)}
|
||||
</div>`
|
||||
: nothing}
|
||||
${result
|
||||
? html`${this.hass!.localize(
|
||||
"ui.panel.config.automation.trace.path.result"
|
||||
)}
|
||||
<pre>${dump(result)}</pre>`
|
||||
: error
|
||||
? html`<div class="error">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.automation.trace.path.error",
|
||||
{
|
||||
error: error,
|
||||
}
|
||||
)}
|
||||
</div>`
|
||||
: nothing}
|
||||
: nothing}
|
||||
${Object.keys(rest).length === 0
|
||||
? nothing
|
||||
: html`<pre>${dump(rest)}</pre>`}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { mdiExclamationThick } from "@mdi/js";
|
||||
import {
|
||||
css,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
html,
|
||||
TemplateResult,
|
||||
svg,
|
||||
css,
|
||||
html,
|
||||
nothing,
|
||||
svg,
|
||||
} from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { NODE_SIZE, SPACING } from "./hat-graph-const";
|
||||
import { isSafari } from "../../util/is_safari";
|
||||
import { NODE_SIZE, SPACING } from "./hat-graph-const";
|
||||
|
||||
/**
|
||||
* @attribute active
|
||||
@@ -21,6 +22,8 @@ export class HatGraphNode extends LitElement {
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public disabled = false;
|
||||
|
||||
@property({ type: Boolean }) public error = false;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) notEnabled = false;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) graphStart = false;
|
||||
@@ -65,16 +68,28 @@ export class HatGraphNode extends LitElement {
|
||||
`}
|
||||
<g class="node">
|
||||
<circle cx="0" cy="0" r=${NODE_SIZE / 2} />
|
||||
${this.error
|
||||
? svg`
|
||||
<g class="error">
|
||||
<circle
|
||||
cx="-12"
|
||||
cy=${-NODE_SIZE / 2}
|
||||
r="8"
|
||||
></circle>
|
||||
<path transform="translate(-18 -21) scale(.5)" class="exclamation" d=${mdiExclamationThick}/>
|
||||
</g>
|
||||
`
|
||||
: nothing}
|
||||
${this.badge
|
||||
? svg`
|
||||
<g class="number">
|
||||
<circle
|
||||
cx="8"
|
||||
cx="12"
|
||||
cy=${-NODE_SIZE / 2}
|
||||
r="8"
|
||||
></circle>
|
||||
<text
|
||||
x="8"
|
||||
x="12"
|
||||
y=${-NODE_SIZE / 2}
|
||||
text-anchor="middle"
|
||||
alignment-baseline="middle"
|
||||
@@ -82,7 +97,7 @@ export class HatGraphNode extends LitElement {
|
||||
</g>
|
||||
`
|
||||
: nothing}
|
||||
<g style="pointer-events: none" transform="translate(${-12} ${-12})">
|
||||
<g style="pointer-events: none" transform="translate(-12 -12)">
|
||||
${this.iconPath
|
||||
? svg`<path class="icon" d=${this.iconPath}/>`
|
||||
: svg`<foreignObject><span class="icon"><slot name="icon"></slot></span></foreignObject>`}
|
||||
@@ -143,13 +158,22 @@ export class HatGraphNode extends LitElement {
|
||||
fill: var(--background-clr);
|
||||
stroke: var(--circle-clr, var(--stroke-clr));
|
||||
}
|
||||
.error circle {
|
||||
fill: var(--error-color);
|
||||
stroke: none;
|
||||
stroke-width: 0;
|
||||
}
|
||||
.error .exclamation {
|
||||
fill: var(--text-primary-color);
|
||||
}
|
||||
.number circle {
|
||||
fill: var(--track-clr);
|
||||
stroke: none;
|
||||
stroke-width: 0;
|
||||
}
|
||||
.number text {
|
||||
font-size: smaller;
|
||||
font-size: 10px;
|
||||
fill: var(--text-primary-color);
|
||||
}
|
||||
path.icon {
|
||||
fill: var(--icon-clr);
|
||||
|
||||
@@ -93,6 +93,7 @@ export class HatScriptGraph extends LitElement {
|
||||
?active=${this.selected === path}
|
||||
.iconPath=${mdiAsterisk}
|
||||
.notEnabled=${config.enabled === false}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
tabindex=${track ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -171,6 +172,7 @@ export class HatScriptGraph extends LitElement {
|
||||
?track=${trace !== undefined}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
slot="head"
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
@@ -424,6 +426,7 @@ export class HatScriptGraph extends LitElement {
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
>
|
||||
${node.service
|
||||
@@ -451,6 +454,7 @@ export class HatScriptGraph extends LitElement {
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -517,6 +521,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
|
||||
@@ -153,7 +153,7 @@ class LogbookRenderer {
|
||||
|
||||
const parts: TemplateResult[] = [];
|
||||
|
||||
let i;
|
||||
let i: number;
|
||||
|
||||
for (
|
||||
i = 0;
|
||||
@@ -232,7 +232,7 @@ class ActionRenderer {
|
||||
const value = this._getItem(index);
|
||||
|
||||
if (renderAllIterations) {
|
||||
let i;
|
||||
let i: number = 0;
|
||||
value.forEach((item) => {
|
||||
i = this._renderIteration(index, item, actionType);
|
||||
});
|
||||
@@ -270,7 +270,12 @@ class ActionRenderer {
|
||||
} catch (err: any) {
|
||||
this._renderEntry(
|
||||
path,
|
||||
`Unable to extract path ${path}. Download trace and report as bug`
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.path_error",
|
||||
{
|
||||
path: path,
|
||||
}
|
||||
)
|
||||
);
|
||||
return index + 1;
|
||||
}
|
||||
@@ -324,20 +329,22 @@ class ActionRenderer {
|
||||
private _handleTrigger(index: number, triggerStep: TriggerTraceStep): number {
|
||||
this._renderEntry(
|
||||
triggerStep.path,
|
||||
`${
|
||||
triggerStep.changed_variables.trigger.alias
|
||||
? `${triggerStep.changed_variables.trigger.alias} triggered`
|
||||
: "Triggered"
|
||||
} ${
|
||||
triggerStep.path === "trigger"
|
||||
? "manually"
|
||||
: `by the ${this.trace.trigger}`
|
||||
} at
|
||||
${formatDateTimeWithSeconds(
|
||||
new Date(triggerStep.timestamp),
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)}`,
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.triggered_by",
|
||||
{
|
||||
triggeredBy: triggerStep.changed_variables.trigger?.alias
|
||||
? "alias"
|
||||
: "other",
|
||||
alias: triggerStep.changed_variables.trigger?.alias,
|
||||
triggeredPath: triggerStep.path === "trigger" ? "manual" : "trigger",
|
||||
trigger: this.trace.trigger,
|
||||
time: formatDateTimeWithSeconds(
|
||||
new Date(triggerStep.timestamp),
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
),
|
||||
}
|
||||
),
|
||||
mdiCircle
|
||||
);
|
||||
return index + 1;
|
||||
@@ -367,12 +374,17 @@ class ActionRenderer {
|
||||
this.keys[index]
|
||||
) as ChooseAction;
|
||||
const disabled = chooseConfig.enabled === false;
|
||||
const name = chooseConfig.alias || "Choose";
|
||||
const name =
|
||||
chooseConfig.alias ||
|
||||
this.hass.localize("ui.panel.config.automation.trace.messages.choose");
|
||||
|
||||
if (defaultExecuted) {
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: Default action executed`,
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.default_action_executed",
|
||||
{ name: name }
|
||||
),
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
@@ -385,8 +397,17 @@ class ActionRenderer {
|
||||
`${this.keys[index]}/choose/${chooseTrace.result.choice}`
|
||||
) as ChooseActionChoice | undefined;
|
||||
const choiceName = choiceConfig
|
||||
? `${choiceConfig.alias || `Option ${choiceNumeric}`} executed`
|
||||
: `Error: ${chooseTrace.error}`;
|
||||
? `${
|
||||
choiceConfig.alias ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.option_executed",
|
||||
{ option: choiceNumeric }
|
||||
)
|
||||
}`
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.error",
|
||||
{ error: chooseTrace.error }
|
||||
);
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: ${choiceName}`,
|
||||
@@ -396,13 +417,16 @@ class ActionRenderer {
|
||||
} else {
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: No action taken`,
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.no_action_executed",
|
||||
{ name: name }
|
||||
),
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
}
|
||||
|
||||
let i;
|
||||
let i: number;
|
||||
|
||||
// Skip over conditions
|
||||
for (i = index + 1; i < this.keys.length; i++) {
|
||||
@@ -479,26 +503,38 @@ class ActionRenderer {
|
||||
const ifTrace = this._getItem(index)[0] as IfActionTraceStep;
|
||||
const ifConfig = this._getDataFromPath(this.keys[index]) as IfAction;
|
||||
const disabled = ifConfig.enabled === false;
|
||||
const name = ifConfig.alias || "If";
|
||||
const name =
|
||||
ifConfig.alias ||
|
||||
this.hass.localize("ui.panel.config.automation.trace.messages.if");
|
||||
|
||||
if (ifTrace.result?.choice) {
|
||||
const choiceConfig = this._getDataFromPath(
|
||||
`${this.keys[index]}/${ifTrace.result.choice}/`
|
||||
) as any;
|
||||
const choiceName = choiceConfig
|
||||
? `${choiceConfig.alias || `${ifTrace.result.choice} action executed`}`
|
||||
: `Error: ${ifTrace.error}`;
|
||||
? choiceConfig.alias ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.action_executed",
|
||||
{ action: ifTrace.result.choice }
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.error",
|
||||
{ error: ifTrace.error }
|
||||
);
|
||||
this._renderEntry(ifPath, `${name}: ${choiceName}`, undefined, disabled);
|
||||
} else {
|
||||
this._renderEntry(
|
||||
ifPath,
|
||||
`${name}: No action taken`,
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.no_action_executed",
|
||||
{ name: name }
|
||||
),
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
}
|
||||
|
||||
let i;
|
||||
let i: number;
|
||||
|
||||
// Skip over conditions
|
||||
for (i = index + 1; i < this.keys.length; i++) {
|
||||
@@ -534,7 +570,11 @@ class ActionRenderer {
|
||||
|
||||
const disabled = parallelConfig.enabled === false;
|
||||
|
||||
const name = parallelConfig.alias || "Execute in parallel";
|
||||
const name =
|
||||
parallelConfig.alias ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.execute_in_parallel"
|
||||
);
|
||||
|
||||
this._renderEntry(parallelPath, name, undefined, disabled);
|
||||
|
||||
@@ -564,7 +604,11 @@ class ActionRenderer {
|
||||
this.entries.push(html`
|
||||
<ha-timeline .icon=${icon} data-path=${path} .notEnabled=${disabled}>
|
||||
${description}${disabled
|
||||
? html`<span class="disabled"> (disabled)</span>`
|
||||
? html`<span class="disabled">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.disabled"
|
||||
)}</span
|
||||
>`
|
||||
: ""}
|
||||
</ha-timeline>
|
||||
`);
|
||||
@@ -636,13 +680,12 @@ export class HaAutomationTracer extends LitElement {
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
const renderRuntime = () => `(runtime:
|
||||
${(
|
||||
const renderRuntime = () =>
|
||||
(
|
||||
(new Date(this.trace!.timestamp.finish!).getTime() -
|
||||
new Date(this.trace!.timestamp.start).getTime()) /
|
||||
1000
|
||||
).toFixed(2)}
|
||||
seconds)`;
|
||||
).toFixed(2);
|
||||
|
||||
let entry: {
|
||||
description: TemplateResult | string;
|
||||
@@ -652,57 +695,90 @@ export class HaAutomationTracer extends LitElement {
|
||||
|
||||
if (this.trace.state === "running") {
|
||||
entry = {
|
||||
description: "Still running",
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.still_running"
|
||||
),
|
||||
icon: mdiProgressClock,
|
||||
};
|
||||
} else if (this.trace.state === "debugged") {
|
||||
entry = {
|
||||
description: "Debugged",
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.debugged"
|
||||
),
|
||||
icon: mdiProgressWrench,
|
||||
};
|
||||
} else if (this.trace.script_execution === "finished") {
|
||||
entry = {
|
||||
description: `Finished at ${renderFinishedAt()} ${renderRuntime()}`,
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.finished",
|
||||
{
|
||||
time: renderFinishedAt(),
|
||||
executiontime: renderRuntime(),
|
||||
}
|
||||
),
|
||||
icon: mdiCircle,
|
||||
};
|
||||
} else if (this.trace.script_execution === "aborted") {
|
||||
entry = {
|
||||
description: `Aborted at ${renderFinishedAt()} ${renderRuntime()}`,
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.aborted",
|
||||
{
|
||||
time: renderFinishedAt(),
|
||||
executiontime: renderRuntime(),
|
||||
}
|
||||
),
|
||||
icon: mdiAlertCircle,
|
||||
};
|
||||
} else if (this.trace.script_execution === "cancelled") {
|
||||
entry = {
|
||||
description: `Cancelled at ${renderFinishedAt()} ${renderRuntime()}`,
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.cancelled",
|
||||
{
|
||||
time: renderFinishedAt(),
|
||||
executiontime: renderRuntime(),
|
||||
}
|
||||
),
|
||||
icon: mdiAlertCircle,
|
||||
};
|
||||
} else {
|
||||
let reason: string;
|
||||
let message:
|
||||
| "stopped_failed_conditions"
|
||||
| "stopped_failed_single"
|
||||
| "stopped_failed_max_runs"
|
||||
| "stopped_error"
|
||||
| "stopped_unknown_reason";
|
||||
let isError = false;
|
||||
let extra: TemplateResult | undefined;
|
||||
|
||||
switch (this.trace.script_execution) {
|
||||
case "failed_conditions":
|
||||
reason = "a condition failed";
|
||||
message = "stopped_failed_conditions";
|
||||
break;
|
||||
case "failed_single":
|
||||
reason = "only a single execution is allowed";
|
||||
message = "stopped_failed_single";
|
||||
break;
|
||||
case "failed_max_runs":
|
||||
reason = "maximum number of parallel runs reached";
|
||||
message = "stopped_failed_max_runs";
|
||||
break;
|
||||
case "error":
|
||||
reason = "an error was encountered";
|
||||
isError = true;
|
||||
message = "stopped_error";
|
||||
extra = html`<br /><br />${this.trace.error!}`;
|
||||
break;
|
||||
default:
|
||||
reason = `of unknown reason "${this.trace.script_execution}"`;
|
||||
isError = true;
|
||||
message = "stopped_unknown_reason";
|
||||
}
|
||||
|
||||
entry = {
|
||||
description: html`Stopped because ${reason} at ${renderFinishedAt()}
|
||||
${renderRuntime()}${extra || ""}`,
|
||||
description: html`${this.hass.localize(
|
||||
`ui.panel.config.automation.trace.messages.${message}`,
|
||||
{
|
||||
time: renderFinishedAt(),
|
||||
executiontime: renderRuntime(),
|
||||
}
|
||||
)}
|
||||
${extra || ""}`,
|
||||
icon: mdiAlertCircle,
|
||||
className: isError ? "error" : undefined,
|
||||
};
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ import {
|
||||
HassEntityBase,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { getExtendedEntityRegistryEntry } from "./entity_registry";
|
||||
import { showEnterCodeDialog } from "../dialogs/enter-code/show-enter-code-dialog";
|
||||
import { showEnterCodeDialogDialog } from "../dialogs/enter-code/show-enter-code-dialog";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
export const FORMAT_TEXT = "text";
|
||||
@@ -38,7 +38,7 @@ export const callProtectedLockService = async (
|
||||
const defaultCode = lockRegistryEntry?.options?.lock?.default_code;
|
||||
|
||||
if (stateObj!.attributes.code_format && !defaultCode) {
|
||||
const response = await showEnterCodeDialog(element, {
|
||||
const response = await showEnterCodeDialogDialog(element, {
|
||||
codeFormat: "text",
|
||||
codePattern: stateObj!.attributes.code_format,
|
||||
title: hass.localize(`ui.card.lock.${service}`),
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { LovelaceLayoutOptions } from "../../../panels/lovelace/types";
|
||||
|
||||
export interface LovelaceCardConfig {
|
||||
index?: number;
|
||||
view_index?: number;
|
||||
view_layout?: any;
|
||||
layout_options?: LovelaceLayoutOptions;
|
||||
type: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import {
|
||||
Trigger,
|
||||
} from "./automation";
|
||||
import { BlueprintInput } from "./blueprint";
|
||||
import { computeObjectId } from "../common/entity/compute_object_id";
|
||||
|
||||
export const MODES = ["single", "restart", "queued", "parallel"] as const;
|
||||
export const MODES_MAX = ["queued", "parallel"] as const;
|
||||
@@ -405,11 +404,3 @@ export const getActionType = (action: Action): ActionType => {
|
||||
}
|
||||
return "unknown";
|
||||
};
|
||||
|
||||
export const hasScriptFields = (
|
||||
hass: HomeAssistant,
|
||||
entityId: string
|
||||
): boolean => {
|
||||
const fields = hass.services.script[computeObjectId(entityId)]?.fields;
|
||||
return fields !== undefined && Object.keys(fields).length > 0;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ export interface EnterCodeDialogParams {
|
||||
cancel?: () => void;
|
||||
}
|
||||
|
||||
export const showEnterCodeDialog = (
|
||||
export const showEnterCodeDialogDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: EnterCodeDialogParams
|
||||
) =>
|
||||
|
||||
@@ -8,7 +8,7 @@ import "../../../components/ha-state-icon";
|
||||
import { AlarmControlPanelEntity } from "../../../data/alarm_control_panel";
|
||||
import "../../../state-control/alarm_control_panel/ha-state-control-alarm_control_panel-modes";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { showEnterCodeDialog } from "../../enter-code/show-enter-code-dialog";
|
||||
import { showEnterCodeDialogDialog } from "../../enter-code/show-enter-code-dialog";
|
||||
import "../components/ha-more-info-state-header";
|
||||
import { moreInfoControlStyle } from "../components/more-info-control-style";
|
||||
|
||||
@@ -22,7 +22,7 @@ class MoreInfoAlarmControlPanel extends LitElement {
|
||||
let code: string | undefined;
|
||||
|
||||
if (this.stateObj!.attributes.code_format) {
|
||||
const response = await showEnterCodeDialog(this, {
|
||||
const response = await showEnterCodeDialogDialog(this, {
|
||||
codeFormat: this.stateObj!.attributes.code_format,
|
||||
title: this.hass.localize("ui.card.alarm_control_panel.disarm"),
|
||||
submitText: this.hass.localize("ui.card.alarm_control_panel.disarm"),
|
||||
|
||||
@@ -71,6 +71,7 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
@click=${this._showBrowseMedia}
|
||||
>
|
||||
<ha-svg-icon
|
||||
class="browse-media-icon"
|
||||
.path=${mdiPlayBoxMultiple}
|
||||
slot="icon"
|
||||
></ha-svg-icon>
|
||||
@@ -255,6 +256,12 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
mwc-button > ha-svg-icon {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.browse-media-icon {
|
||||
margin-left: 8px;
|
||||
margin-inline-start: 8px;
|
||||
margin-inline-end: initial;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -341,7 +341,7 @@ class DialogRestart extends LitElement {
|
||||
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.dialogs.restart.reboot.rebooting"),
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -380,7 +380,7 @@ class DialogRestart extends LitElement {
|
||||
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.dialogs.restart.shutdown.shutting_down"),
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import "@material/mwc-button";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { property, state, query } from "lit/decorators";
|
||||
import { mdiClose } from "@mdi/js";
|
||||
import { computeRTL } from "../common/util/compute_rtl";
|
||||
import "../components/ha-toast";
|
||||
import type { HaToast } from "../components/ha-toast";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import "../components/ha-button";
|
||||
|
||||
export interface ShowToastParams {
|
||||
message: string;
|
||||
@@ -21,72 +22,78 @@ export interface ToastActionParams {
|
||||
class NotificationManager extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _action?: ToastActionParams;
|
||||
@state() private _parameters?: ShowToastParams;
|
||||
|
||||
@state() private _noCancelOnOutsideClick = false;
|
||||
@query("ha-toast") private _toast!: HaToast | undefined;
|
||||
|
||||
@query("ha-toast") private _toast!: HaToast;
|
||||
|
||||
public async showDialog({
|
||||
message,
|
||||
action,
|
||||
duration,
|
||||
dismissable,
|
||||
}: ShowToastParams) {
|
||||
let toast = this._toast;
|
||||
// Can happen on initial load
|
||||
if (!toast) {
|
||||
public async showDialog(parameters: ShowToastParams) {
|
||||
if (this._parameters) {
|
||||
this._parameters = undefined;
|
||||
await this.updateComplete;
|
||||
toast = this._toast;
|
||||
}
|
||||
toast.setAttribute("dir", computeRTL(this.hass) ? "rtl" : "ltr");
|
||||
this._action = action || undefined;
|
||||
this._noCancelOnOutsideClick =
|
||||
dismissable === undefined ? false : !dismissable;
|
||||
toast.hide();
|
||||
toast.show({
|
||||
text: message,
|
||||
duration: duration === undefined ? 3000 : duration,
|
||||
});
|
||||
|
||||
if (!parameters || parameters.duration === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._parameters = parameters;
|
||||
|
||||
if (
|
||||
this._parameters.duration === undefined ||
|
||||
(this._parameters.duration > 0 && this._parameters.duration <= 4000)
|
||||
) {
|
||||
this._parameters.duration = 4000;
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
public shouldUpdate(changedProperties) {
|
||||
return !this._toast || changedProperties.has("_parameters");
|
||||
}
|
||||
|
||||
private _toastClosed() {
|
||||
this._parameters = undefined;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._parameters) {
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<ha-toast .noCancelOnOutsideClick=${this._noCancelOnOutsideClick}>
|
||||
${this._action
|
||||
<ha-toast
|
||||
leading
|
||||
open
|
||||
dir=${computeRTL(this.hass) ? "rtl" : "ltr"}
|
||||
.labelText=${this._parameters.message}
|
||||
.timeoutMs=${this._parameters.duration!}
|
||||
@MDCSnackbar:closed=${this._toastClosed}
|
||||
>
|
||||
${this._parameters?.action
|
||||
? html`
|
||||
<mwc-button
|
||||
.label=${this._action.text}
|
||||
<ha-button
|
||||
slot="action"
|
||||
.label=${this._parameters?.action.text}
|
||||
@click=${this.buttonClicked}
|
||||
></mwc-button>
|
||||
></ha-button>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
${this._parameters?.dismissable
|
||||
? html`<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.close")}
|
||||
.path=${mdiClose}
|
||||
dialogAction="close"
|
||||
slot="dismiss"
|
||||
></ha-icon-button>`
|
||||
: nothing}
|
||||
</ha-toast>
|
||||
`;
|
||||
}
|
||||
|
||||
private buttonClicked() {
|
||||
this._toast.hide();
|
||||
if (this._action) {
|
||||
this._action.action();
|
||||
this._toast?.close("action");
|
||||
if (this._parameters?.action) {
|
||||
this._parameters?.action.action();
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
ha-toast {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
mwc-button {
|
||||
color: var(--primary-color);
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("notification-manager", NotificationManager);
|
||||
|
||||
@@ -93,7 +93,7 @@ export class HaAutomationTrace extends LitElement {
|
||||
|
||||
let devButtons: TemplateResult | string = "";
|
||||
if (__DEV__) {
|
||||
devButtons = html`<div style="position: absolute; right: 0;">
|
||||
devButtons = html`<div style="position: absolute; right: 0; z-index: 1;">
|
||||
<button @click=${this._importTrace}>Import trace</button>
|
||||
<button @click=${this._loadLocalStorageTrace}>Load stored trace</button>
|
||||
</div>`;
|
||||
|
||||
@@ -48,7 +48,6 @@ import {
|
||||
fetchScriptFileConfig,
|
||||
getScriptEditorInitData,
|
||||
getScriptStateConfig,
|
||||
hasScriptFields,
|
||||
isMaxMode,
|
||||
showScriptEditor,
|
||||
triggerScript,
|
||||
@@ -63,7 +62,6 @@ import { showToast } from "../../../util/toast";
|
||||
import "./blueprint-script-editor";
|
||||
import "./manual-script-editor";
|
||||
import type { HaManualScriptEditor } from "./manual-script-editor";
|
||||
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||
|
||||
export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@@ -613,14 +611,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
private async _runScript(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
|
||||
if (hasScriptFields(this.hass, this._entityId!)) {
|
||||
showMoreInfoDialog(this, {
|
||||
entityId: this._entityId!,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await triggerScript(this.hass, this.scriptId!);
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.notification_toast.triggered", {
|
||||
@@ -821,7 +811,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
"ui.panel.config.script.editor.id_already_exists_save_error"
|
||||
),
|
||||
dismissable: false,
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
action: {
|
||||
action: () => {},
|
||||
text: this.hass.localize("ui.dialogs.generic.ok"),
|
||||
|
||||
@@ -21,7 +21,7 @@ import { UNAVAILABLE } from "../../../data/entity";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
|
||||
import { AlarmModesCardFeatureConfig } from "./types";
|
||||
import { showEnterCodeDialog } from "../../../dialogs/enter-code/show-enter-code-dialog";
|
||||
import { showEnterCodeDialogDialog } from "../../../dialogs/enter-code/show-enter-code-dialog";
|
||||
|
||||
export const supportsAlarmModesCardFeature = (stateObj: HassEntity) => {
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
@@ -131,7 +131,7 @@ class HuiAlarmModeCardFeature
|
||||
) {
|
||||
const disarm = mode === "disarmed";
|
||||
|
||||
const response = await showEnterCodeDialog(this, {
|
||||
const response = await showEnterCodeDialogDialog(this, {
|
||||
codeFormat: this.stateObj!.attributes.code_format,
|
||||
title: this.hass!.localize(
|
||||
`ui.card.alarm_control_panel.${disarm ? "disarm" : "arm"}`
|
||||
|
||||
@@ -96,10 +96,7 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
}
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
if (
|
||||
(changedProps.has("_hiddenStats") || changedProps.has("_config")) &&
|
||||
this._data
|
||||
) {
|
||||
if (changedProps.has("_hiddenStats") && this._data) {
|
||||
this._processStatistics();
|
||||
}
|
||||
}
|
||||
@@ -220,17 +217,17 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
const datasets: ChartDataset<"bar", ScatterDataPoint[]>[] = [];
|
||||
const datasetExtras: ChartDatasetExtra[] = [];
|
||||
|
||||
const { data: processedData, dataExtras: processedDataExtras } =
|
||||
this._processDataSet(
|
||||
datasets.push(
|
||||
...this._processDataSet(
|
||||
data,
|
||||
energyData.statsMetadata,
|
||||
energyData.prefs.device_consumption,
|
||||
sorted_devices
|
||||
);
|
||||
)
|
||||
);
|
||||
|
||||
datasets.push(...processedData);
|
||||
|
||||
datasetExtras.push(...processedDataExtras);
|
||||
const items = datasets.length;
|
||||
datasetExtras.push(...Array<ChartDatasetExtra>(items).fill({}));
|
||||
|
||||
if (compareData) {
|
||||
// Add empty dataset to align the bars
|
||||
@@ -250,19 +247,18 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
show_legend: false,
|
||||
});
|
||||
|
||||
const {
|
||||
data: processedCompareData,
|
||||
dataExtras: processedCompareDataExtras,
|
||||
} = this._processDataSet(
|
||||
compareData,
|
||||
energyData.statsMetadata,
|
||||
energyData.prefs.device_consumption,
|
||||
sorted_devices,
|
||||
true
|
||||
datasets.push(
|
||||
...this._processDataSet(
|
||||
compareData,
|
||||
energyData.statsMetadata,
|
||||
energyData.prefs.device_consumption,
|
||||
sorted_devices,
|
||||
true
|
||||
)
|
||||
);
|
||||
datasetExtras.push(
|
||||
...Array<ChartDatasetExtra>(items).fill({ show_legend: false })
|
||||
);
|
||||
|
||||
datasets.push(...processedCompareData);
|
||||
datasetExtras.push(...processedCompareDataExtras);
|
||||
}
|
||||
|
||||
this._start = energyData.start;
|
||||
@@ -285,7 +281,6 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
compare = false
|
||||
) {
|
||||
const data: ChartDataset<"bar", ScatterDataPoint[]>[] = [];
|
||||
const dataExtras: ChartDatasetExtra[] = [];
|
||||
|
||||
devices.forEach((source, idx) => {
|
||||
const color = getColorByIndex(idx);
|
||||
@@ -322,30 +317,23 @@ export class HuiEnergyDevicesDetailGraphCard
|
||||
}
|
||||
}
|
||||
|
||||
const order = sorted_devices.indexOf(source.stat_consumption);
|
||||
const itemExceedsMax = !!(
|
||||
this._config?.max_devices && order >= this._config.max_devices
|
||||
);
|
||||
|
||||
data.push({
|
||||
label: getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_consumption,
|
||||
statisticsMetaData[source.stat_consumption]
|
||||
),
|
||||
hidden:
|
||||
this._hiddenStats.has(source.stat_consumption) || itemExceedsMax,
|
||||
hidden: this._hiddenStats.has(source.stat_consumption),
|
||||
borderColor: compare ? color + "7F" : color,
|
||||
backgroundColor: compare ? color + "32" : color + "7F",
|
||||
data: consumptionData,
|
||||
order: 1 + order,
|
||||
order: 1 + sorted_devices.indexOf(source.stat_consumption),
|
||||
stack: "devices",
|
||||
pointStyle: compare ? false : "circle",
|
||||
xAxisID: compare ? "xAxisCompare" : undefined,
|
||||
});
|
||||
dataExtras.push({ show_legend: !compare && !itemExceedsMax });
|
||||
});
|
||||
return { data, dataExtras };
|
||||
return data;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -177,7 +177,7 @@ class HuiEnergyDistrubutionCard
|
||||
if (hasBattery) {
|
||||
batteryFromGrid = solarConsumption * -1;
|
||||
if (batteryFromGrid > totalFromGrid) {
|
||||
batteryToGrid = batteryFromGrid - totalFromGrid;
|
||||
batteryToGrid = Math.min(0, batteryFromGrid - totalFromGrid);
|
||||
batteryFromGrid = totalFromGrid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ class HuiEnergySelfSufficiencyGaugeCard
|
||||
if (hasBattery) {
|
||||
batteryFromGrid = solarConsumption * -1;
|
||||
if (batteryFromGrid > totalFromGrid) {
|
||||
batteryToGrid = batteryFromGrid - totalFromGrid;
|
||||
batteryToGrid = Math.min(0, batteryFromGrid - totalFromGrid);
|
||||
batteryFromGrid = totalFromGrid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,8 +434,10 @@ export class HuiEnergyUsageGraphCard
|
||||
if (summedData.to_battery) {
|
||||
grid_to_battery[start] = used_solar[start] * -1;
|
||||
if (grid_to_battery[start] > (summedData.from_grid?.[start] || 0)) {
|
||||
battery_to_grid[start] =
|
||||
grid_to_battery[start] - (summedData.from_grid?.[start] || 0);
|
||||
battery_to_grid[start] = Math.min(
|
||||
0,
|
||||
grid_to_battery[start] - (summedData.from_grid?.[start] || 0)
|
||||
);
|
||||
grid_to_battery[start] = summedData.from_grid?.[start];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +52,7 @@ import { actionHandler } from "../common/directives/action-handler-directive";
|
||||
import { findEntities } from "../common/find-entities";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
} from "../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { ButtonCardConfig } from "./types";
|
||||
|
||||
export const getEntityDefaultButtonAction = (entityId?: string) =>
|
||||
@@ -147,14 +143,14 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
public getGridSize(): [number, number] {
|
||||
if (
|
||||
this._config?.show_icon &&
|
||||
(this._config?.show_name || this._config?.show_state)
|
||||
) {
|
||||
return { grid_rows: 2, grid_columns: 2 };
|
||||
return [2, 2];
|
||||
}
|
||||
return { grid_rows: 1, grid_columns: 1 };
|
||||
return [1, 1];
|
||||
}
|
||||
|
||||
public setConfig(config: ButtonCardConfig): void {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket/dist/types";
|
||||
import { css, CSSResultGroup } from "lit";
|
||||
import { HassEntity } from "home-assistant-js-websocket/dist/types";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { findEntities } from "../common/find-entities";
|
||||
import { GraphHeaderFooterConfig } from "../header-footer/types";
|
||||
import { LovelaceCardEditor, LovelaceLayoutOptions } from "../types";
|
||||
import { LovelaceCardEditor } from "../types";
|
||||
import { HuiEntityCard } from "./hui-entity-card";
|
||||
import { EntityCardConfig, SensorCardConfig } from "./types";
|
||||
|
||||
@@ -72,11 +72,8 @@ class HuiSensorCard extends HuiEntityCard {
|
||||
super.setConfig(entityCardConfig);
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
return {
|
||||
grid_columns: 2,
|
||||
grid_rows: 2,
|
||||
};
|
||||
public getGridSize(): [number, number] {
|
||||
return [2, 2];
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -48,11 +48,7 @@ import { findEntities } from "../common/find-entities";
|
||||
import { handleAction } from "../common/handle-action";
|
||||
import { hasAction } from "../common/has-action";
|
||||
import "../components/hui-timestamp-display";
|
||||
import type {
|
||||
LovelaceCard,
|
||||
LovelaceCardEditor,
|
||||
LovelaceLayoutOptions,
|
||||
} from "../types";
|
||||
import type { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { renderTileBadge } from "./tile/badges/tile-badge";
|
||||
import type { ThermostatCardConfig, TileCardConfig } from "./types";
|
||||
|
||||
@@ -128,18 +124,16 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
);
|
||||
}
|
||||
|
||||
public getLayoutOptions(): LovelaceLayoutOptions {
|
||||
const options = {
|
||||
grid_columns: 2,
|
||||
grid_rows: 1,
|
||||
};
|
||||
public getGridSize(): [number, number] {
|
||||
const width = 2;
|
||||
let height = 1;
|
||||
if (this._config?.features?.length) {
|
||||
options.grid_rows += Math.ceil((this._config.features.length * 2) / 3);
|
||||
height += Math.ceil((this._config.features.length * 2) / 3);
|
||||
}
|
||||
if (this._config?.vertical) {
|
||||
options.grid_rows++;
|
||||
height++;
|
||||
}
|
||||
return options;
|
||||
return [width, height];
|
||||
}
|
||||
|
||||
private _handleAction(ev: ActionHandlerEvent) {
|
||||
|
||||
@@ -112,9 +112,9 @@ export const computeSection = (
|
||||
({
|
||||
type: "tile",
|
||||
entity,
|
||||
show_entity_picture:
|
||||
["person", "camera", "image"].includes(computeDomain(entity)) ||
|
||||
undefined,
|
||||
show_entity_picture: ["person", "camera", "image"].includes(
|
||||
computeDomain(entity)
|
||||
),
|
||||
}) as TileCardConfig
|
||||
),
|
||||
...sectionOptions,
|
||||
|
||||
@@ -283,8 +283,6 @@ export class HuiCardEditMode extends LitElement {
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: -6px;
|
||||
inset-inline-end: -6px;
|
||||
inset-inline-start: initial;
|
||||
}
|
||||
.more ha-icon-button {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -28,7 +28,6 @@ import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-list-item";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import { saveConfig } from "../../../data/lovelace/config/types";
|
||||
import { isStrategyView } from "../../../data/lovelace/config/view";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showPromptDialog,
|
||||
@@ -52,7 +51,6 @@ import {
|
||||
} from "../editor/lovelace-path";
|
||||
import { showSelectViewDialog } from "../editor/select-view/show-select-view-dialog";
|
||||
import { Lovelace, LovelaceCard } from "../types";
|
||||
import { SECTION_VIEW_LAYOUT } from "../views/const";
|
||||
|
||||
@customElement("hui-card-options")
|
||||
export class HuiCardOptions extends LitElement {
|
||||
@@ -353,21 +351,6 @@ export class HuiCardOptions extends LitElement {
|
||||
allowDashboardChange: true,
|
||||
header: this.hass!.localize("ui.panel.lovelace.editor.move_card.header"),
|
||||
viewSelectedCallback: async (urlPath, selectedDashConfig, viewIndex) => {
|
||||
const view = this.lovelace!.config.views[viewIndex];
|
||||
|
||||
if (!isStrategyView(view) && view.type === SECTION_VIEW_LAYOUT) {
|
||||
showAlertDialog(this, {
|
||||
title: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_card.error_title"
|
||||
),
|
||||
text: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.move_card.error_text_section"
|
||||
),
|
||||
warning: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (urlPath === this.lovelace!.urlPath) {
|
||||
this.lovelace!.saveConfig(
|
||||
moveCardToContainer(this.lovelace!.config, this.path!, [viewIndex])
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
export { showEnterCodeDialog } from "../../dialogs/enter-code/show-enter-code-dialog";
|
||||
export {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
showPromptDialog,
|
||||
} from "../../dialogs/generic/show-dialog-box";
|
||||
export { importMoreInfoControl } from "../../dialogs/more-info/state_more_info_control";
|
||||
export { createBadgeElement } from "./create-element/create-badge-element";
|
||||
export { createCardElement } from "./create-element/create-card-element";
|
||||
|
||||
@@ -131,15 +131,11 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
</mwc-button>
|
||||
${!this._params.yaml
|
||||
? html`
|
||||
${!(this._sectionConfig && this._viewSupportsSection)
|
||||
? html`
|
||||
<mwc-button slot="primaryAction" @click=${this._pickCard}>
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.suggest_card.create_own"
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
: nothing}
|
||||
<mwc-button slot="primaryAction" @click=${this._pickCard}
|
||||
>${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.suggest_card.create_own"
|
||||
)}</mwc-button
|
||||
>
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
.disabled=${this._saving}
|
||||
@@ -158,7 +154,7 @@ export class HuiDialogSuggestCard extends LitElement {
|
||||
)}
|
||||
</mwc-button>
|
||||
`
|
||||
: nothing}
|
||||
: ""}
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import type { SelectViewDialogParams } from "./show-select-view-dialog";
|
||||
import { isStrategyView } from "../../../../data/lovelace/config/view";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@@ -118,10 +117,8 @@ export class HuiDialogSelectView extends LitElement {
|
||||
: this._config.views.length > 1
|
||||
? html`
|
||||
<mwc-list dialogInitialFocus>
|
||||
${this._config.views.map((view, idx) => {
|
||||
const isStrategy = isStrategyView(view);
|
||||
|
||||
return html`
|
||||
${this._config.views.map(
|
||||
(view, idx) => html`
|
||||
<mwc-radio-list-item
|
||||
.graphic=${this._config?.views.some(({ icon }) => icon)
|
||||
? "icon"
|
||||
@@ -129,19 +126,12 @@ export class HuiDialogSelectView extends LitElement {
|
||||
@click=${this._viewChanged}
|
||||
.value=${idx.toString()}
|
||||
.selected=${this._selectedViewIdx === idx}
|
||||
.disabled=${isStrategy &&
|
||||
!this._params?.includeStrategyViews}
|
||||
>
|
||||
<span>
|
||||
${view.title}${isStrategy
|
||||
? ` (${this.hass.localize("ui.panel.lovelace.editor.select_view.strategy_type")})`
|
||||
: nothing}
|
||||
</span>
|
||||
|
||||
<span>${view.title}</span>
|
||||
<ha-icon .icon=${view.icon} slot="graphic"></ha-icon>
|
||||
</mwc-radio-list-item>
|
||||
`;
|
||||
})}
|
||||
`
|
||||
)}
|
||||
</mwc-list>
|
||||
`
|
||||
: ""}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { LovelaceDashboard } from "../../../../data/lovelace/dashboard";
|
||||
export interface SelectViewDialogParams {
|
||||
lovelaceConfig: LovelaceConfig;
|
||||
allowDashboardChange: boolean;
|
||||
includeStrategyViews?: boolean;
|
||||
dashboards?: LovelaceDashboard[];
|
||||
urlPath?: string | null;
|
||||
header?: string;
|
||||
|
||||
@@ -3,5 +3,4 @@ import { object, string, any } from "superstruct";
|
||||
export const baseLovelaceCardConfig = object({
|
||||
type: string(),
|
||||
view_layout: any(),
|
||||
layout_options: any(),
|
||||
});
|
||||
|
||||
@@ -23,6 +23,7 @@ import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-dialog-header";
|
||||
import "../../../../components/ha-yaml-editor";
|
||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||
import { LovelaceBadgeConfig } from "../../../../data/lovelace/config/badge";
|
||||
import {
|
||||
LovelaceViewConfig,
|
||||
isStrategyView,
|
||||
@@ -60,6 +61,8 @@ export class HuiDialogEditView extends LitElement {
|
||||
|
||||
@state() private _config?: LovelaceViewConfig;
|
||||
|
||||
@state() private _badges?: LovelaceBadgeConfig[];
|
||||
|
||||
@state() private _saving = false;
|
||||
|
||||
@state() private _curTab?: string;
|
||||
@@ -85,6 +88,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
if (this._yamlMode && changedProperties.has("_yamlMode")) {
|
||||
const viewConfig = {
|
||||
...this._config,
|
||||
badges: this._badges,
|
||||
};
|
||||
this._editor?.setValue(viewConfig);
|
||||
}
|
||||
@@ -95,6 +99,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
|
||||
if (this._params.viewIndex === undefined) {
|
||||
this._config = {};
|
||||
this._badges = [];
|
||||
this._dirty = false;
|
||||
return;
|
||||
}
|
||||
@@ -103,15 +108,19 @@ export class HuiDialogEditView extends LitElement {
|
||||
if (isStrategyView(view)) {
|
||||
const { strategy, ...viewConfig } = view;
|
||||
this._config = viewConfig;
|
||||
this._badges = [];
|
||||
return;
|
||||
}
|
||||
this._config = view;
|
||||
const { badges, ...viewConfig } = view;
|
||||
this._config = viewConfig;
|
||||
this._badges = badges ? processEditorEntities(badges) : [];
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this._curTabIndex = 0;
|
||||
this._params = undefined;
|
||||
this._config = {};
|
||||
this._badges = [];
|
||||
this._yamlMode = false;
|
||||
this._dirty = false;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
@@ -157,7 +166,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
break;
|
||||
case "tab-badges":
|
||||
content = html`
|
||||
${this._config?.badges?.length
|
||||
${this._badges?.length
|
||||
? html`
|
||||
${VIEWS_NO_BADGE_SUPPORT.includes(this._type)
|
||||
? html`
|
||||
@@ -169,7 +178,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
`
|
||||
: nothing}
|
||||
<div class="preview-badges">
|
||||
${this._config.badges.map(
|
||||
${this._badges.map(
|
||||
(badgeConfig) => html`
|
||||
<hui-badge-preview
|
||||
.hass=${this.hass}
|
||||
@@ -182,7 +191,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
: nothing}
|
||||
<hui-entity-editor
|
||||
.hass=${this.hass}
|
||||
.entities=${this._config?.badges || []}
|
||||
.entities=${this._badges}
|
||||
@entities-changed=${this._badgesChanged}
|
||||
></hui-entity-editor>
|
||||
`;
|
||||
@@ -202,13 +211,6 @@ export class HuiDialogEditView extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
const isCompatibleViewType =
|
||||
this._config?.type === SECTION_VIEW_LAYOUT
|
||||
? this._config?.type === SECTION_VIEW_LAYOUT &&
|
||||
!this._config?.cards?.length
|
||||
: this._config?.type !== SECTION_VIEW_LAYOUT &&
|
||||
!this._config?.sections?.length;
|
||||
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
@@ -267,19 +269,6 @@ export class HuiDialogEditView extends LitElement {
|
||||
: ``}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
${!isCompatibleViewType
|
||||
? html`
|
||||
<ha-alert class="incompatible" alert-type="warning">
|
||||
${this._config?.type === SECTION_VIEW_LAYOUT
|
||||
? this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.type_warning_sections"
|
||||
)
|
||||
: this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.type_warning_others"
|
||||
)}
|
||||
</ha-alert>
|
||||
`
|
||||
: nothing}
|
||||
${!this._yamlMode
|
||||
? html`<paper-tabs
|
||||
scrollable
|
||||
@@ -321,10 +310,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
: nothing}
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
?disabled=${!this._config ||
|
||||
this._saving ||
|
||||
!this._dirty ||
|
||||
!isCompatibleViewType}
|
||||
?disabled=${!this._config || this._saving || !this._dirty}
|
||||
@click=${this._save}
|
||||
>
|
||||
${this._saving
|
||||
@@ -412,12 +398,13 @@ export class HuiDialogEditView extends LitElement {
|
||||
|
||||
this._saving = true;
|
||||
|
||||
const viewConf = {
|
||||
const viewConf: LovelaceViewConfig = {
|
||||
...this._config,
|
||||
badges: this._badges,
|
||||
};
|
||||
|
||||
if (viewConf.type === SECTION_VIEW_LAYOUT && !viewConf.sections?.length) {
|
||||
viewConf.sections = [{ type: "grid", cards: [] }];
|
||||
viewConf.sections = [{ cards: [] }];
|
||||
} else if (!viewConf.cards?.length) {
|
||||
viewConf.cards = [];
|
||||
}
|
||||
@@ -472,22 +459,16 @@ export class HuiDialogEditView extends LitElement {
|
||||
ev: HASSDomEvent<ViewVisibilityChangeEvent>
|
||||
): void {
|
||||
if (ev.detail.visible && this._config) {
|
||||
this._config = {
|
||||
...this._config,
|
||||
visible: ev.detail.visible,
|
||||
};
|
||||
this._config.visible = ev.detail.visible;
|
||||
}
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
private _badgesChanged(ev: EntitiesEditorEvent): void {
|
||||
if (!this.hass || !ev.detail || !ev.detail.entities) {
|
||||
if (!this._badges || !this.hass || !ev.detail || !ev.detail.entities) {
|
||||
return;
|
||||
}
|
||||
this._config = {
|
||||
...this._config,
|
||||
badges: processEditorEntities(ev.detail.entities),
|
||||
};
|
||||
this._badges = processEditorEntities(ev.detail.entities);
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
@@ -496,7 +477,9 @@ export class HuiDialogEditView extends LitElement {
|
||||
if (!ev.detail.isValid) {
|
||||
return;
|
||||
}
|
||||
this._config = ev.detail.value;
|
||||
const { badges, ...config } = ev.detail.value;
|
||||
this._config = config;
|
||||
this._badges = badges;
|
||||
this._dirty = true;
|
||||
}
|
||||
|
||||
@@ -571,9 +554,6 @@ export class HuiDialogEditView extends LitElement {
|
||||
margin: 12px 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.incompatible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media all and (min-width: 600px) {
|
||||
ha-dialog {
|
||||
|
||||
@@ -37,7 +37,7 @@ export class HuiViewEditor extends LitElement {
|
||||
private _suggestedPath = false;
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(localize: LocalizeFunc) =>
|
||||
(localize: LocalizeFunc, currentType: string, isNew: boolean) =>
|
||||
[
|
||||
{ name: "title", selector: { text: {} } },
|
||||
{
|
||||
@@ -64,6 +64,11 @@ export class HuiViewEditor extends LitElement {
|
||||
label: localize(
|
||||
`ui.panel.lovelace.editor.edit_view.types.${type}`
|
||||
),
|
||||
disabled:
|
||||
!isNew &&
|
||||
(currentType === SECTION_VIEW_LAYOUT
|
||||
? type !== SECTION_VIEW_LAYOUT
|
||||
: type === SECTION_VIEW_LAYOUT),
|
||||
})),
|
||||
},
|
||||
},
|
||||
@@ -90,12 +95,16 @@ export class HuiViewEditor extends LitElement {
|
||||
: this._config.type || DEFAULT_VIEW_LAYOUT;
|
||||
}
|
||||
|
||||
private get _isEmpty(): boolean {
|
||||
return !this._config.sections?.length && !this._config.cards?.length;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this.hass) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const schema = this._schema(this.hass.localize);
|
||||
const schema = this._schema(this.hass.localize, this._type, this._isEmpty);
|
||||
|
||||
const data = {
|
||||
...this._config,
|
||||
@@ -159,6 +168,15 @@ export class HuiViewEditor extends LitElement {
|
||||
return this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.subview_helper"
|
||||
);
|
||||
case "type":
|
||||
if (this._isEmpty) return undefined;
|
||||
return this._type === "sections"
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.type_helper_others"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.type_helper_sections"
|
||||
);
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -9,12 +9,13 @@ import {
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { isUnavailableState } from "../../../data/entity";
|
||||
import { canRun, hasScriptFields, ScriptEntity } from "../../../data/script";
|
||||
import { canRun, ScriptEntity } from "../../../data/script";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||
import "../components/hui-generic-entity-row";
|
||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||
import { ActionRowConfig, LovelaceRow } from "./types";
|
||||
import { computeObjectId } from "../../../common/entity/compute_object_id";
|
||||
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||
|
||||
@customElement("hui-script-entity-row")
|
||||
@@ -94,7 +95,10 @@ class HuiScriptEntityRow extends LitElement implements LovelaceRow {
|
||||
private _runScript(ev): void {
|
||||
ev.stopPropagation();
|
||||
|
||||
if (hasScriptFields(this.hass!, this._config!.entity)) {
|
||||
const fields =
|
||||
this.hass!.services.script[computeObjectId(this._config!.entity)]?.fields;
|
||||
|
||||
if (fields && Object.keys(fields).length > 0) {
|
||||
showMoreInfoDialog(this, { entityId: this._config!.entity });
|
||||
} else {
|
||||
this._callService("turn_on");
|
||||
|
||||
@@ -221,7 +221,7 @@ export class LovelacePanel extends LitElement {
|
||||
action: () => this._fetchConfig(false),
|
||||
text: this.hass!.localize("ui.common.refresh"),
|
||||
},
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ class LovelaceFullConfigEditor extends LitElement {
|
||||
"ui.panel.lovelace.editor.raw_editor.reload"
|
||||
),
|
||||
},
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import type { HomeAssistant } from "../../../types";
|
||||
import { HuiErrorCard } from "../cards/hui-error-card";
|
||||
import "../components/hui-card-edit-mode";
|
||||
import { moveCard } from "../editor/config-util";
|
||||
import type { Lovelace, LovelaceCard, LovelaceLayoutOptions } from "../types";
|
||||
import type { Lovelace, LovelaceCard } from "../types";
|
||||
|
||||
const CARD_SORTABLE_OPTIONS: HaSortableOptions = {
|
||||
delay: 100,
|
||||
@@ -96,27 +96,14 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
(_cardConfig, idx) => {
|
||||
const card = this.cards![idx];
|
||||
(card as any).editMode = editMode;
|
||||
(card as any).lovelace = this.lovelace;
|
||||
|
||||
const configOptions = _cardConfig.layout_options;
|
||||
const cardOptions = (card as any)?.getLayoutOptions?.() as
|
||||
| LovelaceLayoutOptions
|
||||
| undefined;
|
||||
|
||||
const options = {
|
||||
...cardOptions,
|
||||
...configOptions,
|
||||
} as LovelaceLayoutOptions;
|
||||
|
||||
const size = card && (card as any).getGridSize?.();
|
||||
return html`
|
||||
<div
|
||||
class="card"
|
||||
style=${styleMap({
|
||||
"--column-size": options.grid_columns,
|
||||
"--row-size": options.grid_rows,
|
||||
"--column-size": size?.[0],
|
||||
"--row-size": size?.[1],
|
||||
})}
|
||||
class="card ${classMap({
|
||||
"fit-rows": typeof options?.grid_rows === "number",
|
||||
})}"
|
||||
>
|
||||
${editMode
|
||||
? html`
|
||||
@@ -183,18 +170,16 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
haStyle,
|
||||
css`
|
||||
:host {
|
||||
--grid-gap: 8px;
|
||||
--grid-row-height: 66px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--grid-gap);
|
||||
gap: 8px;
|
||||
}
|
||||
.container {
|
||||
--column-count: 4;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--column-count), minmax(0, 1fr));
|
||||
grid-auto-rows: minmax(var(--grid-row-height), auto);
|
||||
gap: var(--grid-gap);
|
||||
grid-auto-rows: minmax(66px, auto);
|
||||
gap: 8px;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -203,7 +188,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
padding: 8px;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
border: 2px dashed var(--divider-color);
|
||||
min-height: var(var(--grid-row-height));
|
||||
min-height: 66px;
|
||||
}
|
||||
|
||||
.title {
|
||||
@@ -230,22 +215,6 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
grid-column: span var(--column-size, 4);
|
||||
}
|
||||
|
||||
.card.fit-rows {
|
||||
height: calc(
|
||||
(var(--row-size, 1) * (var(--grid-row-height) + var(--grid-gap))) - var(
|
||||
--grid-gap
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
.card:has(> *) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.card:has(> *[hidden]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.add {
|
||||
outline: none;
|
||||
grid-row: span var(--row-size, 1);
|
||||
@@ -254,7 +223,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
cursor: pointer;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
border: 2px dashed var(--primary-color);
|
||||
height: var(--grid-row-height);
|
||||
height: 66px;
|
||||
order: 1;
|
||||
}
|
||||
.add:focus {
|
||||
|
||||
@@ -39,17 +39,12 @@ export interface LovelaceBadge extends HTMLElement {
|
||||
setConfig(config: LovelaceBadgeConfig): void;
|
||||
}
|
||||
|
||||
export type LovelaceLayoutOptions = {
|
||||
grid_columns?: number;
|
||||
grid_rows?: number;
|
||||
};
|
||||
|
||||
export interface LovelaceCard extends HTMLElement {
|
||||
hass?: HomeAssistant;
|
||||
isPanel?: boolean;
|
||||
editMode?: boolean;
|
||||
getCardSize(): number | Promise<number>;
|
||||
getLayoutOptions?(): LovelaceLayoutOptions;
|
||||
getGridSize?(): [number, number];
|
||||
setConfig(config: LovelaceCardConfig): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -291,12 +291,6 @@ export class MasonryView extends LitElement implements LovelaceViewElement {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.badges {
|
||||
margin: 8px 16px;
|
||||
font-size: 85%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#columns {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { mdiArrowAll, mdiDelete, mdiPencil, mdiViewGridPlus } from "@mdi/js";
|
||||
import {
|
||||
mdiArrowAll,
|
||||
mdiArrowDown,
|
||||
mdiArrowUp,
|
||||
mdiDelete,
|
||||
mdiPencil,
|
||||
mdiViewGridPlus,
|
||||
} from "@mdi/js";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { repeat } from "lit/directives/repeat";
|
||||
@@ -21,6 +28,8 @@ import {
|
||||
} from "../editor/lovelace-path";
|
||||
import { HuiSection } from "../sections/hui-section";
|
||||
import type { Lovelace, LovelaceBadge } from "../types";
|
||||
import { isTouch } from "../../../util/is_touch";
|
||||
import { listenMediaQuery } from "../../../common/dom/media_query";
|
||||
|
||||
@customElement("hui-sections-view")
|
||||
export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
@@ -38,6 +47,23 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
@state() private _config?: LovelaceViewConfig;
|
||||
|
||||
@state() private _narrow = false;
|
||||
|
||||
private _unsubMql?: () => void;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._unsubMql = listenMediaQuery("(max-width: 600px)", (matches) => {
|
||||
this._narrow = matches;
|
||||
});
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._unsubMql?.();
|
||||
this._unsubMql = undefined;
|
||||
}
|
||||
|
||||
public setConfig(config: LovelaceViewConfig): void {
|
||||
this._config = config;
|
||||
}
|
||||
@@ -58,12 +84,14 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
const editMode = this.lovelace.editMode;
|
||||
|
||||
const supportDnD = !(isTouch && this._narrow);
|
||||
|
||||
return html`
|
||||
${this.badges.length > 0
|
||||
? html`<div class="badges">${this.badges}</div>`
|
||||
: ""}
|
||||
<ha-sortable
|
||||
.disabled=${!editMode}
|
||||
.disabled=${!editMode && !supportDnD}
|
||||
@item-moved=${this._sectionMoved}
|
||||
group="section"
|
||||
handle-selector=".handle"
|
||||
@@ -90,11 +118,28 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
? html`
|
||||
<div class="section-overlay">
|
||||
<div class="section-actions">
|
||||
<ha-svg-icon
|
||||
aria-hidden="true"
|
||||
class="handle"
|
||||
.path=${mdiArrowAll}
|
||||
></ha-svg-icon>
|
||||
${supportDnD
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
aria-hidden="true"
|
||||
class="handle"
|
||||
.path=${mdiArrowAll}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: html`
|
||||
<ha-icon-button
|
||||
.label=${"Down"}
|
||||
@click=${this._moveDown}
|
||||
.index=${idx}
|
||||
.path=${mdiArrowDown}
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
.label=${"Up"}
|
||||
@click=${this._moveUp}
|
||||
.index=${idx}
|
||||
.path=${mdiArrowUp}
|
||||
></ha-icon-button>
|
||||
`}
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.edit")}
|
||||
@click=${this._editSection}
|
||||
@@ -119,13 +164,13 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
${editMode
|
||||
? html`
|
||||
<button
|
||||
class="create"
|
||||
@click=${this._createSection}
|
||||
class="add"
|
||||
@click=${this._addSection}
|
||||
aria-label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.create_section"
|
||||
"ui.panel.lovelace.editor.section.add_section"
|
||||
)}
|
||||
.title=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.section.create_section"
|
||||
"ui.panel.lovelace.editor.section.add_section"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiViewGridPlus}></ha-svg-icon>
|
||||
@@ -137,7 +182,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _createSection(): void {
|
||||
private _addSection(): void {
|
||||
const newConfig = addSection(this.lovelace!.config, this.index!, {
|
||||
type: "grid",
|
||||
cards: [],
|
||||
@@ -231,70 +276,84 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
private _moveDown(ev) {
|
||||
ev.stopPropagation();
|
||||
const { index } = ev.currentTarget;
|
||||
|
||||
const newConfig = moveSection(
|
||||
this.lovelace!.config,
|
||||
[this.index!, index],
|
||||
[this.index!, index + 1]
|
||||
);
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
private _moveUp(ev) {
|
||||
ev.stopPropagation();
|
||||
const { index } = ev.currentTarget;
|
||||
|
||||
const newConfig = moveSection(
|
||||
this.lovelace!.config,
|
||||
[this.index!, index],
|
||||
[this.index!, index - 1]
|
||||
);
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
:host {
|
||||
--grid-gap: 32px;
|
||||
--grid-max-section-count: 4;
|
||||
--grid-section-min-width: 320px;
|
||||
--grid-section-max-width: 500px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.badges {
|
||||
margin: 12px 8px 4px 8px;
|
||||
margin: 12px 8px 16px 8px;
|
||||
font-size: 85%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container > * {
|
||||
position: relative;
|
||||
max-width: var(--grid-section-max-width);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.section {
|
||||
position: relative;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
}
|
||||
|
||||
.container {
|
||||
/* Inputs */
|
||||
--grid-gap: 20px;
|
||||
--grid-max-section-count: 4;
|
||||
--grid-section-min-width: 320px;
|
||||
|
||||
/* Calculated */
|
||||
--max-count: min(var(--section-count), var(--grid-max-section-count));
|
||||
--max-width: min(
|
||||
calc(
|
||||
(var(--max-count) + 1) * var(--grid-section-min-width) +
|
||||
(var(--max-count) + 2) * var(--grid-gap) - 1px
|
||||
),
|
||||
calc(
|
||||
var(--max-count) * var(--grid-section-max-width) +
|
||||
(var(--max-count) + 1) * var(--grid-gap)
|
||||
)
|
||||
--grid-max-width: calc(
|
||||
(var(--max-count) + 1) * var(--grid-section-min-width) +
|
||||
(var(--max-count) + 2) * var(--grid-gap) - 1px
|
||||
);
|
||||
|
||||
display: grid;
|
||||
align-items: start;
|
||||
justify-items: center;
|
||||
grid-template-columns: repeat(
|
||||
auto-fit,
|
||||
minmax(min(var(--grid-section-min-width), 100%), 1fr)
|
||||
minmax(var(--grid-section-min-width), 1fr)
|
||||
);
|
||||
grid-gap: 8px var(--grid-gap);
|
||||
padding: 8px var(--grid-gap);
|
||||
justify-content: center;
|
||||
padding: var(--grid-gap);
|
||||
box-sizing: border-box;
|
||||
max-width: var(--max-width);
|
||||
max-width: var(--grid-max-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.container {
|
||||
grid-template-columns: 1fr;
|
||||
--grid-gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.section-actions {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
top: 20px;
|
||||
right: 0;
|
||||
inset-inline-end: 0;
|
||||
inset-inline-start: initial;
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -313,7 +372,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.create {
|
||||
.add {
|
||||
margin-top: calc(66px + 8px);
|
||||
outline: none;
|
||||
background: none;
|
||||
@@ -321,12 +380,12 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
border: 2px dashed var(--primary-color);
|
||||
order: 1;
|
||||
height: calc(66px + (8px + 2px) * 2);
|
||||
height: 66px;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.create:focus {
|
||||
.add:focus {
|
||||
border: 2px solid var(--primary-color);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
AlarmMode,
|
||||
} from "../../data/alarm_control_panel";
|
||||
import { UNAVAILABLE } from "../../data/entity";
|
||||
import { showEnterCodeDialog } from "../../dialogs/enter-code/show-enter-code-dialog";
|
||||
import { showEnterCodeDialogDialog } from "../../dialogs/enter-code/show-enter-code-dialog";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
||||
@customElement("ha-state-control-alarm_control_panel-modes")
|
||||
@@ -56,7 +56,7 @@ export class HaStateControlAlarmControlPanelModes extends LitElement {
|
||||
) {
|
||||
const disarm = mode === "disarmed";
|
||||
|
||||
const response = await showEnterCodeDialog(this, {
|
||||
const response = await showEnterCodeDialogDialog(this, {
|
||||
codeFormat: this.stateObj!.attributes.code_format,
|
||||
title: this.hass!.localize(
|
||||
`ui.card.alarm_control_panel.${disarm ? "disarm" : "arm"}`
|
||||
|
||||
@@ -5,9 +5,10 @@ import { customElement, property } from "lit/decorators";
|
||||
import "../components/entity/ha-entity-toggle";
|
||||
import "../components/entity/state-info";
|
||||
import { isUnavailableState } from "../data/entity";
|
||||
import { canRun, hasScriptFields, ScriptEntity } from "../data/script";
|
||||
import { canRun, ScriptEntity } from "../data/script";
|
||||
import { haStyle } from "../resources/styles";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { computeObjectId } from "../common/entity/compute_object_id";
|
||||
import { showMoreInfoDialog } from "../dialogs/more-info/show-ha-more-info-dialog";
|
||||
|
||||
@customElement("state-card-script")
|
||||
@@ -58,7 +59,11 @@ class StateCardScript extends LitElement {
|
||||
private _runScript(ev: Event) {
|
||||
ev.stopPropagation();
|
||||
|
||||
if (hasScriptFields(this.hass, this.stateObj.entity_id)) {
|
||||
const fields =
|
||||
this.hass!.services.script[computeObjectId(this.stateObj.entity_id)]
|
||||
?.fields;
|
||||
|
||||
if (fields && Object.keys(fields).length > 0) {
|
||||
showMoreInfoDialog(this, { entityId: this.stateObj.entity_id });
|
||||
} else {
|
||||
this._callService("turn_on");
|
||||
|
||||
@@ -38,7 +38,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
message:
|
||||
this.hass!.localize("ui.notification_toast.starting") ||
|
||||
"Home Assistant is starting, not everything will be available until it is finished.",
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
action: {
|
||||
text:
|
||||
@@ -97,7 +97,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
}
|
||||
showToast(this, {
|
||||
message: "",
|
||||
duration: 1,
|
||||
duration: 0,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
this._disconnectedTimeout = undefined;
|
||||
showToast(this, {
|
||||
message: this.hass!.localize("ui.notification_toast.connection_lost"),
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
});
|
||||
}, 1000);
|
||||
@@ -124,7 +124,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
message:
|
||||
this.hass!.localize("ui.notification_toast.wrapping_up_startup") ||
|
||||
`Wrapping up startup, not everything will be available until it is finished.`,
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
action: {
|
||||
text:
|
||||
@@ -148,7 +148,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
integration: domainToName(this.hass!.localize, integration),
|
||||
}) ||
|
||||
`Starting ${integration}, not everything will be available until it is finished.`,
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
action: {
|
||||
text:
|
||||
|
||||
+28
-12
@@ -3195,6 +3195,29 @@
|
||||
"no_logbook_entries": "No Logbook entries found for this step.",
|
||||
"no_variables_changed": "No variables changed",
|
||||
"unable_to_find_config": "Unable to find config"
|
||||
},
|
||||
"messages": {
|
||||
"no_action_executed": "{name}: No action executed",
|
||||
"default_action_executed": "{name}: Default action executed",
|
||||
"action_executed": "{action} action executed",
|
||||
"option_executed": "Option {option} executed",
|
||||
"error": "Error: {error}",
|
||||
"execute_in_parallel": "Execute in parallel",
|
||||
"if": "If",
|
||||
"choose": "Choose",
|
||||
"still_running": "Still running",
|
||||
"debugged": "Debugged",
|
||||
"finished": "Finished at {time} (runtime: {executiontime} seconds)",
|
||||
"aborted": "Aborted at {time} (runtime: {executiontime} seconds)",
|
||||
"cancelled": "Cancelled at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_failed_conditions": "Stopped because a condition failed at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_failed_single": "Stopped because only a single execution is allowed at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_failed_max_runs": "Stopped because maximum number of parallel runs reached at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_error": "Stopped because an error was encountered at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_unknown_reason": "Stopped because of unknown reason {reason} at {time} (runtime: {executiontime} seconds)",
|
||||
"disabled": "(disabled)",
|
||||
"triggered_by": "{triggeredBy, select, \n alias {{alias} triggered}\n other {Triggered} \n} {triggeredPath, select, \n trigger {by the {trigger}}\n other {manually} \n} at {time}",
|
||||
"path_error": "Unable to extract path {path}. Download trace and report as bug."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5112,8 +5135,8 @@
|
||||
"select_users": "Select which users should see this view in the navigation"
|
||||
},
|
||||
"type": "View type",
|
||||
"type_warning_sections": "You can not change your view to use the 'sections' view type because migration is not supported yet. Start from scratch with a new view if you want to experiment with the 'sections' view.",
|
||||
"type_warning_others": "You can not change your view to an other type because migration is not supported yet. Start from scratch with a new view if you want to use another view type.",
|
||||
"type_helper_sections": "You can not change your view to use the 'sections' view type because migration is not supported yet. Start from scratch with a new view if you want to experiment with the 'sections' view.",
|
||||
"type_helper_others": "You can not change your view to an other type because migration is not supported yet. Start from scratch with a new view if you want to use another view type.",
|
||||
|
||||
"types": {
|
||||
"masonry": "Masonry (default)",
|
||||
@@ -5160,9 +5183,7 @@
|
||||
"search_cards": "Search cards"
|
||||
},
|
||||
"move_card": {
|
||||
"header": "Choose a view to move the card to",
|
||||
"error_title": "Impossible to move the card",
|
||||
"error_text_section": "Moving a card to a section view is not supported yet. Use copy/cut/paste instead."
|
||||
"header": "Choose a view to move the card to"
|
||||
},
|
||||
"change_position": {
|
||||
"title": "Change card position",
|
||||
@@ -5173,13 +5194,12 @@
|
||||
"dashboard_label": "Dashboard",
|
||||
"views_label": "View",
|
||||
"no_config": "No config found.",
|
||||
"no_views": "No views in this dashboard.",
|
||||
"strategy_type": "strategy"
|
||||
"no_views": "No views in this dashboard."
|
||||
},
|
||||
"section": {
|
||||
"unnamed_section": "Unnamed section",
|
||||
"add_card": "[%key:ui::panel::lovelace::editor::edit_card::add%]",
|
||||
"create_section": "Create section"
|
||||
"add_section": "Add section"
|
||||
},
|
||||
"delete_section": {
|
||||
"title": "Delete section",
|
||||
@@ -6197,10 +6217,6 @@
|
||||
"watching": "watching",
|
||||
"minutes_abbr": "min"
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"description": "This dashboard is using the sections view released in Home Assistant 2024.3. Learn more about it in this {blog_post}.",
|
||||
"description_blog_post": "blog post"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -48,7 +48,7 @@ export const registerServiceWorker = async (
|
||||
action: () => installingWorker.postMessage({ type: "skipWaiting" }),
|
||||
text: "reload",
|
||||
},
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user