mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-25 09:09:26 +00:00
Compare commits
17 Commits
limit-quic
...
20220428.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
51f971337d | ||
![]() |
1f3c23de29 | ||
![]() |
bdfb17d957 | ||
![]() |
8c97aee1fe | ||
![]() |
38b4090daa | ||
![]() |
b8c55f2f65 | ||
![]() |
7ca379e0a1 | ||
![]() |
1617a9dfed | ||
![]() |
2c9411c6c3 | ||
![]() |
67626d4a06 | ||
![]() |
8135611688 | ||
![]() |
3ccbf6983e | ||
![]() |
e4f91195d8 | ||
![]() |
2751f8f33b | ||
![]() |
57f2df3b3e | ||
![]() |
6822f0d067 | ||
![]() |
cfba957313 |
@@ -62,6 +62,17 @@ const ACTIONS = [
|
||||
entity_id: "input_boolean.toggle_4",
|
||||
},
|
||||
},
|
||||
{
|
||||
parallel: [
|
||||
{ scene: "scene.kitchen_morning" },
|
||||
{
|
||||
service: "media_player.play_media",
|
||||
target: { entity_id: "media_player.living_room" },
|
||||
data: { media_content_id: "", media_content_type: "" },
|
||||
metadata: { title: "Happy Song" },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@customElement("demo-automation-describe-action")
|
||||
|
@@ -20,6 +20,7 @@ import { HaWaitForTriggerAction } from "../../../../src/panels/config/automation
|
||||
import { HaWaitAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-wait_template";
|
||||
import { Action } from "../../../../src/data/script";
|
||||
import { HaConditionAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-condition";
|
||||
import { HaParallelAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-parallel";
|
||||
|
||||
const SCHEMAS: { name: string; actions: Action[] }[] = [
|
||||
{ name: "Event", actions: [HaEventAction.defaultConfig] },
|
||||
@@ -33,6 +34,7 @@ const SCHEMAS: { name: string; actions: Action[] }[] = [
|
||||
{ name: "Repeat", actions: [HaRepeatAction.defaultConfig] },
|
||||
{ name: "Choose", actions: [HaChooseAction.defaultConfig] },
|
||||
{ name: "Variables", actions: [{ variables: { hello: "1" } }] },
|
||||
{ name: "Parallel", actions: [HaParallelAction.defaultConfig] },
|
||||
];
|
||||
|
||||
@customElement("demo-automation-editor-action")
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = home-assistant-frontend
|
||||
version = 20220427.0
|
||||
version = 20220428.0
|
||||
author = The Home Assistant Authors
|
||||
author_email = hello@home-assistant.io
|
||||
license = Apache-2.0
|
||||
|
@@ -5,6 +5,7 @@ import { fireEvent } from "../../common/dom/fire_event";
|
||||
import {
|
||||
DeviceAutomation,
|
||||
deviceAutomationsEqual,
|
||||
sortDeviceAutomations,
|
||||
} from "../../data/device_automation";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "../ha-select";
|
||||
@@ -127,7 +128,9 @@ export abstract class HaDeviceAutomationPicker<
|
||||
|
||||
private async _updateDeviceInfo() {
|
||||
this._automations = this.deviceId
|
||||
? await this._fetchDeviceAutomations(this.hass, this.deviceId)
|
||||
? (await this._fetchDeviceAutomations(this.hass, this.deviceId)).sort(
|
||||
sortDeviceAutomations
|
||||
)
|
||||
: // No device, clear the list of automations
|
||||
[];
|
||||
|
||||
@@ -161,8 +164,9 @@ export abstract class HaDeviceAutomationPicker<
|
||||
if (this.value && deviceAutomationsEqual(automation, this.value)) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "change");
|
||||
fireEvent(this, "value-changed", { value: automation });
|
||||
const value = { ...automation };
|
||||
delete value.metadata;
|
||||
fireEvent(this, "value-changed", { value });
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
@@ -152,6 +152,7 @@ class DialogMediaPlayerBrowse extends LitElement {
|
||||
ha-media-player-browse {
|
||||
--media-browser-max-height: calc(100vh - 65px);
|
||||
height: calc(100vh - 65px);
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
@media (min-width: 800px) {
|
||||
|
@@ -65,6 +65,7 @@ export interface BaseTrigger {
|
||||
platform: string;
|
||||
id?: string;
|
||||
variables?: Record<string, unknown>;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface StateTrigger extends BaseTrigger {
|
||||
@@ -178,6 +179,7 @@ export type Trigger =
|
||||
interface BaseCondition {
|
||||
condition: string;
|
||||
alias?: string;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface LogicalCondition extends BaseCondition {
|
||||
@@ -235,6 +237,10 @@ export interface TriggerCondition extends BaseCondition {
|
||||
|
||||
type ShorthandBaseCondition = Omit<BaseCondition, "condition">;
|
||||
|
||||
export interface ShorthandAndConditionList extends ShorthandBaseCondition {
|
||||
condition: Condition[];
|
||||
}
|
||||
|
||||
export interface ShorthandAndCondition extends ShorthandBaseCondition {
|
||||
and: Condition[];
|
||||
}
|
||||
@@ -260,10 +266,33 @@ export type Condition =
|
||||
|
||||
export type ConditionWithShorthand =
|
||||
| Condition
|
||||
| ShorthandAndConditionList
|
||||
| ShorthandAndCondition
|
||||
| ShorthandOrCondition
|
||||
| ShorthandNotCondition;
|
||||
|
||||
export const expandConditionWithShorthand = (
|
||||
cond: ConditionWithShorthand
|
||||
): Condition => {
|
||||
if ("condition" in cond && Array.isArray(cond.condition)) {
|
||||
return {
|
||||
condition: "and",
|
||||
conditions: cond.condition,
|
||||
};
|
||||
}
|
||||
|
||||
for (const condition of ["and", "or", "not"]) {
|
||||
if (condition in cond) {
|
||||
return {
|
||||
condition,
|
||||
conditions: cond[condition],
|
||||
} as Condition;
|
||||
}
|
||||
}
|
||||
|
||||
return cond as Condition;
|
||||
};
|
||||
|
||||
export const triggerAutomationActions = (
|
||||
hass: HomeAssistant,
|
||||
entityId: string
|
||||
|
@@ -11,6 +11,8 @@ export interface DeviceAutomation {
|
||||
type?: string;
|
||||
subtype?: string;
|
||||
event?: string;
|
||||
enabled?: boolean;
|
||||
metadata?: { secondary: boolean };
|
||||
}
|
||||
|
||||
export interface DeviceAction extends DeviceAutomation {
|
||||
@@ -179,3 +181,16 @@ export const localizeDeviceAutomationTrigger = (
|
||||
(trigger.subtype ? `"${trigger.subtype}" ${trigger.type}` : trigger.type!)
|
||||
);
|
||||
};
|
||||
|
||||
export const sortDeviceAutomations = (
|
||||
automationA: DeviceAutomation,
|
||||
automationB: DeviceAutomation
|
||||
) => {
|
||||
if (automationA.metadata?.secondary && !automationB.metadata?.secondary) {
|
||||
return 1;
|
||||
}
|
||||
if (!automationA.metadata?.secondary && automationB.metadata?.secondary) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
22
src/data/hardware.ts
Normal file
22
src/data/hardware.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
// Keep in sync with https://github.com/home-assistant/analytics.home-assistant.io/blob/dev/site/src/analytics-os-boards.ts#L6-L24
|
||||
export const BOARD_NAMES: Record<string, string> = {
|
||||
"odroid-n2": "Home Assistant Blue / ODROID-N2",
|
||||
"odroid-xu4": "ODROID-XU4",
|
||||
"odroid-c2": "ODROID-C2",
|
||||
"odroid-c4": "ODROID-C4",
|
||||
rpi: "Raspberry Pi",
|
||||
rpi0: "Raspberry Pi Zero",
|
||||
"rpi0-w": "Raspberry Pi Zero W",
|
||||
rpi2: "Raspberry Pi 2",
|
||||
rpi3: "Raspberry Pi 3 (32-bit)",
|
||||
"rpi3-64": "Raspberry Pi 3",
|
||||
rpi4: "Raspberry Pi 4 (32-bit)",
|
||||
"rpi4-64": "Raspberry Pi 4",
|
||||
tinker: "ASUS Tinker Board",
|
||||
"khadas-vim3": "Khadas VIM3",
|
||||
"generic-aarch64": "Generic AArch64",
|
||||
ova: "Virtual Machine",
|
||||
"generic-x86-64": "Generic x86-64",
|
||||
"intel-nuc": "Intel NUC",
|
||||
yellow: "Home Assistant Yellow",
|
||||
};
|
@@ -13,6 +13,7 @@ import {
|
||||
literal,
|
||||
is,
|
||||
Describe,
|
||||
boolean,
|
||||
} from "superstruct";
|
||||
import { computeObjectId } from "../common/entity/compute_object_id";
|
||||
import { navigate } from "../common/navigate";
|
||||
@@ -25,6 +26,7 @@ export const MODES_MAX = ["queued", "parallel"];
|
||||
|
||||
export const baseActionStruct = object({
|
||||
alias: optional(string()),
|
||||
enabled: optional(boolean()),
|
||||
});
|
||||
|
||||
const targetStruct = object({
|
||||
@@ -88,15 +90,18 @@ export interface BlueprintScriptConfig extends ManualScriptConfig {
|
||||
use_blueprint: { path: string; input?: BlueprintInput };
|
||||
}
|
||||
|
||||
export interface EventAction {
|
||||
interface BaseAction {
|
||||
alias?: string;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface EventAction extends BaseAction {
|
||||
event: string;
|
||||
event_data?: Record<string, any>;
|
||||
event_data_template?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface ServiceAction {
|
||||
alias?: string;
|
||||
export interface ServiceAction extends BaseAction {
|
||||
service?: string;
|
||||
service_template?: string;
|
||||
entity_id?: string;
|
||||
@@ -104,55 +109,48 @@ export interface ServiceAction {
|
||||
data?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface DeviceAction {
|
||||
alias?: string;
|
||||
export interface DeviceAction extends BaseAction {
|
||||
type: string;
|
||||
device_id: string;
|
||||
domain: string;
|
||||
entity_id: string;
|
||||
}
|
||||
|
||||
export interface DelayActionParts {
|
||||
export interface DelayActionParts extends BaseAction {
|
||||
milliseconds?: number;
|
||||
seconds?: number;
|
||||
minutes?: number;
|
||||
hours?: number;
|
||||
days?: number;
|
||||
}
|
||||
export interface DelayAction {
|
||||
alias?: string;
|
||||
export interface DelayAction extends BaseAction {
|
||||
delay: number | Partial<DelayActionParts> | string;
|
||||
}
|
||||
|
||||
export interface ServiceSceneAction {
|
||||
alias?: string;
|
||||
export interface ServiceSceneAction extends BaseAction {
|
||||
service: "scene.turn_on";
|
||||
target?: { entity_id?: string };
|
||||
entity_id?: string;
|
||||
metadata: Record<string, unknown>;
|
||||
}
|
||||
export interface LegacySceneAction {
|
||||
alias?: string;
|
||||
export interface LegacySceneAction extends BaseAction {
|
||||
scene: string;
|
||||
}
|
||||
export type SceneAction = ServiceSceneAction | LegacySceneAction;
|
||||
|
||||
export interface WaitAction {
|
||||
alias?: string;
|
||||
export interface WaitAction extends BaseAction {
|
||||
wait_template: string;
|
||||
timeout?: number;
|
||||
continue_on_timeout?: boolean;
|
||||
}
|
||||
|
||||
export interface WaitForTriggerAction {
|
||||
alias?: string;
|
||||
export interface WaitForTriggerAction extends BaseAction {
|
||||
wait_for_trigger: Trigger | Trigger[];
|
||||
timeout?: number;
|
||||
continue_on_timeout?: boolean;
|
||||
}
|
||||
|
||||
export interface PlayMediaAction {
|
||||
alias?: string;
|
||||
export interface PlayMediaAction extends BaseAction {
|
||||
service: "media_player.play_media";
|
||||
target?: { entity_id?: string };
|
||||
entity_id?: string;
|
||||
@@ -160,13 +158,11 @@ export interface PlayMediaAction {
|
||||
metadata: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface RepeatAction {
|
||||
alias?: string;
|
||||
export interface RepeatAction extends BaseAction {
|
||||
repeat: CountRepeat | WhileRepeat | UntilRepeat;
|
||||
}
|
||||
|
||||
interface BaseRepeat {
|
||||
alias?: string;
|
||||
interface BaseRepeat extends BaseAction {
|
||||
sequence: Action | Action[];
|
||||
}
|
||||
|
||||
@@ -182,38 +178,36 @@ export interface UntilRepeat extends BaseRepeat {
|
||||
until: Condition[];
|
||||
}
|
||||
|
||||
export interface ChooseActionChoice {
|
||||
alias?: string;
|
||||
export interface ChooseActionChoice extends BaseAction {
|
||||
conditions: string | Condition[];
|
||||
sequence: Action | Action[];
|
||||
}
|
||||
|
||||
export interface ChooseAction {
|
||||
alias?: string;
|
||||
export interface ChooseAction extends BaseAction {
|
||||
choose: ChooseActionChoice | ChooseActionChoice[] | null;
|
||||
default?: Action | Action[];
|
||||
}
|
||||
|
||||
export interface IfAction {
|
||||
alias?: string;
|
||||
export interface IfAction extends BaseAction {
|
||||
if: string | Condition[];
|
||||
then: Action | Action[];
|
||||
else?: Action | Action[];
|
||||
}
|
||||
|
||||
export interface VariablesAction {
|
||||
alias?: string;
|
||||
export interface VariablesAction extends BaseAction {
|
||||
variables: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface StopAction {
|
||||
alias?: string;
|
||||
export interface StopAction extends BaseAction {
|
||||
stop: string;
|
||||
error?: boolean;
|
||||
}
|
||||
|
||||
interface UnknownAction {
|
||||
alias?: string;
|
||||
export interface ParallelAction extends BaseAction {
|
||||
parallel: Action | Action[];
|
||||
}
|
||||
|
||||
interface UnknownAction extends BaseAction {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -232,6 +226,7 @@ export type Action =
|
||||
| VariablesAction
|
||||
| PlayMediaAction
|
||||
| StopAction
|
||||
| ParallelAction
|
||||
| UnknownAction;
|
||||
|
||||
export interface ActionTypes {
|
||||
@@ -249,6 +244,7 @@ export interface ActionTypes {
|
||||
service: ServiceAction;
|
||||
play_media: PlayMediaAction;
|
||||
stop: StopAction;
|
||||
parallel: ParallelAction;
|
||||
unknown: UnknownAction;
|
||||
}
|
||||
|
||||
@@ -328,6 +324,9 @@ export const getActionType = (action: Action): ActionType => {
|
||||
if ("stop" in action) {
|
||||
return "stop";
|
||||
}
|
||||
if ("parallel" in action) {
|
||||
return "parallel";
|
||||
}
|
||||
if ("service" in action) {
|
||||
if ("metadata" in action) {
|
||||
if (is(action, activateSceneActionStruct)) {
|
||||
|
@@ -169,5 +169,9 @@ export const describeAction = <T extends ActionType>(
|
||||
}`;
|
||||
}
|
||||
|
||||
if (actionType === "parallel") {
|
||||
return "Run in parallel";
|
||||
}
|
||||
|
||||
return actionType;
|
||||
};
|
||||
|
@@ -99,6 +99,7 @@ class HassSubpage extends LitElement {
|
||||
ha-icon-button-arrow-prev,
|
||||
::slotted([slot="toolbar-icon"]) {
|
||||
pointer-events: auto;
|
||||
color: var(--sidebar-icon-color);
|
||||
}
|
||||
|
||||
.main-title {
|
||||
|
@@ -33,6 +33,7 @@ import "./types/ha-automation-action-delay";
|
||||
import "./types/ha-automation-action-device_id";
|
||||
import "./types/ha-automation-action-event";
|
||||
import "./types/ha-automation-action-if";
|
||||
import "./types/ha-automation-action-parallel";
|
||||
import "./types/ha-automation-action-play_media";
|
||||
import "./types/ha-automation-action-repeat";
|
||||
import "./types/ha-automation-action-service";
|
||||
@@ -54,6 +55,7 @@ const OPTIONS = [
|
||||
"if",
|
||||
"device_id",
|
||||
"stop",
|
||||
"parallel",
|
||||
];
|
||||
|
||||
const getType = (action: Action | undefined) => {
|
||||
@@ -160,62 +162,82 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="card-menu">
|
||||
${this.index !== 0
|
||||
? html`
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.move_up"
|
||||
)}
|
||||
.path=${mdiArrowUp}
|
||||
@click=${this._moveUp}
|
||||
></ha-icon-button>
|
||||
`
|
||||
: ""}
|
||||
${this.index !== this.totalActions - 1
|
||||
? html`
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.move_down"
|
||||
)}
|
||||
.path=${mdiArrowDown}
|
||||
@click=${this._moveDown}
|
||||
></ha-icon-button>
|
||||
`
|
||||
: ""}
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.run_action"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item .disabled=${!this._uiModeAvailable}>
|
||||
${yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item class="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
${this.action.enabled === false
|
||||
? html`<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.disabled"
|
||||
)}
|
||||
</div>`
|
||||
: ""}
|
||||
<div class="card-menu">
|
||||
${this.index !== 0
|
||||
? html`
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.move_up"
|
||||
)}
|
||||
.path=${mdiArrowUp}
|
||||
@click=${this._moveUp}
|
||||
></ha-icon-button>
|
||||
`
|
||||
: ""}
|
||||
${this.index !== this.totalActions - 1
|
||||
? html`
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.move_down"
|
||||
)}
|
||||
.path=${mdiArrowDown}
|
||||
@click=${this._moveDown}
|
||||
></ha-icon-button>
|
||||
`
|
||||
: ""}
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.run_action"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item .disabled=${!this._uiModeAvailable}>
|
||||
${yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.action.enabled === false
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.enable"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.disable"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item class="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
<div
|
||||
class="card-content ${this.action.enabled === false
|
||||
? "disabled"
|
||||
: ""}"
|
||||
>
|
||||
${this._warnings
|
||||
? html`<ha-alert
|
||||
alert-type="warning"
|
||||
@@ -314,11 +336,23 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
fireEvent(this, "duplicate");
|
||||
break;
|
||||
case 3:
|
||||
this._onDisable();
|
||||
break;
|
||||
case 4:
|
||||
this._onDelete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _onDisable() {
|
||||
const enabled = !(this.action.enabled ?? true);
|
||||
const value = { ...this.action, enabled };
|
||||
fireEvent(this, "value-changed", { value });
|
||||
if (this._yamlMode) {
|
||||
this._yamlEditor?.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
private async _runAction() {
|
||||
const validated = await validateConfig(this.hass, {
|
||||
action: this.action,
|
||||
@@ -408,11 +442,27 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
.card-content {
|
||||
padding-top: 16px;
|
||||
margin-top: 0;
|
||||
}
|
||||
.disabled-bar {
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
text-align: center;
|
||||
border-top-right-radius: var(--ha-card-border-radius);
|
||||
border-top-left-radius: var(--ha-card-border-radius);
|
||||
}
|
||||
.card-menu {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
float: right;
|
||||
z-index: 3;
|
||||
margin: 4px;
|
||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
:host-context([style*="direction: rtl;"]) .card-menu {
|
||||
right: initial;
|
||||
|
@@ -0,0 +1,56 @@
|
||||
import { CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { Action, ParallelAction } from "../../../../../data/script";
|
||||
import { HaDeviceAction } from "./ha-automation-action-device_id";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import "../ha-automation-action";
|
||||
import "../../../../../components/ha-textfield";
|
||||
import type { ActionElement } from "../ha-automation-action-row";
|
||||
|
||||
@customElement("ha-automation-action-parallel")
|
||||
export class HaParallelAction extends LitElement implements ActionElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public action!: ParallelAction;
|
||||
|
||||
public static get defaultConfig() {
|
||||
return {
|
||||
parallel: [HaDeviceAction.defaultConfig],
|
||||
};
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const action = this.action;
|
||||
|
||||
return html`
|
||||
<ha-automation-action
|
||||
.actions=${action.parallel}
|
||||
@value-changed=${this._actionsChanged}
|
||||
.hass=${this.hass}
|
||||
></ha-automation-action>
|
||||
`;
|
||||
}
|
||||
|
||||
private _actionsChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const value = ev.detail.value as Action[];
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.action,
|
||||
parallel: value,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return haStyle;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-action-parallel": HaParallelAction;
|
||||
}
|
||||
}
|
@@ -10,6 +10,7 @@ import "../../../../components/ha-select";
|
||||
import type { HaSelect } from "../../../../components/ha-select";
|
||||
import "../../../../components/ha-yaml-editor";
|
||||
import type { Condition } from "../../../../data/automation";
|
||||
import { expandConditionWithShorthand } from "../../../../data/automation";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import "./types/ha-automation-condition-and";
|
||||
@@ -42,10 +43,14 @@ const OPTIONS = [
|
||||
export default class HaAutomationConditionEditor extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public condition!: Condition;
|
||||
@property() condition!: Condition;
|
||||
|
||||
@property() public yamlMode = false;
|
||||
|
||||
private _processedCondition = memoizeOne((condition) =>
|
||||
expandConditionWithShorthand(condition)
|
||||
);
|
||||
|
||||
private _processedTypes = memoizeOne(
|
||||
(localize: LocalizeFunc): [string, string][] =>
|
||||
OPTIONS.map(
|
||||
@@ -60,7 +65,8 @@ export default class HaAutomationConditionEditor extends LitElement {
|
||||
);
|
||||
|
||||
protected render() {
|
||||
const selected = OPTIONS.indexOf(this.condition.condition);
|
||||
const condition = this._processedCondition(this.condition);
|
||||
const selected = OPTIONS.indexOf(condition.condition);
|
||||
const yamlMode = this.yamlMode || selected === -1;
|
||||
return html`
|
||||
${yamlMode
|
||||
@@ -70,7 +76,7 @@ export default class HaAutomationConditionEditor extends LitElement {
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.unsupported_condition",
|
||||
"condition",
|
||||
this.condition.condition
|
||||
condition.condition
|
||||
)}
|
||||
`
|
||||
: ""}
|
||||
@@ -90,7 +96,7 @@ export default class HaAutomationConditionEditor extends LitElement {
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type_select"
|
||||
)}
|
||||
.value=${this.condition.condition}
|
||||
.value=${condition.condition}
|
||||
naturalMenuWidth
|
||||
@selected=${this._typeChanged}
|
||||
>
|
||||
@@ -103,8 +109,8 @@ export default class HaAutomationConditionEditor extends LitElement {
|
||||
|
||||
<div>
|
||||
${dynamicElement(
|
||||
`ha-automation-condition-${this.condition.condition}`,
|
||||
{ hass: this.hass, condition: this.condition }
|
||||
`ha-automation-condition-${condition.condition}`,
|
||||
{ hass: this.hass, condition: condition }
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
@@ -124,7 +130,7 @@ export default class HaAutomationConditionEditor extends LitElement {
|
||||
defaultConfig: Omit<Condition, "condition">;
|
||||
};
|
||||
|
||||
if (type !== this.condition.condition) {
|
||||
if (type !== this._processedCondition(this.condition).condition) {
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
condition: type,
|
||||
|
@@ -2,7 +2,7 @@ import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||
import "../../../../components/ha-button-menu";
|
||||
@@ -19,6 +19,7 @@ import { haStyle } from "../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "./ha-automation-condition-editor";
|
||||
import { validateConfig } from "../../../../data/config";
|
||||
import { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||
|
||||
export interface ConditionElement extends LitElement {
|
||||
condition: Condition;
|
||||
@@ -59,47 +60,69 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
|
||||
@state() private _warnings?: string[];
|
||||
|
||||
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
||||
|
||||
protected render() {
|
||||
if (!this.condition) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="card-menu">
|
||||
<ha-progress-button @click=${this._testCondition}>
|
||||
${this.condition.enabled === false
|
||||
? html`<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.test"
|
||||
"ui.panel.config.automation.editor.actions.disabled"
|
||||
)}
|
||||
</ha-progress-button>
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
>
|
||||
</ha-icon-button>
|
||||
<mwc-list-item>
|
||||
${this._yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item class="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
</div>`
|
||||
: ""}
|
||||
<div class="card-menu">
|
||||
<ha-progress-button @click=${this._testCondition}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.test"
|
||||
)}
|
||||
</ha-progress-button>
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
>
|
||||
</ha-icon-button>
|
||||
<mwc-list-item>
|
||||
${this._yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.condition.enabled === false
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.enable"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.disable"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item class="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
<div
|
||||
class="card-content ${this.condition.enabled === false
|
||||
? "disabled"
|
||||
: ""}"
|
||||
>
|
||||
${this._warnings
|
||||
? html`<ha-alert
|
||||
alert-type="warning"
|
||||
@@ -153,11 +176,23 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
fireEvent(this, "duplicate");
|
||||
break;
|
||||
case 2:
|
||||
this._onDisable();
|
||||
break;
|
||||
case 3:
|
||||
this._onDelete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private _onDisable() {
|
||||
const enabled = !(this.condition.enabled ?? true);
|
||||
const value = { ...this.condition, enabled };
|
||||
fireEvent(this, "value-changed", { value });
|
||||
if (this._yamlMode) {
|
||||
this._yamlEditor?.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
private _onDelete() {
|
||||
showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
@@ -238,9 +273,24 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
.card-content {
|
||||
padding-top: 16px;
|
||||
margin-top: 0;
|
||||
}
|
||||
.disabled-bar {
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
text-align: center;
|
||||
border-top-right-radius: var(--ha-card-border-radius);
|
||||
border-top-left-radius: var(--ha-card-border-radius);
|
||||
}
|
||||
.card-menu {
|
||||
float: right;
|
||||
z-index: 3;
|
||||
margin: 4px;
|
||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import { object, optional, number, string } from "superstruct";
|
||||
import { object, optional, number, string, boolean } from "superstruct";
|
||||
|
||||
export const baseTriggerStruct = object({
|
||||
platform: string(),
|
||||
id: optional(string()),
|
||||
enabled: optional(boolean()),
|
||||
});
|
||||
|
||||
export const forDictStruct = object({
|
||||
|
@@ -3,7 +3,7 @@ import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||
@@ -16,7 +16,7 @@ import "../../../../components/ha-alert";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import "../../../../components/ha-yaml-editor";
|
||||
import { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||
import "../../../../components/ha-select";
|
||||
import type { HaSelect } from "../../../../components/ha-select";
|
||||
import "../../../../components/ha-textfield";
|
||||
@@ -104,6 +104,8 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
|
||||
@state() private _triggerColor = false;
|
||||
|
||||
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
||||
|
||||
private _triggerUnsub?: Promise<UnsubscribeFunc>;
|
||||
|
||||
private _processedTypes = memoizeOne(
|
||||
@@ -126,40 +128,60 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
<div class="card-menu">
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.edit_id"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item .disabled=${selected === -1}>
|
||||
${yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item class="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
${this.trigger.enabled === false
|
||||
? html`<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.disabled"
|
||||
)}
|
||||
</div>`
|
||||
: ""}
|
||||
<div class="card-menu">
|
||||
<ha-button-menu corner="BOTTOM_START" @action=${this._handleAction}>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.edit_id"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item .disabled=${selected === -1}>
|
||||
${yamlMode
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_ui"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.edit_yaml"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.duplicate"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item>
|
||||
${this.trigger.enabled === false
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.enable"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.disable"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
<mwc-list-item class="warning">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.delete"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
<div
|
||||
class="card-content ${this.trigger.enabled === false
|
||||
? "disabled"
|
||||
: ""}"
|
||||
>
|
||||
${this._warnings
|
||||
? html`<ha-alert
|
||||
alert-type="warning"
|
||||
@@ -214,7 +236,6 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
`
|
||||
)}
|
||||
</ha-select>
|
||||
|
||||
${showId
|
||||
? html`
|
||||
<ha-textfield
|
||||
@@ -250,7 +271,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
protected override updated(changedProps: PropertyValues): void {
|
||||
protected override updated(changedProps: PropertyValues<this>): void {
|
||||
super.updated(changedProps);
|
||||
if (changedProps.has("trigger")) {
|
||||
this._subscribeTrigger();
|
||||
@@ -347,6 +368,9 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
fireEvent(this, "duplicate");
|
||||
break;
|
||||
case 3:
|
||||
this._onDisable();
|
||||
break;
|
||||
case 4:
|
||||
this._onDelete();
|
||||
break;
|
||||
}
|
||||
@@ -365,6 +389,15 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _onDisable() {
|
||||
const enabled = !(this.trigger.enabled ?? true);
|
||||
const value = { ...this.trigger, enabled };
|
||||
fireEvent(this, "value-changed", { value });
|
||||
if (this._yamlMode) {
|
||||
this._yamlEditor?.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
private _typeChanged(ev: CustomEvent) {
|
||||
const type = (ev.target as HaSelect).value;
|
||||
|
||||
@@ -439,10 +472,27 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
.card-content {
|
||||
padding-top: 16px;
|
||||
margin-top: 0;
|
||||
}
|
||||
.disabled-bar {
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
text-align: center;
|
||||
border-top-right-radius: var(--ha-card-border-radius);
|
||||
border-top-left-radius: var(--ha-card-border-radius);
|
||||
}
|
||||
.card-menu {
|
||||
float: right;
|
||||
z-index: 3;
|
||||
margin: 4px;
|
||||
--mdc-theme-text-primary-on-background: var(--primary-text-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
:host-context([style*="direction: rtl;"]) .card-menu {
|
||||
float: left;
|
||||
|
@@ -110,7 +110,9 @@ class ConfigAnalytics extends LitElement {
|
||||
ha-settings-row {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
}
|
||||
.card-actions {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
|
@@ -1,15 +1,23 @@
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import timezones from "google-timezones-json";
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { UNIT_C } from "../../../common/const";
|
||||
import { stopPropagation } from "../../../common/dom/stop_propagation";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { HaProgressButton } from "../../../components/buttons/ha-progress-button";
|
||||
import "../../../components/buttons/ha-progress-button";
|
||||
import type { HaProgressButton } from "../../../components/buttons/ha-progress-button";
|
||||
import { currencies } from "../../../components/currency-datalist";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-formfield";
|
||||
import "../../../components/ha-radio";
|
||||
import type { HaRadio } from "../../../components/ha-radio";
|
||||
import "../../../components/ha-select";
|
||||
import "../../../components/ha-settings-row";
|
||||
import "../../../components/ha-textfield";
|
||||
import "../../../components/map/ha-locations-editor";
|
||||
import type { MarkerLocation } from "../../../components/map/ha-locations-editor";
|
||||
import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core";
|
||||
import { SYMBOL_TO_ISO } from "../../../data/currency";
|
||||
import "../../../layouts/hass-subpage";
|
||||
@@ -34,6 +42,8 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
|
||||
@state() private _timeZone?: string;
|
||||
|
||||
@state() private _location?: [number, number];
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const canEdit = ["storage", "default"].includes(
|
||||
this.hass.config.config_source
|
||||
@@ -47,7 +57,7 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
.header=${this.hass.localize("ui.panel.config.core.caption")}
|
||||
>
|
||||
<div class="content">
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
${!canEdit
|
||||
? html`
|
||||
@@ -177,27 +187,42 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
href="https://en.wikipedia.org/wiki/ISO_4217#Active_codes"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="find-value"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.core.section.core.core_config.find_currency_value"
|
||||
)}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<ha-settings-row>
|
||||
<div slot="heading">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.core.section.core.core_config.edit_location"
|
||||
)}
|
||||
</div>
|
||||
<div slot="description" class="secondary">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.core.section.core.core_config.edit_location_description"
|
||||
)}
|
||||
</div>
|
||||
<mwc-button @click=${this._editLocation}
|
||||
>${this.hass.localize("ui.common.edit")}</mwc-button
|
||||
>
|
||||
</ha-settings-row>
|
||||
${this.narrow
|
||||
? html`
|
||||
<ha-locations-editor
|
||||
.hass=${this.hass}
|
||||
.locations=${this._markerLocation(
|
||||
this.hass.config.latitude,
|
||||
this.hass.config.longitude,
|
||||
this._location
|
||||
)}
|
||||
@location-updated=${this._locationChanged}
|
||||
></ha-locations-editor>
|
||||
`
|
||||
: html`
|
||||
<ha-settings-row>
|
||||
<div slot="heading">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.core.section.core.core_config.edit_location"
|
||||
)}
|
||||
</div>
|
||||
<div slot="description" class="secondary">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.core.section.core.core_config.edit_location_description"
|
||||
)}
|
||||
</div>
|
||||
<mwc-button @click=${this._editLocation}
|
||||
>${this.hass.localize("ui.common.edit")}</mwc-button
|
||||
>
|
||||
</ha-settings-row>
|
||||
`}
|
||||
<div class="card-actions">
|
||||
<ha-progress-button @click=${this._updateEntry}>
|
||||
${this.hass!.localize("ui.panel.config.zone.detail.update")}
|
||||
@@ -237,7 +262,11 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
this._unitSystem = (ev.target as HaRadio).value as "metric" | "imperial";
|
||||
}
|
||||
|
||||
private async _updateEntry(ev) {
|
||||
private _locationChanged(ev: CustomEvent) {
|
||||
this._location = ev.detail.location;
|
||||
}
|
||||
|
||||
private async _updateEntry(ev: CustomEvent) {
|
||||
const button = ev.target as HaProgressButton;
|
||||
if (button.progress) {
|
||||
return;
|
||||
@@ -261,6 +290,21 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _markerLocation = memoizeOne(
|
||||
(
|
||||
lat: number,
|
||||
lng: number,
|
||||
location?: [number, number]
|
||||
): MarkerLocation[] => [
|
||||
{
|
||||
id: "location",
|
||||
latitude: location ? location[0] : lat,
|
||||
longitude: location ? location[1] : lng,
|
||||
location_editable: true,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
private _editLocation() {
|
||||
navigate("/config/zone");
|
||||
}
|
||||
@@ -274,7 +318,7 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
margin: 0 auto;
|
||||
}
|
||||
ha-card {
|
||||
max-width: 500px;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
@@ -302,6 +346,15 @@ class HaConfigSectionGeneral extends LitElement {
|
||||
ha-select {
|
||||
display: block;
|
||||
}
|
||||
a.find-value {
|
||||
margin-top: 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
ha-locations-editor {
|
||||
display: block;
|
||||
height: 400px;
|
||||
padding: 16px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -1,12 +1,13 @@
|
||||
import { ActionDetail } from "@material/mwc-list";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { canShowPage } from "../../../common/config/can_show_page";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-navigation-list";
|
||||
import { CloudStatus } from "../../../data/cloud";
|
||||
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
} from "../../../dialogs/generic/show-dialog-box";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
@@ -41,33 +42,24 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
back-path="/config"
|
||||
.header=${this.hass.localize("ui.panel.config.dashboard.system.main")}
|
||||
>
|
||||
<ha-button-menu
|
||||
corner="BOTTOM_START"
|
||||
<mwc-button
|
||||
slot="toolbar-icon"
|
||||
@action=${this._handleAction}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.overflow_menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<mwc-list-item>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.restart_homeassistant"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
class="warning"
|
||||
.label=${this.narrow
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.restart_homeassistant_short"
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.restart_homeassistant"
|
||||
)}
|
||||
@click=${this._restart}
|
||||
></mwc-button>
|
||||
<ha-config-section
|
||||
.narrow=${this.narrow}
|
||||
.isWide=${this.isWide}
|
||||
full-width
|
||||
>
|
||||
<ha-card outlined>
|
||||
${this.narrow
|
||||
? html`<div class="title">
|
||||
${this.hass.localize("ui.panel.config.dashboard.system.main")}
|
||||
</div>`
|
||||
: ""}
|
||||
<ha-navigation-list
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
@@ -79,19 +71,28 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleAction(ev: CustomEvent<ActionDetail>) {
|
||||
switch (ev.detail.index) {
|
||||
case 0:
|
||||
showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.confirm_restart"
|
||||
),
|
||||
confirm: () => {
|
||||
this.hass.callService("homeassistant", "restart");
|
||||
},
|
||||
private _restart() {
|
||||
showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.confirm_restart_title"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.confirm_restart_text"
|
||||
),
|
||||
confirmText: this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.restart_homeassistant_short"
|
||||
),
|
||||
confirm: () => {
|
||||
this.hass.callService("homeassistant", "restart").catch((reason) => {
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.system_dashboard.restart_error"
|
||||
),
|
||||
text: reason.message,
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
@@ -39,9 +39,9 @@ import { configSections } from "../ha-panel-config";
|
||||
import "./ha-config-navigation";
|
||||
import "./ha-config-updates";
|
||||
|
||||
const randomTip = (hass: HomeAssistant) => {
|
||||
const randomTip = (hass: HomeAssistant, narrow: boolean) => {
|
||||
const weighted: string[] = [];
|
||||
const tips = [
|
||||
let tips = [
|
||||
{
|
||||
content: hass.localize(
|
||||
"ui.panel.config.tips.join",
|
||||
@@ -84,11 +84,16 @@ const randomTip = (hass: HomeAssistant) => {
|
||||
</span>`
|
||||
),
|
||||
weight: 2,
|
||||
narrow: true,
|
||||
},
|
||||
{ content: hass.localize("ui.tips.key_c_hint"), weight: 1 },
|
||||
{ content: hass.localize("ui.tips.key_m_hint"), weight: 1 },
|
||||
{ content: hass.localize("ui.tips.key_c_hint"), weight: 1, narrow: false },
|
||||
{ content: hass.localize("ui.tips.key_m_hint"), weight: 1, narrow: false },
|
||||
];
|
||||
|
||||
if (narrow) {
|
||||
tips = tips.filter((tip) => tip.narrow);
|
||||
}
|
||||
|
||||
tips.forEach((tip) => {
|
||||
for (let i = 0; i < tip.weight; i++) {
|
||||
weighted.push(tip.content);
|
||||
@@ -215,7 +220,7 @@ class HaConfigDashboard extends LitElement {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (!this._tip && changedProps.has("hass")) {
|
||||
this._tip = randomTip(this.hass);
|
||||
this._tip = randomTip(this.hass, this.narrow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { property } from "lit/decorators";
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-chip";
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
DeviceAutomation,
|
||||
} from "../../../../data/device_automation";
|
||||
import { showScriptEditor } from "../../../../data/script";
|
||||
import { buttonLinkStyle } from "../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
|
||||
declare global {
|
||||
@@ -29,6 +30,8 @@ export abstract class HaDeviceAutomationCard<
|
||||
|
||||
@property() public automations: T[] = [];
|
||||
|
||||
@state() public _showSecondary = false;
|
||||
|
||||
protected headerKey = "";
|
||||
|
||||
protected type = "";
|
||||
@@ -60,28 +63,47 @@ export abstract class HaDeviceAutomationCard<
|
||||
if (this.automations.length === 0) {
|
||||
return html``;
|
||||
}
|
||||
const automations = this._showSecondary
|
||||
? this.automations
|
||||
: this.automations.filter(
|
||||
(automation) => automation.metadata?.secondary === false
|
||||
);
|
||||
return html`
|
||||
<h3>${this.hass.localize(this.headerKey)}</h3>
|
||||
<div class="content">
|
||||
<ha-chip-set>
|
||||
${this.automations.map(
|
||||
${automations.map(
|
||||
(automation, idx) =>
|
||||
html`
|
||||
<ha-chip .index=${idx} @click=${this._handleAutomationClicked}>
|
||||
<ha-chip
|
||||
.index=${idx}
|
||||
@click=${this._handleAutomationClicked}
|
||||
class=${automation.metadata?.secondary ? "secondary" : ""}
|
||||
>
|
||||
${this._localizeDeviceAutomation(this.hass, automation)}
|
||||
</ha-chip>
|
||||
`
|
||||
)}
|
||||
</ha-chip-set>
|
||||
${!this._showSecondary && automations.length < this.automations.length
|
||||
? html`<button class="link" @click=${this._toggleSecondary}>
|
||||
Show ${this.automations.length - automations.length} more...
|
||||
</button>`
|
||||
: ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _toggleSecondary() {
|
||||
this._showSecondary = !this._showSecondary;
|
||||
}
|
||||
|
||||
private _handleAutomationClicked(ev: CustomEvent) {
|
||||
const automation = this.automations[(ev.currentTarget as any).index];
|
||||
const automation = { ...this.automations[(ev.currentTarget as any).index] };
|
||||
if (!automation) {
|
||||
return;
|
||||
}
|
||||
delete automation.metadata;
|
||||
if (this.script) {
|
||||
showScriptEditor({ sequence: [automation as DeviceAction] });
|
||||
fireEvent(this, "entry-selected");
|
||||
@@ -93,11 +115,18 @@ export abstract class HaDeviceAutomationCard<
|
||||
fireEvent(this, "entry-selected");
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
static styles = [
|
||||
buttonLinkStyle,
|
||||
css`
|
||||
h3 {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
.secondary {
|
||||
--ha-chip-background-color: rgba(var(--rgb-primary-text-color), 0.07);
|
||||
}
|
||||
button.link {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import {
|
||||
fetchDeviceActions,
|
||||
fetchDeviceConditions,
|
||||
fetchDeviceTriggers,
|
||||
sortDeviceAutomations,
|
||||
} from "../../../../data/device_automation";
|
||||
import { haStyleDialog } from "../../../../resources/styles";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
@@ -63,16 +64,16 @@ export class DialogDeviceAutomation extends LitElement {
|
||||
const { device, script } = this._params;
|
||||
|
||||
fetchDeviceActions(this.hass, device.id).then((actions) => {
|
||||
this._actions = actions;
|
||||
this._actions = actions.sort(sortDeviceAutomations);
|
||||
});
|
||||
if (script) {
|
||||
return;
|
||||
}
|
||||
fetchDeviceTriggers(this.hass, device.id).then((triggers) => {
|
||||
this._triggers = triggers;
|
||||
this._triggers = triggers.sort(sortDeviceAutomations);
|
||||
});
|
||||
fetchDeviceConditions(this.hass, device.id).then((conditions) => {
|
||||
this._conditions = conditions;
|
||||
this._conditions = conditions.sort(sortDeviceAutomations);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -224,14 +224,14 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
||||
path: "/config/person",
|
||||
translationKey: "ui.panel.config.person.caption",
|
||||
iconPath: mdiAccount,
|
||||
iconColor: "#E48629",
|
||||
iconColor: "#5A87FA",
|
||||
},
|
||||
{
|
||||
component: "users",
|
||||
path: "/config/users",
|
||||
translationKey: "ui.panel.config.users.caption",
|
||||
iconPath: mdiBadgeAccountHorizontal,
|
||||
iconColor: "#E48629",
|
||||
iconColor: "#5A87FA",
|
||||
core: true,
|
||||
advancedOnly: true,
|
||||
},
|
||||
@@ -254,6 +254,13 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
||||
},
|
||||
],
|
||||
general: [
|
||||
{
|
||||
path: "/config/general",
|
||||
translationKey: "ui.panel.config.core.caption",
|
||||
iconPath: mdiCog,
|
||||
iconColor: "#653249",
|
||||
core: true,
|
||||
},
|
||||
{
|
||||
path: "/config/updates",
|
||||
translationKey: "ui.panel.config.updates.caption",
|
||||
@@ -315,13 +322,6 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
||||
iconColor: "#507FfE",
|
||||
components: ["system_health", "hassio"],
|
||||
},
|
||||
{
|
||||
path: "/config/general",
|
||||
translationKey: "ui.panel.config.core.caption",
|
||||
iconPath: mdiCog,
|
||||
iconColor: "#653249",
|
||||
core: true,
|
||||
},
|
||||
],
|
||||
about: [
|
||||
{
|
||||
|
@@ -8,6 +8,7 @@ import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-settings-row";
|
||||
import { BOARD_NAMES } from "../../../data/hardware";
|
||||
import {
|
||||
extractApiErrorMessage,
|
||||
ignoreSupervisorError,
|
||||
@@ -56,6 +57,18 @@ class HaConfigHardware extends LitElement {
|
||||
.narrow=${this.narrow}
|
||||
.header=${this.hass.localize("ui.panel.config.hardware.caption")}
|
||||
>
|
||||
<ha-button-menu corner="BOTTOM_START" slot="toolbar-icon">
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
slot="trigger"
|
||||
></ha-icon-button>
|
||||
<mwc-list-item @click=${this._openHardware}
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.hardware.available_hardware.title"
|
||||
)}</mwc-list-item
|
||||
>
|
||||
</ha-button-menu>
|
||||
${this._error
|
||||
? html`
|
||||
<ha-alert alert-type="error"
|
||||
@@ -68,59 +81,47 @@ class HaConfigHardware extends LitElement {
|
||||
<div class="content">
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<ha-settings-row>
|
||||
<span slot="heading"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.hardware.board"
|
||||
)}</span
|
||||
>
|
||||
<div slot="description">
|
||||
<span class="value">${this._OSData.board}</span>
|
||||
</div>
|
||||
</ha-settings-row>
|
||||
${this._OSData?.board
|
||||
? html`
|
||||
<ha-settings-row>
|
||||
<span slot="heading"
|
||||
>${BOARD_NAMES[this._OSData.board] ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.hardware.board"
|
||||
)}</span
|
||||
>
|
||||
<div slot="description">
|
||||
<span class="value">${this._OSData.board}</span>
|
||||
</div>
|
||||
</ha-settings-row>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<div class="buttons">
|
||||
${this._hostData.features.includes("reboot")
|
||||
? html`
|
||||
<ha-progress-button
|
||||
class="warning"
|
||||
@click=${this._hostReboot}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.hardware.reboot_host"
|
||||
)}
|
||||
</ha-progress-button>
|
||||
`
|
||||
: ""}
|
||||
${this._hostData.features.includes("shutdown")
|
||||
? html`
|
||||
<ha-progress-button
|
||||
class="warning"
|
||||
@click=${this._hostShutdown}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.hardware.shutdown_host"
|
||||
)}
|
||||
</ha-progress-button>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<ha-button-menu corner="BOTTOM_START">
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
slot="trigger"
|
||||
></ha-icon-button>
|
||||
<mwc-list-item
|
||||
.action=${"hardware"}
|
||||
@click=${this._openHardware}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.hardware.available_hardware.title"
|
||||
)}
|
||||
</mwc-list-item>
|
||||
</ha-button-menu>
|
||||
${this._hostData.features.includes("reboot")
|
||||
? html`
|
||||
<ha-progress-button
|
||||
class="warning"
|
||||
@click=${this._hostReboot}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.hardware.reboot_host"
|
||||
)}
|
||||
</ha-progress-button>
|
||||
`
|
||||
: ""}
|
||||
${this._hostData.features.includes("shutdown")
|
||||
? html`
|
||||
<ha-progress-button
|
||||
class="warning"
|
||||
@click=${this._hostShutdown}
|
||||
>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.hardware.shutdown_host"
|
||||
)}
|
||||
</ha-progress-button>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</ha-card>
|
||||
</div>
|
||||
@@ -241,10 +242,6 @@ class HaConfigHardware extends LitElement {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -111,6 +111,9 @@ export class HassioHostname extends LitElement {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
ha-settings-row {
|
||||
border-top: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
@@ -27,9 +27,9 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
|
||||
@state() private _reloadableDomains: string[] = [];
|
||||
|
||||
private _validateLog = "";
|
||||
@state() private _isValid: boolean | null = null;
|
||||
|
||||
private _isValid: boolean | null = null;
|
||||
private _validateLog = "";
|
||||
|
||||
protected updated(changedProperties) {
|
||||
const oldHass = changedProperties.get("hass");
|
||||
@@ -82,11 +82,6 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
"ui.panel.developer-tools.tabs.yaml.section.validation.invalid"
|
||||
)}
|
||||
</span>
|
||||
<mwc-button raised @click=${this._validateConfig}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.yaml.section.validation.check_config"
|
||||
)}
|
||||
</mwc-button>
|
||||
</div>
|
||||
<div id="configLog" class="validate-log">
|
||||
${this._validateLog}
|
||||
@@ -94,10 +89,7 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
`}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<mwc-button
|
||||
@click=${this._validateConfig}
|
||||
.disabled=${this._validateLog}
|
||||
>
|
||||
<mwc-button @click=${this._validateConfig}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.yaml.section.validation.check_config"
|
||||
)}
|
||||
@@ -175,13 +167,20 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
|
||||
private _restart() {
|
||||
showConfirmationDialog(this, {
|
||||
text: this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.yaml.section.server_management.confirm_restart"
|
||||
title: this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.yaml.section.server_management.confirm_restart_title"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.yaml.section.server_management.confirm_restart_text"
|
||||
),
|
||||
confirmText: this.hass.localize(
|
||||
"ui.panel.developer-tools.tabs.yaml.section.server_management.restart"
|
||||
),
|
||||
confirmText: this.hass!.localize("ui.common.leave"),
|
||||
dismissText: this.hass!.localize("ui.common.stay"),
|
||||
confirm: () => {
|
||||
this.hass.callService("homeassistant", "restart");
|
||||
this.hass.callService("homeassistant", "restart").catch((reason) => {
|
||||
this._isValid = false;
|
||||
this._validateLog = reason.message;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -191,17 +190,17 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
haStyle,
|
||||
css`
|
||||
.validate-container {
|
||||
height: 140px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.validate-result {
|
||||
color: var(--success-color);
|
||||
font-weight: 500;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.config-invalid {
|
||||
margin: 1em 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.config-invalid .text {
|
||||
@@ -215,7 +214,7 @@ export class DeveloperYamlConfig extends LitElement {
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 28px 20px 0;
|
||||
padding: 28px 20px 16px;
|
||||
max-width: 1040px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ const cardConfigStruct = assign(
|
||||
|
||||
const SCHEMA: HaFormSchema[] = [
|
||||
{ name: "title", selector: { text: {} } },
|
||||
{ name: "content", required: true, selector: { text: { multiline: true } } },
|
||||
{ name: "content", required: true, selector: { template: {} } },
|
||||
{ name: "theme", selector: { theme: {} } },
|
||||
];
|
||||
|
||||
|
@@ -686,6 +686,16 @@ export class BarMediaPlayer extends LitElement {
|
||||
mwc-list-item[selected] {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
:host-context([style*="direction: rtl;"]) ha-svg-icon[slot="icon"] {
|
||||
margin-left: 8px !important;
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
:host-context([style*="direction: rtl;"])
|
||||
ha-svg-icon[slot="trailingIcon"] {
|
||||
margin-left: 0px !important;
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
@@ -278,6 +278,7 @@ class PanelMediaBrowser extends LitElement {
|
||||
|
||||
ha-media-player-browse {
|
||||
height: calc(100vh - (100px + var(--header-height)));
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
:host([narrow]) ha-media-player-browse {
|
||||
|
@@ -34,6 +34,9 @@ export const getMyRedirects = (hasSupervisor: boolean): Redirects => ({
|
||||
developer_statistics: {
|
||||
redirect: "/developer-tools/statistics",
|
||||
},
|
||||
server_controls: {
|
||||
redirect: "/developer-tools/yaml",
|
||||
},
|
||||
config: {
|
||||
redirect: "/config/dashboard",
|
||||
},
|
||||
@@ -129,10 +132,7 @@ export const getMyRedirects = (hasSupervisor: boolean): Redirects => ({
|
||||
redirect: "/config/users",
|
||||
},
|
||||
general: {
|
||||
redirect: "/config/core",
|
||||
},
|
||||
server_controls: {
|
||||
redirect: "/developer-tools/yaml",
|
||||
redirect: "/config/general",
|
||||
},
|
||||
logs: {
|
||||
redirect: "/config/logs",
|
||||
@@ -140,6 +140,27 @@ export const getMyRedirects = (hasSupervisor: boolean): Redirects => ({
|
||||
info: {
|
||||
redirect: "/config/info",
|
||||
},
|
||||
system_health: {
|
||||
redirect: "/config/system_health",
|
||||
},
|
||||
hardware: {
|
||||
redirect: "/config/hardware",
|
||||
},
|
||||
storage: {
|
||||
redirect: "/config/storage",
|
||||
},
|
||||
network: {
|
||||
redirect: "/config/network",
|
||||
},
|
||||
analytics: {
|
||||
redirect: "/config/analytics",
|
||||
},
|
||||
updates: {
|
||||
redirect: "/config/updates",
|
||||
},
|
||||
system_dashboard: {
|
||||
redirect: "/config/system",
|
||||
},
|
||||
customize: {
|
||||
// customize was removed in 2021.12, fallback to dashboard
|
||||
redirect: "/config/dashboard",
|
||||
|
@@ -1493,7 +1493,7 @@
|
||||
"unit_system_metric": "Metric",
|
||||
"imperial_example": "Fahrenheit, pounds",
|
||||
"metric_example": "Celsius, kilograms",
|
||||
"find_currency_value": "Find your value",
|
||||
"find_currency_value": "Find my value",
|
||||
"save_button": "Save",
|
||||
"currency": "Currency",
|
||||
"edit_location": "Edit location",
|
||||
@@ -1519,7 +1519,7 @@
|
||||
"caption": "Hardware",
|
||||
"available_hardware": {
|
||||
"failed_to_get": "Failed to get available hardware",
|
||||
"title": "Available hardware",
|
||||
"title": "All Hardware",
|
||||
"subsystem": "Subsystem",
|
||||
"device_path": "Device path",
|
||||
"id": "ID",
|
||||
@@ -1675,7 +1675,7 @@
|
||||
"introduction": "The automation editor allows you to create and edit automations. Please follow the link below to read the instructions to make sure that you have configured Home Assistant correctly.",
|
||||
"learn_more": "Learn more about automations",
|
||||
"pick_automation": "Pick automation to edit",
|
||||
"no_automations": "We couldn’t find any automations",
|
||||
"no_automations": "We couldn't find any automations",
|
||||
"add_automation": "Create automation",
|
||||
"only_editable": "Only automations in automations.yaml are editable.",
|
||||
"dev_only_editable": "Only automations that have a unique ID assigned are debuggable.",
|
||||
@@ -1961,6 +1961,9 @@
|
||||
"run_action_error": "Error running action",
|
||||
"run_action_success": "Action run successfully",
|
||||
"duplicate": "[%key:ui::panel::config::automation::editor::triggers::duplicate%]",
|
||||
"enable": "Enable",
|
||||
"disable": "Disable",
|
||||
"disabled": "Disabled",
|
||||
"delete": "[%key:ui::panel::mailbox::delete_button%]",
|
||||
"delete_confirm": "[%key:ui::panel::config::automation::editor::triggers::delete_confirm%]",
|
||||
"unsupported_action": "No visual editor support for action: {action}",
|
||||
@@ -2050,6 +2053,9 @@
|
||||
"label": "Stop",
|
||||
"stop": "Reason for stopping",
|
||||
"error": "Stop because of an unexpected error"
|
||||
},
|
||||
"parallel": {
|
||||
"label": "Run in parallel"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3164,8 +3170,11 @@
|
||||
"supervisor_stats": "Supervisor Stats"
|
||||
},
|
||||
"system_dashboard": {
|
||||
"confirm_restart": "Are you sure you want to restart Home Assistant?",
|
||||
"restart_homeassistant": "Restart Home Assistant"
|
||||
"confirm_restart_text": "Restarting Home Assistant will stop all your active dashboards, automations and scripts.",
|
||||
"confirm_restart_title": "Restart Home Assistant?",
|
||||
"restart_homeassistant": "Restart Home Assistant",
|
||||
"restart_homeassistant_short": "Restart",
|
||||
"restart_error": "Failed to restart Home Assistant"
|
||||
}
|
||||
},
|
||||
"lovelace": {
|
||||
@@ -4151,10 +4160,10 @@
|
||||
"section": {
|
||||
"validation": {
|
||||
"heading": "Configuration validation",
|
||||
"introduction": "Validate your configuration if you recently made some changes to your configuration and want to make sure that it is all valid.",
|
||||
"introduction": "Validate your configuration if you recently made some changes to it and want to make sure that it is all valid.",
|
||||
"check_config": "Check configuration",
|
||||
"valid": "Configuration valid!",
|
||||
"invalid": "Configuration invalid"
|
||||
"invalid": "Configuration invalid!"
|
||||
},
|
||||
"reloading": {
|
||||
"heading": "YAML configuration reloading",
|
||||
@@ -4196,12 +4205,12 @@
|
||||
},
|
||||
"server_management": {
|
||||
"heading": "Home Assistant",
|
||||
"introduction": "Restarting Home Assistant will stop your dashboard and automations. After the reboot, each configuration will be reloaded.",
|
||||
"confirm_restart_text": "Restarting Home Assistant will stop all your active dashboards, automations and scripts.",
|
||||
"confirm_restart_title": "Restart Home Assistant?",
|
||||
"restart": "Restart",
|
||||
"restart_home_assistant": "Restart Home Assistant",
|
||||
"confirm_restart": "Are you sure you want to restart Home Assistant?",
|
||||
"stop": "Stop",
|
||||
"confirm_stop": "Are you sure you want to stop Home Assistant?"
|
||||
"confirm_stop": "Are you sure you want to stop Home Assistant?",
|
||||
"restart_error": "Failed to restart Home Assistant"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user