mirror of
https://github.com/home-assistant/frontend.git
synced 2026-07-07 07:54:27 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea9ef9a165 | |||
| 5270ca4db6 | |||
| 12cb94cdc0 | |||
| d473a30263 | |||
| e767b807b0 | |||
| f593fb6043 | |||
| bbf8ee7c64 | |||
| 3d9993563f | |||
| fc3e353e94 | |||
| e9738bd5ae | |||
| 87d9298b20 | |||
| a29b92a92a | |||
| 5b4504688a | |||
| 0a4401b417 | |||
| 8e1e42cd50 | |||
| 014f9b8b73 | |||
| 774c7e275c | |||
| e288b003d8 | |||
| 4aa8518ed6 | |||
| 6acbf6395c | |||
| 2030feabf7 | |||
| 46d1dbcb47 | |||
| 2f6297ec17 | |||
| a3400a2f9c | |||
| c345f41416 | |||
| 292cdc7621 | |||
| c5ba74e0b4 | |||
| 41b24de559 | |||
| 4fe7b18161 | |||
| 399a979c33 | |||
| 03c5482860 | |||
| a116a50604 | |||
| 0dfa292c40 | |||
| 5914a6c1a4 |
@@ -74,7 +74,7 @@ jobs:
|
||||
echo "home-assistant-frontend==$version" > ./requirements.txt
|
||||
|
||||
- name: Build wheels
|
||||
uses: home-assistant/wheels@2023.09.1
|
||||
uses: home-assistant/wheels@2023.10.1
|
||||
with:
|
||||
abi: cp311
|
||||
tag: musllinux_1_2
|
||||
|
||||
@@ -324,8 +324,7 @@ export class HcMain extends HassElement {
|
||||
{
|
||||
type: DEFAULT_STRATEGY,
|
||||
},
|
||||
this.hass!,
|
||||
{ narrow: false }
|
||||
this.hass!
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
+5
-5
@@ -80,7 +80,7 @@
|
||||
"@material/mwc-top-app-bar": "0.27.0",
|
||||
"@material/mwc-top-app-bar-fixed": "0.27.0",
|
||||
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/web": "=1.0.0-pre.17",
|
||||
"@material/web": "=1.0.0",
|
||||
"@mdi/js": "7.2.96",
|
||||
"@mdi/svg": "7.2.96",
|
||||
"@polymer/iron-flex-layout": "3.0.1",
|
||||
@@ -180,7 +180,7 @@
|
||||
"@types/leaflet": "1.9.6",
|
||||
"@types/leaflet-draw": "1.0.8",
|
||||
"@types/luxon": "3.3.2",
|
||||
"@types/mocha": "10.0.1",
|
||||
"@types/mocha": "10.0.2",
|
||||
"@types/qrcode": "1.5.2",
|
||||
"@types/serve-handler": "6.1.2",
|
||||
"@types/sortablejs": "1.15.3",
|
||||
@@ -193,7 +193,7 @@
|
||||
"@web/dev-server-rollup": "0.4.1",
|
||||
"babel-loader": "9.1.3",
|
||||
"babel-plugin-template-html-minifier": "4.1.0",
|
||||
"chai": "4.3.8",
|
||||
"chai": "4.3.10",
|
||||
"del": "7.1.0",
|
||||
"eslint": "8.50.0",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
@@ -209,7 +209,7 @@
|
||||
"esprima": "4.0.1",
|
||||
"fancy-log": "2.0.0",
|
||||
"fs-extra": "11.1.1",
|
||||
"glob": "10.3.7",
|
||||
"glob": "10.3.10",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-flatmap": "1.0.2",
|
||||
"gulp-json-transform": "0.4.8",
|
||||
@@ -223,7 +223,7 @@
|
||||
"lint-staged": "14.0.1",
|
||||
"lit-analyzer": "2.0.0-pre.3",
|
||||
"lodash.template": "4.5.0",
|
||||
"magic-string": "0.30.3",
|
||||
"magic-string": "0.30.4",
|
||||
"map-stream": "0.0.7",
|
||||
"mocha": "10.2.0",
|
||||
"object-hash": "3.0.0",
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20230928.0"
|
||||
version = "20231002.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "The Home Assistant frontend"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
export function getAllCombinations<T>(arr: T[]) {
|
||||
return arr.reduce<T[][]>(
|
||||
(combinations, element) =>
|
||||
combinations.concat(
|
||||
combinations.map((combination) => [...combination, element])
|
||||
),
|
||||
[[]]
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ThemeVars } from "../../data/ws-themes";
|
||||
import { darkStyles, derivedStyles } from "../../resources/styles";
|
||||
import { darkStyles, derivedStyles } from "../../resources/styles-data";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import {
|
||||
hex2rgb,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const NARROW_MEDIA_QUERY = `(max-width: 870px)`;
|
||||
@@ -189,8 +189,13 @@ export class HaForm extends LitElement implements HaFormElement {
|
||||
? ev.detail.value
|
||||
: { [schema.name]: ev.detail.value };
|
||||
|
||||
this.data = {
|
||||
...this.data,
|
||||
...newValue,
|
||||
};
|
||||
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.data, ...newValue },
|
||||
value: this.data,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,22 +7,25 @@ import { fireEvent } from "../common/dom/fire_event";
|
||||
@customElement("ha-formfield")
|
||||
export class HaFormfield extends FormfieldBase {
|
||||
protected _labelClick() {
|
||||
const input = this.input;
|
||||
if (input) {
|
||||
input.focus();
|
||||
switch (input.tagName) {
|
||||
case "HA-CHECKBOX":
|
||||
case "HA-RADIO":
|
||||
if ((input as any).disabled) {
|
||||
break;
|
||||
}
|
||||
(input as any).checked = !(input as any).checked;
|
||||
fireEvent(input, "change");
|
||||
break;
|
||||
default:
|
||||
input.click();
|
||||
break;
|
||||
}
|
||||
const input = this.input as HTMLInputElement | undefined;
|
||||
if (!input) return;
|
||||
|
||||
input.focus();
|
||||
if (input.disabled) {
|
||||
return;
|
||||
}
|
||||
switch (input.tagName) {
|
||||
case "HA-CHECKBOX":
|
||||
input.checked = !input.checked;
|
||||
fireEvent(input, "change");
|
||||
break;
|
||||
case "HA-RADIO":
|
||||
input.checked = true;
|
||||
fireEvent(input, "change");
|
||||
break;
|
||||
default:
|
||||
input.click();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,6 @@ export class HaOutlinedIconButton extends IconButton {
|
||||
--md-ripple-hover-opacity: 0;
|
||||
--md-ripple-pressed-opacity: 0;
|
||||
}
|
||||
.outlined {
|
||||
/* Fix md-outlined-icon-button padding and margin for iOS */
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -60,7 +60,8 @@ export const moreInfoControlCircularSliderStyle = css`
|
||||
justify-content: space-between;
|
||||
}
|
||||
.buttons ha-outlined-icon-button {
|
||||
--md-outlined-icon-button-container-size: 48px;
|
||||
--md-outlined-icon-button-container-width: 48px;
|
||||
--md-outlined-icon-button-container-height: 48px;
|
||||
--md-outlined-icon-button-icon-size: 24px;
|
||||
}
|
||||
/* Accessibility */
|
||||
|
||||
@@ -16,6 +16,7 @@ import "../components/ha-drawer";
|
||||
import { showNotificationDrawer } from "../dialogs/notifications/show-notification-drawer";
|
||||
import type { HomeAssistant, Route } from "../types";
|
||||
import "./partial-panel-resolver";
|
||||
import { NARROW_MEDIA_QUERY } from "../common/util/media_query";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
@@ -50,7 +51,7 @@ export class HomeAssistantMain extends LitElement {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
listenMediaQuery("(max-width: 870px)", (matches) => {
|
||||
listenMediaQuery(NARROW_MEDIA_QUERY, (matches) => {
|
||||
this.narrow = matches;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import { stringCompare } from "../common/string/compare";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
import { ConfigEntry, subscribeConfigEntries } from "../data/config_entries";
|
||||
import { subscribeConfigFlowInProgress } from "../data/config_flow";
|
||||
import { DataEntryFlowProgress } from "../data/data_entry_flow";
|
||||
import { domainToName } from "../data/integration";
|
||||
import { scanUSBDevices } from "../data/usb";
|
||||
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
||||
@@ -24,12 +23,13 @@ import "./integration-badge";
|
||||
import { onBoardingStyles } from "./styles";
|
||||
|
||||
const HIDDEN_DOMAINS = new Set([
|
||||
"google_translate",
|
||||
"hassio",
|
||||
"met",
|
||||
"radio_browser",
|
||||
"rpi_power",
|
||||
"shopping_list",
|
||||
"sun",
|
||||
"google_translate",
|
||||
]);
|
||||
|
||||
@customElement("onboarding-integrations")
|
||||
@@ -40,19 +40,20 @@ class OnboardingIntegrations extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _entries: ConfigEntry[] = [];
|
||||
|
||||
@state() private _discovered?: DataEntryFlowProgress[];
|
||||
@state() private _discoveredDomains?: Set<string>;
|
||||
|
||||
public hassSubscribe(): Array<UnsubscribeFunc | Promise<UnsubscribeFunc>> {
|
||||
return [
|
||||
subscribeConfigFlowInProgress(this.hass, (flows) => {
|
||||
this._discovered = flows.filter(
|
||||
(flow) => !HIDDEN_DOMAINS.has(flow.handler)
|
||||
this._discoveredDomains = new Set(
|
||||
flows
|
||||
.filter((flow) => !HIDDEN_DOMAINS.has(flow.handler))
|
||||
.map((flow) => flow.handler)
|
||||
);
|
||||
this.hass.loadBackendTranslation(
|
||||
"title",
|
||||
Array.from(this._discoveredDomains)
|
||||
);
|
||||
const integrations: Set<string> = new Set();
|
||||
for (const flow of this._discovered) {
|
||||
integrations.add(flow.handler);
|
||||
}
|
||||
this.hass.loadBackendTranslation("title", Array.from(integrations));
|
||||
}),
|
||||
subscribeConfigEntries(
|
||||
this.hass,
|
||||
@@ -97,41 +98,27 @@ class OnboardingIntegrations extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._discovered) {
|
||||
if (!this._discoveredDomains) {
|
||||
return nothing;
|
||||
}
|
||||
// Render discovered and existing entries together sorted by localized title.
|
||||
const entries: Array<[string, string]> = this._entries.map((entry) => [
|
||||
entry.domain,
|
||||
domainToName(this.hass.localize, entry.domain),
|
||||
]);
|
||||
const discovered: Array<[string, string]> = this._discovered.map((flow) => [
|
||||
flow.handler,
|
||||
domainToName(this.hass.localize, flow.handler),
|
||||
]);
|
||||
let domains = [...entries, ...discovered].sort((a, b) =>
|
||||
let uniqueDomains: Set<string> = new Set();
|
||||
this._entries.forEach((entry) => {
|
||||
uniqueDomains.add(entry.domain);
|
||||
});
|
||||
uniqueDomains = new Set([...uniqueDomains, ...this._discoveredDomains]);
|
||||
let domains: Array<[string, string]> = [];
|
||||
for (const domain of uniqueDomains.values()) {
|
||||
domains.push([domain, domainToName(this.hass.localize, domain)]);
|
||||
}
|
||||
domains = domains.sort((a, b) =>
|
||||
stringCompare(a[0], b[0], this.hass.locale.language)
|
||||
);
|
||||
|
||||
const foundDevices = domains.length;
|
||||
const foundIntegrations = domains.length;
|
||||
|
||||
if (domains.length > 12) {
|
||||
const uniqueDomains: Set<string> = new Set();
|
||||
domains.forEach(([domain]) => {
|
||||
uniqueDomains.add(domain);
|
||||
});
|
||||
if (uniqueDomains.size < domains.length) {
|
||||
domains = domains.filter(([domain]) => {
|
||||
if (uniqueDomains.has(domain)) {
|
||||
uniqueDomains.delete(domain);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
if (domains.length > 12) {
|
||||
domains = domains.slice(0, 11);
|
||||
}
|
||||
domains = domains.slice(0, 11);
|
||||
}
|
||||
|
||||
return html`
|
||||
@@ -152,11 +139,11 @@ class OnboardingIntegrations extends SubscribeMixin(LitElement) {
|
||||
.darkOptimizedIcon=${this.hass.themes?.darkMode}
|
||||
></integration-badge>`
|
||||
)}
|
||||
${foundDevices > domains.length
|
||||
${foundIntegrations > domains.length
|
||||
? html`<div class="more">
|
||||
${this.onboardingLocalize(
|
||||
"ui.panel.page-onboarding.integration.more_integrations",
|
||||
{ count: foundDevices - domains.length }
|
||||
{ count: foundIntegrations - domains.length }
|
||||
)}
|
||||
</div>`
|
||||
: nothing}
|
||||
|
||||
@@ -110,16 +110,14 @@ class HaConfigSectionStorage extends LitElement {
|
||||
></ha-metric>
|
||||
${this._hostInfo.disk_life_time !== "" &&
|
||||
this._hostInfo.disk_life_time >= 10
|
||||
? html`
|
||||
? // prettier-ignore
|
||||
html`
|
||||
<ha-metric
|
||||
.heading=${this.hass.localize(
|
||||
"ui.panel.config.storage.emmc_lifetime_used"
|
||||
)}
|
||||
.value=${this._hostInfo.disk_life_time}
|
||||
.tooltip=${`${
|
||||
this._hostInfo.disk_life_time - 10
|
||||
} % -
|
||||
${this._hostInfo.disk_life_time} %`}
|
||||
.tooltip=${`${this._hostInfo.disk_life_time - 10}% - ${this._hostInfo.disk_life_time}%`}
|
||||
class="emmc"
|
||||
></ha-metric>
|
||||
`
|
||||
|
||||
+22
-4
@@ -14,6 +14,7 @@ import { AssistPipeline } from "../../../../data/assist_pipeline";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { fetchWakeWordInfo, WakeWord } from "../../../../data/wake_word";
|
||||
import { documentationUrl } from "../../../../util/documentation-url";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
|
||||
@customElement("assist-pipeline-detail-wakeword")
|
||||
export class AssistPipelineDetailWakeWord extends LitElement {
|
||||
@@ -71,6 +72,11 @@ export class AssistPipelineDetailWakeWord extends LitElement {
|
||||
changedProps.has("data") &&
|
||||
changedProps.get("data")?.wake_word_entity !== this.data?.wake_word_entity
|
||||
) {
|
||||
if (this.data?.wake_word_id) {
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.data, wake_word_id: undefined },
|
||||
});
|
||||
}
|
||||
this._fetchWakeWords();
|
||||
}
|
||||
}
|
||||
@@ -122,13 +128,25 @@ export class AssistPipelineDetailWakeWord extends LitElement {
|
||||
}
|
||||
|
||||
private async _fetchWakeWords() {
|
||||
this._wakeWords = undefined;
|
||||
if (!this.data?.wake_word_entity) {
|
||||
this._wakeWords = undefined;
|
||||
return;
|
||||
}
|
||||
this._wakeWords = (
|
||||
await fetchWakeWordInfo(this.hass, this.data.wake_word_entity)
|
||||
).wake_words;
|
||||
const wakeWordEntity = this.data.wake_word_entity;
|
||||
const wakewordInfo = await fetchWakeWordInfo(this.hass, wakeWordEntity);
|
||||
if (this.data.wake_word_entity !== wakeWordEntity) {
|
||||
// wake word entity changed while we were fetching
|
||||
return;
|
||||
}
|
||||
this._wakeWords = wakewordInfo.wake_words;
|
||||
if (
|
||||
!this.data?.wake_word_id ||
|
||||
!this._wakeWords.some((ww) => ww.id === this.data!.wake_word_id)
|
||||
) {
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.data, wake_word_id: this._wakeWords[0]?.id },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
||||
@@ -246,7 +246,10 @@ export class AssistPipelineRunDebug extends LitElement {
|
||||
const url = updatedRun.tts!.tts_output!.url;
|
||||
const audio = new Audio(url);
|
||||
audio.addEventListener("ended", () => {
|
||||
if (this._continueConversationCheckbox.checked) {
|
||||
if (
|
||||
this.isConnected &&
|
||||
this._continueConversationCheckbox.checked
|
||||
) {
|
||||
this._runAudioWakeWordPipeline();
|
||||
} else {
|
||||
this._finished = true;
|
||||
@@ -320,7 +323,10 @@ export class AssistPipelineRunDebug extends LitElement {
|
||||
const url = updatedRun.tts!.tts_output!.url;
|
||||
const audio = new Audio(url);
|
||||
audio.addEventListener("ended", () => {
|
||||
if (this._continueConversationCheckbox.checked) {
|
||||
if (
|
||||
this.isConnected &&
|
||||
this._continueConversationCheckbox.checked
|
||||
) {
|
||||
this._runAudioPipeline();
|
||||
} else {
|
||||
this._finished = true;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { NARROW_MEDIA_QUERY } from "../../../common/util/media_query";
|
||||
import {
|
||||
EnergyPreferences,
|
||||
getEnergyPreferences,
|
||||
@@ -10,7 +11,6 @@ import {
|
||||
LovelaceViewConfig,
|
||||
} from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceStrategyParams } from "../../lovelace/strategies/types";
|
||||
|
||||
const setupWizard = async (): Promise<LovelaceViewConfig> => {
|
||||
await import("../cards/energy-setup-wizard-card");
|
||||
@@ -32,8 +32,7 @@ export interface EnergeryViewStrategyConfig extends LovelaceStrategyConfig {
|
||||
export class EnergyViewStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
config: EnergeryViewStrategyConfig,
|
||||
hass: HomeAssistant,
|
||||
params: LovelaceStrategyParams
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
const view: LovelaceViewConfig = { cards: [] };
|
||||
|
||||
@@ -67,11 +66,24 @@ export class EnergyViewStrategy extends ReactiveElement {
|
||||
(source) => source.type === "water"
|
||||
);
|
||||
|
||||
if (params.narrow || config.show_date_selection) {
|
||||
const dateSelectionCard = {
|
||||
type: "energy-date-selection",
|
||||
collection_key: "energy_dashboard",
|
||||
view_layout: { position: "sidebar" },
|
||||
};
|
||||
|
||||
if (config.show_date_selection) {
|
||||
view.cards!.push(dateSelectionCard);
|
||||
} else {
|
||||
view.cards!.push({
|
||||
type: "energy-date-selection",
|
||||
collection_key: "energy_dashboard",
|
||||
view_layout: { position: "sidebar" },
|
||||
type: "conditional",
|
||||
conditions: [
|
||||
{
|
||||
condition: "screen",
|
||||
media_query: NARROW_MEDIA_QUERY,
|
||||
},
|
||||
],
|
||||
card: dateSelectionCard,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { mdiResponsive, mdiStateMachine } from "@mdi/js";
|
||||
import { Condition } from "./validate-condition";
|
||||
|
||||
export const ICON_CONDITION: Record<Condition["condition"], string> = {
|
||||
state: mdiStateMachine,
|
||||
screen: mdiResponsive,
|
||||
};
|
||||
@@ -1,10 +1,44 @@
|
||||
import { UNAVAILABLE } from "../../../data/entity";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
export interface Condition {
|
||||
entity: string;
|
||||
export type Condition = StateCondition | ScreenCondition;
|
||||
|
||||
export type LegacyCondition = {
|
||||
entity?: string;
|
||||
state?: string;
|
||||
state_not?: string;
|
||||
};
|
||||
|
||||
export type StateCondition = {
|
||||
condition: "state";
|
||||
entity?: string;
|
||||
state?: string;
|
||||
state_not?: string;
|
||||
};
|
||||
|
||||
export type ScreenCondition = {
|
||||
condition: "screen";
|
||||
media_query?: string;
|
||||
};
|
||||
|
||||
function checkStateCondition(condition: StateCondition, hass: HomeAssistant) {
|
||||
const state =
|
||||
condition.entity && hass.states[condition.entity]
|
||||
? hass.states[condition.entity].state
|
||||
: UNAVAILABLE;
|
||||
|
||||
return condition.state != null
|
||||
? state === condition.state
|
||||
: state !== condition.state_not;
|
||||
}
|
||||
|
||||
function checkScreenCondition(
|
||||
condition: ScreenCondition,
|
||||
_hass: HomeAssistant
|
||||
) {
|
||||
return condition.media_query
|
||||
? matchMedia(condition.media_query).matches
|
||||
: false;
|
||||
}
|
||||
|
||||
export function checkConditionsMet(
|
||||
@@ -12,18 +46,30 @@ export function checkConditionsMet(
|
||||
hass: HomeAssistant
|
||||
): boolean {
|
||||
return conditions.every((c) => {
|
||||
const state = hass.states[c.entity]
|
||||
? hass!.states[c.entity].state
|
||||
: UNAVAILABLE;
|
||||
if (c.condition === "screen") {
|
||||
return checkScreenCondition(c, hass);
|
||||
}
|
||||
|
||||
return c.state != null ? state === c.state : state !== c.state_not;
|
||||
return checkStateCondition(c, hass);
|
||||
});
|
||||
}
|
||||
|
||||
export function validateConditionalConfig(conditions: Condition[]): boolean {
|
||||
return conditions.every(
|
||||
(c) =>
|
||||
(c.entity &&
|
||||
(c.state != null || c.state_not != null)) as unknown as boolean
|
||||
function valideStateCondition(condition: StateCondition) {
|
||||
return (
|
||||
condition.entity != null &&
|
||||
(condition.state != null || condition.state_not != null)
|
||||
);
|
||||
}
|
||||
|
||||
function validateScreenCondition(condition: ScreenCondition) {
|
||||
return condition.media_query != null;
|
||||
}
|
||||
|
||||
export function validateConditionalConfig(conditions: Condition[]): boolean {
|
||||
return conditions.every((c) => {
|
||||
if (c.condition === "screen") {
|
||||
return validateScreenCondition(c);
|
||||
}
|
||||
return valideStateCondition(c);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,11 +3,14 @@ import { customElement, property } from "lit/decorators";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ConditionalCardConfig } from "../cards/types";
|
||||
import {
|
||||
ScreenCondition,
|
||||
checkConditionsMet,
|
||||
validateConditionalConfig,
|
||||
} from "../common/validate-condition";
|
||||
import { ConditionalRowConfig, LovelaceRow } from "../entity-rows/types";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { listenMediaQuery } from "../../../common/dom/media_query";
|
||||
import { deepEqual } from "../../../common/util/deep-equal";
|
||||
|
||||
@customElement("hui-conditional-base")
|
||||
export class HuiConditionalBase extends ReactiveElement {
|
||||
@@ -21,6 +24,10 @@ export class HuiConditionalBase extends ReactiveElement {
|
||||
|
||||
protected _element?: LovelaceCard | LovelaceRow;
|
||||
|
||||
private _mediaQueriesListeners: Array<() => void> = [];
|
||||
|
||||
private _mediaQueries: string[] = [];
|
||||
|
||||
protected createRenderRoot() {
|
||||
return this;
|
||||
}
|
||||
@@ -47,27 +54,98 @@ export class HuiConditionalBase extends ReactiveElement {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._clearMediaQueries();
|
||||
}
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._listenMediaQueries();
|
||||
this._updateVisibility();
|
||||
}
|
||||
|
||||
private _clearMediaQueries() {
|
||||
this._mediaQueries = [];
|
||||
while (this._mediaQueriesListeners.length) {
|
||||
this._mediaQueriesListeners.pop()!();
|
||||
}
|
||||
}
|
||||
|
||||
private _listenMediaQueries() {
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
|
||||
const conditions = this._config.conditions.filter(
|
||||
(c) => c.condition === "screen"
|
||||
) as ScreenCondition[];
|
||||
|
||||
const mediaQueries = conditions
|
||||
.filter((c) => c.media_query)
|
||||
.map((c) => c.media_query as string);
|
||||
|
||||
if (deepEqual(mediaQueries, this._mediaQueries)) return;
|
||||
|
||||
this._mediaQueries = mediaQueries;
|
||||
while (this._mediaQueriesListeners.length) {
|
||||
this._mediaQueriesListeners.pop()!();
|
||||
}
|
||||
mediaQueries.forEach((query) => {
|
||||
const listener = listenMediaQuery(query, (matches) => {
|
||||
// For performance, if there is only one condition, set the visibility directly
|
||||
if (this._config!.conditions.length === 1) {
|
||||
this._setVisibility(matches);
|
||||
return;
|
||||
}
|
||||
this._updateVisibility();
|
||||
});
|
||||
this._mediaQueriesListeners.push(listener);
|
||||
});
|
||||
}
|
||||
|
||||
protected update(changed: PropertyValues): void {
|
||||
super.update(changed);
|
||||
|
||||
if (
|
||||
changed.has("_element") ||
|
||||
changed.has("_config") ||
|
||||
changed.has("hass")
|
||||
) {
|
||||
this._listenMediaQueries();
|
||||
this._updateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private _updateVisibility() {
|
||||
if (!this._element || !this.hass || !this._config) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._element.editMode = this.editMode;
|
||||
|
||||
const visible =
|
||||
this.editMode || checkConditionsMet(this._config.conditions, this.hass);
|
||||
this.hidden = !visible;
|
||||
const conditionMet = checkConditionsMet(
|
||||
this._config!.conditions,
|
||||
this.hass!
|
||||
);
|
||||
this._setVisibility(conditionMet);
|
||||
}
|
||||
|
||||
private _setVisibility(conditionMet: boolean) {
|
||||
if (!this._element || !this.hass) {
|
||||
return;
|
||||
}
|
||||
const visible = this.editMode || conditionMet;
|
||||
this.hidden = !visible;
|
||||
this.style.setProperty("display", visible ? "" : "none");
|
||||
|
||||
if (visible) {
|
||||
this._element.hass = this.hass;
|
||||
if (!this._element.parentElement) {
|
||||
this.appendChild(this._element);
|
||||
if (!this._element!.parentElement) {
|
||||
this.appendChild(this._element!);
|
||||
}
|
||||
} else if (this._element.parentElement) {
|
||||
this.removeChild(this._element);
|
||||
this.removeChild(this._element!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
import { preventDefault } from "@fullcalendar/core/internal";
|
||||
import { ActionDetail } from "@material/mwc-list";
|
||||
import { mdiCheck, mdiDelete, mdiDotsVertical } from "@mdi/js";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import "../../../../components/ha-list-item";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import "../../../../components/ha-yaml-editor";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { Condition, LegacyCondition } from "../../common/validate-condition";
|
||||
import type { LovelaceConditionEditorConstructor } from "./types";
|
||||
import { ICON_CONDITION } from "../../common/icon-condition";
|
||||
|
||||
@customElement("ha-card-condition-editor")
|
||||
export default class HaCardConditionEditor extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) condition!: Condition | LegacyCondition;
|
||||
|
||||
@state() public _yamlMode = false;
|
||||
|
||||
protected render() {
|
||||
const condition: Condition = {
|
||||
condition: "state",
|
||||
...this.condition,
|
||||
};
|
||||
const element = customElements.get(
|
||||
`ha-card-condition-${condition.condition}`
|
||||
) as LovelaceConditionEditorConstructor | undefined;
|
||||
const supported = element !== undefined;
|
||||
|
||||
const valid =
|
||||
element &&
|
||||
(!element.validateUIConfig || element.validateUIConfig(condition));
|
||||
|
||||
const yamlMode = this._yamlMode || !supported || !valid;
|
||||
|
||||
return html`
|
||||
<div class="header">
|
||||
<ha-svg-icon
|
||||
class="icon"
|
||||
.path=${ICON_CONDITION[condition.condition]}
|
||||
></ha-svg-icon>
|
||||
<span class="title">
|
||||
${this.hass.localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.${condition.condition}.label`
|
||||
) || condition.condition}
|
||||
</span>
|
||||
<ha-button-menu
|
||||
slot="icons"
|
||||
@action=${this._handleAction}
|
||||
@click=${preventDefault}
|
||||
@closed=${stopPropagation}
|
||||
fixed
|
||||
.corner=${"BOTTOM_END"}
|
||||
.menuCorner=${"END"}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
>
|
||||
</ha-icon-button>
|
||||
|
||||
<ha-list-item graphic="icon" .disabled=${!supported || !valid}>
|
||||
${this.hass.localize("ui.panel.lovelace.editor.edit_card.edit_ui")}
|
||||
${!yamlMode
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
class="selected_menu_item"
|
||||
slot="graphic"
|
||||
.path=${mdiCheck}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: ``}
|
||||
</ha-list-item>
|
||||
|
||||
<ha-list-item graphic="icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_card.edit_yaml"
|
||||
)}
|
||||
${yamlMode
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
class="selected_menu_item"
|
||||
slot="graphic"
|
||||
.path=${mdiCheck}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: ``}
|
||||
</ha-list-item>
|
||||
|
||||
<li divider role="separator"></li>
|
||||
|
||||
<ha-list-item class="warning" graphic="icon">
|
||||
${this.hass!.localize("ui.common.delete")}
|
||||
<ha-svg-icon
|
||||
class="warning"
|
||||
slot="graphic"
|
||||
.path=${mdiDelete}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
${!valid
|
||||
? html`
|
||||
<ha-alert alert-type="warning">
|
||||
${this.hass.localize("ui.errors.config.editor_not_supported")}
|
||||
</ha-alert>
|
||||
`
|
||||
: nothing}
|
||||
<div class="content">
|
||||
${yamlMode
|
||||
? html`
|
||||
<ha-yaml-editor
|
||||
.hass=${this.hass}
|
||||
.defaultValue=${this.condition}
|
||||
@value-changed=${this._onYamlChange}
|
||||
></ha-yaml-editor>
|
||||
`
|
||||
: html`
|
||||
${dynamicElement(`ha-card-condition-${condition.condition}`, {
|
||||
hass: this.hass,
|
||||
condition: condition,
|
||||
})}
|
||||
`}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
this._yamlMode = false;
|
||||
break;
|
||||
case 1:
|
||||
this._yamlMode = true;
|
||||
break;
|
||||
case 2:
|
||||
this._delete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _delete() {
|
||||
fireEvent(this, "value-changed", { value: null });
|
||||
}
|
||||
|
||||
private _onYamlChange(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (!ev.detail.isValid) {
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
|
||||
static styles = [
|
||||
haStyle,
|
||||
css`
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.header span {
|
||||
flex: 1;
|
||||
font-size: 16px;
|
||||
}
|
||||
.content {
|
||||
padding: 12px;
|
||||
}
|
||||
.header .icon {
|
||||
padding: 12px;
|
||||
}
|
||||
.selected_menu_item {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
li[role="separator"] {
|
||||
border-bottom-color: var(--divider-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-card-condition-editor": HaCardConditionEditor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Condition } from "../../common/validate-condition";
|
||||
|
||||
export interface LovelaceConditionEditorConstructor {
|
||||
defaultConfig?: Condition;
|
||||
validateUIConfig?: (condition: Condition) => boolean;
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { getAllCombinations } from "../../../../../common/array/combinations";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { LocalizeFunc } from "../../../../../common/translations/localize";
|
||||
import "../../../../../components/ha-form/ha-form";
|
||||
import type { SchemaUnion } from "../../../../../components/ha-form/types";
|
||||
import { HaFormSchema } from "../../../../../components/ha-form/types";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { ScreenCondition } from "../../../common/validate-condition";
|
||||
|
||||
const BREAKPOINT_VALUES = [0, 768, 1024, 1280, Infinity];
|
||||
const BREAKPOINTS = ["mobile", "tablet", "desktop", "wide"] as const;
|
||||
|
||||
type BreakpointSize = [number, number];
|
||||
type Breakpoint = (typeof BREAKPOINTS)[number];
|
||||
|
||||
function mergeConsecutiveRanges(arr: [number, number][]): [number, number][] {
|
||||
if (arr.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
[...arr].sort((a, b) => a[0] - b[0]);
|
||||
|
||||
const mergedRanges = [arr[0]];
|
||||
|
||||
for (let i = 1; i < arr.length; i++) {
|
||||
const currentRange = arr[i];
|
||||
const previousRange = mergedRanges[mergedRanges.length - 1];
|
||||
|
||||
if (currentRange[0] <= previousRange[1] + 1) {
|
||||
previousRange[1] = currentRange[1];
|
||||
} else {
|
||||
mergedRanges.push(currentRange);
|
||||
}
|
||||
}
|
||||
|
||||
return mergedRanges;
|
||||
}
|
||||
|
||||
function buildMediaQuery(size: BreakpointSize) {
|
||||
const [min, max] = size;
|
||||
const query: string[] = [];
|
||||
if (min != null) {
|
||||
query.push(`(min-width: ${min}px)`);
|
||||
}
|
||||
if (max != null && max !== Infinity) {
|
||||
query.push(`(max-width: ${max - 1}px)`);
|
||||
}
|
||||
return query.join(" and ");
|
||||
}
|
||||
|
||||
function computeBreakpointsSize(breakpoints: Breakpoint[]) {
|
||||
const sizes = breakpoints.map<BreakpointSize>((breakpoint) => {
|
||||
const index = BREAKPOINTS.indexOf(breakpoint);
|
||||
return [BREAKPOINT_VALUES[index], BREAKPOINT_VALUES[index + 1] || Infinity];
|
||||
});
|
||||
|
||||
const mergedSizes = mergeConsecutiveRanges(sizes);
|
||||
|
||||
const queries = mergedSizes
|
||||
.map((size) => buildMediaQuery(size))
|
||||
.filter((size) => size);
|
||||
|
||||
return queries.join(", ");
|
||||
}
|
||||
|
||||
function computeBreakpointsKey(breakpoints) {
|
||||
return [...breakpoints].sort().join("_");
|
||||
}
|
||||
|
||||
// Compute all possible media queries from each breakpoints combination (2 ^ breakpoints = 16)
|
||||
const queries = getAllCombinations(BREAKPOINTS as unknown as Breakpoint[])
|
||||
.filter((arr) => arr.length !== 0)
|
||||
.map(
|
||||
(breakpoints) =>
|
||||
[breakpoints, computeBreakpointsSize(breakpoints)] as [
|
||||
Breakpoint[],
|
||||
string,
|
||||
]
|
||||
);
|
||||
|
||||
// Store them in maps to avoid recomputing them
|
||||
const mediaQueryMap = new Map(
|
||||
queries.map(([b, m]) => [computeBreakpointsKey(b), m])
|
||||
);
|
||||
const mediaQueryReverseMap = new Map(queries.map(([b, m]) => [m, b]));
|
||||
|
||||
type ScreenConditionData = {
|
||||
breakpoints: Breakpoint[];
|
||||
};
|
||||
|
||||
@customElement("ha-card-condition-screen")
|
||||
export class HaCardConditionScreen extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public condition!: ScreenCondition;
|
||||
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
||||
public static get defaultConfig(): ScreenCondition {
|
||||
return { condition: "screen", media_query: "" };
|
||||
}
|
||||
|
||||
protected static validateUIConfig(condition: ScreenCondition) {
|
||||
return (
|
||||
!condition.media_query || mediaQueryReverseMap.get(condition.media_query)
|
||||
);
|
||||
}
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(localize: LocalizeFunc) =>
|
||||
[
|
||||
{
|
||||
name: "breakpoints",
|
||||
selector: {
|
||||
select: {
|
||||
mode: "list",
|
||||
options: BREAKPOINTS.map((b) => {
|
||||
const value = BREAKPOINT_VALUES[BREAKPOINTS.indexOf(b)];
|
||||
return {
|
||||
value: b,
|
||||
label: `${localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.screen.breakpoints_list.${b}`
|
||||
)}${
|
||||
value
|
||||
? ` (${localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.screen.min`,
|
||||
{ size: value }
|
||||
)})`
|
||||
: ""
|
||||
}`,
|
||||
};
|
||||
}),
|
||||
multiple: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
] as const satisfies readonly HaFormSchema[]
|
||||
);
|
||||
|
||||
protected render() {
|
||||
const breakpoints = this.condition.media_query
|
||||
? mediaQueryReverseMap.get(this.condition.media_query)
|
||||
: undefined;
|
||||
|
||||
const data: ScreenConditionData = {
|
||||
breakpoints: breakpoints ?? [],
|
||||
};
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${data}
|
||||
.schema=${this._schema(this.hass.localize)}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._valueChanged}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
></ha-form>
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
const data = ev.detail.value as ScreenConditionData;
|
||||
|
||||
const { breakpoints } = data;
|
||||
|
||||
const condition: ScreenCondition = {
|
||||
condition: "screen",
|
||||
media_query: mediaQueryMap.get(computeBreakpointsKey(breakpoints)) ?? "",
|
||||
};
|
||||
|
||||
fireEvent(this, "value-changed", { value: condition });
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
): string => {
|
||||
switch (schema.name) {
|
||||
case "breakpoints":
|
||||
return this.hass.localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.screen.${schema.name}`
|
||||
);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-card-condition-screen": HaCardConditionScreen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
import { html, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { assert, literal, object, optional, string } from "superstruct";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { LocalizeFunc } from "../../../../../common/translations/localize";
|
||||
import "../../../../../components/ha-form/ha-form";
|
||||
import type { SchemaUnion } from "../../../../../components/ha-form/types";
|
||||
import { HaFormSchema } from "../../../../../components/ha-form/types";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { StateCondition } from "../../../common/validate-condition";
|
||||
|
||||
const stateConditionStruct = object({
|
||||
condition: literal("state"),
|
||||
entity: string(),
|
||||
state: optional(string()),
|
||||
state_not: optional(string()),
|
||||
});
|
||||
|
||||
type StateConditionData = {
|
||||
condition: "state";
|
||||
entity: string;
|
||||
invert: "true" | "false";
|
||||
state?: string;
|
||||
};
|
||||
|
||||
@customElement("ha-card-condition-state")
|
||||
export class HaCardConditionState extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public condition!: StateCondition;
|
||||
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
||||
public static get defaultConfig(): StateCondition {
|
||||
return { condition: "state", entity: "", state: "" };
|
||||
}
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues): void {
|
||||
if (!changedProperties.has("condition")) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
assert(this.condition, stateConditionStruct);
|
||||
} catch (err: any) {
|
||||
fireEvent(this, "ui-mode-not-available", err);
|
||||
}
|
||||
}
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(localize: LocalizeFunc) =>
|
||||
[
|
||||
{ name: "entity", selector: { entity: {} } },
|
||||
{
|
||||
name: "",
|
||||
type: "grid",
|
||||
schema: [
|
||||
{
|
||||
name: "invert",
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: [
|
||||
{
|
||||
label: localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.state_equal"
|
||||
),
|
||||
value: "false",
|
||||
},
|
||||
{
|
||||
label: localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.state_not_equal"
|
||||
),
|
||||
value: "true",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "state",
|
||||
selector: {
|
||||
state: {},
|
||||
},
|
||||
context: {
|
||||
filter_entity: "entity",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
] as const satisfies readonly HaFormSchema[]
|
||||
);
|
||||
|
||||
protected render() {
|
||||
const { state, state_not, ...content } = this.condition;
|
||||
|
||||
const data: StateConditionData = {
|
||||
...content,
|
||||
entity: this.condition.entity ?? "",
|
||||
invert: this.condition.state_not ? "true" : "false",
|
||||
state: this.condition.state_not ?? this.condition.state ?? "",
|
||||
};
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${data}
|
||||
.schema=${this._schema(this.hass.localize)}
|
||||
.disabled=${this.disabled}
|
||||
@value-changed=${this._valueChanged}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
></ha-form>
|
||||
`;
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
const data = ev.detail.value as StateConditionData;
|
||||
|
||||
const { invert, state, entity, condition: _, ...content } = data;
|
||||
|
||||
const condition: StateCondition = {
|
||||
condition: "state",
|
||||
...content,
|
||||
entity: entity ?? "",
|
||||
state: invert === "false" ? state ?? "" : undefined,
|
||||
state_not: invert === "true" ? state ?? "" : undefined,
|
||||
};
|
||||
|
||||
fireEvent(this, "value-changed", { value: condition });
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
): string => {
|
||||
const entity = this.condition.entity
|
||||
? this.hass.states[this.condition.entity]
|
||||
: undefined;
|
||||
switch (schema.name) {
|
||||
case "entity":
|
||||
return this.hass.localize("ui.components.entity.entity-picker.entity");
|
||||
case "state":
|
||||
if (entity) {
|
||||
return `${this.hass.localize(
|
||||
"ui.components.entity.entity-state-picker.state"
|
||||
)} (${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.current_state"
|
||||
)}: ${this.hass.formatEntityState(entity)})`;
|
||||
}
|
||||
return `${this.hass.localize(
|
||||
"ui.components.entity.entity-state-picker.state"
|
||||
)}`;
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-card-condition-state": HaCardConditionState;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,56 @@
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import "@material/mwc-tab-bar/mwc-tab-bar";
|
||||
import "@material/mwc-tab/mwc-tab";
|
||||
import { mdiCodeBraces, mdiContentCopy, mdiListBoxOutline } from "@mdi/js";
|
||||
import deepClone from "deep-clone-simple";
|
||||
import type { MDCTabBarActivatedEvent } from "@material/tab-bar";
|
||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import {
|
||||
any,
|
||||
array,
|
||||
assert,
|
||||
assign,
|
||||
object,
|
||||
optional,
|
||||
string,
|
||||
} from "superstruct";
|
||||
mdiCodeBraces,
|
||||
mdiContentCopy,
|
||||
mdiListBoxOutline,
|
||||
mdiPlus,
|
||||
} from "@mdi/js";
|
||||
import deepClone from "deep-clone-simple";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { any, array, assert, assign, object, optional } from "superstruct";
|
||||
import { storage } from "../../../../common/decorators/storage";
|
||||
import { fireEvent, HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
import "../../../../components/entity/ha-entity-picker";
|
||||
import "../../../../components/ha-select";
|
||||
import "../../../../components/ha-textfield";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-list-item";
|
||||
import "../../../../components/ha-menu-button";
|
||||
import type { HaSelect } from "../../../../components/ha-select";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import type {
|
||||
LovelaceCardConfig,
|
||||
LovelaceConfig,
|
||||
} from "../../../../data/lovelace";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { ConditionalCardConfig } from "../../cards/types";
|
||||
import { ICON_CONDITION } from "../../common/icon-condition";
|
||||
import { Condition } from "../../common/validate-condition";
|
||||
import type { LovelaceCardEditor } from "../../types";
|
||||
import "../card-editor/hui-card-element-editor";
|
||||
import type { HuiCardElementEditor } from "../card-editor/hui-card-element-editor";
|
||||
import "../card-editor/hui-card-picker";
|
||||
import "../conditions/ha-card-condition-editor";
|
||||
import { LovelaceConditionEditorConstructor } from "../conditions/types";
|
||||
import "../conditions/types/ha-card-condition-screen";
|
||||
import "../conditions/types/ha-card-condition-state";
|
||||
import "../hui-element-editor";
|
||||
import type { ConfigChangedEvent } from "../hui-element-editor";
|
||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||
import type { GUIModeChangedEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
const conditionStruct = object({
|
||||
entity: string(),
|
||||
state: optional(string()),
|
||||
state_not: optional(string()),
|
||||
});
|
||||
const UI_CONDITION = [
|
||||
"state",
|
||||
"screen",
|
||||
] as const satisfies readonly Condition["condition"][];
|
||||
|
||||
const cardConfigStruct = assign(
|
||||
baseLovelaceCardConfig,
|
||||
object({
|
||||
card: any(),
|
||||
conditions: optional(array(conditionStruct)),
|
||||
conditions: optional(array(any())),
|
||||
})
|
||||
);
|
||||
|
||||
@@ -127,7 +131,6 @@ export class HuiConditionalCardEditor
|
||||
)}
|
||||
.path=${isGuiMode ? mdiCodeBraces : mdiListBoxOutline}
|
||||
></ha-icon-button>
|
||||
|
||||
<ha-icon-button
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_card.copy"
|
||||
@@ -166,61 +169,44 @@ export class HuiConditionalCardEditor
|
||||
${this._config.conditions.map(
|
||||
(cond, idx) => html`
|
||||
<div class="condition">
|
||||
<div class="entity">
|
||||
<ha-entity-picker
|
||||
.hass=${this.hass}
|
||||
.value=${cond.entity}
|
||||
.idx=${idx}
|
||||
.configValue=${"entity"}
|
||||
@change=${this._changeCondition}
|
||||
allow-custom-entity
|
||||
></ha-entity-picker>
|
||||
</div>
|
||||
<div class="state">
|
||||
<ha-select
|
||||
.value=${cond.state_not !== undefined
|
||||
? "true"
|
||||
: "false"}
|
||||
.idx=${idx}
|
||||
.configValue=${"invert"}
|
||||
@selected=${this._changeCondition}
|
||||
@closed=${stopPropagation}
|
||||
naturalMenuWidth
|
||||
fixedMenuPosition
|
||||
>
|
||||
<mwc-list-item value="false">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.state_equal"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item value="true">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.state_not_equal"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-select>
|
||||
<ha-textfield
|
||||
.label="${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.generic.state"
|
||||
)} (${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.current_state"
|
||||
)}: ${this.hass?.states[cond.entity].state})"
|
||||
.value=${cond.state_not !== undefined
|
||||
? cond.state_not
|
||||
: cond.state}
|
||||
.idx=${idx}
|
||||
.configValue=${"state"}
|
||||
@input=${this._changeCondition}
|
||||
></ha-textfield>
|
||||
</div>
|
||||
<ha-card-condition-editor
|
||||
.index=${idx}
|
||||
@value-changed=${this._conditionChanged}
|
||||
.hass=${this.hass}
|
||||
.condition=${cond}
|
||||
></ha-card-condition-editor>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
<div class="condition">
|
||||
<ha-entity-picker
|
||||
.hass=${this.hass}
|
||||
@change=${this._addCondition}
|
||||
></ha-entity-picker>
|
||||
<div>
|
||||
<ha-button-menu
|
||||
@action=${this._addCondition}
|
||||
fixed
|
||||
@closed=${stopPropagation}
|
||||
>
|
||||
<ha-button
|
||||
slot="trigger"
|
||||
outlined
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.add_condition"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
${UI_CONDITION.map(
|
||||
(condition) => html`
|
||||
<ha-list-item .value=${condition} graphic="icon">
|
||||
${this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.${condition}.label`
|
||||
) || condition}
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${ICON_CONDITION[condition]}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
@@ -289,53 +275,40 @@ export class HuiConditionalCardEditor
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
private _addCondition(ev: Event): void {
|
||||
const target = ev.target! as any;
|
||||
if (target.value === "" || !this._config) {
|
||||
private _addCondition(ev: CustomEvent): void {
|
||||
const condition = (ev.currentTarget as HaSelect).items[ev.detail.index]
|
||||
.value as Condition["condition"];
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
const conditions = [...this._config.conditions];
|
||||
conditions.push({
|
||||
entity: target.value,
|
||||
state: "",
|
||||
});
|
||||
|
||||
const elClass = customElements.get(`ha-card-condition-${condition}`) as
|
||||
| LovelaceConditionEditorConstructor
|
||||
| undefined;
|
||||
|
||||
conditions.push(
|
||||
elClass?.defaultConfig
|
||||
? { ...elClass.defaultConfig }
|
||||
: { condition: condition }
|
||||
);
|
||||
this._config = { ...this._config, conditions };
|
||||
target.value = "";
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
private _changeCondition(ev: Event): void {
|
||||
const target = ev.target as any;
|
||||
if (!this._config || !target) {
|
||||
return;
|
||||
}
|
||||
const conditions = [...this._config.conditions];
|
||||
if (target.configValue === "entity" && target.value === "") {
|
||||
conditions.splice(target.idx, 1);
|
||||
private _conditionChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const conditions = [...this._config!.conditions];
|
||||
const newValue = ev.detail.value;
|
||||
const index = (ev.target as any).index;
|
||||
|
||||
if (newValue === null) {
|
||||
conditions.splice(index, 1);
|
||||
} else {
|
||||
const condition = { ...conditions[target.idx] };
|
||||
if (target.configValue === "entity") {
|
||||
condition.entity = target.value;
|
||||
} else if (target.configValue === "state") {
|
||||
if (condition.state_not !== undefined) {
|
||||
condition.state_not = target.value;
|
||||
} else {
|
||||
condition.state = target.value;
|
||||
}
|
||||
} else if (target.configValue === "invert") {
|
||||
if (target.value === "true") {
|
||||
if (condition.state) {
|
||||
condition.state_not = condition.state;
|
||||
delete condition.state;
|
||||
}
|
||||
} else if (condition.state_not) {
|
||||
condition.state = condition.state_not;
|
||||
delete condition.state_not;
|
||||
}
|
||||
}
|
||||
conditions[target.idx] = condition;
|
||||
conditions[index] = newValue;
|
||||
}
|
||||
this._config = { ...this._config, conditions };
|
||||
|
||||
this._config = { ...this._config!, conditions };
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
@@ -352,22 +325,13 @@ export class HuiConditionalCardEditor
|
||||
.condition {
|
||||
margin-top: 8px;
|
||||
border: 1px solid var(--divider-color);
|
||||
}
|
||||
.condition .content {
|
||||
padding: 12px;
|
||||
}
|
||||
.condition .state {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
ha-button-menu {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.condition .state ha-select {
|
||||
margin-right: 16px;
|
||||
margin-inline-end: 16px;
|
||||
margin-inline-start: initial;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.condition .state ha-textfield {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-top: 8px;
|
||||
border: 1px solid var(--divider-color);
|
||||
|
||||
@@ -174,9 +174,7 @@ export class HuiSaveConfig extends LitElement implements HassDialog {
|
||||
await lovelace.saveConfig(
|
||||
this._emptyConfig
|
||||
? EMPTY_CONFIG
|
||||
: await expandLovelaceConfigStrategies(lovelace.config, this.hass, {
|
||||
narrow: this._params.narrow,
|
||||
})
|
||||
: await expandLovelaceConfigStrategies(lovelace.config, this.hass)
|
||||
);
|
||||
lovelace.setEditMode(true);
|
||||
this._saving = false;
|
||||
|
||||
@@ -167,8 +167,7 @@ export class LovelacePanel extends LitElement {
|
||||
{
|
||||
type: DEFAULT_STRATEGY,
|
||||
},
|
||||
this.hass!,
|
||||
{ narrow: this.narrow }
|
||||
this.hass!
|
||||
);
|
||||
this._setLovelaceConfig(conf, undefined, "generated");
|
||||
this._panelState = "loaded";
|
||||
@@ -258,8 +257,7 @@ export class LovelacePanel extends LitElement {
|
||||
if (rawConf.strategy) {
|
||||
conf = await generateLovelaceDashboardStrategy(
|
||||
rawConf.strategy,
|
||||
this.hass!,
|
||||
{ narrow: this.narrow }
|
||||
this.hass!
|
||||
);
|
||||
} else {
|
||||
conf = rawConf;
|
||||
@@ -276,8 +274,7 @@ export class LovelacePanel extends LitElement {
|
||||
{
|
||||
type: DEFAULT_STRATEGY,
|
||||
},
|
||||
this.hass!,
|
||||
{ narrow: this.narrow }
|
||||
this.hass!
|
||||
);
|
||||
confMode = "generated";
|
||||
} finally {
|
||||
@@ -365,8 +362,7 @@ export class LovelacePanel extends LitElement {
|
||||
if (newConfig.strategy) {
|
||||
conf = await generateLovelaceDashboardStrategy(
|
||||
newConfig.strategy,
|
||||
this.hass!,
|
||||
{ narrow: this.narrow }
|
||||
this.hass!
|
||||
);
|
||||
} else {
|
||||
conf = newConfig;
|
||||
@@ -404,8 +400,7 @@ export class LovelacePanel extends LitElement {
|
||||
{
|
||||
type: DEFAULT_STRATEGY,
|
||||
},
|
||||
this.hass!,
|
||||
{ narrow: this.narrow }
|
||||
this.hass!
|
||||
);
|
||||
this._updateLovelace({
|
||||
config: generatedConf,
|
||||
|
||||
@@ -8,7 +8,6 @@ import { isLegacyStrategy } from "./legacy-strategy";
|
||||
import {
|
||||
LovelaceDashboardStrategy,
|
||||
LovelaceStrategy,
|
||||
LovelaceStrategyParams,
|
||||
LovelaceViewStrategy,
|
||||
} from "./types";
|
||||
|
||||
@@ -77,8 +76,7 @@ const generateStrategy = async <T extends LovelaceStrategyConfigType>(
|
||||
configType: T,
|
||||
renderError: (err: string | Error) => StrategyConfig<T>,
|
||||
strategyConfig: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant,
|
||||
params: LovelaceStrategyParams
|
||||
hass: HomeAssistant
|
||||
): Promise<StrategyConfig<T>> => {
|
||||
const strategyType = strategyConfig.type;
|
||||
if (!strategyType) {
|
||||
@@ -95,7 +93,7 @@ const generateStrategy = async <T extends LovelaceStrategyConfigType>(
|
||||
return (await strategy.generateDashboard({
|
||||
config: { strategy: strategyConfig, views: [] },
|
||||
hass,
|
||||
narrow: params.narrow,
|
||||
narrow: undefined,
|
||||
})) as StrategyConfig<T>;
|
||||
}
|
||||
if (configType === "view" && "generateView" in strategy) {
|
||||
@@ -103,7 +101,7 @@ const generateStrategy = async <T extends LovelaceStrategyConfigType>(
|
||||
config: { views: [] },
|
||||
view: { strategy: strategyConfig },
|
||||
hass,
|
||||
narrow: params.narrow,
|
||||
narrow: undefined,
|
||||
})) as StrategyConfig<T>;
|
||||
}
|
||||
}
|
||||
@@ -115,7 +113,7 @@ const generateStrategy = async <T extends LovelaceStrategyConfigType>(
|
||||
|
||||
delete config.options;
|
||||
|
||||
return await strategy.generate(config, hass, params);
|
||||
return await strategy.generate(config, hass);
|
||||
} catch (err: any) {
|
||||
if (err.message !== "timeout") {
|
||||
// eslint-disable-next-line
|
||||
@@ -128,8 +126,7 @@ const generateStrategy = async <T extends LovelaceStrategyConfigType>(
|
||||
|
||||
export const generateLovelaceDashboardStrategy = async (
|
||||
strategyConfig: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant,
|
||||
params: LovelaceStrategyParams
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceConfig> =>
|
||||
generateStrategy(
|
||||
"dashboard",
|
||||
@@ -147,14 +144,12 @@ export const generateLovelaceDashboardStrategy = async (
|
||||
],
|
||||
}),
|
||||
strategyConfig,
|
||||
hass,
|
||||
params
|
||||
hass
|
||||
);
|
||||
|
||||
export const generateLovelaceViewStrategy = async (
|
||||
strategyConfig: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant,
|
||||
params: LovelaceStrategyParams
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> =>
|
||||
generateStrategy(
|
||||
"view",
|
||||
@@ -167,8 +162,7 @@ export const generateLovelaceViewStrategy = async (
|
||||
],
|
||||
}),
|
||||
strategyConfig,
|
||||
hass,
|
||||
params
|
||||
hass
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -176,18 +170,15 @@ export const generateLovelaceViewStrategy = async (
|
||||
*/
|
||||
export const expandLovelaceConfigStrategies = async (
|
||||
config: LovelaceConfig,
|
||||
hass: HomeAssistant,
|
||||
params: LovelaceStrategyParams
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceConfig> => {
|
||||
const newConfig = config.strategy
|
||||
? await generateLovelaceDashboardStrategy(config.strategy, hass, params)
|
||||
? await generateLovelaceDashboardStrategy(config.strategy, hass)
|
||||
: { ...config };
|
||||
|
||||
newConfig.views = await Promise.all(
|
||||
newConfig.views.map((view) =>
|
||||
view.strategy
|
||||
? generateLovelaceViewStrategy(view.strategy, hass, params)
|
||||
: view
|
||||
view.strategy ? generateLovelaceViewStrategy(view.strategy, hass) : view
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@ import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { LovelaceConfig, LovelaceStrategyConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceStrategyParams } from "./types";
|
||||
|
||||
@customElement("original-states-dashboard-strategy")
|
||||
export class OriginalStatesDashboardStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
_config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant,
|
||||
_params?: LovelaceStrategyParams
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceConfig> {
|
||||
return {
|
||||
title: hass.config.location_name,
|
||||
|
||||
@@ -9,14 +9,12 @@ import {
|
||||
} from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { generateDefaultViewConfig } from "../common/generate-lovelace-config";
|
||||
import { LovelaceStrategyParams } from "./types";
|
||||
|
||||
@customElement("original-states-view-strategy")
|
||||
export class OriginalStatesViewStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
_config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant,
|
||||
_params?: LovelaceStrategyParams
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceViewConfig> {
|
||||
if (hass.config.state === STATE_NOT_RUNNING) {
|
||||
return {
|
||||
|
||||
@@ -5,16 +5,8 @@ import {
|
||||
} from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
export type LovelaceStrategyParams = {
|
||||
narrow?: boolean;
|
||||
};
|
||||
|
||||
export type LovelaceStrategy<T = any> = {
|
||||
generate(
|
||||
config: LovelaceStrategyConfig,
|
||||
hass: HomeAssistant,
|
||||
params?: LovelaceStrategyParams
|
||||
): Promise<T>;
|
||||
generate(config: LovelaceStrategyConfig, hass: HomeAssistant): Promise<T>;
|
||||
};
|
||||
|
||||
export interface LovelaceDashboardStrategy
|
||||
|
||||
@@ -192,8 +192,7 @@ export class HUIView extends ReactiveElement {
|
||||
isStrategy = true;
|
||||
viewConfig = await generateLovelaceViewStrategy(
|
||||
viewConfig.strategy,
|
||||
this.hass!,
|
||||
{ narrow: this.narrow }
|
||||
this.hass!
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import "@polymer/polymer/lib/elements/custom-style";
|
||||
import { derivedStyles } from "./styles";
|
||||
import { derivedStyles } from "./styles-data";
|
||||
|
||||
export const DEFAULT_PRIMARY_COLOR = "#03a9f4";
|
||||
export const DEFAULT_ACCENT_COLOR = "#ff9800";
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
export const darkStyles = {
|
||||
"primary-background-color": "#111111",
|
||||
"card-background-color": "#1c1c1c",
|
||||
"secondary-background-color": "#282828",
|
||||
"clear-background-color": "#111111",
|
||||
"primary-text-color": "#e1e1e1",
|
||||
"secondary-text-color": "#9b9b9b",
|
||||
"disabled-text-color": "#6f6f6f",
|
||||
"app-header-text-color": "#e1e1e1",
|
||||
"app-header-background-color": "#101e24",
|
||||
"switch-unchecked-button-color": "#999999",
|
||||
"switch-unchecked-track-color": "#9b9b9b",
|
||||
"divider-color": "rgba(225, 225, 225, .12)",
|
||||
"mdc-ripple-color": "#AAAAAA",
|
||||
"mdc-linear-progress-buffer-color": "rgba(255, 255, 255, 0.1)",
|
||||
|
||||
"input-idle-line-color": "rgba(255, 255, 255, 0.42)",
|
||||
"input-hover-line-color": "rgba(255, 255, 255, 0.87)",
|
||||
"input-disabled-line-color": "rgba(255, 255, 255, 0.06)",
|
||||
"input-outlined-idle-border-color": "rgba(255, 255, 255, 0.38)",
|
||||
"input-outlined-hover-border-color": "rgba(255, 255, 255, 0.87)",
|
||||
"input-outlined-disabled-border-color": "rgba(255, 255, 255, 0.06)",
|
||||
"input-fill-color": "rgba(255, 255, 255, 0.05)",
|
||||
"input-disabled-fill-color": "rgba(255, 255, 255, 0.02)",
|
||||
"input-ink-color": "rgba(255, 255, 255, 0.87)",
|
||||
"input-label-ink-color": "rgba(255, 255, 255, 0.6)",
|
||||
"input-disabled-ink-color": "rgba(255, 255, 255, 0.37)",
|
||||
"input-dropdown-icon-color": "rgba(255, 255, 255, 0.54)",
|
||||
|
||||
"codemirror-keyword": "#C792EA",
|
||||
"codemirror-operator": "#89DDFF",
|
||||
"codemirror-variable": "#f07178",
|
||||
"codemirror-variable-2": "#EEFFFF",
|
||||
"codemirror-variable-3": "#DECB6B",
|
||||
"codemirror-builtin": "#FFCB6B",
|
||||
"codemirror-atom": "#F78C6C",
|
||||
"codemirror-number": "#FF5370",
|
||||
"codemirror-def": "#82AAFF",
|
||||
"codemirror-string": "#C3E88D",
|
||||
"codemirror-string-2": "#f07178",
|
||||
"codemirror-comment": "#545454",
|
||||
"codemirror-tag": "#FF5370",
|
||||
"codemirror-meta": "#FFCB6B",
|
||||
"codemirror-attribute": "#C792EA",
|
||||
"codemirror-property": "#C792EA",
|
||||
"codemirror-qualifier": "#DECB6B",
|
||||
"codemirror-type": "#DECB6B",
|
||||
"energy-grid-return-color": "#a280db",
|
||||
"map-filter":
|
||||
"invert(.9) hue-rotate(170deg) brightness(1.5) contrast(1.2) saturate(.3)",
|
||||
"disabled-color": "#464646",
|
||||
};
|
||||
|
||||
export const derivedStyles = {
|
||||
"state-icon-error-color": "var(--error-state-color, var(--error-color))",
|
||||
"state-unavailable-color":
|
||||
"var(--state-icon-unavailable-color, var(--disabled-text-color))",
|
||||
"sidebar-text-color": "var(--primary-text-color)",
|
||||
"sidebar-background-color": "var(--card-background-color)",
|
||||
"sidebar-selected-text-color": "var(--primary-color)",
|
||||
"sidebar-selected-icon-color": "var(--primary-color)",
|
||||
"sidebar-icon-color": "rgba(var(--rgb-primary-text-color), 0.6)",
|
||||
"switch-checked-color": "var(--primary-color)",
|
||||
"switch-checked-button-color":
|
||||
"var(--switch-checked-color, var(--primary-background-color))",
|
||||
"switch-checked-track-color": "var(--switch-checked-color, #000000)",
|
||||
"switch-unchecked-button-color":
|
||||
"var(--switch-unchecked-color, var(--primary-background-color))",
|
||||
"switch-unchecked-track-color": "var(--switch-unchecked-color, #000000)",
|
||||
"slider-color": "var(--primary-color)",
|
||||
"slider-secondary-color": "var(--light-primary-color)",
|
||||
"slider-track-color": "var(--scrollbar-thumb-color)",
|
||||
"label-badge-background-color": "var(--card-background-color)",
|
||||
"label-badge-text-color": "rgba(var(--rgb-primary-text-color), 0.8)",
|
||||
"paper-listbox-background-color": "var(--card-background-color)",
|
||||
"paper-item-icon-color": "var(--state-icon-color)",
|
||||
"paper-item-icon-active-color": "var(--state-icon-active-color)",
|
||||
"table-header-background-color": "var(--input-fill-color)",
|
||||
"table-row-background-color": "var(--primary-background-color)",
|
||||
"table-row-alternative-background-color": "var(--secondary-background-color)",
|
||||
"paper-slider-knob-color": "var(--slider-color)",
|
||||
"paper-slider-knob-start-color": "var(--slider-color)",
|
||||
"paper-slider-pin-color": "var(--slider-color)",
|
||||
"paper-slider-pin-start-color": "var(--slider-color)",
|
||||
"paper-slider-active-color": "var(--slider-color)",
|
||||
"paper-slider-secondary-color": "var(--slider-secondary-color)",
|
||||
"paper-slider-container-color": "var(--slider-track-color)",
|
||||
"data-table-background-color": "var(--card-background-color)",
|
||||
"markdown-code-background-color": "var(--primary-background-color)",
|
||||
|
||||
// https://github.com/material-components/material-web/blob/master/docs/theming.md
|
||||
"mdc-theme-primary": "var(--primary-color)",
|
||||
"mdc-theme-secondary": "var(--accent-color)",
|
||||
"mdc-theme-background": "var(--primary-background-color)",
|
||||
"mdc-theme-surface": "var(--card-background-color)",
|
||||
"mdc-theme-on-primary": "var(--text-primary-color)",
|
||||
"mdc-theme-on-secondary": "var(--text-primary-color)",
|
||||
"mdc-theme-on-surface": "var(--primary-text-color)",
|
||||
"mdc-theme-text-disabled-on-light": "var(--disabled-text-color)",
|
||||
"mdc-theme-text-primary-on-background": "var(--primary-text-color)",
|
||||
"mdc-theme-text-secondary-on-background": "var(--secondary-text-color)",
|
||||
"mdc-theme-text-hint-on-background": "var(--secondary-text-color)",
|
||||
"mdc-theme-text-icon-on-background": "var(--secondary-text-color)",
|
||||
"mdc-theme-error": "var(--error-color)",
|
||||
"app-header-text-color": "var(--text-primary-color)",
|
||||
"app-header-background-color": "var(--primary-color)",
|
||||
"mdc-checkbox-unchecked-color": "rgba(var(--rgb-primary-text-color), 0.54)",
|
||||
"mdc-checkbox-disabled-color": "var(--disabled-text-color)",
|
||||
"mdc-radio-unchecked-color": "rgba(var(--rgb-primary-text-color), 0.54)",
|
||||
"mdc-radio-disabled-color": "var(--disabled-text-color)",
|
||||
"mdc-tab-text-label-color-default": "var(--primary-text-color)",
|
||||
"mdc-button-disabled-ink-color": "var(--disabled-text-color)",
|
||||
"mdc-button-outline-color": "var(--divider-color)",
|
||||
"mdc-dialog-scroll-divider-color": "var(--divider-color)",
|
||||
"mdc-dialog-heading-ink-color": "var(--primary-text-color)",
|
||||
"mdc-dialog-content-ink-color": "var(--primary-text-color)",
|
||||
|
||||
"mdc-text-field-idle-line-color": "var(--input-idle-line-color)",
|
||||
"mdc-text-field-hover-line-color": "var(--input-hover-line-color)",
|
||||
"mdc-text-field-disabled-line-color": "var(--input-disabled-line-color)",
|
||||
"mdc-text-field-outlined-idle-border-color":
|
||||
"var(--input-outlined-idle-border-color)",
|
||||
"mdc-text-field-outlined-hover-border-color":
|
||||
"var(--input-outlined-hover-border-color)",
|
||||
"mdc-text-field-outlined-disabled-border-color":
|
||||
"var(--input-outlined-disabled-border-color)",
|
||||
"mdc-text-field-fill-color": "var(--input-fill-color)",
|
||||
"mdc-text-field-disabled-fill-color": "var(--input-disabled-fill-color)",
|
||||
"mdc-text-field-ink-color": "var(--input-ink-color)",
|
||||
"mdc-text-field-label-ink-color": "var(--input-label-ink-color)",
|
||||
"mdc-text-field-disabled-ink-color": "var(--input-disabled-ink-color)",
|
||||
|
||||
"mdc-select-idle-line-color": "var(--input-idle-line-color)",
|
||||
"mdc-select-hover-line-color": "var(--input-hover-line-color)",
|
||||
"mdc-select-outlined-idle-border-color":
|
||||
"var(--input-outlined-idle-border-color)",
|
||||
"mdc-select-outlined-hover-border-color":
|
||||
"var(--input-outlined-hover-border-color)",
|
||||
"mdc-select-outlined-disabled-border-color":
|
||||
"var(--input-outlined-disabled-border-color)",
|
||||
"mdc-select-fill-color": "var(--input-fill-color)",
|
||||
"mdc-select-disabled-fill-color": "var(--input-disabled-fill-color)",
|
||||
"mdc-select-ink-color": "var(--input-ink-color)",
|
||||
"mdc-select-label-ink-color": "var(--input-label-ink-color)",
|
||||
"mdc-select-disabled-ink-color": "var(--input-disabled-ink-color)",
|
||||
"mdc-select-dropdown-icon-color": "var(--input-dropdown-icon-color)",
|
||||
"mdc-select-disabled-dropdown-icon-color": "var(--input-disabled-ink-color)",
|
||||
|
||||
"chip-background-color": "rgba(var(--rgb-primary-text-color), 0.15)",
|
||||
// Vaadin
|
||||
"material-body-text-color": "var(--primary-text-color)",
|
||||
"material-background-color": "var(--card-background-color)",
|
||||
"material-secondary-background-color": "var(--secondary-background-color)",
|
||||
"material-secondary-text-color": "var(--secondary-text-color)",
|
||||
};
|
||||
@@ -1,161 +1,5 @@
|
||||
import { css } from "lit";
|
||||
|
||||
export const darkStyles = {
|
||||
"primary-background-color": "#111111",
|
||||
"card-background-color": "#1c1c1c",
|
||||
"secondary-background-color": "#282828",
|
||||
"clear-background-color": "#111111",
|
||||
"primary-text-color": "#e1e1e1",
|
||||
"secondary-text-color": "#9b9b9b",
|
||||
"disabled-text-color": "#6f6f6f",
|
||||
"app-header-text-color": "#e1e1e1",
|
||||
"app-header-background-color": "#101e24",
|
||||
"switch-unchecked-button-color": "#999999",
|
||||
"switch-unchecked-track-color": "#9b9b9b",
|
||||
"divider-color": "rgba(225, 225, 225, .12)",
|
||||
"mdc-ripple-color": "#AAAAAA",
|
||||
"mdc-linear-progress-buffer-color": "rgba(255, 255, 255, 0.1)",
|
||||
|
||||
"input-idle-line-color": "rgba(255, 255, 255, 0.42)",
|
||||
"input-hover-line-color": "rgba(255, 255, 255, 0.87)",
|
||||
"input-disabled-line-color": "rgba(255, 255, 255, 0.06)",
|
||||
"input-outlined-idle-border-color": "rgba(255, 255, 255, 0.38)",
|
||||
"input-outlined-hover-border-color": "rgba(255, 255, 255, 0.87)",
|
||||
"input-outlined-disabled-border-color": "rgba(255, 255, 255, 0.06)",
|
||||
"input-fill-color": "rgba(255, 255, 255, 0.05)",
|
||||
"input-disabled-fill-color": "rgba(255, 255, 255, 0.02)",
|
||||
"input-ink-color": "rgba(255, 255, 255, 0.87)",
|
||||
"input-label-ink-color": "rgba(255, 255, 255, 0.6)",
|
||||
"input-disabled-ink-color": "rgba(255, 255, 255, 0.37)",
|
||||
"input-dropdown-icon-color": "rgba(255, 255, 255, 0.54)",
|
||||
|
||||
"codemirror-keyword": "#C792EA",
|
||||
"codemirror-operator": "#89DDFF",
|
||||
"codemirror-variable": "#f07178",
|
||||
"codemirror-variable-2": "#EEFFFF",
|
||||
"codemirror-variable-3": "#DECB6B",
|
||||
"codemirror-builtin": "#FFCB6B",
|
||||
"codemirror-atom": "#F78C6C",
|
||||
"codemirror-number": "#FF5370",
|
||||
"codemirror-def": "#82AAFF",
|
||||
"codemirror-string": "#C3E88D",
|
||||
"codemirror-string-2": "#f07178",
|
||||
"codemirror-comment": "#545454",
|
||||
"codemirror-tag": "#FF5370",
|
||||
"codemirror-meta": "#FFCB6B",
|
||||
"codemirror-attribute": "#C792EA",
|
||||
"codemirror-property": "#C792EA",
|
||||
"codemirror-qualifier": "#DECB6B",
|
||||
"codemirror-type": "#DECB6B",
|
||||
"energy-grid-return-color": "#a280db",
|
||||
"map-filter":
|
||||
"invert(.9) hue-rotate(170deg) brightness(1.5) contrast(1.2) saturate(.3)",
|
||||
"disabled-color": "#464646",
|
||||
};
|
||||
|
||||
export const derivedStyles = {
|
||||
"state-icon-error-color": "var(--error-state-color, var(--error-color))",
|
||||
"state-unavailable-color":
|
||||
"var(--state-icon-unavailable-color, var(--disabled-text-color))",
|
||||
"sidebar-text-color": "var(--primary-text-color)",
|
||||
"sidebar-background-color": "var(--card-background-color)",
|
||||
"sidebar-selected-text-color": "var(--primary-color)",
|
||||
"sidebar-selected-icon-color": "var(--primary-color)",
|
||||
"sidebar-icon-color": "rgba(var(--rgb-primary-text-color), 0.6)",
|
||||
"switch-checked-color": "var(--primary-color)",
|
||||
"switch-checked-button-color":
|
||||
"var(--switch-checked-color, var(--primary-background-color))",
|
||||
"switch-checked-track-color": "var(--switch-checked-color, #000000)",
|
||||
"switch-unchecked-button-color":
|
||||
"var(--switch-unchecked-color, var(--primary-background-color))",
|
||||
"switch-unchecked-track-color": "var(--switch-unchecked-color, #000000)",
|
||||
"slider-color": "var(--primary-color)",
|
||||
"slider-secondary-color": "var(--light-primary-color)",
|
||||
"slider-track-color": "var(--scrollbar-thumb-color)",
|
||||
"label-badge-background-color": "var(--card-background-color)",
|
||||
"label-badge-text-color": "rgba(var(--rgb-primary-text-color), 0.8)",
|
||||
"paper-listbox-background-color": "var(--card-background-color)",
|
||||
"paper-item-icon-color": "var(--state-icon-color)",
|
||||
"paper-item-icon-active-color": "var(--state-icon-active-color)",
|
||||
"table-header-background-color": "var(--input-fill-color)",
|
||||
"table-row-background-color": "var(--primary-background-color)",
|
||||
"table-row-alternative-background-color": "var(--secondary-background-color)",
|
||||
"paper-slider-knob-color": "var(--slider-color)",
|
||||
"paper-slider-knob-start-color": "var(--slider-color)",
|
||||
"paper-slider-pin-color": "var(--slider-color)",
|
||||
"paper-slider-pin-start-color": "var(--slider-color)",
|
||||
"paper-slider-active-color": "var(--slider-color)",
|
||||
"paper-slider-secondary-color": "var(--slider-secondary-color)",
|
||||
"paper-slider-container-color": "var(--slider-track-color)",
|
||||
"data-table-background-color": "var(--card-background-color)",
|
||||
"markdown-code-background-color": "var(--primary-background-color)",
|
||||
|
||||
// https://github.com/material-components/material-web/blob/master/docs/theming.md
|
||||
"mdc-theme-primary": "var(--primary-color)",
|
||||
"mdc-theme-secondary": "var(--accent-color)",
|
||||
"mdc-theme-background": "var(--primary-background-color)",
|
||||
"mdc-theme-surface": "var(--card-background-color)",
|
||||
"mdc-theme-on-primary": "var(--text-primary-color)",
|
||||
"mdc-theme-on-secondary": "var(--text-primary-color)",
|
||||
"mdc-theme-on-surface": "var(--primary-text-color)",
|
||||
"mdc-theme-text-disabled-on-light": "var(--disabled-text-color)",
|
||||
"mdc-theme-text-primary-on-background": "var(--primary-text-color)",
|
||||
"mdc-theme-text-secondary-on-background": "var(--secondary-text-color)",
|
||||
"mdc-theme-text-hint-on-background": "var(--secondary-text-color)",
|
||||
"mdc-theme-text-icon-on-background": "var(--secondary-text-color)",
|
||||
"mdc-theme-error": "var(--error-color)",
|
||||
"app-header-text-color": "var(--text-primary-color)",
|
||||
"app-header-background-color": "var(--primary-color)",
|
||||
"mdc-checkbox-unchecked-color": "rgba(var(--rgb-primary-text-color), 0.54)",
|
||||
"mdc-checkbox-disabled-color": "var(--disabled-text-color)",
|
||||
"mdc-radio-unchecked-color": "rgba(var(--rgb-primary-text-color), 0.54)",
|
||||
"mdc-radio-disabled-color": "var(--disabled-text-color)",
|
||||
"mdc-tab-text-label-color-default": "var(--primary-text-color)",
|
||||
"mdc-button-disabled-ink-color": "var(--disabled-text-color)",
|
||||
"mdc-button-outline-color": "var(--divider-color)",
|
||||
"mdc-dialog-scroll-divider-color": "var(--divider-color)",
|
||||
"mdc-dialog-heading-ink-color": "var(--primary-text-color)",
|
||||
"mdc-dialog-content-ink-color": "var(--primary-text-color)",
|
||||
|
||||
"mdc-text-field-idle-line-color": "var(--input-idle-line-color)",
|
||||
"mdc-text-field-hover-line-color": "var(--input-hover-line-color)",
|
||||
"mdc-text-field-disabled-line-color": "var(--input-disabled-line-color)",
|
||||
"mdc-text-field-outlined-idle-border-color":
|
||||
"var(--input-outlined-idle-border-color)",
|
||||
"mdc-text-field-outlined-hover-border-color":
|
||||
"var(--input-outlined-hover-border-color)",
|
||||
"mdc-text-field-outlined-disabled-border-color":
|
||||
"var(--input-outlined-disabled-border-color)",
|
||||
"mdc-text-field-fill-color": "var(--input-fill-color)",
|
||||
"mdc-text-field-disabled-fill-color": "var(--input-disabled-fill-color)",
|
||||
"mdc-text-field-ink-color": "var(--input-ink-color)",
|
||||
"mdc-text-field-label-ink-color": "var(--input-label-ink-color)",
|
||||
"mdc-text-field-disabled-ink-color": "var(--input-disabled-ink-color)",
|
||||
|
||||
"mdc-select-idle-line-color": "var(--input-idle-line-color)",
|
||||
"mdc-select-hover-line-color": "var(--input-hover-line-color)",
|
||||
"mdc-select-outlined-idle-border-color":
|
||||
"var(--input-outlined-idle-border-color)",
|
||||
"mdc-select-outlined-hover-border-color":
|
||||
"var(--input-outlined-hover-border-color)",
|
||||
"mdc-select-outlined-disabled-border-color":
|
||||
"var(--input-outlined-disabled-border-color)",
|
||||
"mdc-select-fill-color": "var(--input-fill-color)",
|
||||
"mdc-select-disabled-fill-color": "var(--input-disabled-fill-color)",
|
||||
"mdc-select-ink-color": "var(--input-ink-color)",
|
||||
"mdc-select-label-ink-color": "var(--input-label-ink-color)",
|
||||
"mdc-select-disabled-ink-color": "var(--input-disabled-ink-color)",
|
||||
"mdc-select-dropdown-icon-color": "var(--input-dropdown-icon-color)",
|
||||
"mdc-select-disabled-dropdown-icon-color": "var(--input-disabled-ink-color)",
|
||||
|
||||
"chip-background-color": "rgba(var(--rgb-primary-text-color), 0.15)",
|
||||
// Vaadin
|
||||
"material-body-text-color": "var(--primary-text-color)",
|
||||
"material-background-color": "var(--card-background-color)",
|
||||
"material-secondary-background-color": "var(--secondary-background-color)",
|
||||
"material-secondary-text-color": "var(--secondary-text-color)",
|
||||
};
|
||||
|
||||
export const buttonLinkStyle = css`
|
||||
button.link {
|
||||
background: none;
|
||||
|
||||
@@ -4670,6 +4670,8 @@
|
||||
"confirm_cancel": "Are you sure you want to cancel?",
|
||||
"show_visual_editor": "Show visual editor",
|
||||
"show_code_editor": "Show code editor",
|
||||
"edit_ui": "[%key:ui::panel::config::automation::editor::edit_ui%]",
|
||||
"edit_yaml": "[%key:ui::panel::config::automation::editor::edit_yaml%]",
|
||||
"add": "Add card",
|
||||
"edit": "Edit",
|
||||
"clear": "Clear",
|
||||
@@ -4768,7 +4770,24 @@
|
||||
"state_not_equal": "State is not equal to",
|
||||
"current_state": "current",
|
||||
"condition_explanation": "The card will be shown when ALL conditions below are fulfilled.",
|
||||
"change_type": "Change type"
|
||||
"change_type": "Change type",
|
||||
"add_condition": "Add condition",
|
||||
"condition": {
|
||||
"screen": {
|
||||
"label": "Screen",
|
||||
"breakpoints": "Screen sizes",
|
||||
"breakpoints_list": {
|
||||
"mobile": "Mobile",
|
||||
"tablet": "Tablet",
|
||||
"desktop": "Desktop",
|
||||
"wide": "Wide"
|
||||
},
|
||||
"min": "min: {size}px"
|
||||
},
|
||||
"state": {
|
||||
"label": "Entity state"
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"required": "required",
|
||||
|
||||
@@ -174,7 +174,8 @@
|
||||
"nativeName": "Українська"
|
||||
},
|
||||
"ur": {
|
||||
"nativeName": "اُردُو"
|
||||
"nativeName": "اُردُو",
|
||||
"isRTL": true
|
||||
},
|
||||
"vi": {
|
||||
"nativeName": "Tiếng Việt"
|
||||
|
||||
@@ -3164,13 +3164,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@material/web@npm:=1.0.0-pre.17":
|
||||
version: 1.0.0-pre.17
|
||||
resolution: "@material/web@npm:1.0.0-pre.17"
|
||||
"@material/web@npm:=1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "@material/web@npm:1.0.0"
|
||||
dependencies:
|
||||
lit: ^2.7.4 || ^3.0.0
|
||||
tslib: ^2.4.0
|
||||
checksum: a6443931677d981a0152fe52927b1aa2a9490354c81fbf77f3f9f33accfdc567dc2a431ae0a3cb375dff60a322ff7babd49fb62b186bcf43285e09fecd48a594
|
||||
checksum: 0c6772ab2b2c144bba62f323a6d657d44ea3b2c9a2b8e745e0e5d17081983724e8e72857a58a930df28073ec931ed04a4f2364bdcbdf72ce5c85a03abc0578f3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4418,10 +4418,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/mocha@npm:10.0.1":
|
||||
version: 10.0.1
|
||||
resolution: "@types/mocha@npm:10.0.1"
|
||||
checksum: 224ea9fce7b1734ccdb9aa99a622d902a538ce1847bca7fd22c5fb38adcf3ed536f50f48f587085db988a4bb3c2eb68f4b98e1cd6a38bc5547bd3bbbedc54495
|
||||
"@types/mocha@npm:10.0.2":
|
||||
version: 10.0.2
|
||||
resolution: "@types/mocha@npm:10.0.2"
|
||||
checksum: a78a02691f102beb02f9ec435458107d21b518fc477c3b2f37c90b8e70b67bff888351715ae173bd31ede25ee5e0d688aefb0faf4284034d08ba63027c8b0c01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6518,18 +6518,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chai@npm:4.3.8":
|
||||
version: 4.3.8
|
||||
resolution: "chai@npm:4.3.8"
|
||||
"chai@npm:4.3.10":
|
||||
version: 4.3.10
|
||||
resolution: "chai@npm:4.3.10"
|
||||
dependencies:
|
||||
assertion-error: ^1.1.0
|
||||
check-error: ^1.0.2
|
||||
deep-eql: ^4.1.2
|
||||
get-func-name: ^2.0.0
|
||||
loupe: ^2.3.1
|
||||
check-error: ^1.0.3
|
||||
deep-eql: ^4.1.3
|
||||
get-func-name: ^2.0.2
|
||||
loupe: ^2.3.6
|
||||
pathval: ^1.1.1
|
||||
type-detect: ^4.0.5
|
||||
checksum: 29e0984ed13308319cadc35437c8ef0a3e271544d226c991bf7e3b6d771bf89707321669e11d05e362bc0ad0bd26585079b989d1032f3c106e3bb95d7f079cce
|
||||
type-detect: ^4.0.8
|
||||
checksum: 536668c60a0d985a0fbd94418028e388d243a925d7c5e858c7443e334753511614a3b6a124bac9ca077dfc4c37acc367d62f8c294960f440749536dc181dfc6d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6579,10 +6579,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"check-error@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "check-error@npm:1.0.2"
|
||||
checksum: d9d106504404b8addd1ee3f63f8c0eaa7cd962a1a28eb9c519b1c4a1dc7098be38007fc0060f045ee00f075fbb7a2a4f42abcf61d68323677e11ab98dc16042e
|
||||
"check-error@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "check-error@npm:1.0.3"
|
||||
dependencies:
|
||||
get-func-name: ^2.0.2
|
||||
checksum: e2131025cf059b21080f4813e55b3c480419256914601750b0fee3bd9b2b8315b531e551ef12560419b8b6d92a3636511322752b1ce905703239e7cc451b6399
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7282,7 +7284,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"deep-eql@npm:^4.1.2":
|
||||
"deep-eql@npm:^4.1.3":
|
||||
version: 4.1.3
|
||||
resolution: "deep-eql@npm:4.1.3"
|
||||
dependencies:
|
||||
@@ -9071,7 +9073,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-func-name@npm:^2.0.0":
|
||||
"get-func-name@npm:^2.0.0, get-func-name@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "get-func-name@npm:2.0.2"
|
||||
checksum: 3f62f4c23647de9d46e6f76d2b3eafe58933a9b3830c60669e4180d6c601ce1b4aa310ba8366143f55e52b139f992087a9f0647274e8745621fa2af7e0acf13b
|
||||
@@ -9199,18 +9201,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:10.3.7, glob@npm:^10.2.2":
|
||||
version: 10.3.7
|
||||
resolution: "glob@npm:10.3.7"
|
||||
"glob@npm:10.3.10, glob@npm:^10.2.2":
|
||||
version: 10.3.10
|
||||
resolution: "glob@npm:10.3.10"
|
||||
dependencies:
|
||||
foreground-child: ^3.1.0
|
||||
jackspeak: ^2.0.3
|
||||
jackspeak: ^2.3.5
|
||||
minimatch: ^9.0.1
|
||||
minipass: ^5.0.0 || ^6.0.2 || ^7.0.0
|
||||
path-scurry: ^1.10.1
|
||||
bin:
|
||||
glob: dist/esm/bin.mjs
|
||||
checksum: 9a27f1fa8774c3a8ab8f05c26a77276edaf5418aac29aff70c5d847ef75dabf536554cb113e945193323fb769fbe32edde12559d2d52266f38662595cbc7a031
|
||||
checksum: 4f2fe2511e157b5a3f525a54092169a5f92405f24d2aed3142f4411df328baca13059f4182f1db1bf933e2c69c0bd89e57ae87edd8950cba8c7ccbe84f721cf3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9687,7 +9689,7 @@ __metadata:
|
||||
"@material/mwc-top-app-bar": 0.27.0
|
||||
"@material/mwc-top-app-bar-fixed": 0.27.0
|
||||
"@material/top-app-bar": =14.0.0-canary.53b3cad2f.0
|
||||
"@material/web": =1.0.0-pre.17
|
||||
"@material/web": =1.0.0
|
||||
"@mdi/js": 7.2.96
|
||||
"@mdi/svg": 7.2.96
|
||||
"@octokit/auth-oauth-device": 6.0.1
|
||||
@@ -9720,7 +9722,7 @@ __metadata:
|
||||
"@types/leaflet": 1.9.6
|
||||
"@types/leaflet-draw": 1.0.8
|
||||
"@types/luxon": 3.3.2
|
||||
"@types/mocha": 10.0.1
|
||||
"@types/mocha": 10.0.2
|
||||
"@types/qrcode": 1.5.2
|
||||
"@types/serve-handler": 6.1.2
|
||||
"@types/sortablejs": 1.15.3
|
||||
@@ -9742,7 +9744,7 @@ __metadata:
|
||||
app-datepicker: 5.1.1
|
||||
babel-loader: 9.1.3
|
||||
babel-plugin-template-html-minifier: 4.1.0
|
||||
chai: 4.3.8
|
||||
chai: 4.3.10
|
||||
chart.js: 4.4.0
|
||||
comlink: 4.4.1
|
||||
core-js: 3.32.2
|
||||
@@ -9767,7 +9769,7 @@ __metadata:
|
||||
fancy-log: 2.0.0
|
||||
fs-extra: 11.1.1
|
||||
fuse.js: 6.6.2
|
||||
glob: 10.3.7
|
||||
glob: 10.3.10
|
||||
google-timezones-json: 1.2.0
|
||||
gulp: 4.0.2
|
||||
gulp-flatmap: 1.0.2
|
||||
@@ -9791,7 +9793,7 @@ __metadata:
|
||||
lit-analyzer: 2.0.0-pre.3
|
||||
lodash.template: 4.5.0
|
||||
luxon: 3.4.3
|
||||
magic-string: 0.30.3
|
||||
magic-string: 0.30.4
|
||||
map-stream: 0.0.7
|
||||
marked: 9.0.3
|
||||
memoize-one: 6.0.0
|
||||
@@ -10901,16 +10903,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jackspeak@npm:^2.0.3":
|
||||
version: 2.3.3
|
||||
resolution: "jackspeak@npm:2.3.3"
|
||||
"jackspeak@npm:^2.3.5":
|
||||
version: 2.3.6
|
||||
resolution: "jackspeak@npm:2.3.6"
|
||||
dependencies:
|
||||
"@isaacs/cliui": ^8.0.2
|
||||
"@pkgjs/parseargs": ^0.11.0
|
||||
dependenciesMeta:
|
||||
"@pkgjs/parseargs":
|
||||
optional: true
|
||||
checksum: 4313a7c0cc44c7753c4cb9869935f0b06f4cf96827515f63f58ff46b3d2f6e29aba6b3b5151778397c3f5ae67ef8bfc48871967bd10343c27e90cff198ec7808
|
||||
checksum: 57d43ad11eadc98cdfe7496612f6bbb5255ea69fe51ea431162db302c2a11011642f50cfad57288bd0aea78384a0612b16e131944ad8ecd09d619041c8531b54
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -11651,7 +11653,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loupe@npm:^2.3.1":
|
||||
"loupe@npm:^2.3.6":
|
||||
version: 2.3.6
|
||||
resolution: "loupe@npm:2.3.6"
|
||||
dependencies:
|
||||
@@ -11708,12 +11710,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"magic-string@npm:0.30.3":
|
||||
version: 0.30.3
|
||||
resolution: "magic-string@npm:0.30.3"
|
||||
"magic-string@npm:0.30.4":
|
||||
version: 0.30.4
|
||||
resolution: "magic-string@npm:0.30.4"
|
||||
dependencies:
|
||||
"@jridgewell/sourcemap-codec": ^1.4.15
|
||||
checksum: a5a9ddf9bd3bf49a2de1048bf358464f1bda7b3cc1311550f4a0ba8f81a4070e25445d53a5ee28850161336f1bff3cf28aa3320c6b4aeff45ce3e689f300b2f3
|
||||
checksum: bef57c926d14e9926c142307c1494cc4bdea28a56601a7624f1a5bcd34a63800e2d8a363e826436ce86104460a63ee76c7c185a6ab1f8f7ee5af2de475b98947
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -13265,13 +13267,13 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"postcss@npm:^8.4.14":
|
||||
version: 8.4.30
|
||||
resolution: "postcss@npm:8.4.30"
|
||||
version: 8.4.31
|
||||
resolution: "postcss@npm:8.4.31"
|
||||
dependencies:
|
||||
nanoid: ^3.3.6
|
||||
picocolors: ^1.0.0
|
||||
source-map-js: ^1.0.2
|
||||
checksum: 6c810c10c9bd3e03ca016e0b6b6756261e640aba1a9a7b1200b55502bc34b9165e38f590aef3493afc2f30ab55cdfcd43fd0f8408d69a77318ddbcf2a8ad164b
|
||||
checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -15521,7 +15523,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.5, type-detect@npm:^4.0.8":
|
||||
"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.8":
|
||||
version: 4.0.8
|
||||
resolution: "type-detect@npm:4.0.8"
|
||||
checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15
|
||||
|
||||
Reference in New Issue
Block a user