mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-21 08:16:36 +00:00
Merge pull request #9510 from home-assistant/dev
This commit is contained in:
commit
fabbcac99f
@ -302,15 +302,23 @@ gulp.task("gen-index-hassio-prod", async () => {
|
||||
|
||||
function writeHassioEntrypoint(latestEntrypoint, es5Entrypoint) {
|
||||
fs.mkdirSync(paths.hassio_output_root, { recursive: true });
|
||||
// Safari 12 and below does not have a compliant ES2015 implementation of template literals, so we ship ES5
|
||||
fs.writeFileSync(
|
||||
path.resolve(paths.hassio_output_root, "entrypoint.js"),
|
||||
`
|
||||
try {
|
||||
new Function("import('${latestEntrypoint}')")();
|
||||
} catch (err) {
|
||||
function loadES5() {
|
||||
var el = document.createElement('script');
|
||||
el.src = '${es5Entrypoint}';
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
if (/.*Version\\/(?:11|12)(?:\\.\\d+)*.*Safari\\//.test(navigator.userAgent)) {
|
||||
loadES5();
|
||||
} else {
|
||||
try {
|
||||
new Function("import('${latestEntrypoint}')")();
|
||||
} catch (err) {
|
||||
loadES5();
|
||||
}
|
||||
}
|
||||
`,
|
||||
{ encoding: "utf-8" }
|
||||
|
22
script/core
22
script/core
@ -9,12 +9,6 @@ if [ -z "${DEVCONTAINER}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -z "${CODESPACES}" ]; then
|
||||
WORKSPACE="/root/workspace/frontend"
|
||||
else
|
||||
WORKSPACE="/workspaces/frontend"
|
||||
fi
|
||||
|
||||
if [ -z $(which hass) ]; then
|
||||
echo "Installing Home Asstant core from dev."
|
||||
python3 -m pip install --upgrade \
|
||||
@ -22,9 +16,9 @@ if [ -z $(which hass) ]; then
|
||||
git+git://github.com/home-assistant/home-assistant.git@dev
|
||||
fi
|
||||
|
||||
if [ ! -d "${WORKSPACE}/config" ]; then
|
||||
if [ ! -d "/workspaces/frontend/config" ]; then
|
||||
echo "Creating default configuration."
|
||||
mkdir -p "${WORKSPACE}/config";
|
||||
mkdir -p "/workspaces/frontend/config";
|
||||
hass --script ensure_config -c config
|
||||
echo "demo:
|
||||
|
||||
@ -32,24 +26,24 @@ logger:
|
||||
default: info
|
||||
logs:
|
||||
homeassistant.components.frontend: debug
|
||||
" >> "${WORKSPACE}/config/configuration.yaml"
|
||||
" >> /workspaces/frontend/config/configuration.yaml
|
||||
|
||||
if [ ! -z "${HASSIO}" ]; then
|
||||
echo "
|
||||
# frontend:
|
||||
# development_repo: ${WORKSPACE}
|
||||
# development_repo: /workspaces/frontend
|
||||
|
||||
hassio:
|
||||
development_repo: ${WORKSPACE}" >> "${WORKSPACE}/config/configuration.yaml"
|
||||
development_repo: /workspaces/frontend" >> /workspaces/frontend/config/configuration.yaml
|
||||
else
|
||||
echo "
|
||||
frontend:
|
||||
development_repo: ${WORKSPACE}
|
||||
development_repo: /workspaces/frontend
|
||||
|
||||
# hassio:
|
||||
# development_repo: ${WORKSPACE}" >> "${WORKSPACE}/config/configuration.yaml"
|
||||
# development_repo: /workspaces/frontend" >> /workspaces/frontend/config/configuration.yaml
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
hass -c "${WORKSPACE}/config"
|
||||
hass -c /workspaces/frontend/config
|
||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20210630.0",
|
||||
version="20210706.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
@ -20,7 +20,7 @@ interface Tooltip extends TooltipModel<any> {
|
||||
export default class HaChartBase extends LitElement {
|
||||
public chart?: Chart;
|
||||
|
||||
@property()
|
||||
@property({ attribute: "chart-type", reflect: true })
|
||||
public chartType: ChartType = "line";
|
||||
|
||||
@property({ attribute: false })
|
||||
@ -228,6 +228,9 @@ export default class HaChartBase extends LitElement {
|
||||
height: 0;
|
||||
transition: height 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
:host(:not([chart-type="timeline"])) canvas {
|
||||
max-height: 400px;
|
||||
}
|
||||
.chartLegend {
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class StateHistoryChartLine extends LitElement {
|
||||
<ha-chart-base
|
||||
.data=${this._chartData}
|
||||
.options=${this._chartOptions}
|
||||
chartType="line"
|
||||
chart-type="line"
|
||||
></ha-chart-base>
|
||||
`;
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ export class StateHistoryChartTimeline extends LitElement {
|
||||
<ha-chart-base
|
||||
.data=${this._chartData}
|
||||
.options=${this._chartOptions}
|
||||
chartType="timeline"
|
||||
chart-type="timeline"
|
||||
></ha-chart-base>
|
||||
`;
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
import { dump } from "js-yaml";
|
||||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../../components/ha-code-editor";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import { AutomationTraceExtended } from "../../../../data/trace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "../ha-code-editor";
|
||||
import "../ha-icon-button";
|
||||
import { TraceExtended } from "../../data/trace";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
||||
@customElement("ha-automation-trace-blueprint-config")
|
||||
export class HaAutomationTraceBlueprintConfig extends LitElement {
|
||||
@customElement("ha-trace-blueprint-config")
|
||||
export class HaTraceBlueprintConfig extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public trace!: AutomationTraceExtended;
|
||||
@property({ attribute: false }) public trace!: TraceExtended;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
@ -24,6 +24,6 @@ export class HaAutomationTraceBlueprintConfig extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-trace-blueprint-config": HaAutomationTraceBlueprintConfig;
|
||||
"ha-trace-blueprint-config": HaTraceBlueprintConfig;
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
import { dump } from "js-yaml";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../../components/ha-code-editor";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import { AutomationTraceExtended } from "../../../../data/trace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "../ha-code-editor";
|
||||
import "../ha-icon-button";
|
||||
import { TraceExtended } from "../../data/trace";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
||||
@customElement("ha-automation-trace-config")
|
||||
export class HaAutomationTraceConfig extends LitElement {
|
||||
@customElement("ha-trace-config")
|
||||
export class HaTraceConfig extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public trace!: AutomationTraceExtended;
|
||||
@property({ attribute: false }) public trace!: TraceExtended;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
@ -28,6 +28,6 @@ export class HaAutomationTraceConfig extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-trace-config": HaAutomationTraceConfig;
|
||||
"ha-trace-config": HaTraceConfig;
|
||||
}
|
||||
}
|
@ -1,16 +1,19 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../../components/trace/hat-logbook-note";
|
||||
import type { LogbookEntry } from "../../../../data/logbook";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import "../../../logbook/ha-logbook";
|
||||
import { LogbookEntry } from "../../data/logbook";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "./hat-logbook-note";
|
||||
import "../../panels/logbook/ha-logbook";
|
||||
import { TraceExtended } from "../../data/trace";
|
||||
|
||||
@customElement("ha-automation-trace-logbook")
|
||||
export class HaAutomationTraceLogbook extends LitElement {
|
||||
@customElement("ha-trace-logbook")
|
||||
export class HaTraceLogbook extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
|
||||
|
||||
@property({ attribute: false }) public trace!: TraceExtended;
|
||||
|
||||
@property({ attribute: false }) public logbookEntries!: LogbookEntry[];
|
||||
|
||||
protected render(): TemplateResult {
|
||||
@ -22,7 +25,7 @@ export class HaAutomationTraceLogbook extends LitElement {
|
||||
.entries=${this.logbookEntries}
|
||||
.narrow=${this.narrow}
|
||||
></ha-logbook>
|
||||
<hat-logbook-note></hat-logbook-note>
|
||||
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
|
||||
`
|
||||
: html`<div class="padded-box">
|
||||
No Logbook entries found for this step.
|
||||
@ -42,6 +45,6 @@ export class HaAutomationTraceLogbook extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-trace-logbook": HaAutomationTraceLogbook;
|
||||
"ha-trace-logbook": HaTraceLogbook;
|
||||
}
|
||||
}
|
@ -2,33 +2,33 @@ import { dump } from "js-yaml";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { formatDateTimeWithSeconds } from "../../../../common/datetime/format_date_time";
|
||||
import "../../../../components/ha-code-editor";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import type { NodeInfo } from "../../../../components/trace/hat-graph";
|
||||
import "../../../../components/trace/hat-logbook-note";
|
||||
import { LogbookEntry } from "../../../../data/logbook";
|
||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||
import "../ha-code-editor";
|
||||
import "../ha-icon-button";
|
||||
import type { NodeInfo } from "./hat-graph";
|
||||
import "./hat-logbook-note";
|
||||
import { LogbookEntry } from "../../data/logbook";
|
||||
import {
|
||||
ActionTraceStep,
|
||||
AutomationTraceExtended,
|
||||
ChooseActionTraceStep,
|
||||
getDataFromPath,
|
||||
} from "../../../../data/trace";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "../../../logbook/ha-logbook";
|
||||
import { traceTabStyles } from "./styles";
|
||||
TraceExtended,
|
||||
} from "../../data/trace";
|
||||
import "../../panels/logbook/ha-logbook";
|
||||
import { traceTabStyles } from "./trace-tab-styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
||||
@customElement("ha-automation-trace-path-details")
|
||||
export class HaAutomationTracePathDetails extends LitElement {
|
||||
@customElement("ha-trace-path-details")
|
||||
export class HaTracePathDetails extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
|
||||
|
||||
@property() private selected!: NodeInfo;
|
||||
@property({ attribute: false }) public trace!: TraceExtended;
|
||||
|
||||
@property() public trace!: AutomationTraceExtended;
|
||||
@property({ attribute: false }) public logbookEntries!: LogbookEntry[];
|
||||
|
||||
@property() public logbookEntries!: LogbookEntry[];
|
||||
@property({ attribute: false }) public selected!: NodeInfo;
|
||||
|
||||
@property() renderedNodes: Record<string, any> = {};
|
||||
|
||||
@ -230,7 +230,7 @@ export class HaAutomationTracePathDetails extends LitElement {
|
||||
.entries=${entries}
|
||||
.narrow=${this.narrow}
|
||||
></ha-logbook>
|
||||
<hat-logbook-note></hat-logbook-note>
|
||||
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
|
||||
`
|
||||
: html`<div class="padded-box">
|
||||
No Logbook entries found for this step.
|
||||
@ -267,6 +267,6 @@ export class HaAutomationTracePathDetails extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-trace-path-details": HaAutomationTracePathDetails;
|
||||
"ha-trace-path-details": HaTracePathDetails;
|
||||
}
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { NodeInfo } from "../../../../components/trace/hat-graph";
|
||||
import "../../../../components/trace/hat-logbook-note";
|
||||
import "../../../../components/trace/hat-trace-timeline";
|
||||
import type { LogbookEntry } from "../../../../data/logbook";
|
||||
import type { AutomationTraceExtended } from "../../../../data/trace";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { NodeInfo } from "./hat-graph";
|
||||
import "./hat-logbook-note";
|
||||
import "./hat-trace-timeline";
|
||||
import type { LogbookEntry } from "../../data/logbook";
|
||||
import type { TraceExtended } from "../../data/trace";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
|
||||
@customElement("ha-automation-trace-timeline")
|
||||
export class HaAutomationTraceTimeline extends LitElement {
|
||||
@customElement("ha-trace-timeline")
|
||||
export class HaTraceTimeline extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public trace!: AutomationTraceExtended;
|
||||
@property({ attribute: false }) public trace!: TraceExtended;
|
||||
|
||||
@property({ attribute: false }) public logbookEntries!: LogbookEntry[];
|
||||
|
||||
@ -27,7 +27,7 @@ export class HaAutomationTraceTimeline extends LitElement {
|
||||
allowPick
|
||||
>
|
||||
</hat-trace-timeline>
|
||||
<hat-logbook-note></hat-logbook-note>
|
||||
<hat-logbook-note .domain=${this.trace.domain}></hat-logbook-note>
|
||||
`;
|
||||
}
|
||||
|
||||
@ -45,6 +45,6 @@ export class HaAutomationTraceTimeline extends LitElement {
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-trace-timeline": HaAutomationTraceTimeline;
|
||||
"ha-trace-timeline": HaTraceTimeline;
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ export class HatGraphNode extends LitElement {
|
||||
|
||||
@property({ reflect: true, type: Boolean }) disabled?: boolean;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) graphstart?: boolean;
|
||||
@property({ reflect: true, type: Boolean }) graphStart?: boolean;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) nofocus?: boolean;
|
||||
|
||||
@ -21,20 +21,20 @@ export class HatGraphNode extends LitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
const height = NODE_SIZE + (this.graphstart ? 2 : SPACING + 1);
|
||||
const height = NODE_SIZE + (this.graphStart ? 2 : SPACING + 1);
|
||||
const width = SPACING + NODE_SIZE;
|
||||
return svg`
|
||||
<svg
|
||||
width="${width}px"
|
||||
height="${height}px"
|
||||
viewBox="-${Math.ceil(width / 2)} -${
|
||||
this.graphstart
|
||||
this.graphStart
|
||||
? Math.ceil(height / 2)
|
||||
: Math.ceil((NODE_SIZE + SPACING * 2) / 2)
|
||||
} ${width} ${height}"
|
||||
>
|
||||
${
|
||||
this.graphstart
|
||||
this.graphStart
|
||||
? ``
|
||||
: svg`
|
||||
<path
|
||||
|
@ -30,16 +30,16 @@ export class HatGraph extends LitElement {
|
||||
|
||||
@property({ reflect: true, type: Boolean }) branching?: boolean;
|
||||
|
||||
@property({ reflect: true, converter: track_converter })
|
||||
@property({ converter: track_converter })
|
||||
track_start?: number[];
|
||||
|
||||
@property({ reflect: true, converter: track_converter }) track_end?: number[];
|
||||
@property({ converter: track_converter }) track_end?: number[];
|
||||
|
||||
@property({ reflect: true, type: Boolean }) disabled?: boolean;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) selected?: boolean;
|
||||
@property({ type: Boolean }) selected?: boolean;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) short = false;
|
||||
@property({ type: Boolean }) short = false;
|
||||
|
||||
async updateChildren() {
|
||||
this._num_items = this.children.length;
|
||||
@ -68,7 +68,7 @@ export class HatGraph extends LitElement {
|
||||
|
||||
return html`
|
||||
<slot name="head" @slotchange=${this.updateChildren}> </slot>
|
||||
${this.branching
|
||||
${this.branching && branches.some((branch) => !branch.start)
|
||||
? svg`
|
||||
<svg
|
||||
id="top"
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
|
||||
@customElement("hat-logbook-note")
|
||||
class HatLogbookNote extends LitElement {
|
||||
@property() public domain = "automation";
|
||||
|
||||
render() {
|
||||
return html`
|
||||
Not all shown logbook entries might be related to this automation.
|
||||
Not all shown logbook entries might be related to this ${this.domain}.
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,9 @@ import {
|
||||
WaitForTriggerAction,
|
||||
} from "../../data/script";
|
||||
import {
|
||||
AutomationTraceExtended,
|
||||
ChooseActionTraceStep,
|
||||
ConditionTraceStep,
|
||||
TraceExtended,
|
||||
} from "../../data/trace";
|
||||
import "../ha-svg-icon";
|
||||
import { NodeInfo, NODE_SIZE, SPACING } from "./hat-graph";
|
||||
@ -53,7 +53,7 @@ declare global {
|
||||
|
||||
@customElement("hat-script-graph")
|
||||
class HatScriptGraph extends LitElement {
|
||||
@property({ attribute: false }) public trace!: AutomationTraceExtended;
|
||||
@property({ attribute: false }) public trace!: TraceExtended;
|
||||
|
||||
@property({ attribute: false }) public selected;
|
||||
|
||||
@ -137,7 +137,11 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_choose_node(config: ChooseAction, path: string) {
|
||||
private render_choose_node(
|
||||
config: ChooseAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
const trace = this.trace.trace[path] as ChooseActionTraceStep[] | undefined;
|
||||
const trace_path = trace?.[0].result
|
||||
? trace[0].result.choice === "default"
|
||||
@ -157,6 +161,7 @@ class HatScriptGraph extends LitElement {
|
||||
})}
|
||||
>
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiCallSplit}
|
||||
class=${classMap({
|
||||
track: trace !== undefined,
|
||||
@ -210,7 +215,11 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_condition_node(node: Condition, path: string) {
|
||||
private render_condition_node(
|
||||
node: Condition,
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
const trace = (this.trace.trace[path] as ConditionTraceStep[]) || undefined;
|
||||
const track_path =
|
||||
trace?.[0].result === undefined ? 0 : trace[0].result.result ? 1 : 2;
|
||||
@ -228,23 +237,18 @@ class HatScriptGraph extends LitElement {
|
||||
short
|
||||
>
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
slot="head"
|
||||
class=${classMap({
|
||||
track: Boolean(trace),
|
||||
})}
|
||||
.iconPath=${mdiAbTesting}
|
||||
nofocus
|
||||
graphEnd
|
||||
></hat-graph-node>
|
||||
<div
|
||||
style=${`width: ${NODE_SIZE + SPACING}px;`}
|
||||
graphStart
|
||||
graphEnd
|
||||
></div>
|
||||
<div style=${`width: ${NODE_SIZE + SPACING}px;`}></div>
|
||||
<div></div>
|
||||
<hat-graph-node
|
||||
.iconPath=${mdiClose}
|
||||
graphEnd
|
||||
nofocus
|
||||
class=${classMap({
|
||||
track: track_path === 2,
|
||||
@ -254,9 +258,14 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_delay_node(node: DelayAction, path: string) {
|
||||
private render_delay_node(
|
||||
node: DelayAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiTimerOutline}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
class=${classMap({
|
||||
@ -268,9 +277,14 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_device_node(node: DeviceAction, path: string) {
|
||||
private render_device_node(
|
||||
node: DeviceAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiDevices}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
class=${classMap({
|
||||
@ -282,9 +296,14 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_event_node(node: EventAction, path: string) {
|
||||
private render_event_node(
|
||||
node: EventAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiExclamation}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
class=${classMap({
|
||||
@ -296,7 +315,11 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_repeat_node(node: RepeatAction, path: string) {
|
||||
private render_repeat_node(
|
||||
node: RepeatAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
const trace: any = this.trace.trace[path];
|
||||
const track_path = trace ? [0, 1] : [];
|
||||
const repeats = this.trace?.trace[`${path}/repeat/sequence/0`]?.length;
|
||||
@ -313,6 +336,7 @@ class HatScriptGraph extends LitElement {
|
||||
})}
|
||||
>
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiRefresh}
|
||||
class=${classMap({
|
||||
track: trace,
|
||||
@ -337,9 +361,14 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_scene_node(node: SceneAction, path: string) {
|
||||
private render_scene_node(
|
||||
node: SceneAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiExclamation}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
class=${classMap({
|
||||
@ -351,9 +380,14 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_service_node(node: ServiceAction, path: string) {
|
||||
private render_service_node(
|
||||
node: ServiceAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiChevronRight}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
class=${classMap({
|
||||
@ -367,10 +401,12 @@ class HatScriptGraph extends LitElement {
|
||||
|
||||
private render_wait_node(
|
||||
node: WaitAction | WaitForTriggerAction,
|
||||
path: string
|
||||
path: string,
|
||||
graphStart = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiTrafficLight}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
class=${classMap({
|
||||
@ -382,9 +418,10 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_other_node(node: Action, path: string) {
|
||||
private render_other_node(node: Action, path: string, graphStart = false) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiCodeBrackets}
|
||||
@focus=${this.selectNode(node, path)}
|
||||
class=${classMap({
|
||||
@ -395,7 +432,7 @@ class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_node(node: Action, path: string) {
|
||||
private render_node(node: Action, path: string, graphStart = false) {
|
||||
const NODE_TYPES = {
|
||||
choose: this.render_choose_node,
|
||||
condition: this.render_condition_node,
|
||||
@ -411,7 +448,7 @@ class HatScriptGraph extends LitElement {
|
||||
};
|
||||
|
||||
const type = Object.keys(NODE_TYPES).find((key) => key in node) || "other";
|
||||
const nodeEl = NODE_TYPES[type].bind(this)(node, path);
|
||||
const nodeEl = NODE_TYPES[type].bind(this)(node, path, graphStart);
|
||||
this.renderedNodes[path] = { config: node, path };
|
||||
if (this.trace && path in this.trace.trace) {
|
||||
this.trackedNodes[path] = this.renderedNodes[path];
|
||||
@ -423,35 +460,47 @@ class HatScriptGraph extends LitElement {
|
||||
const paths = Object.keys(this.trackedNodes);
|
||||
const manual_triggered = this.trace && "trigger" in this.trace.trace;
|
||||
let track_path = manual_triggered ? undefined : [0];
|
||||
const trigger_nodes = ensureArray(this.trace.config.trigger).map(
|
||||
(trigger, i) => {
|
||||
if (this.trace && `trigger/${i}` in this.trace.trace) {
|
||||
track_path = [i];
|
||||
}
|
||||
return this.render_trigger(trigger, i);
|
||||
}
|
||||
);
|
||||
const trigger_nodes =
|
||||
"trigger" in this.trace.config
|
||||
? ensureArray(this.trace.config.trigger).map((trigger, i) => {
|
||||
if (this.trace && `trigger/${i}` in this.trace.trace) {
|
||||
track_path = [i];
|
||||
}
|
||||
return this.render_trigger(trigger, i);
|
||||
})
|
||||
: undefined;
|
||||
try {
|
||||
return html`
|
||||
<hat-graph class="parent">
|
||||
<div></div>
|
||||
<hat-graph
|
||||
branching
|
||||
id="trigger"
|
||||
.short=${trigger_nodes.length < 2}
|
||||
.track_start=${track_path}
|
||||
.track_end=${track_path}
|
||||
>
|
||||
${trigger_nodes}
|
||||
</hat-graph>
|
||||
<hat-graph id="condition">
|
||||
${ensureArray(this.trace.config.condition)?.map((condition, i) =>
|
||||
this.render_condition(condition!, i)
|
||||
)}
|
||||
</hat-graph>
|
||||
${ensureArray(this.trace.config.action).map((action, i) =>
|
||||
this.render_node(action, `action/${i}`)
|
||||
)}
|
||||
${trigger_nodes
|
||||
? html`<hat-graph
|
||||
branching
|
||||
id="trigger"
|
||||
.short=${trigger_nodes.length < 2}
|
||||
.track_start=${track_path}
|
||||
.track_end=${track_path}
|
||||
>
|
||||
${trigger_nodes}
|
||||
</hat-graph>`
|
||||
: ""}
|
||||
${"condition" in this.trace.config
|
||||
? html`<hat-graph id="condition">
|
||||
${ensureArray(
|
||||
this.trace.config.condition
|
||||
)?.map((condition, i) => this.render_condition(condition!, i))}
|
||||
</hat-graph>`
|
||||
: ""}
|
||||
${"action" in this.trace.config
|
||||
? html`${ensureArray(this.trace.config.action).map((action, i) =>
|
||||
this.render_node(action, `action/${i}`)
|
||||
)}`
|
||||
: ""}
|
||||
${"sequence" in this.trace.config
|
||||
? html`${ensureArray(this.trace.config.sequence).map((action, i) =>
|
||||
this.render_node(action, `sequence/${i}`, i === 0)
|
||||
)}`
|
||||
: ""}
|
||||
</hat-graph>
|
||||
<div class="actions">
|
||||
<mwc-icon-button
|
||||
@ -564,6 +613,7 @@ class HatScriptGraph extends LitElement {
|
||||
}
|
||||
.parent {
|
||||
margin-left: 8px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
.error {
|
||||
padding: 16px;
|
||||
|
@ -51,7 +51,18 @@ export interface ForDict {
|
||||
seconds?: number | string;
|
||||
}
|
||||
|
||||
export interface StateTrigger {
|
||||
export interface ContextConstraint {
|
||||
context_id?: string;
|
||||
parent_id?: string;
|
||||
user_id?: string | string[];
|
||||
}
|
||||
|
||||
export interface BaseTrigger {
|
||||
platform: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export interface StateTrigger extends BaseTrigger {
|
||||
platform: "state";
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
@ -60,25 +71,25 @@ export interface StateTrigger {
|
||||
for?: string | number | ForDict;
|
||||
}
|
||||
|
||||
export interface MqttTrigger {
|
||||
export interface MqttTrigger extends BaseTrigger {
|
||||
platform: "mqtt";
|
||||
topic: string;
|
||||
payload?: string;
|
||||
}
|
||||
|
||||
export interface GeoLocationTrigger {
|
||||
export interface GeoLocationTrigger extends BaseTrigger {
|
||||
platform: "geo_location";
|
||||
source: string;
|
||||
zone: string;
|
||||
event: "enter" | "leave";
|
||||
}
|
||||
|
||||
export interface HassTrigger {
|
||||
export interface HassTrigger extends BaseTrigger {
|
||||
platform: "homeassistant";
|
||||
event: "start" | "shutdown";
|
||||
}
|
||||
|
||||
export interface NumericStateTrigger {
|
||||
export interface NumericStateTrigger extends BaseTrigger {
|
||||
platform: "numeric_state";
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
@ -88,54 +99,48 @@ export interface NumericStateTrigger {
|
||||
for?: string | number | ForDict;
|
||||
}
|
||||
|
||||
export interface SunTrigger {
|
||||
export interface SunTrigger extends BaseTrigger {
|
||||
platform: "sun";
|
||||
offset: number;
|
||||
event: "sunrise" | "sunset";
|
||||
}
|
||||
|
||||
export interface TimePatternTrigger {
|
||||
export interface TimePatternTrigger extends BaseTrigger {
|
||||
platform: "time_pattern";
|
||||
hours?: number | string;
|
||||
minutes?: number | string;
|
||||
seconds?: number | string;
|
||||
}
|
||||
|
||||
export interface WebhookTrigger {
|
||||
export interface WebhookTrigger extends BaseTrigger {
|
||||
platform: "webhook";
|
||||
webhook_id: string;
|
||||
}
|
||||
|
||||
export interface ZoneTrigger {
|
||||
export interface ZoneTrigger extends BaseTrigger {
|
||||
platform: "zone";
|
||||
entity_id: string;
|
||||
zone: string;
|
||||
event: "enter" | "leave";
|
||||
}
|
||||
|
||||
export interface TagTrigger {
|
||||
export interface TagTrigger extends BaseTrigger {
|
||||
platform: "tag";
|
||||
tag_id: string;
|
||||
device_id?: string;
|
||||
}
|
||||
|
||||
export interface TimeTrigger {
|
||||
export interface TimeTrigger extends BaseTrigger {
|
||||
platform: "time";
|
||||
at: string;
|
||||
}
|
||||
|
||||
export interface TemplateTrigger {
|
||||
export interface TemplateTrigger extends BaseTrigger {
|
||||
platform: "template";
|
||||
value_template: string;
|
||||
}
|
||||
|
||||
export interface ContextConstraint {
|
||||
context_id?: string;
|
||||
parent_id?: string;
|
||||
user_id?: string | string[];
|
||||
}
|
||||
|
||||
export interface EventTrigger {
|
||||
export interface EventTrigger extends BaseTrigger {
|
||||
platform: "event";
|
||||
event_type: string;
|
||||
event_data?: any;
|
||||
@ -158,24 +163,26 @@ export type Trigger =
|
||||
| EventTrigger
|
||||
| DeviceTrigger;
|
||||
|
||||
export interface LogicalCondition {
|
||||
condition: "and" | "not" | "or";
|
||||
interface BaseCondition {
|
||||
condition: string;
|
||||
alias?: string;
|
||||
}
|
||||
|
||||
export interface LogicalCondition extends BaseCondition {
|
||||
condition: "and" | "not" | "or";
|
||||
conditions: Condition | Condition[];
|
||||
}
|
||||
|
||||
export interface StateCondition {
|
||||
export interface StateCondition extends BaseCondition {
|
||||
condition: "state";
|
||||
alias?: string;
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
state: string | number;
|
||||
for?: string | number | ForDict;
|
||||
}
|
||||
|
||||
export interface NumericStateCondition {
|
||||
export interface NumericStateCondition extends BaseCondition {
|
||||
condition: "numeric_state";
|
||||
alias?: string;
|
||||
entity_id: string;
|
||||
attribute?: string;
|
||||
above?: number;
|
||||
@ -183,36 +190,37 @@ export interface NumericStateCondition {
|
||||
value_template?: string;
|
||||
}
|
||||
|
||||
export interface SunCondition {
|
||||
export interface SunCondition extends BaseCondition {
|
||||
condition: "sun";
|
||||
alias?: string;
|
||||
after_offset: number;
|
||||
before_offset: number;
|
||||
after: "sunrise" | "sunset";
|
||||
before: "sunrise" | "sunset";
|
||||
}
|
||||
|
||||
export interface ZoneCondition {
|
||||
export interface ZoneCondition extends BaseCondition {
|
||||
condition: "zone";
|
||||
alias?: string;
|
||||
entity_id: string;
|
||||
zone: string;
|
||||
}
|
||||
|
||||
export interface TimeCondition {
|
||||
export interface TimeCondition extends BaseCondition {
|
||||
condition: "time";
|
||||
alias?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
weekday?: string | string[];
|
||||
}
|
||||
|
||||
export interface TemplateCondition {
|
||||
export interface TemplateCondition extends BaseCondition {
|
||||
condition: "template";
|
||||
alias?: string;
|
||||
value_template: string;
|
||||
}
|
||||
|
||||
export interface TriggerCondition extends BaseCondition {
|
||||
condition: "trigger";
|
||||
id: string;
|
||||
}
|
||||
|
||||
export type Condition =
|
||||
| StateCondition
|
||||
| NumericStateCondition
|
||||
@ -221,7 +229,8 @@ export type Condition =
|
||||
| TimeCondition
|
||||
| TemplateCondition
|
||||
| DeviceCondition
|
||||
| LogicalCondition;
|
||||
| LogicalCondition
|
||||
| TriggerCondition;
|
||||
|
||||
export const triggerAutomationActions = (
|
||||
hass: HomeAssistant,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import { HaFormSchema } from "../components/ha-form/ha-form";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { BaseTrigger } from "./automation";
|
||||
|
||||
export interface DeviceAutomation {
|
||||
alias?: string;
|
||||
@ -20,9 +21,10 @@ export interface DeviceCondition extends DeviceAutomation {
|
||||
condition: "device";
|
||||
}
|
||||
|
||||
export interface DeviceTrigger extends DeviceAutomation {
|
||||
platform: "device";
|
||||
}
|
||||
export type DeviceTrigger = DeviceAutomation &
|
||||
BaseTrigger & {
|
||||
platform: "device";
|
||||
};
|
||||
|
||||
export interface DeviceCapabilities {
|
||||
extra_fields: HaFormSchema[];
|
||||
|
@ -7,6 +7,7 @@ import { computeObjectId } from "../common/entity/compute_object_id";
|
||||
import { navigate } from "../common/navigate";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { Condition, Trigger } from "./automation";
|
||||
import { BlueprintInput } from "./blueprint";
|
||||
|
||||
export const MODES = ["single", "restart", "queued", "parallel"] as const;
|
||||
export const MODES_MAX = ["queued", "parallel"];
|
||||
@ -28,6 +29,10 @@ export interface ScriptConfig {
|
||||
max?: number;
|
||||
}
|
||||
|
||||
export interface BlueprintScriptConfig extends ScriptConfig {
|
||||
use_blueprint: { path: string; input?: BlueprintInput };
|
||||
}
|
||||
|
||||
export interface EventAction {
|
||||
alias?: string;
|
||||
event: string;
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
BlueprintAutomationConfig,
|
||||
ManualAutomationConfig,
|
||||
} from "./automation";
|
||||
import { BlueprintScriptConfig, ScriptConfig } from "./script";
|
||||
|
||||
interface BaseTraceStep {
|
||||
path: string;
|
||||
@ -54,7 +55,7 @@ export type ActionTraceStep =
|
||||
| ChooseActionTraceStep
|
||||
| ChooseChoiceActionTraceStep;
|
||||
|
||||
export interface AutomationTrace {
|
||||
interface BaseTrace {
|
||||
domain: string;
|
||||
item_id: string;
|
||||
last_step: string | null;
|
||||
@ -81,23 +82,46 @@ export interface AutomationTrace {
|
||||
// The exception is in the trace itself or in the last element of the trace
|
||||
// Script execution stopped by async_stop called on the script run because home assistant is shutting down, script mode is SCRIPT_MODE_RESTART etc:
|
||||
| "cancelled";
|
||||
// Automation only, should become it's own type when we support script in frontend
|
||||
}
|
||||
|
||||
interface BaseTraceExtended {
|
||||
trace: Record<string, ActionTraceStep[]>;
|
||||
context: Context;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface AutomationTrace extends BaseTrace {
|
||||
domain: "automation";
|
||||
trigger: string;
|
||||
}
|
||||
|
||||
export interface AutomationTraceExtended extends AutomationTrace {
|
||||
trace: Record<string, ActionTraceStep[]>;
|
||||
context: Context;
|
||||
export interface AutomationTraceExtended
|
||||
extends AutomationTrace,
|
||||
BaseTraceExtended {
|
||||
config: ManualAutomationConfig;
|
||||
blueprint_inputs?: BlueprintAutomationConfig;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface ScriptTrace extends BaseTrace {
|
||||
domain: "script";
|
||||
}
|
||||
|
||||
export interface ScriptTraceExtended extends ScriptTrace, BaseTraceExtended {
|
||||
config: ScriptConfig;
|
||||
blueprint_inputs?: BlueprintScriptConfig;
|
||||
}
|
||||
|
||||
export type TraceExtended = AutomationTraceExtended | ScriptTraceExtended;
|
||||
|
||||
interface TraceTypes {
|
||||
automation: {
|
||||
short: AutomationTrace;
|
||||
extended: AutomationTraceExtended;
|
||||
};
|
||||
script: {
|
||||
short: ScriptTrace;
|
||||
extended: ScriptTraceExtended;
|
||||
};
|
||||
}
|
||||
|
||||
export const loadTrace = <T extends keyof TraceTypes>(
|
||||
@ -141,7 +165,7 @@ export const loadTraceContexts = (
|
||||
});
|
||||
|
||||
export const getDataFromPath = (
|
||||
config: ManualAutomationConfig,
|
||||
config: TraceExtended["config"],
|
||||
path: string
|
||||
): any => {
|
||||
const parts = path.split("/").reverse();
|
||||
|
@ -20,6 +20,7 @@ import "./types/ha-automation-condition-state";
|
||||
import "./types/ha-automation-condition-sun";
|
||||
import "./types/ha-automation-condition-template";
|
||||
import "./types/ha-automation-condition-time";
|
||||
import "./types/ha-automation-condition-trigger";
|
||||
import "./types/ha-automation-condition-zone";
|
||||
|
||||
const OPTIONS = [
|
||||
@ -32,6 +33,7 @@ const OPTIONS = [
|
||||
"sun",
|
||||
"template",
|
||||
"time",
|
||||
"trigger",
|
||||
"zone",
|
||||
];
|
||||
|
||||
|
@ -0,0 +1,99 @@
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import {
|
||||
AutomationConfig,
|
||||
Trigger,
|
||||
TriggerCondition,
|
||||
} from "../../../../../data/automation";
|
||||
import { HomeAssistant } from "../../../../../types";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||
import { ensureArray } from "../../../../../common/ensure-array";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
|
||||
@customElement("ha-automation-condition-trigger")
|
||||
export class HaTriggerCondition extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public condition!: TriggerCondition;
|
||||
|
||||
@state() private _triggers?: Trigger | Trigger[];
|
||||
|
||||
private _unsub?: UnsubscribeFunc;
|
||||
|
||||
public static get defaultConfig() {
|
||||
return {
|
||||
id: "",
|
||||
};
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
const details = { callback: (config) => this._automationUpdated(config) };
|
||||
fireEvent(this, "subscribe-automation-config", details);
|
||||
this._unsub = (details as any).unsub;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
if (this._unsub) {
|
||||
this._unsub();
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { id } = this.condition;
|
||||
if (!this._triggers) {
|
||||
return this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.trigger.no_triggers"
|
||||
);
|
||||
}
|
||||
return html`<paper-dropdown-menu-light
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.conditions.type.trigger.id"
|
||||
)}
|
||||
no-animations
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected=${id}
|
||||
attr-for-selected="data-trigger-id"
|
||||
@selected-item-changed=${this._triggerPicked}
|
||||
>
|
||||
${ensureArray(this._triggers).map((trigger) =>
|
||||
trigger.id
|
||||
? html`
|
||||
<paper-item data-trigger-id=${trigger.id}>
|
||||
${trigger.id}
|
||||
</paper-item>
|
||||
`
|
||||
: ""
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu-light>`;
|
||||
}
|
||||
|
||||
private _automationUpdated(config?: AutomationConfig) {
|
||||
this._triggers = config?.trigger;
|
||||
}
|
||||
|
||||
private _triggerPicked(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (!ev.detail.value) {
|
||||
return;
|
||||
}
|
||||
const newTrigger = ev.detail.value.dataset.triggerId;
|
||||
if (this.condition.id === newTrigger) {
|
||||
return;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value: { ...this.condition, id: newTrigger },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-condition-trigger": HaTriggerCondition;
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import "@polymer/paper-radio-button/paper-radio-button";
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
|
@ -11,6 +11,7 @@ import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import {
|
||||
css,
|
||||
CSSResultGroup,
|
||||
@ -51,12 +52,9 @@ import { HomeAssistant, Route } from "../../../types";
|
||||
import { showToast } from "../../../util/toast";
|
||||
import "../ha-config-section";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import "./action/ha-automation-action";
|
||||
import { HaDeviceAction } from "./action/types/ha-automation-action-device_id";
|
||||
import "./blueprint-automation-editor";
|
||||
import "./condition/ha-automation-condition";
|
||||
import "./manual-automation-editor";
|
||||
import "./trigger/ha-automation-trigger";
|
||||
import { HaDeviceTrigger } from "./trigger/types/ha-automation-trigger-device";
|
||||
|
||||
declare global {
|
||||
@ -65,6 +63,10 @@ declare global {
|
||||
}
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"subscribe-automation-config": {
|
||||
callback: (config: AutomationConfig) => void;
|
||||
unsub?: UnsubscribeFunc;
|
||||
};
|
||||
"ui-mode-not-available": Error;
|
||||
duplicate: undefined;
|
||||
}
|
||||
@ -95,6 +97,13 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
|
||||
@query("ha-yaml-editor", true) private _editor?: HaYamlEditor;
|
||||
|
||||
private _configSubscriptions: Record<
|
||||
string,
|
||||
(config?: AutomationConfig) => void
|
||||
> = {};
|
||||
|
||||
private _configSubscriptionsId = 1;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const stateObj = this._entityId
|
||||
? this.hass.states[this._entityId]
|
||||
@ -200,6 +209,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
class="content ${classMap({
|
||||
"yaml-mode": this._mode === "yaml",
|
||||
})}"
|
||||
@subscribe-automation-config=${this._subscribeAutomationConfig}
|
||||
>
|
||||
${this._errors
|
||||
? html` <div class="errors">${this._errors}</div> `
|
||||
@ -336,6 +346,12 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
) {
|
||||
this._setEntityId();
|
||||
}
|
||||
|
||||
if (changedProps.has("_config")) {
|
||||
Object.values(this._configSubscriptions).forEach((sub) =>
|
||||
sub(this._config)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _setEntityId() {
|
||||
@ -516,6 +532,15 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
);
|
||||
}
|
||||
|
||||
private _subscribeAutomationConfig(ev) {
|
||||
const id = this._configSubscriptionsId++;
|
||||
this._configSubscriptions[id] = ev.detail.callback;
|
||||
ev.detail.unsub = () => {
|
||||
delete this._configSubscriptions[id];
|
||||
};
|
||||
ev.detail.callback(this._config);
|
||||
}
|
||||
|
||||
protected handleKeyboardSave() {
|
||||
this._saveAutomation();
|
||||
}
|
||||
|
@ -9,31 +9,28 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { repeat } from "lit/directives/repeat";
|
||||
import { isComponentLoaded } from "../../../../common/config/is_component_loaded";
|
||||
import { formatDateTimeWithSeconds } from "../../../../common/datetime/format_date_time";
|
||||
import type { NodeInfo } from "../../../../components/trace/hat-graph";
|
||||
import "../../../../components/trace/hat-script-graph";
|
||||
import { AutomationEntity } from "../../../../data/automation";
|
||||
import {
|
||||
getLogbookDataForContext,
|
||||
LogbookEntry,
|
||||
} from "../../../../data/logbook";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
|
||||
import type { NodeInfo } from "../../../components/trace/hat-graph";
|
||||
import "../../../components/trace/hat-script-graph";
|
||||
import { AutomationEntity } from "../../../data/automation";
|
||||
import { getLogbookDataForContext, LogbookEntry } from "../../../data/logbook";
|
||||
import {
|
||||
AutomationTrace,
|
||||
AutomationTraceExtended,
|
||||
loadTrace,
|
||||
loadTraces,
|
||||
} from "../../../../data/trace";
|
||||
import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import { HomeAssistant, Route } from "../../../../types";
|
||||
import { configSections } from "../../ha-panel-config";
|
||||
import "./ha-automation-trace-blueprint-config";
|
||||
import "./ha-automation-trace-config";
|
||||
import "./ha-automation-trace-logbook";
|
||||
import "./ha-automation-trace-path-details";
|
||||
import "./ha-automation-trace-timeline";
|
||||
import { traceTabStyles } from "./styles";
|
||||
} from "../../../data/trace";
|
||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant, Route } from "../../../types";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import "../../../components/trace/ha-trace-blueprint-config";
|
||||
import "../../../components/trace/ha-trace-config";
|
||||
import "../../../components/trace/ha-trace-logbook";
|
||||
import "../../../components/trace/ha-trace-path-details";
|
||||
import "../../../components/trace/ha-trace-timeline";
|
||||
import { traceTabStyles } from "../../../components/trace/trace-tab-styles";
|
||||
|
||||
@customElement("ha-automation-trace")
|
||||
export class HaAutomationTrace extends LitElement {
|
||||
@ -209,7 +206,7 @@ export class HaAutomationTrace extends LitElement {
|
||||
@click=${this._showTab}
|
||||
>
|
||||
Blueprint Config
|
||||
</div>
|
||||
</button>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
@ -219,46 +216,47 @@ export class HaAutomationTrace extends LitElement {
|
||||
? ""
|
||||
: this._view === "details"
|
||||
? html`
|
||||
<ha-automation-trace-path-details
|
||||
<ha-trace-path-details
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.trace=${this._trace}
|
||||
.selected=${this._selected}
|
||||
.logbookEntries=${this._logbookEntries}
|
||||
.trackedNodes=${trackedNodes}
|
||||
.renderedNodes=${renderedNodes}
|
||||
></ha-automation-trace-path-details>
|
||||
.renderedNodes=${renderedNodes!}
|
||||
></ha-trace-path-details>
|
||||
`
|
||||
: this._view === "config"
|
||||
? html`
|
||||
<ha-automation-trace-config
|
||||
<ha-trace-config
|
||||
.hass=${this.hass}
|
||||
.trace=${this._trace}
|
||||
></ha-automation-trace-config>
|
||||
></ha-trace-config>
|
||||
`
|
||||
: this._view === "logbook"
|
||||
? html`
|
||||
<ha-automation-trace-logbook
|
||||
<ha-trace-logbook
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.trace=${this._trace}
|
||||
.logbookEntries=${this._logbookEntries}
|
||||
></ha-automation-trace-logbook>
|
||||
></ha-trace-logbook>
|
||||
`
|
||||
: this._view === "blueprint"
|
||||
? html`
|
||||
<ha-automation-trace-blueprint-config
|
||||
<ha-trace-blueprint-config
|
||||
.hass=${this.hass}
|
||||
.trace=${this._trace}
|
||||
></ha-automation-trace-blueprint-config>
|
||||
></ha-trace-blueprint-config>
|
||||
`
|
||||
: html`
|
||||
<ha-automation-trace-timeline
|
||||
<ha-trace-timeline
|
||||
.hass=${this.hass}
|
||||
.trace=${this._trace}
|
||||
.logbookEntries=${this._logbookEntries}
|
||||
.selected=${this._selected}
|
||||
@value-changed=${this._timelinePathPicked}
|
||||
></ha-automation-trace-timeline>
|
||||
></ha-trace-timeline>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
@ -51,7 +51,7 @@ class HaConfigAutomation extends HassRouterPage {
|
||||
},
|
||||
trace: {
|
||||
tag: "ha-automation-trace",
|
||||
load: () => import("./trace/ha-automation-trace"),
|
||||
load: () => import("./ha-automation-trace"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -162,6 +162,14 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
)}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu-light>
|
||||
<paper-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.triggers.id"
|
||||
)}
|
||||
.value=${this.trigger.id}
|
||||
@value-changed=${this._idChanged}
|
||||
>
|
||||
</paper-input>
|
||||
<div>
|
||||
${dynamicElement(
|
||||
`ha-automation-trigger-${this.trigger.platform}`,
|
||||
@ -212,15 +220,35 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
const elClass = customElements.get(`ha-automation-trigger-${type}`);
|
||||
|
||||
if (type !== this.trigger.platform) {
|
||||
const value = {
|
||||
platform: type,
|
||||
...elClass.defaultConfig,
|
||||
};
|
||||
if (this.trigger.id) {
|
||||
value.id = this.trigger.id;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
platform: type,
|
||||
...elClass.defaultConfig,
|
||||
},
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _idChanged(ev: CustomEvent) {
|
||||
const newId = ev.detail.value;
|
||||
if (newId === this.trigger.id) {
|
||||
return;
|
||||
}
|
||||
const value = { ...this.trigger };
|
||||
if (!newId) {
|
||||
delete value.id;
|
||||
} else {
|
||||
value.id = newId;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
||||
private _onYamlChange(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (!ev.detail.isValid) {
|
||||
|
@ -42,6 +42,10 @@ class HaConfigScript extends HassRouterPage {
|
||||
edit: {
|
||||
tag: "ha-script-editor",
|
||||
},
|
||||
trace: {
|
||||
tag: "ha-script-trace",
|
||||
load: () => import("./ha-script-trace"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -81,7 +85,7 @@ class HaConfigScript extends HassRouterPage {
|
||||
|
||||
if (
|
||||
(!changedProps || changedProps.has("route")) &&
|
||||
this._currentPage === "edit"
|
||||
this._currentPage !== "dashboard"
|
||||
) {
|
||||
pageEl.creatingNew = undefined;
|
||||
const scriptEntityId = this.routeTail.path.substr(1);
|
||||
|
@ -297,7 +297,16 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
<div
|
||||
class="card-actions layout horizontal justified center"
|
||||
>
|
||||
<span></span>
|
||||
<a
|
||||
href="/config/script/trace/${this
|
||||
.scriptEntityId}"
|
||||
>
|
||||
<mwc-button>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.script.editor.show_trace"
|
||||
)}
|
||||
</mwc-button>
|
||||
</a>
|
||||
<mwc-button
|
||||
@click=${this._runScript}
|
||||
title="${this.hass.localize(
|
||||
|
@ -1,6 +1,7 @@
|
||||
import "@material/mwc-icon-button";
|
||||
import {
|
||||
mdiHelpCircle,
|
||||
mdiHistory,
|
||||
mdiInformationOutline,
|
||||
mdiPencil,
|
||||
mdiPlay,
|
||||
@ -140,6 +141,21 @@ class HaScriptPicker extends LitElement {
|
||||
</mwc-icon-button>
|
||||
`,
|
||||
};
|
||||
columns.trace = {
|
||||
title: "",
|
||||
type: "icon-button",
|
||||
template: (_info, script: any) => html`
|
||||
<a href="/config/script/trace/${script.entity_id}">
|
||||
<mwc-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.script.picker.dev_script"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiHistory}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</a>
|
||||
`,
|
||||
};
|
||||
columns.edit = {
|
||||
title: "",
|
||||
type: "icon-button",
|
||||
|
502
src/panels/config/script/ha-script-trace.ts
Normal file
502
src/panels/config/script/ha-script-trace.ts
Normal file
@ -0,0 +1,502 @@
|
||||
import {
|
||||
mdiDownload,
|
||||
mdiPencil,
|
||||
mdiRayEndArrow,
|
||||
mdiRayStartArrow,
|
||||
mdiRefresh,
|
||||
} from "@mdi/js";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { repeat } from "lit/directives/repeat";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
|
||||
import type { NodeInfo } from "../../../components/trace/hat-graph";
|
||||
import "../../../components/trace/hat-script-graph";
|
||||
import { getLogbookDataForContext, LogbookEntry } from "../../../data/logbook";
|
||||
import { ScriptEntity } from "../../../data/script";
|
||||
import {
|
||||
loadTrace,
|
||||
loadTraces,
|
||||
ScriptTrace,
|
||||
ScriptTraceExtended,
|
||||
} from "../../../data/trace";
|
||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { HomeAssistant, Route } from "../../../types";
|
||||
import { traceTabStyles } from "../../../components/trace/trace-tab-styles";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import "../../../components/trace/ha-trace-blueprint-config";
|
||||
import "../../../components/trace/ha-trace-config";
|
||||
import "../../../components/trace/ha-trace-logbook";
|
||||
import "../../../components/trace/ha-trace-path-details";
|
||||
import "../../../components/trace/ha-trace-timeline";
|
||||
|
||||
@customElement("ha-script-trace")
|
||||
export class HaScriptTrace extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public scriptEntityId!: string;
|
||||
|
||||
@property({ attribute: false }) public scripts!: ScriptEntity[];
|
||||
|
||||
@property({ type: Boolean }) public isWide?: boolean;
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public narrow!: boolean;
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
@state() private _traces?: ScriptTrace[];
|
||||
|
||||
@state() private _runId?: string;
|
||||
|
||||
@state() private _selected?: NodeInfo;
|
||||
|
||||
@state() private _trace?: ScriptTraceExtended;
|
||||
|
||||
@state() private _logbookEntries?: LogbookEntry[];
|
||||
|
||||
@state() private _view:
|
||||
| "details"
|
||||
| "config"
|
||||
| "timeline"
|
||||
| "logbook"
|
||||
| "blueprint" = "details";
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const stateObj = this.scriptEntityId
|
||||
? this.hass.states[this.scriptEntityId]
|
||||
: undefined;
|
||||
|
||||
const graph = this.shadowRoot!.querySelector("hat-script-graph");
|
||||
const trackedNodes = graph?.trackedNodes;
|
||||
const renderedNodes = graph?.renderedNodes;
|
||||
|
||||
const title = stateObj?.attributes.friendly_name || this.scriptEntityId;
|
||||
|
||||
let devButtons: TemplateResult | string = "";
|
||||
if (__DEV__) {
|
||||
devButtons = html`<div style="position: absolute; right: 0;">
|
||||
<button @click=${this._importTrace}>Import trace</button>
|
||||
<button @click=${this._loadLocalStorageTrace}>Load stored trace</button>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const actionButtons = html`
|
||||
<mwc-icon-button label="Refresh" @click=${() => this._loadTraces()}>
|
||||
<ha-svg-icon .path=${mdiRefresh}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<mwc-icon-button
|
||||
.disabled=${!this._trace}
|
||||
label="Download Trace"
|
||||
@click=${this._downloadTrace}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiDownload}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
`;
|
||||
|
||||
return html`
|
||||
${devButtons}
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
.tabs=${configSections.automation}
|
||||
>
|
||||
${this.narrow
|
||||
? html`<span slot="header"> ${title} </span>
|
||||
<div slot="toolbar-icon">${actionButtons}</div>`
|
||||
: ""}
|
||||
<div class="toolbar">
|
||||
${!this.narrow
|
||||
? html`<div>
|
||||
${title}
|
||||
<a
|
||||
class="linkButton"
|
||||
href="/config/script/edit/${this.scriptEntityId}"
|
||||
>
|
||||
<mwc-icon-button label="Edit Script" tabindex="-1">
|
||||
<ha-svg-icon .path=${mdiPencil}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</a>
|
||||
</div>`
|
||||
: ""}
|
||||
${this._traces && this._traces.length > 0
|
||||
? html`
|
||||
<div>
|
||||
<mwc-icon-button
|
||||
.disabled=${this._traces[this._traces.length - 1].run_id ===
|
||||
this._runId}
|
||||
label="Older trace"
|
||||
@click=${this._pickOlderTrace}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiRayEndArrow}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
<select .value=${this._runId} @change=${this._pickTrace}>
|
||||
${repeat(
|
||||
this._traces,
|
||||
(trace) => trace.run_id,
|
||||
(trace) =>
|
||||
html`<option value=${trace.run_id}>
|
||||
${formatDateTimeWithSeconds(
|
||||
new Date(trace.timestamp.start),
|
||||
this.hass.locale
|
||||
)}
|
||||
</option>`
|
||||
)}
|
||||
</select>
|
||||
<mwc-icon-button
|
||||
.disabled=${this._traces[0].run_id === this._runId}
|
||||
label="Newer trace"
|
||||
@click=${this._pickNewerTrace}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiRayStartArrow}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
${!this.narrow ? html`<div>${actionButtons}</div>` : ""}
|
||||
</div>
|
||||
|
||||
${this._traces === undefined
|
||||
? html`<div class="container">Loading…</div>`
|
||||
: this._traces.length === 0
|
||||
? html`<div class="container">No traces found</div>`
|
||||
: this._trace === undefined
|
||||
? ""
|
||||
: html`
|
||||
<div class="main">
|
||||
<div class="graph">
|
||||
<hat-script-graph
|
||||
.trace=${this._trace}
|
||||
.selected=${this._selected?.path}
|
||||
@graph-node-selected=${this._pickNode}
|
||||
></hat-script-graph>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<div class="tabs top">
|
||||
${[
|
||||
["details", "Step Details"],
|
||||
["timeline", "Trace Timeline"],
|
||||
["logbook", "Related logbook entries"],
|
||||
["config", "Script Config"],
|
||||
].map(
|
||||
([view, label]) => html`
|
||||
<button
|
||||
tabindex="0"
|
||||
.view=${view}
|
||||
class=${classMap({ active: this._view === view })}
|
||||
@click=${this._showTab}
|
||||
>
|
||||
${label}
|
||||
</button>
|
||||
`
|
||||
)}
|
||||
${this._trace.blueprint_inputs
|
||||
? html`
|
||||
<button
|
||||
tabindex="0"
|
||||
.view=${"blueprint"}
|
||||
class=${classMap({
|
||||
active: this._view === "blueprint",
|
||||
})}
|
||||
@click=${this._showTab}
|
||||
>
|
||||
Blueprint Config
|
||||
</button>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
${this._selected === undefined ||
|
||||
this._logbookEntries === undefined ||
|
||||
trackedNodes === undefined
|
||||
? ""
|
||||
: this._view === "details"
|
||||
? html`
|
||||
<ha-trace-path-details
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.trace=${this._trace}
|
||||
.selected=${this._selected}
|
||||
.logbookEntries=${this._logbookEntries}
|
||||
.trackedNodes=${trackedNodes}
|
||||
.renderedNodes=${renderedNodes!}
|
||||
></ha-trace-path-details>
|
||||
`
|
||||
: this._view === "config"
|
||||
? html`
|
||||
<ha-trace-config
|
||||
.hass=${this.hass}
|
||||
.trace=${this._trace}
|
||||
></ha-trace-config>
|
||||
`
|
||||
: this._view === "logbook"
|
||||
? html`
|
||||
<ha-trace-logbook
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.trace=${this._trace}
|
||||
.logbookEntries=${this._logbookEntries}
|
||||
></ha-trace-logbook>
|
||||
`
|
||||
: this._view === "blueprint"
|
||||
? html`
|
||||
<ha-trace-blueprint-config
|
||||
.hass=${this.hass}
|
||||
.trace=${this._trace}
|
||||
></ha-trace-blueprint-config>
|
||||
`
|
||||
: html`
|
||||
<ha-trace-timeline
|
||||
.hass=${this.hass}
|
||||
.trace=${this._trace}
|
||||
.logbookEntries=${this._logbookEntries}
|
||||
.selected=${this._selected}
|
||||
@value-changed=${this._timelinePathPicked}
|
||||
></ha-trace-timeline>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
</hass-tabs-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
if (!this.scriptEntityId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams(location.search);
|
||||
this._loadTraces(params.get("run_id") || undefined);
|
||||
}
|
||||
|
||||
protected updated(changedProps) {
|
||||
super.updated(changedProps);
|
||||
|
||||
// Only reset if automationId has changed and we had one before.
|
||||
if (changedProps.get("scriptEntityId")) {
|
||||
this._traces = undefined;
|
||||
this._runId = undefined;
|
||||
this._trace = undefined;
|
||||
this._logbookEntries = undefined;
|
||||
if (this.scriptEntityId) {
|
||||
this._loadTraces();
|
||||
}
|
||||
}
|
||||
|
||||
if (changedProps.has("_runId") && this._runId) {
|
||||
this._trace = undefined;
|
||||
this._logbookEntries = undefined;
|
||||
this.shadowRoot!.querySelector("select")!.value = this._runId;
|
||||
this._loadTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private _pickOlderTrace() {
|
||||
const curIndex = this._traces!.findIndex((tr) => tr.run_id === this._runId);
|
||||
this._runId = this._traces![curIndex + 1].run_id;
|
||||
this._selected = undefined;
|
||||
}
|
||||
|
||||
private _pickNewerTrace() {
|
||||
const curIndex = this._traces!.findIndex((tr) => tr.run_id === this._runId);
|
||||
this._runId = this._traces![curIndex - 1].run_id;
|
||||
this._selected = undefined;
|
||||
}
|
||||
|
||||
private _pickTrace(ev) {
|
||||
this._runId = ev.target.value;
|
||||
this._selected = undefined;
|
||||
}
|
||||
|
||||
private _pickNode(ev) {
|
||||
this._selected = ev.detail;
|
||||
}
|
||||
|
||||
private async _loadTraces(runId?: string) {
|
||||
this._traces = await loadTraces(
|
||||
this.hass,
|
||||
"script",
|
||||
this.scriptEntityId.split(".")[1]
|
||||
);
|
||||
// Newest will be on top.
|
||||
this._traces.reverse();
|
||||
|
||||
if (runId) {
|
||||
this._runId = runId;
|
||||
}
|
||||
|
||||
// Check if current run ID still exists
|
||||
if (
|
||||
this._runId &&
|
||||
!this._traces.some((trace) => trace.run_id === this._runId)
|
||||
) {
|
||||
this._runId = undefined;
|
||||
this._selected = undefined;
|
||||
|
||||
// If we came here from a trace passed into the url, clear it.
|
||||
if (runId) {
|
||||
const params = new URLSearchParams(location.search);
|
||||
params.delete("run_id");
|
||||
history.replaceState(
|
||||
null,
|
||||
"",
|
||||
`${location.pathname}?${params.toString()}`
|
||||
);
|
||||
}
|
||||
|
||||
await showAlertDialog(this, {
|
||||
text: "Chosen trace is no longer available",
|
||||
});
|
||||
}
|
||||
|
||||
// See if we can set a default runID
|
||||
if (!this._runId && this._traces.length > 0) {
|
||||
this._runId = this._traces[0].run_id;
|
||||
}
|
||||
}
|
||||
|
||||
private async _loadTrace() {
|
||||
const trace = await loadTrace(
|
||||
this.hass,
|
||||
"script",
|
||||
this.scriptEntityId.split(".")[1],
|
||||
this._runId!
|
||||
);
|
||||
this._logbookEntries = isComponentLoaded(this.hass, "logbook")
|
||||
? await getLogbookDataForContext(
|
||||
this.hass,
|
||||
trace.timestamp.start,
|
||||
trace.context.id
|
||||
)
|
||||
: [];
|
||||
|
||||
this._trace = trace;
|
||||
}
|
||||
|
||||
private _downloadTrace() {
|
||||
const aEl = document.createElement("a");
|
||||
aEl.download = `trace ${this.scriptEntityId} ${
|
||||
this._trace!.timestamp.start
|
||||
}.json`;
|
||||
aEl.href = `data:application/json;charset=utf-8,${encodeURI(
|
||||
JSON.stringify(
|
||||
{
|
||||
trace: this._trace,
|
||||
logbookEntries: this._logbookEntries,
|
||||
},
|
||||
undefined,
|
||||
2
|
||||
)
|
||||
)}`;
|
||||
aEl.click();
|
||||
}
|
||||
|
||||
private _importTrace() {
|
||||
const traceText = prompt("Enter downloaded trace");
|
||||
if (!traceText) {
|
||||
return;
|
||||
}
|
||||
localStorage.devTrace = traceText;
|
||||
this._loadLocalTrace(traceText);
|
||||
}
|
||||
|
||||
private _loadLocalStorageTrace() {
|
||||
if (localStorage.devTrace) {
|
||||
this._loadLocalTrace(localStorage.devTrace);
|
||||
}
|
||||
}
|
||||
|
||||
private _loadLocalTrace(traceText: string) {
|
||||
const traceInfo = JSON.parse(traceText);
|
||||
this._trace = traceInfo.trace;
|
||||
this._logbookEntries = traceInfo.logbookEntries;
|
||||
}
|
||||
|
||||
private _showTab(ev) {
|
||||
this._view = (ev.target as any).view;
|
||||
}
|
||||
|
||||
private _timelinePathPicked(ev) {
|
||||
const path = ev.detail.value;
|
||||
const nodes = this.shadowRoot!.querySelector("hat-script-graph")!
|
||||
.trackedNodes;
|
||||
if (nodes[path]) {
|
||||
this._selected = nodes[path];
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
traceTabStyles,
|
||||
css`
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 20px;
|
||||
height: var(--header-height);
|
||||
padding: 0 16px;
|
||||
background-color: var(--primary-background-color);
|
||||
font-weight: 400;
|
||||
color: var(--app-header-text-color, white);
|
||||
border-bottom: var(--app-header-border-bottom, none);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.toolbar > * {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
:host([narrow]) .toolbar > * {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.main {
|
||||
height: calc(100% - 56px);
|
||||
display: flex;
|
||||
background-color: var(--card-background-color);
|
||||
}
|
||||
|
||||
:host([narrow]) .main {
|
||||
height: auto;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.graph {
|
||||
border-right: 1px solid var(--divider-color);
|
||||
overflow-x: auto;
|
||||
max-width: 50%;
|
||||
}
|
||||
:host([narrow]) .graph {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
background-color: var(--card-background-color);
|
||||
}
|
||||
|
||||
.linkButton {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-script-trace": HaScriptTrace;
|
||||
}
|
||||
}
|
@ -126,7 +126,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
this._applyTranslations(this.hass!);
|
||||
}
|
||||
|
||||
protected panelUrlChanged(newPanelUrl) {
|
||||
protected panelUrlChanged(newPanelUrl: string) {
|
||||
super.panelUrlChanged(newPanelUrl);
|
||||
// this may be triggered before hassConnected
|
||||
this._loadFragmentTranslations(
|
||||
@ -339,13 +339,16 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
...data,
|
||||
},
|
||||
};
|
||||
const changes: Partial<HomeAssistant> = {
|
||||
resources,
|
||||
localize: await computeLocalize(this, language, resources),
|
||||
};
|
||||
|
||||
// Update resources immediately, so when a new update comes in we don't miss values
|
||||
this._updateHass({ resources });
|
||||
|
||||
const localize = await computeLocalize(this, language, resources);
|
||||
|
||||
if (language === (this.hass ?? this._pendingHass).language) {
|
||||
this._updateHass(changes);
|
||||
this._updateHass({
|
||||
localize,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,7 +303,7 @@
|
||||
"entries_not_found": "No logbook entries found.",
|
||||
"by": "by",
|
||||
"by_service": "by service",
|
||||
"show_trace": "Show trace",
|
||||
"show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]",
|
||||
"retrieval_error": "Error during logbook entry retrieval",
|
||||
"messages": {
|
||||
"was_away": "was detected away",
|
||||
@ -1308,6 +1308,7 @@
|
||||
"introduction": "Triggers are what starts the processing of an automation rule. It is possible to specify multiple triggers for the same rule. Once a trigger starts, Home Assistant will validate the conditions, if any, and call the action.",
|
||||
"learn_more": "Learn more about triggers",
|
||||
"add": "Add trigger",
|
||||
"id": "Trigger ID (used by the trigger condition)",
|
||||
"duplicate": "Duplicate",
|
||||
"delete": "[%key:ui::panel::mailbox::delete_button%]",
|
||||
"delete_confirm": "Are you sure you want to delete this?",
|
||||
@ -1475,6 +1476,11 @@
|
||||
"sun": "Sunday"
|
||||
}
|
||||
},
|
||||
"trigger": {
|
||||
"label": "Trigger",
|
||||
"no_triggers": "No triggers available",
|
||||
"id": "Trigger Id"
|
||||
},
|
||||
"zone": {
|
||||
"label": "[%key:ui::panel::config::automation::editor::triggers::type::zone::label%]",
|
||||
"entity": "[%key:ui::panel::config::automation::editor::triggers::type::zone::entity%]",
|
||||
@ -1634,6 +1640,7 @@
|
||||
"show_info": "Show info about script",
|
||||
"run_script": "Run script",
|
||||
"edit_script": "Edit script",
|
||||
"dev_script": "Debug script",
|
||||
"headers": {
|
||||
"name": "Name"
|
||||
},
|
||||
@ -1647,6 +1654,7 @@
|
||||
"id_already_exists_save_error": "You can't save this script because the ID is not unique, pick another ID or leave it blank to automatically generate one.",
|
||||
"id_already_exists": "This ID already exists",
|
||||
"introduction": "Use scripts to run a sequence of actions.",
|
||||
"show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]",
|
||||
"header": "Script: {name}",
|
||||
"default_name": "New Script",
|
||||
"modes": {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2319,7 +2319,7 @@
|
||||
"none": "Encara no hi ha res configurat",
|
||||
"none_found": "No s'han trobat integracions",
|
||||
"none_found_detail": "Ajusta els paràmetres de cerca.",
|
||||
"note_about_integrations": "Encara no es poden configurar totes les integracions a través de la IU.",
|
||||
"note_about_integrations": "No s'ha trobat cap integració que coincident, és possible que la integració encara no estigui disponible per configurar-se a través de la interfície d'usuari.",
|
||||
"note_about_website_reference": "En pots trobar més al ",
|
||||
"reconfigure": "Reconfigura",
|
||||
"rename_dialog": "Edita el nom de l'entrada de configuració",
|
||||
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "Afegeix node",
|
||||
"close": "Tanca",
|
||||
"heal_network": "Guareix la xarxa",
|
||||
"home_id": "ID principal",
|
||||
"network": "Xarxa",
|
||||
"node_id": "ID del node",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "Estat del node",
|
||||
"zwave_info": "Informació Z-Wave"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "La guarició de la xarxa s'ha cancel·lat.",
|
||||
"healing_complete": "La guarició de la xarxa s'ha completat.",
|
||||
"healing_failed": "La guarició ha fallat. Pots trobar informació addicional als registres.",
|
||||
"in_progress": "La guarició de la xarxa està en curs. Trigarà una estona.",
|
||||
"introduction": "Inicia una guarició de la teva xarxa Z-Wave. La guarició de xarxa farà que tots els dispositius tornin a calcular les seves rutes cap al controlador. Es recomana si recentment has canviat o mogut dispositius o el controlador.",
|
||||
"run_in_background": "Pots tancar aquest diàleg, la guarició de la xarxa continuarà en segon pla.",
|
||||
"start_heal": "Comença la guarició",
|
||||
"stop_heal": "Atura la guarició",
|
||||
"title": "Guareix la xarxa Z-Wave",
|
||||
"traffic_warning": "El procés de guarició genera una gran quantitat de trànsit a la xarxa Z-Wave. Això pot fer que els dispositius responguin lentament (o gens) mentre la guarició està en procés."
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "Nivell dels registres",
|
||||
"log_level_changed": "Nivell de registre canviat a: {level}",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "Zatím nic nastaveno",
|
||||
"none_found": "Žádné integrace nenalezeny.",
|
||||
"none_found_detail": "Upravte kritéria vyhledávání.",
|
||||
"note_about_integrations": "Některé integrace zatím nelze nastavit prostřednictvím uživatelského rozhraní.",
|
||||
"note_about_integrations": "Vašemu vyhledávání neodpovídá žádná integrace, je možné, že integraci, kterou chcete nastavit, ještě nelze nastavit prostřednictvím uživatelského rozhraní.",
|
||||
"note_about_website_reference": "Další jsou k dispozici na ",
|
||||
"reconfigure": "Přenastavit",
|
||||
"rename_dialog": "Upravit název této položky nastavení",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "Noch nichts konfiguriert",
|
||||
"none_found": "Keine Integrationen gefunden",
|
||||
"none_found_detail": "Passe deine Suchkriterien an.",
|
||||
"note_about_integrations": "Nicht alle Integrationen können über die Benutzeroberfläche konfiguriert werden.",
|
||||
"note_about_integrations": "Es wurden keine Integrationen für deine Suche gefunden. Möglicherweise ist die Integration, die du einrichten möchtest, noch nicht zum Einrichten über die Benutzeroberfläche verfügbar.",
|
||||
"note_about_website_reference": "Weitere Informationen findest du auf der ",
|
||||
"reconfigure": "Neu konfigurieren",
|
||||
"rename_dialog": "Bearbeite den Namen dieses Konfigurationseintrags",
|
||||
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "Knoten hinzufügen",
|
||||
"close": "Schließen",
|
||||
"heal_network": "Netzwerk heilen",
|
||||
"home_id": "Heim-ID",
|
||||
"network": "Netzwerk",
|
||||
"node_id": "Knoten-ID",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "Node Status",
|
||||
"zwave_info": "Z-Wave Info"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "Die Netzwerkheilung wurde abgebrochen.",
|
||||
"healing_complete": "Die Netzwerkheilung ist abgeschlossen.",
|
||||
"healing_failed": "Heilung fehlgeschlagen. Zusätzliche Informationen könnten in den Protokollen verfügbar sein.",
|
||||
"in_progress": "Die Netzwerkheilung ist im Gange. Dies wird einige Zeit in Anspruch nehmen.",
|
||||
"introduction": "Startet einen Netzwerk-Heal im Z-Wave-Netzwerk. Ein Netzwerk-Heal veranlasst alle Geräte, ihre Routen zurück zum Controller neu zu berechnen und wird empfohlen, wenn kürzlich Geräte oder Controller verschoben wurden.",
|
||||
"run_in_background": "Dieser Dialog kann geschlossen werden und die Netzwerkheilung wird im Hintergrund fortgesetzt.",
|
||||
"start_heal": "Starten der Heilung",
|
||||
"stop_heal": "Stoppen der Heilung",
|
||||
"title": "Heile dein Z-Wave-Netzwerk",
|
||||
"traffic_warning": "Der Heilungsprozess erzeugt eine große Menge an Datenverkehr im Z-Wave-Netzwerk. Dies kann dazu führen, dass Geräte langsam (oder gar nicht) reagieren, während der Heilungsprozess läuft."
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "Protokollstufe",
|
||||
"log_level_changed": "Log Level geändert auf: {level}",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "Todavía no hay nada configurado",
|
||||
"none_found": "No se han encontrado integraciones",
|
||||
"none_found_detail": "Ajusta tus criterios de búsqueda.",
|
||||
"note_about_integrations": "Todavía no se pueden configurar todas las integraciones a través de la interfaz de usuario.",
|
||||
"note_about_integrations": "No hay integraciones que coincidan con tu búsqueda, es posible que la integración que deseas configurar aún no esté disponible para configurar a través de la interfaz de usuario.",
|
||||
"note_about_website_reference": "Hay más disponibles en el ",
|
||||
"reconfigure": "Reconfigurar",
|
||||
"rename_dialog": "Edita el nombre de esta entrada de configuración",
|
||||
@ -2990,7 +2990,7 @@
|
||||
"zwave_info": "Información de Z-Wave"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "Se ha cancelado la curación en red.",
|
||||
"healing_cancelled": "Se ha cancelado la curación de la red.",
|
||||
"healing_complete": "La curación de la red se ha completado.",
|
||||
"healing_failed": "La curación falló. Puede haber información adicional disponible en los registros.",
|
||||
"in_progress": "La curación de la red está en curso. Esto llevará algún tiempo.",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "Midagi pole veel seadistatud",
|
||||
"none_found": "Sidumisi ei leitud",
|
||||
"none_found_detail": "Korrigeerige oma otsingukriteeriume.",
|
||||
"note_about_integrations": "Kõiki sidumisi ei saa veel kasutajaliidese kaudu seadistada.",
|
||||
"note_about_integrations": "Otsingule ei vastanud ükski sidumine, soovitud üksus ei pruugi olla veel kasutajaliidese kaudu seadistamiseks saadaval.",
|
||||
"note_about_website_reference": "Rohkem on saadaval ",
|
||||
"reconfigure": "Seadistage uuesti",
|
||||
"rename_dialog": "Muuda selle seadistuskirje nime",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "כלום אינו הוגדר עדיין",
|
||||
"none_found": "לא נמצאו אינטגרציות",
|
||||
"none_found_detail": "התאם את קריטריוני החיפוש שלך.",
|
||||
"note_about_integrations": "לא ניתן להגדיר עדיין את כל השילובים דרך ממשק המשתמש.",
|
||||
"note_about_integrations": "אין שילובים שתאמו לחיפוש שלך, ייתכן שהשילוב שברצונך להגדיר לא יהיה זמין עדיין להגדרה באמצעות ממשק המשתמש.",
|
||||
"note_about_website_reference": "מידע נוסף זמין ב:",
|
||||
"reconfigure": "קביעת תצורה מחדש",
|
||||
"rename_dialog": "ערוך את שם ישות התצורה הזו",
|
||||
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "הוסף צומת",
|
||||
"close": "סגור",
|
||||
"heal_network": "ריפוי רשת",
|
||||
"home_id": "מזהה בית",
|
||||
"network": "רשת",
|
||||
"node_id": "מזהה צומת",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "מצב הצומת",
|
||||
"zwave_info": "מידע Z-Wave"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "ריפוי הרשת בוטל.",
|
||||
"healing_complete": "ריפוי הרשת הושלם.",
|
||||
"healing_failed": "הריפוי נכשל. מידע נוסף עשוי להיות זמין ביומנים.",
|
||||
"in_progress": "ריפוי הרשת בעיצומו. זה ייקח קצת זמן.",
|
||||
"introduction": "התחל ריפוי רשת ברשת Z-Wave שלך. ריפוי רשת יגרום לכל ההתקנים לחשב מחדש את הנתיבים שלהם בחזרה לבקר ומומלץ אם העברת לאחרונה התקנים או הבקר שלך.",
|
||||
"run_in_background": "באפשרותך לסגור תיבת דו שיח זו וריפוי הרשת ימשיך ברקע.",
|
||||
"start_heal": "התחל ריפוי",
|
||||
"stop_heal": "הפסק ריפוי",
|
||||
"title": "רפא את רשת Z-Wave שלך",
|
||||
"traffic_warning": "תהליך הריפוי מייצר כמות גדולה של תעבורה ברשת Z-Wave. הדבר עלול לגרום להתקנים להגיב באיטיות (או בכלל לא) בזמן שהריפוי מתבצע."
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "רמת יומן",
|
||||
"log_level_changed": "רמת היומן שונתה ל: {level}",
|
||||
|
@ -121,7 +121,8 @@
|
||||
"edit_in_ui": "Szerkesztés a felhasználói felületen",
|
||||
"edit_in_yaml": "Szerkesztés YAML-ben",
|
||||
"header": "Lehetőségek",
|
||||
"invalid_yaml": "Érvénytelen YAML"
|
||||
"invalid_yaml": "Érvénytelen YAML",
|
||||
"show_unused_optional": "A nem használt opcionális konfigurációs lehetőségek megjelenítése"
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
@ -194,6 +195,7 @@
|
||||
"hostname": "Gazdagép neve",
|
||||
"install": "telepítés",
|
||||
"new_update_available": "{name} {version} elérhető",
|
||||
"not_available_arch": "Ez a kiegészítő nem kompatibilis a készülék processzorával vagy az eszközre telepített operációs rendszerrel.",
|
||||
"not_available_version": "A(z) {core_version_installed} otthoni segédet futtatja, hogy frissítse az Otthoni segéd legalább {core_version_needed} verzióját.",
|
||||
"open_web_ui": "Webes felhasználói felület megnyitása",
|
||||
"option": {
|
||||
@ -328,6 +330,7 @@
|
||||
"add_new_registry": "Hozzáadás új rendszerleíró adatbázishoz",
|
||||
"add_registry": "Hozzáadás a rendszerleíró adatbázishoz",
|
||||
"failed_to_add": "Nem sikerült hozzáadni a rendszerleíró adatbázishoz",
|
||||
"no_registries": "Nincsenek konfigurálva regiszterek",
|
||||
"password": "Jelszó",
|
||||
"registry": "Regisztrálás",
|
||||
"remove": "Eltávolítás",
|
||||
@ -678,6 +681,7 @@
|
||||
"addon": "Bővítmény",
|
||||
"error": {
|
||||
"fetch_addons": {
|
||||
"description": "A kiegészítők lekérése hibát eredményezett.",
|
||||
"title": "Hiba történt a bővítmények beolvasása közben"
|
||||
},
|
||||
"no_supervisor": {
|
||||
@ -746,6 +750,7 @@
|
||||
}
|
||||
},
|
||||
"history_charts": {
|
||||
"history_disabled": "Előzményintegráció letiltva",
|
||||
"loading_history": "Állapot előzmények betöltése...",
|
||||
"no_history_found": "Nem található előzmény."
|
||||
},
|
||||
@ -929,6 +934,7 @@
|
||||
"enabled_label": "Entitás engedélyezése",
|
||||
"enabled_restart_confirm": "Az entitások engedélyezésének befejezéséhez indítsd újra a Home Assistant-et",
|
||||
"entity_id": "Entitás ID",
|
||||
"follow_device_area": "Kövesse a készülék területét",
|
||||
"icon": "Ikon",
|
||||
"icon_error": "Az ikonokat a 'prefix:ikonnév' formátumban kell megadni, pl.: 'mdi:home'",
|
||||
"name": "Név",
|
||||
@ -1214,6 +1220,8 @@
|
||||
"no_type_provided": "Nincs megadva típus."
|
||||
},
|
||||
"supervisor": {
|
||||
"ask": "Kérjen segítséget",
|
||||
"observer": "Ellenőrizze a Figyelőt",
|
||||
"reboot": "Próbálja újraindítani a gazdagépet",
|
||||
"system_health": "Rendszerállapot ellenőrzése"
|
||||
}
|
||||
@ -1742,6 +1750,7 @@
|
||||
"target_browser": "Böngésző"
|
||||
},
|
||||
"female": "Nő",
|
||||
"info": "Csinálj az otthonodnak személyiséget azzal, hogy a szövegfelolvasó szolgáltatásaink segítségével beszélhessünk veled. Ez használható az automatizálásokban és a szkriptekben a(z) {service} szolgáltatás használatával.",
|
||||
"male": "Férfi",
|
||||
"title": "Szövegről beszédre",
|
||||
"try": "Próbálja meg"
|
||||
@ -1879,6 +1888,7 @@
|
||||
"title": "Alapvető elemzés"
|
||||
},
|
||||
"diagnostics": {
|
||||
"description": "Megosztja az összeomlási jelentéseket, ha váratlan hibák lépnek fel.",
|
||||
"title": "Diagnosztika"
|
||||
},
|
||||
"statistics": {
|
||||
@ -2188,8 +2198,10 @@
|
||||
"services": "{count} {count, plural,\n one {szolgáltatás}\n other {szolgáltatás}\n}",
|
||||
"state": {
|
||||
"loaded": "Betöltve",
|
||||
"migration_error": "Migrációs hiba",
|
||||
"not_loaded": "Nincs betöltve",
|
||||
"setup_error": "Nem sikerült beállítani"
|
||||
"setup_error": "Nem sikerült beállítani",
|
||||
"setup_retry": "A beállítás újbóli megkísérlése"
|
||||
},
|
||||
"system_options": "Rendszerbeállítások",
|
||||
"unnamed_entry": "Névtelen bejegyzés"
|
||||
@ -2212,6 +2224,7 @@
|
||||
"not_all_required_fields": "Nincs kitöltve minden szükséges mező.",
|
||||
"not_loaded": "Az integrációt nem sikerült betölteni. Próbálja meg újraindítani a Home Assistantot.",
|
||||
"pick_flow_step": {
|
||||
"new_flow": "Nem, állítson be egy másik {integration}",
|
||||
"title": "Felfedeztük ezeket, be akarod állítani őket?"
|
||||
},
|
||||
"submit": "Küldés"
|
||||
@ -2869,6 +2882,7 @@
|
||||
"zwave_js": {
|
||||
"add_node": {
|
||||
"inclusion_finished": "A csomópont hozzá lett adva.",
|
||||
"introduction": "Ez a varázsló végigvezeti Önt egy csomópont hozzáadásán a Z-Wave-hálózathoz.",
|
||||
"title": "Adjon hozzá egy Z-Wave csomópontot",
|
||||
"view_device": "Eszköz megtekintése"
|
||||
},
|
||||
@ -2885,8 +2899,10 @@
|
||||
"dashboard": {
|
||||
"driver_version": "Illesztőprogram verzió",
|
||||
"dump_not_ready_confirm": "Letöltés",
|
||||
"dump_not_ready_title": "Még nem minden csomópont áll készen",
|
||||
"header": "Kezelje Z-Wave hálózatát",
|
||||
"home_id": "Otthon azonosító",
|
||||
"introduction": "A Z-Wave hálózat és a Z-Wave csomópontok kezelése",
|
||||
"nodes_ready": "Csomópontok készen állnak",
|
||||
"server_version": "Szerver verzió"
|
||||
},
|
||||
@ -3703,6 +3719,7 @@
|
||||
"working": "Kérlek várj"
|
||||
},
|
||||
"initializing": "Inicializálás",
|
||||
"logging_in_to_with": "Bejelentkezés a következőhöz: ** {locationName} ** a ** {authProviderName} ** szolgáltatással.",
|
||||
"logging_in_with": "Bejelentkezés **{authProviderName}** használatával.",
|
||||
"pick_auth_provider": "Vagy válassz a következő bejelentkezési módok közül"
|
||||
},
|
||||
@ -3875,6 +3892,7 @@
|
||||
"header": "Többfaktoros Hitelesítési Modulok"
|
||||
},
|
||||
"number_format": {
|
||||
"description": "Válassza ki a számok formátumát.",
|
||||
"dropdown_label": "Számformátum",
|
||||
"formats": {
|
||||
"comma_decimal": "1 234 567,89",
|
||||
|
@ -865,8 +865,10 @@
|
||||
"related-filter-menu": {
|
||||
"filter_by_area": "エリアで絞り込む",
|
||||
"filter_by_device": "デバイスで絞り込む",
|
||||
"filter_by_entity": "エンティティで絞り込む",
|
||||
"filtered_by_area": "エリア: {area_name}",
|
||||
"filtered_by_device": "デバイス: {device_name}"
|
||||
"filtered_by_device": "デバイス: {device_name}",
|
||||
"filtered_by_entity": "エンティティ: {entity_name}"
|
||||
},
|
||||
"related-items": {
|
||||
"area": "エリア",
|
||||
@ -2952,6 +2954,7 @@
|
||||
"common": {
|
||||
"add_node": "ノードの追加",
|
||||
"close": "閉じる",
|
||||
"heal_network": "ネットワークの修復",
|
||||
"home_id": "ホームID",
|
||||
"network": "ネットワーク",
|
||||
"node_id": "ノードID",
|
||||
@ -2978,6 +2981,18 @@
|
||||
"node_status": "ノードの状態",
|
||||
"zwave_info": "Z-Wave情報"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "ネットワークの修復がキャンセルされました。",
|
||||
"healing_complete": "ネットワークの修復が完了しました。",
|
||||
"healing_failed": "修復に失敗しました。追加情報はログで利用できる場合があります。",
|
||||
"in_progress": "ネットワークの修復が進行中です。これには少し時間がかかります。",
|
||||
"introduction": "Z-Wave ネットワークでネットワーク修復を開始します。ネットワークの修復は、すべてのデバイスがコントローラに戻ってルートを再計算し、最近デバイスまたはコントローラを移動した場合に推奨されます。",
|
||||
"run_in_background": "このダイアログを閉じると、ネットワークの修復がバックグラウンドで続行されます。",
|
||||
"start_heal": "修復を開始する",
|
||||
"stop_heal": "修復をやめる",
|
||||
"title": "Z-Waveネットワークの修復",
|
||||
"traffic_warning": "この修復プロセスでは、Z-Wave ネットワーク上に大量のトラフィックが生成されます。これにより、修復が進行中のデバイスの応答が遅くなる (またはまったく反応しない) ことがあります。"
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "ログレベル",
|
||||
"log_level_changed": "ログレベルが変更されました。{level}に変更されました。",
|
||||
|
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "노드 추가하기",
|
||||
"close": "닫기",
|
||||
"heal_network": "네트워크 복구",
|
||||
"home_id": "집 ID",
|
||||
"network": "네트워크",
|
||||
"node_id": "노드 ID",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "노드 상태",
|
||||
"zwave_info": "Z-Wave 정보"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "네트워크 복구가 취소되었습니다.",
|
||||
"healing_complete": "네트워크 복구가 완료되었습니다.",
|
||||
"healing_failed": "복구에 실패했습니다. 로그에서 추가 정보를 확인할 수 있습니다.",
|
||||
"in_progress": "네트워크 복구가 진행 중입니다. 시간이 좀 걸립니다.",
|
||||
"introduction": "Z-Wave 네트워크 복구를 시작합니다. 네트워크 복구 시 모든 장치가 컨트롤러와의 경로를 재설정하며 최근 장치나 컨트롤러의 위치를 이동 한 경우 권장됩니다.",
|
||||
"run_in_background": "이 대화 상자를 닫을 수 있으며 네트워크 복구는 백그라운드에서 계속됩니다.",
|
||||
"start_heal": "복구 시작",
|
||||
"stop_heal": "복구 중지",
|
||||
"title": "Z-Wave 네트워크 복구",
|
||||
"traffic_warning": "복구 프로세스는 Z-Wave 네트워크에서 많은 양의 트래픽을 생성합니다. 이로 인해 치료가 진행되는 동안 장치가 느리게 (또는 전혀 응답하지 않을) 수 있습니다."
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "로그 레벨",
|
||||
"log_level_changed": "로그 레벨이 변경되었습니다: {level}",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "Ingenting er konfigurert enda",
|
||||
"none_found": "Ingen integrasjoner funnet",
|
||||
"none_found_detail": "Juster dine søkekriterier",
|
||||
"note_about_integrations": "Ikke alle integrasjoner kan konfigureres via brukergrensesnittet ennå.",
|
||||
"note_about_integrations": "Ingen integrasjoner samsvarte med søket, integreringen du vil konfigurere, er kanskje ikke tilgjengelig for konfigurering via brukergrensesnittet ennå.",
|
||||
"note_about_website_reference": "Flere er tilgjengelige på",
|
||||
"reconfigure": "Konfigurer på nytt",
|
||||
"rename_dialog": "Redigere navnet på denne config-oppføringen",
|
||||
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "Legg til node",
|
||||
"close": "Lukk",
|
||||
"heal_network": "Helbrede nettverk",
|
||||
"home_id": "Hjem-ID",
|
||||
"network": "Nettverk",
|
||||
"node_id": "Node-ID",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "Node status",
|
||||
"zwave_info": "Z-Wave Informasjon"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "Nettverkshelbredelse er avbrutt.",
|
||||
"healing_complete": "Nettverksheling er fullført.",
|
||||
"healing_failed": "Helbredelse mislyktes. Ytterligere informasjon kan være tilgjengelig i loggene.",
|
||||
"in_progress": "Nettverkshelbredelse pågår. Dette vil ta litt tid.",
|
||||
"introduction": "Start en nettverkshelbredelse på Z-Wave-nettverket. En nettverkshelbredelse vil føre til at alle enheter beregner rutene sine tilbake til kontrolleren, og anbefales hvis du nylig har flyttet enheter eller kontrolleren din.",
|
||||
"run_in_background": "Du kan lukke denne dialogboksen, og nettverksreparasjonen fortsetter i bakgrunnen.",
|
||||
"start_heal": "Begynn å helbrede",
|
||||
"stop_heal": "Stopp helbredelse",
|
||||
"title": "Helbred ditt Z-Wave-nettverk",
|
||||
"traffic_warning": "Helbredelsesprosessen genererer stor trafikk på Z-Wave-nettverket. Dette kan føre til at enheter reagerer sakte (eller ikke i det hele tatt) mens legingen pågår."
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "Loggnivå",
|
||||
"log_level_changed": "Loggnivå endret til: {level}",
|
||||
|
@ -942,9 +942,9 @@
|
||||
},
|
||||
"dialogs": {
|
||||
"config_entry_system_options": {
|
||||
"enable_new_entities_description": "Of nieuw ontdekte apparaten voor {integratie} automatisch moeten worden toegevoegd.",
|
||||
"enable_new_entities_description": "Of nieuw ontdekte apparaten voor {integration} automatisch moeten worden toegevoegd.",
|
||||
"enable_new_entities_label": "Voeg nieuwe entiteiten automatisch toe",
|
||||
"enable_polling_description": "Of Home Assistant automatisch moet pollen voor updates voor {integration} entiteiten",
|
||||
"enable_polling_description": "Of Home Assistant automatisch moet pollen voor {integration} entiteiten updates.",
|
||||
"enable_polling_label": "Schakel polling voor updates in.",
|
||||
"restart_home_assistant": "U moet Home Assistant opnieuw starten om uw wijzigingen door te voeren.",
|
||||
"title": "Systeeminstellingen voor {integration}",
|
||||
@ -2319,7 +2319,7 @@
|
||||
"none": "Er is nog niets geconfigureerd",
|
||||
"none_found": "Geen integraties gevonden",
|
||||
"none_found_detail": "Pas uw zoekcriteria aan.",
|
||||
"note_about_integrations": "Nog niet alle integraties kunnen via de UI worden geconfigureerd.",
|
||||
"note_about_integrations": "Er kwamen geen integraties overeen met uw zoekopdracht. De integratie die u wilt instellen, is mogelijk nog niet beschikbaar om via de gebruikersinterface in te stellen.",
|
||||
"note_about_website_reference": "Meer zijn beschikbaar op de ",
|
||||
"reconfigure": "Herconfigureer",
|
||||
"rename_dialog": "Bewerk de naam van dit configuratie item",
|
||||
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "Knooppunt toevoegen",
|
||||
"close": "Sluiten",
|
||||
"heal_network": "Herstel netwerk",
|
||||
"home_id": "Home ID",
|
||||
"network": "Netwerk",
|
||||
"node_id": "Knooppunt-ID",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "Knooppuntstatus",
|
||||
"zwave_info": "Z-Wave info"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "Netwerkherstel is geannuleerd.",
|
||||
"healing_complete": "Netwerkherstel is compleet.",
|
||||
"healing_failed": "Herstellen mislukt. Aanvullende informatie is mogelijk beschikbaar in de logboeken.",
|
||||
"in_progress": "Netwerkherstel wordt uitgevoerd. Dit zal eveen duren.",
|
||||
"introduction": "Start een netwerkherstel op uw Z-Wave netwerk. Een netwerkherstel zorgt ervoor dat alle apparaten hun routes naar de controller opnieuw berekenen en wordt aanbevolen als je recent apparaten of uw controller hebt verplaatst.",
|
||||
"run_in_background": "U kunt dit dialoogvenster sluiten en het netwerkherstel zal voortzetten op de achtergrond.",
|
||||
"start_heal": "Start herstellen",
|
||||
"stop_heal": "Stop herstellen",
|
||||
"title": "Herstel uw Z-Wave netwerk",
|
||||
"traffic_warning": "Het herstelproces genereert een grote hoeveelheid verkeer op het Z-wave netwerk. Dit kan ertoe leiden dat apparaten traag reageren (of helemaal niet) als het herstel wordt uitgevoerd."
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "Log niveau",
|
||||
"log_level_changed": "Logboekniveau gewijzigd in: {level}",
|
||||
|
@ -205,7 +205,7 @@
|
||||
}
|
||||
},
|
||||
"changelog": "Lista zmian",
|
||||
"cpu_usage": "Zużycie procesora przez dodatek",
|
||||
"cpu_usage": "Użycie procesora przez dodatek",
|
||||
"hostname": "Nazwa hosta",
|
||||
"install": "zainstaluj",
|
||||
"new_update_available": "{name} {version} jest dostępna",
|
||||
@ -239,7 +239,7 @@
|
||||
"enable": "Włącz tryb ochrony",
|
||||
"title": "Ostrzeżenie: Tryb ochrony jest wyłączony!"
|
||||
},
|
||||
"ram_usage": "Zużycie pamięci przez dodatek",
|
||||
"ram_usage": "Użycie pamięci przez dodatek",
|
||||
"rebuild": "przeinstaluj",
|
||||
"restart": "uruchom ponownie",
|
||||
"start": "uruchom",
|
||||
@ -433,8 +433,8 @@
|
||||
},
|
||||
"system": {
|
||||
"core": {
|
||||
"cpu_usage": "Zużycie procesora przez HA Core",
|
||||
"ram_usage": "Zużycie pamięci przez HA Core"
|
||||
"cpu_usage": "Użycie procesora przez HA Core",
|
||||
"ram_usage": "Użycie pamięci przez HA Core"
|
||||
},
|
||||
"host": {
|
||||
"change": "Zmień",
|
||||
@ -469,7 +469,7 @@
|
||||
"beta_release_items": "Obejmuje to wersje beta dla:",
|
||||
"beta_warning": "Wersje beta są przeznaczone dla testerów i wczesnych użytkowników i mogą zawierać niestabilne zmiany w kodzie",
|
||||
"channel": "Kanał",
|
||||
"cpu_usage": "Zużycie procesora przez Supervisora",
|
||||
"cpu_usage": "Użycie procesora przez Supervisora",
|
||||
"failed_to_reload": "Nie udało się wczytać ponownie Supervisora",
|
||||
"failed_to_set_option": "Nie udało się ustawić opcji Supervisora",
|
||||
"failed_to_update": "Nie udało się zaktualizować Supervisora",
|
||||
@ -477,7 +477,7 @@
|
||||
"join_beta_description": "Pobieraj aktualizacje beta dla Home Assistanta (RC), Supervisora i hosta",
|
||||
"leave_beta_action": "Opuść kanał beta",
|
||||
"leave_beta_description": "Pobieraj stabilne aktualizacje dla Home Assistanta, Supervisora i hosta",
|
||||
"ram_usage": "Zużycie pamięci przez Supervisora",
|
||||
"ram_usage": "Użycie pamięci przez Supervisora",
|
||||
"reload_supervisor": "Wczytaj ponownie",
|
||||
"search": "Szukaj",
|
||||
"share_diagnostics": "Udostępnij dane diagnostyczne",
|
||||
@ -2319,7 +2319,7 @@
|
||||
"none": "Nic jeszcze nie zostało skonfigurowane",
|
||||
"none_found": "Nie znaleziono integracji",
|
||||
"none_found_detail": "Dostosuj kryteria wyszukiwania.",
|
||||
"note_about_integrations": "Jeszcze nie wszystkie integracje można skonfigurować za pomocą interfejsu użytkownika.",
|
||||
"note_about_integrations": "Żadne integracje nie pasują do Twojego wyszukiwania. Integracja, którą chcesz skonfigurować, może być jeszcze niedostępna do skonfigurowania za pomocą interfejsu użytkownika.",
|
||||
"note_about_website_reference": "Więcej jest dostępnych na stronie integracji ",
|
||||
"reconfigure": "Zmień konfigurację",
|
||||
"rename_dialog": "Edytuj nazwę tego wpisu konfiguracji",
|
||||
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "Dodaj węzeł",
|
||||
"close": "Zamknij",
|
||||
"heal_network": "Uzdrawiaj sieć",
|
||||
"home_id": "Identyfikator domu",
|
||||
"network": "Sieć",
|
||||
"node_id": "Identyfikator węzła",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "Stan węzła",
|
||||
"zwave_info": "Informacje Z-Wave"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "Uzdrawianie sieci zostało anulowane.",
|
||||
"healing_complete": "Uzdrawianie sieci zostało zakończone.",
|
||||
"healing_failed": "Uzdrawianie nie powiodło się. Dodatkowe informacje mogą być dostępne w logach.",
|
||||
"in_progress": "Trwa uzdrawianie sieci. To zajmie trochę czasu.",
|
||||
"introduction": "Rozpocznij uzdrawianie sieci Z-Wave. Uzdrawianie sieci spowoduje, że wszystkie urządzenia ponownie obliczą swoje trasy z powrotem do kontrolera i jest zalecane, jeśli niedawno przeniesiono urządzenia lub kontroler.",
|
||||
"run_in_background": "Możesz zamknąć to okno, a uzdrawianie sieci będzie kontynuowane w tle.",
|
||||
"start_heal": "Rozpocznij uzdrawianie",
|
||||
"stop_heal": "Zatrzymaj uzdrawianie",
|
||||
"title": "Uzdrawianie sieci Z-Wave",
|
||||
"traffic_warning": "Proces uzdrawiania generuje duży ruch w sieci Z-Wave. Może to spowodować, że urządzenia będą reagować powoli (lub wcale) podczas trwania uzdrawiania."
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "Poziom loga",
|
||||
"log_level_changed": "Poziom dziennika zmieniony na: {level}",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "Пока ничего не настроено",
|
||||
"none_found": "Интеграции не найдены",
|
||||
"none_found_detail": "Измените критерии поиска",
|
||||
"note_about_integrations": "Пока что не все интеграции могут быть настроены через пользовательский интерфейс.",
|
||||
"note_about_integrations": "Не найдено соответствий по Вашему запросу. Интеграция, которую Вы хотели бы настроить, может быть недоступна для настройки через пользовательский интерфейс.",
|
||||
"note_about_website_reference": "Все доступные интеграции Вы можете найти на ",
|
||||
"reconfigure": "Перенастроить",
|
||||
"rename_dialog": "Название интеграции",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "尚未配置任何集成",
|
||||
"none_found": "未找到集成",
|
||||
"none_found_detail": "请调整搜索条件。",
|
||||
"note_about_integrations": "并非所有集成都可以通过 UI 进行配置。",
|
||||
"note_about_integrations": "未搜索到相关集成,可能是您要配置的集成还不支持通过 UI 配置。",
|
||||
"note_about_website_reference": "更多可用信息,尽在 ",
|
||||
"reconfigure": "重新配置",
|
||||
"rename_dialog": "编辑此配置项的名称",
|
||||
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "添加节点",
|
||||
"close": "关闭",
|
||||
"heal_network": "修复网络",
|
||||
"home_id": "家庭 ID",
|
||||
"network": "网络",
|
||||
"node_id": "节点 ID",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "节点状态",
|
||||
"zwave_info": "Z-Wave 信息"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "网络修复已取消。",
|
||||
"healing_complete": "网络修复完成。",
|
||||
"healing_failed": "修复失败。日志中会有更多信息。",
|
||||
"in_progress": "正在修复网络。可能需要一段时间。",
|
||||
"introduction": "在此 Z-Wave 网络上启动网络修复。网络修复会使所有设备重新计算它们到控制器的路由。如果您最近挪动了设备或控制器,建议使用此功能。",
|
||||
"run_in_background": "您可以关闭此对话框,网络修复将在后台继续进行。",
|
||||
"start_heal": "开始修复",
|
||||
"stop_heal": "停止修复",
|
||||
"title": "修复 Z-Wave 网络",
|
||||
"traffic_warning": "修复过程会在 Z-Wave 网络上产生大量流量。修复期间,设备可能会响应缓慢或完全无响应。"
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "日志级别",
|
||||
"log_level_changed": "日志级别更改为: {level}",
|
||||
|
@ -2319,7 +2319,7 @@
|
||||
"none": "尚未設定",
|
||||
"none_found": "找不到相關整合。",
|
||||
"none_found_detail": "調整搜尋條件。",
|
||||
"note_about_integrations": "目前並非所有整合皆可以透過 UI 進行設定。",
|
||||
"note_about_integrations": "沒有找到符合的整合,所要設定的整合可能尚未支援透過 UI 進行設定。",
|
||||
"note_about_website_reference": "更多資訊請參閱",
|
||||
"reconfigure": "重新設定",
|
||||
"rename_dialog": "編輯設定實體名稱",
|
||||
@ -2962,6 +2962,7 @@
|
||||
"common": {
|
||||
"add_node": "新增節點",
|
||||
"close": "關閉",
|
||||
"heal_network": "修復網路",
|
||||
"home_id": "家庭 ID",
|
||||
"network": "網路",
|
||||
"node_id": "節點 ID",
|
||||
@ -2988,6 +2989,18 @@
|
||||
"node_status": "節點狀態",
|
||||
"zwave_info": "Z-Wave 資訊"
|
||||
},
|
||||
"heal_network": {
|
||||
"healing_cancelled": "網路修復已取消。",
|
||||
"healing_complete": "網路修復已完成。",
|
||||
"healing_failed": "修復失敗。日誌中可能包含其他相關資訊。",
|
||||
"in_progress": "網路修復進行中,可能需要一點時間。",
|
||||
"introduction": "於 Z-Wave 網路開始網路修復。網路修復將導致所有裝置重新計算其連回控制器的路徑,檢如近期有移動裝置或控制器的話,建議執行此動作。",
|
||||
"run_in_background": "可以關閉此對話框、網路修復將於背景繼續執行。",
|
||||
"start_heal": "開始修復",
|
||||
"stop_heal": "停止修復",
|
||||
"title": "修復 Z-Wave 網路",
|
||||
"traffic_warning": "修復過程將對 Z-Wave 網路產生大量流量,過程中可能會導致裝置回應減緩(或失去回應)。"
|
||||
},
|
||||
"logs": {
|
||||
"log_level": "日誌記錄等級",
|
||||
"log_level_changed": "日誌等級變更為:{level}",
|
||||
|
Loading…
x
Reference in New Issue
Block a user