mirror of
https://github.com/home-assistant/frontend.git
synced 2025-09-13 15:09:41 +00:00
Compare commits
14 Commits
parallel-t
...
new-system
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6e49d79538 | ||
![]() |
454f852531 | ||
![]() |
b53645ce92 | ||
![]() |
de34a5a597 | ||
![]() |
bd8e15bdd1 | ||
![]() |
45c7e0eeeb | ||
![]() |
a35a380ec7 | ||
![]() |
02e67d1146 | ||
![]() |
a5411f7ac4 | ||
![]() |
e8da203fe1 | ||
![]() |
10aa0a8829 | ||
![]() |
85a37e2d2f | ||
![]() |
ba8621fa2c | ||
![]() |
43e80f1a2e |
@@ -68,6 +68,7 @@ class HassioAddonRepositoryEl extends LitElement {
|
||||
${addons.map(
|
||||
(addon) => html`
|
||||
<ha-card
|
||||
outlined
|
||||
.addon=${addon}
|
||||
class=${addon.available ? "" : "not_available"}
|
||||
@click=${this._addonTapped}
|
||||
|
@@ -50,6 +50,7 @@ class HassioAddonAudio extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.supervisor.localize("addon.configuration.audio.header")}
|
||||
>
|
||||
<div class="card-content">
|
||||
|
@@ -162,7 +162,7 @@ class HassioAddonConfig extends LitElement {
|
||||
);
|
||||
return html`
|
||||
<h1>${this.addon.name}</h1>
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="header">
|
||||
<h2>
|
||||
${this.supervisor.localize("addon.configuration.options.header")}
|
||||
|
@@ -58,6 +58,7 @@ class HassioAddonNetwork extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.supervisor.localize(
|
||||
"addon.configuration.network.header"
|
||||
)}
|
||||
|
@@ -38,7 +38,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
||||
}
|
||||
return html`
|
||||
<div class="content">
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
|
@@ -166,7 +166,7 @@ class HassioAddonInfo extends LitElement {
|
||||
`
|
||||
: ""}
|
||||
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<div class="addon-header">
|
||||
${!this.narrow ? this.addon.name : ""}
|
||||
@@ -649,7 +649,7 @@ class HassioAddonInfo extends LitElement {
|
||||
|
||||
${this.addon.long_description
|
||||
? html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<ha-markdown
|
||||
.content=${this.addon.long_description}
|
||||
|
@@ -34,7 +34,7 @@ class HassioAddonLogs extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<h1>${this.addon.name}</h1>
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
|
@@ -26,7 +26,7 @@ class HassioAddons extends LitElement {
|
||||
<div class="card-group">
|
||||
${!this.supervisor.supervisor.addons?.length
|
||||
? html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<button class="link" @click=${this._openStore}>
|
||||
${this.supervisor.localize("dashboard.no_addons")}
|
||||
@@ -38,7 +38,11 @@ class HassioAddons extends LitElement {
|
||||
.sort((a, b) => caseInsensitiveStringCompare(a.name, b.name))
|
||||
.map(
|
||||
(addon) => html`
|
||||
<ha-card .addon=${addon} @click=${this._addonTapped}>
|
||||
<ha-card
|
||||
outlined
|
||||
.addon=${addon}
|
||||
@click=${this._addonTapped}
|
||||
>
|
||||
<div class="card-content">
|
||||
<hassio-card-content
|
||||
.hass=${this.hass}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = home-assistant-frontend
|
||||
version = 20220429.0
|
||||
version = 20220502.0
|
||||
author = The Home Assistant Authors
|
||||
author_email = hello@home-assistant.io
|
||||
license = Apache-2.0
|
||||
|
@@ -10,6 +10,8 @@ export class HaTimeline extends LitElement {
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public raised = false;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) notEnabled = false;
|
||||
|
||||
@property({ type: Boolean }) public lastItem = false;
|
||||
|
||||
@property({ type: String }) public icon?: string;
|
||||
@@ -76,6 +78,9 @@ export class HaTimeline extends LitElement {
|
||||
margin-right: 8px;
|
||||
width: 24px;
|
||||
}
|
||||
:host([notEnabled]) ha-svg-icon {
|
||||
opacity: 0.5;
|
||||
}
|
||||
ha-svg-icon {
|
||||
color: var(
|
||||
--timeline-ball-color,
|
||||
|
@@ -114,6 +114,11 @@ export class HaTracePathDetails extends LitElement {
|
||||
const { path, timestamp, result, error, changed_variables, ...rest } =
|
||||
trace as any;
|
||||
|
||||
if (result?.enabled === false) {
|
||||
return html`This node was disabled and skipped during execution so
|
||||
no further trace information is available.`;
|
||||
}
|
||||
|
||||
return html`
|
||||
${curPath === this.selected.path
|
||||
? ""
|
||||
|
@@ -19,6 +19,8 @@ export class HatGraphNode extends LitElement {
|
||||
|
||||
@property({ reflect: true, type: Boolean }) disabled?: boolean;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) notEnabled = false;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) graphStart?: boolean;
|
||||
|
||||
@property({ type: Boolean, attribute: "nofocus" }) noFocus = false;
|
||||
@@ -114,8 +116,14 @@ export class HatGraphNode extends LitElement {
|
||||
--stroke-clr: var(--hover-clr);
|
||||
--icon-clr: var(--default-icon-clr);
|
||||
}
|
||||
:host([disabled]) circle {
|
||||
stroke: var(--disabled-clr);
|
||||
:host([notEnabled]) circle {
|
||||
--stroke-clr: var(--disabled-clr);
|
||||
}
|
||||
:host([notEnabled][active]) circle {
|
||||
--stroke-clr: var(--disabled-active-clr);
|
||||
}
|
||||
:host([notEnabled]:hover) circle {
|
||||
--stroke-clr: var(--disabled-hover-clr);
|
||||
}
|
||||
svg {
|
||||
width: 100%;
|
||||
|
@@ -96,6 +96,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(config, path)}
|
||||
?active=${this.selected === path}
|
||||
.iconPath=${mdiAsterisk}
|
||||
.notEnabled=${config.enabled === false}
|
||||
tabindex=${track ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -130,20 +131,31 @@ export class HatScriptGraph extends LitElement {
|
||||
other: this.render_other_node,
|
||||
};
|
||||
|
||||
private render_action_node(node: Action, path: string, graphStart = false) {
|
||||
private render_action_node(
|
||||
node: Action,
|
||||
path: string,
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
const type =
|
||||
Object.keys(this.typeRenderers).find((key) => key in node) || "other";
|
||||
this.renderedNodes[path] = { config: node, path };
|
||||
if (this.trace && path in this.trace.trace) {
|
||||
this.trackedNodes[path] = this.renderedNodes[path];
|
||||
}
|
||||
return this.typeRenderers[type].bind(this)(node, path, graphStart);
|
||||
return this.typeRenderers[type].bind(this)(
|
||||
node,
|
||||
path,
|
||||
graphStart,
|
||||
disabled
|
||||
);
|
||||
}
|
||||
|
||||
private render_choose_node(
|
||||
config: ChooseAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
const trace = this.trace.trace[path] as ChooseActionTraceStep[] | undefined;
|
||||
const trace_path = trace
|
||||
@@ -160,12 +172,14 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(config, path)}
|
||||
?track=${trace !== undefined}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
>
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiArrowDecision}
|
||||
?track=${trace !== undefined}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
slot="head"
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
@@ -188,12 +202,15 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(config, branch_path)}
|
||||
?track=${track_this}
|
||||
?active=${this.selected === branch_path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
></hat-graph-node>
|
||||
${branch.sequence !== null
|
||||
? ensureArray(branch.sequence).map((action, j) =>
|
||||
this.render_action_node(
|
||||
action,
|
||||
`${branch_path}/sequence/${j}`
|
||||
`${branch_path}/sequence/${j}`,
|
||||
false,
|
||||
disabled || config.enabled === false
|
||||
)
|
||||
)
|
||||
: ""}
|
||||
@@ -205,7 +222,12 @@ export class HatScriptGraph extends LitElement {
|
||||
<hat-graph-spacer ?track=${track_default}></hat-graph-spacer>
|
||||
${config.default !== null
|
||||
? ensureArray(config.default)?.map((action, i) =>
|
||||
this.render_action_node(action, `${path}/default/${i}`)
|
||||
this.render_action_node(
|
||||
action,
|
||||
`${path}/default/${i}`,
|
||||
false,
|
||||
disabled || config.enabled === false
|
||||
)
|
||||
)
|
||||
: ""}
|
||||
</div>
|
||||
@@ -213,7 +235,12 @@ export class HatScriptGraph extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private render_if_node(config: IfAction, path: string, graphStart = false) {
|
||||
private render_if_node(
|
||||
config: IfAction,
|
||||
path: string,
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
const trace = this.trace.trace[path] as IfActionTraceStep[] | undefined;
|
||||
let trackThen = false;
|
||||
let trackElse = false;
|
||||
@@ -234,12 +261,14 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(config, path)}
|
||||
?track=${trace !== undefined}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
>
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiCallSplit}
|
||||
?track=${trace !== undefined}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
slot="head"
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
@@ -249,10 +278,16 @@ export class HatScriptGraph extends LitElement {
|
||||
.iconPath=${mdiCallMissed}
|
||||
?track=${trackElse}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
nofocus
|
||||
></hat-graph-node
|
||||
>${ensureArray(config.else).map((action, j) =>
|
||||
this.render_action_node(action, `${path}/else/${j}`)
|
||||
this.render_action_node(
|
||||
action,
|
||||
`${path}/else/${j}`,
|
||||
false,
|
||||
disabled || config.enabled === false
|
||||
)
|
||||
)}
|
||||
</div>`
|
||||
: html`<hat-graph-spacer ?track=${trackElse}></hat-graph-spacer>`}
|
||||
@@ -261,10 +296,16 @@ export class HatScriptGraph extends LitElement {
|
||||
.iconPath=${mdiCallReceived}
|
||||
?track=${trackThen}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
${ensureArray(config.then).map((action, j) =>
|
||||
this.render_action_node(action, `${path}/then/${j}`)
|
||||
this.render_action_node(
|
||||
action,
|
||||
`${path}/then/${j}`,
|
||||
false,
|
||||
disabled || config.enabled === false
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</hat-graph-branch>
|
||||
@@ -274,7 +315,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_condition_node(
|
||||
node: Condition,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
const trace = this.trace.trace[path] as ConditionTraceStep[] | undefined;
|
||||
let track = false;
|
||||
@@ -300,6 +342,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${track}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
tabindex=${trace === undefined ? "-1" : "0"}
|
||||
short
|
||||
>
|
||||
@@ -308,6 +351,7 @@ export class HatScriptGraph extends LitElement {
|
||||
slot="head"
|
||||
?track=${track}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
.iconPath=${mdiAbTesting}
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
@@ -322,6 +366,7 @@ export class HatScriptGraph extends LitElement {
|
||||
nofocus
|
||||
?track=${trackFailed}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
></hat-graph-node>
|
||||
</hat-graph-branch>
|
||||
`;
|
||||
@@ -330,7 +375,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_delay_node(
|
||||
node: DelayAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
@@ -339,6 +385,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -347,7 +394,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_device_node(
|
||||
node: DeviceAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
@@ -356,6 +404,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -364,7 +413,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_event_node(
|
||||
node: EventAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
@@ -373,6 +423,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -381,7 +432,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_repeat_node(
|
||||
node: RepeatAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
const trace: any = this.trace.trace[path];
|
||||
const repeats = this.trace?.trace[`${path}/repeat/sequence/0`]?.length;
|
||||
@@ -391,12 +443,14 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
>
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiRefresh}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
slot="head"
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
@@ -404,12 +458,18 @@ export class HatScriptGraph extends LitElement {
|
||||
.iconPath=${mdiArrowUp}
|
||||
?track=${repeats > 1}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
nofocus
|
||||
.badge=${repeats > 1 ? repeats : undefined}
|
||||
></hat-graph-node>
|
||||
<div ?track=${trace}>
|
||||
${ensureArray(node.repeat.sequence).map((action, i) =>
|
||||
this.render_action_node(action, `${path}/repeat/sequence/${i}`)
|
||||
this.render_action_node(
|
||||
action,
|
||||
`${path}/repeat/sequence/${i}`,
|
||||
false,
|
||||
disabled || node.enabled === false
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</hat-graph-branch>
|
||||
@@ -419,7 +479,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_scene_node(
|
||||
node: SceneAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
@@ -428,6 +489,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -436,7 +498,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_service_node(
|
||||
node: ServiceAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
@@ -445,6 +508,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -453,7 +517,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_wait_node(
|
||||
node: WaitAction | WaitForTriggerAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
@@ -462,6 +527,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -470,7 +536,8 @@ export class HatScriptGraph extends LitElement {
|
||||
private render_parallel_node(
|
||||
node: ParallelAction,
|
||||
path: string,
|
||||
graphStart = false
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
const trace: any = this.trace.trace[path];
|
||||
return html`
|
||||
@@ -479,12 +546,14 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
>
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
.iconPath=${mdiShuffleDisabled}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
slot="head"
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
@@ -495,20 +564,29 @@ export class HatScriptGraph extends LitElement {
|
||||
(sAction, j) =>
|
||||
this.render_action_node(
|
||||
sAction,
|
||||
`${path}/parallel/${i}/sequence/${j}`
|
||||
`${path}/parallel/${i}/sequence/${j}`,
|
||||
false,
|
||||
disabled || node.enabled === false
|
||||
)
|
||||
)}
|
||||
</div>`
|
||||
: this.render_action_node(
|
||||
action,
|
||||
`${path}/parallel/${i}/sequence/0`
|
||||
`${path}/parallel/${i}/sequence/0`,
|
||||
false,
|
||||
disabled || node.enabled === false
|
||||
)
|
||||
)}
|
||||
</hat-graph-branch>
|
||||
`;
|
||||
}
|
||||
|
||||
private render_stop_node(node: Action, path: string, graphStart = false) {
|
||||
private render_stop_node(
|
||||
node: Action,
|
||||
path: string,
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
const trace = this.trace.trace[path] as StopActionTraceStep[] | undefined;
|
||||
return html`
|
||||
<hat-graph-node
|
||||
@@ -519,11 +597,17 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
}
|
||||
|
||||
private render_other_node(node: Action, path: string, graphStart = false) {
|
||||
private render_other_node(
|
||||
node: Action,
|
||||
path: string,
|
||||
graphStart = false,
|
||||
disabled = false
|
||||
) {
|
||||
return html`
|
||||
<hat-graph-node
|
||||
.graphStart=${graphStart}
|
||||
@@ -531,6 +615,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
}
|
||||
@@ -669,6 +754,8 @@ export class HatScriptGraph extends LitElement {
|
||||
--track-clr: var(--track-color, var(--accent-color));
|
||||
--hover-clr: var(--hover-color, var(--primary-color));
|
||||
--disabled-clr: var(--disabled-color, var(--disabled-text-color));
|
||||
--disabled-active-clr: rgba(var(--rgb-primary-color), 0.5);
|
||||
--disabled-hover-clr: rgba(var(--rgb-primary-color), 0.7);
|
||||
--default-trigger-color: 3, 169, 244;
|
||||
--rgb-trigger-color: var(--trigger-color, var(--default-trigger-color));
|
||||
--background-clr: var(--background-color, white);
|
||||
|
@@ -296,7 +296,12 @@ class ActionRenderer {
|
||||
return this._handleParallel(index);
|
||||
}
|
||||
|
||||
this._renderEntry(path, describeAction(this.hass, data, actionType));
|
||||
this._renderEntry(
|
||||
path,
|
||||
describeAction(this.hass, data, actionType),
|
||||
undefined,
|
||||
data.enabled === false
|
||||
);
|
||||
|
||||
let i = index + 1;
|
||||
|
||||
@@ -349,10 +354,16 @@ class ActionRenderer {
|
||||
const chooseConfig = this._getDataFromPath(
|
||||
this.keys[index]
|
||||
) as ChooseAction;
|
||||
const disabled = chooseConfig.enabled === false;
|
||||
const name = chooseConfig.alias || "Choose";
|
||||
|
||||
if (defaultExecuted) {
|
||||
this._renderEntry(choosePath, `${name}: Default action executed`);
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: Default action executed`,
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
} else if (chooseTrace.result) {
|
||||
const choiceNumeric =
|
||||
chooseTrace.result.choice !== "default"
|
||||
@@ -364,9 +375,19 @@ class ActionRenderer {
|
||||
const choiceName = choiceConfig
|
||||
? `${choiceConfig.alias || `Option ${choiceNumeric}`} executed`
|
||||
: `Error: ${chooseTrace.error}`;
|
||||
this._renderEntry(choosePath, `${name}: ${choiceName}`);
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: ${choiceName}`,
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
} else {
|
||||
this._renderEntry(choosePath, `${name}: No action taken`);
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: No action taken`,
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
}
|
||||
|
||||
let i;
|
||||
@@ -414,9 +435,11 @@ class ActionRenderer {
|
||||
const repeatConfig = this._getDataFromPath(
|
||||
this.keys[index]
|
||||
) as RepeatAction;
|
||||
const disabled = repeatConfig.enabled === false;
|
||||
|
||||
const name = repeatConfig.alias || describeAction(this.hass, repeatConfig);
|
||||
|
||||
this._renderEntry(repeatPath, name);
|
||||
this._renderEntry(repeatPath, name, undefined, disabled);
|
||||
|
||||
let i;
|
||||
|
||||
@@ -441,18 +464,24 @@ class ActionRenderer {
|
||||
|
||||
const ifTrace = this._getItem(index)[0] as IfActionTraceStep;
|
||||
const ifConfig = this._getDataFromPath(this.keys[index]) as IfAction;
|
||||
const disabled = ifConfig.enabled === false;
|
||||
const name = ifConfig.alias || "If";
|
||||
|
||||
if (ifTrace.result) {
|
||||
if (ifTrace.result?.choice) {
|
||||
const choiceConfig = this._getDataFromPath(
|
||||
`${this.keys[index]}/${ifTrace.result.choice}/`
|
||||
) as any;
|
||||
const choiceName = choiceConfig
|
||||
? `${choiceConfig.alias || `${ifTrace.result.choice} action executed`}`
|
||||
: `Error: ${ifTrace.error}`;
|
||||
this._renderEntry(ifPath, `${name}: ${choiceName}`);
|
||||
this._renderEntry(ifPath, `${name}: ${choiceName}`, undefined, disabled);
|
||||
} else {
|
||||
this._renderEntry(ifPath, `${name}: No action taken`);
|
||||
this._renderEntry(
|
||||
ifPath,
|
||||
`${name}: No action taken`,
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
}
|
||||
|
||||
let i;
|
||||
@@ -489,9 +518,11 @@ class ActionRenderer {
|
||||
this.keys[index]
|
||||
) as ParallelAction;
|
||||
|
||||
const disabled = parallelConfig.enabled === false;
|
||||
|
||||
const name = parallelConfig.alias || "Execute in parallel";
|
||||
|
||||
this._renderEntry(parallelPath, name);
|
||||
this._renderEntry(parallelPath, name, undefined, disabled);
|
||||
|
||||
let i;
|
||||
|
||||
@@ -513,11 +544,14 @@ class ActionRenderer {
|
||||
private _renderEntry(
|
||||
path: string,
|
||||
description: string,
|
||||
icon = mdiRecordCircleOutline
|
||||
icon = mdiRecordCircleOutline,
|
||||
disabled = false
|
||||
) {
|
||||
this.entries.push(html`
|
||||
<ha-timeline .icon=${icon} data-path=${path}>
|
||||
${description}
|
||||
<ha-timeline .icon=${icon} data-path=${path} .notEnabled=${disabled}>
|
||||
${description}${disabled
|
||||
? html`<span class="disabled"> (disabled)</span>`
|
||||
: ""}
|
||||
</ha-timeline>
|
||||
`);
|
||||
}
|
||||
|
@@ -179,7 +179,10 @@ export const fetchHassioInfo = async (
|
||||
};
|
||||
|
||||
export const fetchHassioLogs = async (hass: HomeAssistant, provider: string) =>
|
||||
hass.callApi<string>("GET", `hassio/${provider}/logs`);
|
||||
hass.callApi<string>(
|
||||
"GET",
|
||||
`hassio/${provider.includes("_") ? `addons/${provider}` : provider}/logs`
|
||||
);
|
||||
|
||||
export const setSupervisorOption = async (
|
||||
hass: HomeAssistant,
|
||||
|
@@ -17,6 +17,7 @@ import { styleMap } from "lit/directives/style-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { canShowPage } from "../../common/config/can_show_page";
|
||||
import { componentsWithService } from "../../common/config/components_with_service";
|
||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||
@@ -33,6 +34,7 @@ import "../../components/ha-circular-progress";
|
||||
import "../../components/ha-header-bar";
|
||||
import "../../components/ha-icon-button";
|
||||
import "../../components/ha-textfield";
|
||||
import { fetchHassioSupervisorInfo } from "../../data/hassio/supervisor";
|
||||
import { domainToName } from "../../data/integration";
|
||||
import { getPanelNameTranslationKey } from "../../data/panel";
|
||||
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
||||
@@ -245,9 +247,10 @@ export class QuickBar extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _initializeItemsIfNeeded() {
|
||||
private async _initializeItemsIfNeeded() {
|
||||
if (this._commandMode) {
|
||||
this._commandItems = this._commandItems || this._generateCommandItems();
|
||||
this._commandItems =
|
||||
this._commandItems || (await this._generateCommandItems());
|
||||
} else {
|
||||
this._entityItems = this._entityItems || this._generateEntityItems();
|
||||
}
|
||||
@@ -485,11 +488,11 @@ export class QuickBar extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
private _generateCommandItems(): CommandItem[] {
|
||||
private async _generateCommandItems(): Promise<CommandItem[]> {
|
||||
return [
|
||||
...this._generateReloadCommands(),
|
||||
...this._generateServerControlCommands(),
|
||||
...this._generateNavigationCommands(),
|
||||
...(await this._generateNavigationCommands()),
|
||||
].sort((a, b) =>
|
||||
caseInsensitiveStringCompare(a.strings.join(" "), b.strings.join(" "))
|
||||
);
|
||||
@@ -578,11 +581,40 @@ export class QuickBar extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _generateNavigationCommands(): CommandItem[] {
|
||||
private async _generateNavigationCommands(): Promise<CommandItem[]> {
|
||||
const panelItems = this._generateNavigationPanelCommands();
|
||||
const sectionItems = this._generateNavigationConfigSectionCommands();
|
||||
const supervisorItems: BaseNavigationCommand[] = [];
|
||||
if (isComponentLoaded(this.hass, "hassio")) {
|
||||
const supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
|
||||
supervisorItems.push({
|
||||
path: "/hassio/store",
|
||||
primaryText: this.hass.localize(
|
||||
"ui.dialogs.quick-bar.commands.navigation.addon_store"
|
||||
),
|
||||
});
|
||||
supervisorItems.push({
|
||||
path: "/hassio/dashboard",
|
||||
primaryText: this.hass.localize(
|
||||
"ui.dialogs.quick-bar.commands.navigation.addon_dashboard"
|
||||
),
|
||||
});
|
||||
for (const addon of supervisorInfo.addons) {
|
||||
supervisorItems.push({
|
||||
path: `/hassio/addon/${addon.slug}`,
|
||||
primaryText: this.hass.localize(
|
||||
"ui.dialogs.quick-bar.commands.navigation.addon_info",
|
||||
{ addon: addon.name }
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return this._finalizeNavigationCommands([...panelItems, ...sectionItems]);
|
||||
return this._finalizeNavigationCommands([
|
||||
...panelItems,
|
||||
...sectionItems,
|
||||
...supervisorItems,
|
||||
]);
|
||||
}
|
||||
|
||||
private _generateNavigationPanelCommands(): BaseNavigationCommand[] {
|
||||
@@ -610,20 +642,14 @@ export class QuickBar extends LitElement {
|
||||
if (!canShowPage(this.hass, page)) {
|
||||
continue;
|
||||
}
|
||||
if (!page.component) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const info = this._getNavigationInfoFromConfig(page);
|
||||
|
||||
if (!info) {
|
||||
continue;
|
||||
}
|
||||
// Add to list, but only if we do not already have an entry for the same path and component
|
||||
if (
|
||||
items.some(
|
||||
(e) => e.path === info.path && e.component === info.component
|
||||
)
|
||||
) {
|
||||
if (items.some((e) => e.path === info.path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -637,14 +663,19 @@ export class QuickBar extends LitElement {
|
||||
private _getNavigationInfoFromConfig(
|
||||
page: PageNavigation
|
||||
): NavigationInfo | undefined {
|
||||
if (!page.component) {
|
||||
return undefined;
|
||||
}
|
||||
const caption = this.hass.localize(
|
||||
`ui.dialogs.quick-bar.commands.navigation.${page.component}`
|
||||
);
|
||||
const path = page.path.substring(1);
|
||||
|
||||
if (page.translationKey && caption) {
|
||||
let name = path.substring(path.indexOf("/") + 1);
|
||||
name = name.indexOf("/") > -1 ? name.substring(0, name.indexOf("/")) : name;
|
||||
|
||||
const caption =
|
||||
(name &&
|
||||
this.hass.localize(
|
||||
`ui.dialogs.quick-bar.commands.navigation.${name}`
|
||||
)) ||
|
||||
(page.translationKey && this.hass.localize(page.translationKey));
|
||||
|
||||
if (caption) {
|
||||
return { ...page, primaryText: caption };
|
||||
}
|
||||
|
||||
|
@@ -259,6 +259,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
<ha-svg-icon .path=${mdiImagePlus} slot="icon"></ha-svg-icon>
|
||||
</mwc-button>`}
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize("ui.panel.config.devices.caption")}
|
||||
>${devices.length
|
||||
? devices.map(
|
||||
@@ -281,6 +282,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
`}
|
||||
</ha-card>
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.areas.editor.linked_entities_caption"
|
||||
)}
|
||||
@@ -314,6 +316,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
${isComponentLoaded(this.hass, "automation")
|
||||
? html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations_heading"
|
||||
)}
|
||||
@@ -361,6 +364,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
${isComponentLoaded(this.hass, "scene")
|
||||
? html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes_heading"
|
||||
)}
|
||||
@@ -400,6 +404,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
${isComponentLoaded(this.hass, "script")
|
||||
? html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts_heading"
|
||||
)}
|
||||
|
@@ -164,7 +164,7 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
const yamlMode = this._yamlMode;
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
${this.action.enabled === false
|
||||
? html`<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
|
@@ -32,7 +32,7 @@ export default class HaAutomationAction extends LitElement {
|
||||
></ha-automation-action-row>
|
||||
`
|
||||
)}
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-actions add-card">
|
||||
<mwc-button @click=${this._addAction}>
|
||||
${this.hass.localize(
|
||||
|
@@ -69,7 +69,7 @@ export class HaChooseAction extends LitElement implements ActionElement {
|
||||
</div>
|
||||
</ha-card>`
|
||||
)}
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-actions add-card">
|
||||
<mwc-button @click=${this._addOption}>
|
||||
${this.hass.localize(
|
||||
|
@@ -75,7 +75,7 @@ export class HaBlueprintAutomationEditor extends LitElement {
|
||||
"ui.panel.config.automation.editor.introduction"
|
||||
)}
|
||||
</span>
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<ha-textfield
|
||||
.label=${this.hass.localize(
|
||||
@@ -145,6 +145,7 @@ export class HaBlueprintAutomationEditor extends LitElement {
|
||||
</ha-config-section>
|
||||
|
||||
<ha-card
|
||||
outlined
|
||||
class="blueprint"
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.blueprint.header"
|
||||
|
@@ -5,7 +5,6 @@ import { dynamicElement } from "../../../../common/dom/dynamic-element-directive
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stringCompare } from "../../../../common/string/compare";
|
||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-select";
|
||||
import type { HaSelect } from "../../../../components/ha-select";
|
||||
import "../../../../components/ha-yaml-editor";
|
||||
|
@@ -67,7 +67,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
${this.condition.enabled === false
|
||||
? html`<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
|
@@ -56,7 +56,7 @@ export default class HaAutomationCondition extends LitElement {
|
||||
></ha-automation-condition-row>
|
||||
`
|
||||
)}
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-actions add-card">
|
||||
<mwc-button @click=${this._addCondition}>
|
||||
${this.hass.localize(
|
||||
|
@@ -3,7 +3,6 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-blueprint-picker";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-circular-progress";
|
||||
import { createCloseHeading } from "../../../components/ha-dialog";
|
||||
import { showAutomationEditor } from "../../../data/automation";
|
||||
|
@@ -239,8 +239,8 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
? html`
|
||||
${!this.narrow
|
||||
? html`
|
||||
<ha-card
|
||||
><div class="card-header">
|
||||
<ha-card outlined>
|
||||
<div class="card-header">
|
||||
${this._config.alias}
|
||||
</div>
|
||||
${stateObj
|
||||
@@ -275,8 +275,8 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
.defaultValue=${this._preprocessYaml()}
|
||||
@value-changed=${this._yamlChanged}
|
||||
></ha-yaml-editor>
|
||||
<ha-card
|
||||
><div class="card-actions">
|
||||
<ha-card outlined>
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._copyYaml}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.copy_to_clipboard"
|
||||
|
@@ -47,7 +47,7 @@ export class HaManualAutomationEditor extends LitElement {
|
||||
"ui.panel.config.automation.editor.introduction"
|
||||
)}
|
||||
</span>
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<ha-textfield
|
||||
.label=${this.hass.localize(
|
||||
|
@@ -127,7 +127,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
const showId = "id" in this.trigger || this._requestShowId;
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
${this.trigger.enabled === false
|
||||
? html`<div class="disabled-bar">
|
||||
${this.hass.localize(
|
||||
|
@@ -27,7 +27,7 @@ export default class HaAutomationTrigger extends LitElement {
|
||||
></ha-automation-trigger-row>
|
||||
`
|
||||
)}
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-actions add-card">
|
||||
<mwc-button @click=${this._addTrigger}>
|
||||
${this.hass.localize(
|
||||
|
@@ -1,26 +1,28 @@
|
||||
import "@material/mwc-button";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import type { ActionDetail } from "@material/mwc-list";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import "@material/mwc-list/mwc-list-item";
|
||||
import { mdiDotsVertical } from "@mdi/js";
|
||||
import { LitElement, css, html, PropertyValues } from "lit";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
import { css, html, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { formatDateTime } from "../../../../common/datetime/format_date_time";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
||||
import { debounce } from "../../../../common/util/debounce";
|
||||
import "../../../../components/buttons/ha-call-api-button";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-alert";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import { debounce } from "../../../../common/util/debounce";
|
||||
import {
|
||||
cloudLogout,
|
||||
CloudStatusLoggedIn,
|
||||
fetchCloudSubscriptionInfo,
|
||||
SubscriptionInfo,
|
||||
} from "../../../../data/cloud";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import "../../../../layouts/hass-subpage";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import "../../ha-config-section";
|
||||
import "./cloud-alexa-pref";
|
||||
@@ -28,8 +30,6 @@ import "./cloud-google-pref";
|
||||
import "./cloud-remote-pref";
|
||||
import "./cloud-tts-pref";
|
||||
import "./cloud-webhooks";
|
||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
|
||||
@customElement("cloud-account")
|
||||
export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
@@ -81,6 +81,7 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
</div>
|
||||
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.nabu_casa_account"
|
||||
)}
|
||||
@@ -210,6 +211,7 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
||||
|
||||
<cloud-webhooks
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.cloudStatus=${this.cloudStatus}
|
||||
dir=${this._rtlDirection}
|
||||
></cloud-webhooks>
|
||||
|
@@ -26,6 +26,7 @@ export class CloudAlexaPref extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass!.localize(
|
||||
"ui.panel.config.cloud.account.alexa.title"
|
||||
)}
|
||||
|
@@ -31,6 +31,7 @@ export class CloudGooglePref extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.google.title"
|
||||
)}
|
||||
|
@@ -34,6 +34,7 @@ export class CloudRemotePref extends LitElement {
|
||||
if (!remote_certificate) {
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.remote.title"
|
||||
)}
|
||||
@@ -49,6 +50,7 @@ export class CloudRemotePref extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.cloud.account.remote.title"
|
||||
)}
|
||||
|
@@ -44,6 +44,7 @@ export class CloudTTSPref extends LitElement {
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize("ui.panel.config.cloud.account.tts.title")}
|
||||
>
|
||||
<div class="card-content">
|
||||
|
@@ -40,6 +40,7 @@ export class CloudWebhooks extends LitElement {
|
||||
protected render() {
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass!.localize(
|
||||
"ui.panel.config.cloud.account.webhooks.title"
|
||||
)}
|
||||
|
@@ -153,7 +153,7 @@ class CloudAlexa extends SubscribeMixin(LitElement) {
|
||||
></ha-icon-button>`;
|
||||
|
||||
target.push(html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<div class="top-line">
|
||||
<state-info
|
||||
|
@@ -36,6 +36,7 @@ export class CloudForgotPassword extends LitElement {
|
||||
>
|
||||
<div class="content">
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.cloud.forgot_password.subtitle"
|
||||
)}
|
||||
|
@@ -159,7 +159,7 @@ class CloudGoogleAssistant extends SubscribeMixin(LitElement) {
|
||||
></ha-icon-button>`;
|
||||
|
||||
target.push(html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<div class="top-line">
|
||||
<state-info
|
||||
|
@@ -99,6 +99,7 @@ export class CloudLogin extends LitElement {
|
||||
: ""}
|
||||
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.cloud.login.sign_in"
|
||||
)}
|
||||
@@ -157,7 +158,7 @@ export class CloudLogin extends LitElement {
|
||||
</div>
|
||||
</ha-card>
|
||||
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<paper-item @click=${this._handleRegister}>
|
||||
<paper-item-body two-line>
|
||||
${this.hass.localize(
|
||||
|
@@ -121,6 +121,7 @@ export class CloudRegister extends LitElement {
|
||||
</ul>
|
||||
</div>
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.cloud.register.create_account"
|
||||
)}
|
||||
|
@@ -196,7 +196,7 @@ class HaConfigSectionUpdates extends LitElement {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
padding: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@@ -1,9 +1,21 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { canShowPage } from "../../../common/config/can_show_page";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-navigation-list";
|
||||
import { CloudStatus } from "../../../data/cloud";
|
||||
import "../../../components/ha-tip";
|
||||
import { BackupContent, fetchBackupInfo } from "../../../data/backup";
|
||||
import { CloudStatus, fetchCloudStatus } from "../../../data/cloud";
|
||||
import { BOARD_NAMES } from "../../../data/hardware";
|
||||
import { fetchHassioBackups, HassioBackup } from "../../../data/hassio/backup";
|
||||
import {
|
||||
fetchHassioHassOsInfo,
|
||||
fetchHassioHostInfo,
|
||||
HassioHassOSInfo,
|
||||
HassioHostInfo,
|
||||
} from "../../../data/hassio/host";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
@@ -27,15 +39,80 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public showAdvanced!: boolean;
|
||||
|
||||
@state() private _latestBackupDate?: string;
|
||||
|
||||
@state() private _boardName?: string;
|
||||
|
||||
@state() private _storageInfo?: { used: number; free: number; total: number };
|
||||
|
||||
@state() private _externalAccess = false;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const pages = configSections.general
|
||||
.filter((page) => canShowPage(this.hass, page))
|
||||
.map((page) => ({
|
||||
...page,
|
||||
name: page.translationKey
|
||||
? this.hass.localize(page.translationKey)
|
||||
: page.name,
|
||||
}));
|
||||
.map((page) => {
|
||||
let description = "";
|
||||
|
||||
switch (page.translationKey) {
|
||||
case "backup":
|
||||
description = this._latestBackupDate
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.backup.description",
|
||||
"relative_time",
|
||||
relativeTime(
|
||||
new Date(this._latestBackupDate),
|
||||
this.hass.locale
|
||||
)
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.backup.description_no_backup"
|
||||
);
|
||||
break;
|
||||
case "network":
|
||||
description = this.hass.localize(
|
||||
"ui.panel.config.network.description",
|
||||
"state",
|
||||
this._externalAccess
|
||||
? this.hass.localize("ui.panel.config.network.enabled")
|
||||
: this.hass.localize("ui.panel.config.network.disabled")
|
||||
);
|
||||
break;
|
||||
case "storage":
|
||||
description = this._storageInfo
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.storage.description",
|
||||
"percent_used",
|
||||
`${Math.round(
|
||||
(this._storageInfo.used / this._storageInfo.total) * 100
|
||||
)}%`,
|
||||
"free_space",
|
||||
`${this._storageInfo.free} GB`
|
||||
)
|
||||
: "";
|
||||
break;
|
||||
case "hardware":
|
||||
description =
|
||||
this._boardName ||
|
||||
this.hass.localize("ui.panel.config.hardware.description");
|
||||
break;
|
||||
|
||||
default:
|
||||
description = this.hass.localize(
|
||||
`ui.panel.config.${page.translationKey}.description`
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
...page,
|
||||
name: page.translationKey
|
||||
? this.hass.localize(
|
||||
`ui.panel.config.${page.translationKey}.caption`
|
||||
)
|
||||
: page.name,
|
||||
description,
|
||||
};
|
||||
});
|
||||
|
||||
return html`
|
||||
<hass-subpage
|
||||
@@ -59,14 +136,32 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
.pages=${pages}
|
||||
hasSecondary
|
||||
></ha-navigation-list>
|
||||
</ha-card>
|
||||
<div class="yaml-config">Looking for YAML Configuration? It has moved to <a href="/developer-tools/yaml">Developer Tools</a></a></div>
|
||||
${this.hass.userData?.showAdvanced
|
||||
? html`<ha-tip>
|
||||
Looking for YAML Configuration? It has moved to
|
||||
<a href="/developer-tools/yaml">Developer Tools</a>
|
||||
</ha-tip>`
|
||||
: ""}
|
||||
</ha-config-section>
|
||||
</hass-subpage>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(_changedProperties): void {
|
||||
super.firstUpdated(_changedProperties);
|
||||
|
||||
this._fetchNetworkStatus();
|
||||
const isHassioLoaded = isComponentLoaded(this.hass, "hassio");
|
||||
this._fetchBackupInfo(isHassioLoaded);
|
||||
if (isHassioLoaded) {
|
||||
this._fetchHardwareInfo();
|
||||
this._fetchStorageInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private _restart() {
|
||||
showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
@@ -91,6 +186,48 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private async _fetchBackupInfo(isHassioLoaded: boolean) {
|
||||
const backups: BackupContent[] | HassioBackup[] = isHassioLoaded
|
||||
? await fetchHassioBackups(this.hass)
|
||||
: await fetchBackupInfo(this.hass).then(
|
||||
(backupData) => backupData.backups
|
||||
);
|
||||
|
||||
if (backups.length > 0) {
|
||||
this._latestBackupDate = (backups as any[]).reduce((a, b) =>
|
||||
a.date > b.date ? a : b
|
||||
).date;
|
||||
}
|
||||
}
|
||||
|
||||
private async _fetchHardwareInfo() {
|
||||
const osData: HassioHassOSInfo = await fetchHassioHassOsInfo(this.hass);
|
||||
if (osData.board) {
|
||||
this._boardName = BOARD_NAMES[osData.board];
|
||||
}
|
||||
}
|
||||
|
||||
private async _fetchStorageInfo() {
|
||||
const hostInfo: HassioHostInfo = await fetchHassioHostInfo(this.hass);
|
||||
this._storageInfo = {
|
||||
used: hostInfo.disk_used,
|
||||
free: hostInfo.disk_free,
|
||||
total: hostInfo.disk_total,
|
||||
};
|
||||
}
|
||||
|
||||
private async _fetchNetworkStatus() {
|
||||
if (isComponentLoaded(this.hass, "cloud")) {
|
||||
fetchCloudStatus(this.hass).then((cloudStatus) => {
|
||||
if (cloudStatus.logged_in) {
|
||||
this._externalAccess = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._externalAccess = this.hass.config.external_url !== null;
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
@@ -135,12 +272,9 @@ class HaConfigSystemNavigation extends LitElement {
|
||||
|
||||
ha-navigation-list {
|
||||
--navigation-list-item-title-font-size: 16px;
|
||||
--navigation-list-item-padding: 4px;
|
||||
}
|
||||
.yaml-config {
|
||||
margin-bottom: max(env(safe-area-inset-bottom), 24px);
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
ha-tip {
|
||||
margin-bottom: max(env(safe-area-inset-bottom), 8px);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
@@ -6,7 +6,7 @@ import { canShowPage } from "../../../common/config/can_show_page";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-navigation-list";
|
||||
import type { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud";
|
||||
import type { CloudStatus } from "../../../data/cloud";
|
||||
import type { PageNavigation } from "../../../layouts/hass-tabs-subpage";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
|
||||
@@ -37,9 +37,7 @@ class HaConfigNavigation extends LitElement {
|
||||
? page.info.logged_in
|
||||
? `
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.cloud.description_login",
|
||||
"email",
|
||||
(page.info as CloudStatusLoggedIn).email
|
||||
"ui.panel.config.cloud.description_login"
|
||||
)}
|
||||
`
|
||||
: `
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { customElement } from "lit/decorators";
|
||||
import "../../../../components/ha-card";
|
||||
import {
|
||||
DeviceAction,
|
||||
localizeDeviceAutomationAction,
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-chip";
|
||||
import "../../../../components/ha-chip-set";
|
||||
import { showAutomationEditor } from "../../../../data/automation";
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { customElement } from "lit/decorators";
|
||||
import "../../../../components/ha-card";
|
||||
import {
|
||||
DeviceCondition,
|
||||
localizeDeviceAutomationCondition,
|
||||
|
@@ -62,7 +62,7 @@ export class HaDeviceEntitiesCard extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
if (!this.entities.length) {
|
||||
return html`
|
||||
<ha-card .header=${this.header}>
|
||||
<ha-card outlined .header=${this.header}>
|
||||
<div class="empty card-content">
|
||||
${this.hass.localize("ui.panel.config.devices.entities.none")}
|
||||
</div>
|
||||
@@ -89,7 +89,7 @@ export class HaDeviceEntitiesCard extends LitElement {
|
||||
});
|
||||
|
||||
return html`
|
||||
<ha-card .header=${this.header}>
|
||||
<ha-card outlined .header=${this.header}>
|
||||
<div id="entities" @hass-more-info=${this._overrideMoreInfo}>
|
||||
${shownEntities.map((entry) =>
|
||||
this.hass.states[entry.entity_id]
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../../components/ha-card";
|
||||
import { AreaRegistryEntry } from "../../../../data/area_registry";
|
||||
import {
|
||||
computeDeviceName,
|
||||
@@ -24,6 +25,7 @@ export class HaDeviceCard extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.devices.device_info",
|
||||
"type",
|
||||
@@ -145,3 +147,9 @@ export class HaDeviceCard extends LitElement {
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-device-info-card": HaDeviceCard;
|
||||
}
|
||||
}
|
||||
|
@@ -579,7 +579,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
${
|
||||
isComponentLoaded(this.hass, "automation")
|
||||
? html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.automation.automations_heading"
|
||||
@@ -673,7 +673,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
${
|
||||
isComponentLoaded(this.hass, "scene") && entities.length
|
||||
? html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.scene.scenes_heading"
|
||||
@@ -771,7 +771,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
${
|
||||
isComponentLoaded(this.hass, "script")
|
||||
? html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.devices.script.scripts_heading"
|
||||
|
@@ -51,7 +51,7 @@ export class EnergyBatterySettings extends LitElement {
|
||||
});
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
<ha-svg-icon .path=${mdiBatteryHigh}></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.energy.battery.title")}
|
||||
|
@@ -36,7 +36,7 @@ export class EnergyDeviceSettings extends LitElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
<ha-svg-icon .path=${mdiDevices}></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
|
@@ -51,7 +51,7 @@ export class EnergyGasSettings extends LitElement {
|
||||
});
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
<ha-svg-icon .path=${mdiFire}></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.energy.gas.title")}
|
||||
|
@@ -80,7 +80,7 @@ export class EnergyGridSettings extends LitElement {
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
<ha-svg-icon .path=${mdiTransmissionTower}></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.energy.grid.title")}
|
||||
|
@@ -54,7 +54,7 @@ export class EnergySolarSettings extends LitElement {
|
||||
});
|
||||
|
||||
return html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
<ha-svg-icon .path=${mdiSolarPower}></ha-svg-icon>
|
||||
${this.hass.localize("ui.panel.config.energy.solar.title")}
|
||||
|
@@ -256,68 +256,68 @@ export const configSections: { [name: string]: PageNavigation[] } = {
|
||||
general: [
|
||||
{
|
||||
path: "/config/general",
|
||||
translationKey: "ui.panel.config.core.caption",
|
||||
translationKey: "core",
|
||||
iconPath: mdiCog,
|
||||
iconColor: "#653249",
|
||||
core: true,
|
||||
},
|
||||
{
|
||||
path: "/config/updates",
|
||||
translationKey: "ui.panel.config.updates.caption",
|
||||
translationKey: "updates",
|
||||
iconPath: mdiUpdate,
|
||||
iconColor: "#3B808E",
|
||||
},
|
||||
{
|
||||
component: "logs",
|
||||
path: "/config/logs",
|
||||
translationKey: "ui.panel.config.logs.caption",
|
||||
translationKey: "logs",
|
||||
iconPath: mdiMathLog,
|
||||
iconColor: "#C65326",
|
||||
core: true,
|
||||
},
|
||||
{
|
||||
path: "/config/backup",
|
||||
translationKey: "ui.panel.config.backup.caption",
|
||||
translationKey: "backup",
|
||||
iconPath: mdiBackupRestore,
|
||||
iconColor: "#0D47A1",
|
||||
component: "backup",
|
||||
},
|
||||
{
|
||||
path: "/hassio/backups",
|
||||
translationKey: "ui.panel.config.backup.caption",
|
||||
translationKey: "backup",
|
||||
iconPath: mdiBackupRestore,
|
||||
iconColor: "#0D47A1",
|
||||
component: "hassio",
|
||||
},
|
||||
{
|
||||
path: "/config/analytics",
|
||||
translationKey: "ui.panel.config.analytics.caption",
|
||||
translationKey: "analytics",
|
||||
iconPath: mdiShape,
|
||||
iconColor: "#f1c447",
|
||||
},
|
||||
{
|
||||
path: "/config/network",
|
||||
translationKey: "ui.panel.config.network.caption",
|
||||
translationKey: "network",
|
||||
iconPath: mdiNetwork,
|
||||
iconColor: "#B1345C",
|
||||
},
|
||||
{
|
||||
path: "/config/storage",
|
||||
translationKey: "ui.panel.config.storage.caption",
|
||||
translationKey: "storage",
|
||||
iconPath: mdiDatabase,
|
||||
iconColor: "#518C43",
|
||||
component: "hassio",
|
||||
},
|
||||
{
|
||||
path: "/config/hardware",
|
||||
translationKey: "ui.panel.config.hardware.caption",
|
||||
translationKey: "hardware",
|
||||
iconPath: mdiMemory,
|
||||
iconColor: "#301A8E",
|
||||
component: "hassio",
|
||||
},
|
||||
{
|
||||
path: "/config/system_health",
|
||||
translationKey: "ui.panel.config.system_health.caption",
|
||||
translationKey: "system_health",
|
||||
iconPath: mdiHeart,
|
||||
iconColor: "#507FfE",
|
||||
components: ["system_health", "hassio"],
|
||||
|
@@ -21,6 +21,7 @@ import { fetchErrorLog } from "../../../data/error_log";
|
||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||
import { fetchHassioLogs } from "../../../data/hassio/supervisor";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { debounce } from "../../../common/util/debounce";
|
||||
|
||||
@customElement("error-log-card")
|
||||
class ErrorLogCard extends LitElement {
|
||||
@@ -76,6 +77,12 @@ class ErrorLogCard extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _debounceSearch = debounce(
|
||||
() => (this._isLogLoaded ? this._refreshLogs() : this._debounceSearch()),
|
||||
150,
|
||||
false
|
||||
);
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
@@ -93,11 +100,15 @@ class ErrorLogCard extends LitElement {
|
||||
}
|
||||
|
||||
if (
|
||||
(changedProps.has("filter") && this._isLogLoaded) ||
|
||||
(changedProps.has("show") && this.show) ||
|
||||
(changedProps.has("provider") && this.show)
|
||||
) {
|
||||
this._refreshLogs();
|
||||
return;
|
||||
}
|
||||
|
||||
if (changedProps.has("filter")) {
|
||||
this._debounceSearch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +127,18 @@ class ErrorLogCard extends LitElement {
|
||||
if (isComponentLoaded(this.hass, "hassio")) {
|
||||
try {
|
||||
log = await fetchHassioLogs(this.hass, this.provider);
|
||||
if (this.filter) {
|
||||
log = log
|
||||
.split("\n")
|
||||
.filter((entry) =>
|
||||
entry.toLowerCase().includes(this.filter.toLowerCase())
|
||||
)
|
||||
.join("\n");
|
||||
}
|
||||
if (!log) {
|
||||
this._logHTML = this.hass.localize("ui.panel.config.logs.no_errors");
|
||||
return;
|
||||
}
|
||||
this._logHTML = html`<ha-ansi-to-html .content=${log}>
|
||||
</ha-ansi-to-html>`;
|
||||
this._isLogLoaded = true;
|
||||
@@ -136,31 +159,33 @@ class ErrorLogCard extends LitElement {
|
||||
|
||||
this._isLogLoaded = true;
|
||||
|
||||
this._logHTML = log
|
||||
? log
|
||||
.split("\n")
|
||||
.filter((entry) => {
|
||||
if (this.filter) {
|
||||
return entry.toLowerCase().includes(this.filter.toLowerCase());
|
||||
}
|
||||
return entry;
|
||||
})
|
||||
.map((entry) => {
|
||||
if (entry.includes("INFO"))
|
||||
return html`<div class="info">${entry}</div>`;
|
||||
const split = log && log.split("\n");
|
||||
|
||||
if (entry.includes("WARNING"))
|
||||
return html`<div class="warning">${entry}</div>`;
|
||||
this._logHTML = split
|
||||
? (this.filter
|
||||
? split.filter((entry) => {
|
||||
if (this.filter) {
|
||||
return entry.toLowerCase().includes(this.filter.toLowerCase());
|
||||
}
|
||||
return entry;
|
||||
})
|
||||
: split
|
||||
).map((entry) => {
|
||||
if (entry.includes("INFO"))
|
||||
return html`<div class="info">${entry}</div>`;
|
||||
|
||||
if (
|
||||
entry.includes("ERROR") ||
|
||||
entry.includes("FATAL") ||
|
||||
entry.includes("CRITICAL")
|
||||
)
|
||||
return html`<div class="error">${entry}</div>`;
|
||||
if (entry.includes("WARNING"))
|
||||
return html`<div class="warning">${entry}</div>`;
|
||||
|
||||
return html`<div>${entry}</div>`;
|
||||
})
|
||||
if (
|
||||
entry.includes("ERROR") ||
|
||||
entry.includes("FATAL") ||
|
||||
entry.includes("CRITICAL")
|
||||
)
|
||||
return html`<div class="error">${entry}</div>`;
|
||||
|
||||
return html`<div>${entry}</div>`;
|
||||
})
|
||||
: this.hass.localize("ui.panel.config.logs.no_errors");
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import { extractSearchParam } from "../../../common/url/search-params";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/search-input";
|
||||
import { LogProvider } from "../../../data/error_log";
|
||||
import { fetchHassioSupervisorInfo } from "../../../data/hassio/supervisor";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import "../../../layouts/hass-tabs-subpage";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
@@ -59,6 +60,8 @@ export class HaConfigLogs extends LitElement {
|
||||
|
||||
@state() private _selectedLogProvider = "core";
|
||||
|
||||
@state() private _logProviders = logProviders;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (this.systemLog && this.systemLog.loaded) {
|
||||
@@ -66,6 +69,13 @@ export class HaConfigLogs extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps): void {
|
||||
super.firstUpdated(changedProps);
|
||||
if (isComponentLoaded(this.hass, "hassio")) {
|
||||
this._getInstalledAddons();
|
||||
}
|
||||
}
|
||||
|
||||
private async _filterChanged(ev) {
|
||||
this._filter = ev.detail.value;
|
||||
}
|
||||
@@ -107,7 +117,7 @@ export class HaConfigLogs extends LitElement {
|
||||
<ha-button-menu corner="BOTTOM_START" slot="toolbar-icon">
|
||||
<mwc-button
|
||||
slot="trigger"
|
||||
.label=${logProviders.find(
|
||||
.label=${this._logProviders.find(
|
||||
(p) => p.key === this._selectedLogProvider
|
||||
)!.name}
|
||||
>
|
||||
@@ -116,7 +126,7 @@ export class HaConfigLogs extends LitElement {
|
||||
.path=${mdiChevronDown}
|
||||
></ha-svg-icon>
|
||||
</mwc-button>
|
||||
${logProviders.map(
|
||||
${this._logProviders.map(
|
||||
(provider) => html`
|
||||
<mwc-list-item
|
||||
?selected=${provider.key === this._selectedLogProvider}
|
||||
@@ -155,6 +165,21 @@ export class HaConfigLogs extends LitElement {
|
||||
this._selectedLogProvider = (ev.currentTarget as any).provider;
|
||||
}
|
||||
|
||||
private async _getInstalledAddons() {
|
||||
try {
|
||||
const supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
|
||||
this._logProviders = [
|
||||
...this._logProviders,
|
||||
...supervisorInfo.addons.map((addon) => ({
|
||||
key: addon.slug,
|
||||
name: addon.name,
|
||||
})),
|
||||
];
|
||||
} catch (err) {
|
||||
// Ignore, nothing the user can do anyway
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@@ -88,7 +88,7 @@ class HaConfigPerson extends LitElement {
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<ha-card class="storage">
|
||||
<ha-card outlined class="storage">
|
||||
${this._storageItems.map(
|
||||
(entry) => html`
|
||||
<paper-icon-item @click=${this._openEditEntry} .entry=${entry}>
|
||||
@@ -117,7 +117,7 @@ class HaConfigPerson extends LitElement {
|
||||
</ha-card>
|
||||
${this._configItems.length > 0
|
||||
? html`
|
||||
<ha-card header="Configuration.yaml persons">
|
||||
<ha-card outlined header="Configuration.yaml persons">
|
||||
${this._configItems.map(
|
||||
(entry) => html`
|
||||
<paper-icon-item>
|
||||
|
@@ -287,7 +287,7 @@ export class HaSceneEditor extends SubscribeMixin(
|
||||
"ui.panel.config.scene.editor.introduction"
|
||||
)}
|
||||
</div>
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<ha-textfield
|
||||
.value=${this._config.name}
|
||||
@@ -335,7 +335,7 @@ export class HaSceneEditor extends SubscribeMixin(
|
||||
${devices.map(
|
||||
(device) =>
|
||||
html`
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<h1 class="card-header">
|
||||
${device.name}
|
||||
<ha-icon-button
|
||||
@@ -373,6 +373,7 @@ export class HaSceneEditor extends SubscribeMixin(
|
||||
)}
|
||||
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.scene.editor.devices.add"
|
||||
)}
|
||||
@@ -405,6 +406,7 @@ export class HaSceneEditor extends SubscribeMixin(
|
||||
${entities.length
|
||||
? html`
|
||||
<ha-card
|
||||
outlined
|
||||
class="entities"
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.scene.editor.entities.without_device"
|
||||
@@ -445,6 +447,7 @@ export class HaSceneEditor extends SubscribeMixin(
|
||||
: ""}
|
||||
|
||||
<ha-card
|
||||
outlined
|
||||
header=${this.hass.localize(
|
||||
"ui.panel.config.scene.editor.entities.add"
|
||||
)}
|
||||
|
@@ -51,7 +51,7 @@ export class HaBlueprintScriptEditor extends LitElement {
|
||||
"ui.panel.config.automation.editor.blueprint.header"
|
||||
)}</span
|
||||
>
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="blueprint-picker-container">
|
||||
${this._blueprints
|
||||
? Object.keys(this._blueprints).length
|
||||
|
@@ -290,7 +290,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
"ui.panel.config.script.editor.introduction"
|
||||
)}
|
||||
</span>
|
||||
<ha-card>
|
||||
<ha-card outlined>
|
||||
<div class="card-content">
|
||||
<ha-form
|
||||
.schema=${schema}
|
||||
@@ -387,8 +387,8 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
? html`
|
||||
${!this.narrow
|
||||
? html`
|
||||
<ha-card
|
||||
><div class="card-header">${this._config?.alias}</div>
|
||||
<ha-card outlined>
|
||||
<div class="card-header">${this._config?.alias}</div>
|
||||
<div
|
||||
class="card-actions layout horizontal justified center"
|
||||
>
|
||||
@@ -412,8 +412,8 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
.defaultValue=${this._preprocessYaml()}
|
||||
@value-changed=${this._yamlChanged}
|
||||
></ha-yaml-editor>
|
||||
<ha-card
|
||||
><div class="card-actions">
|
||||
<ha-card outlined>
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._copyYaml}>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.copy_to_clipboard"
|
||||
|
@@ -3,6 +3,7 @@ import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-metric";
|
||||
import { fetchHassioHostInfo, HassioHostInfo } from "../../../data/hassio/host";
|
||||
import "../../../layouts/hass-subpage";
|
||||
|
@@ -9,7 +9,6 @@ import { html, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { DataTableColumnContainer } from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-fab";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-relative-time";
|
||||
|
@@ -228,7 +228,7 @@ export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
<span slot="introduction">
|
||||
${hass.localize("ui.panel.config.zone.introduction")}
|
||||
</span>
|
||||
<ha-card>${listBox}</ha-card>
|
||||
<ha-card outlined>${listBox}</ha-card>
|
||||
</ha-config-section>
|
||||
`
|
||||
: ""}
|
||||
@@ -471,7 +471,6 @@ export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
ha-card {
|
||||
max-width: 600px;
|
||||
margin: 16px auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@@ -266,10 +266,14 @@ class HUIRoot extends LitElement {
|
||||
</ha-tabs>
|
||||
`
|
||||
: html`<div main-title>${this.config.title}</div>`}
|
||||
<ha-icon-button
|
||||
.path=${mdiMagnify}
|
||||
@click=${this._showQuickBar}
|
||||
></ha-icon-button>
|
||||
${!this.narrow
|
||||
? html`
|
||||
<ha-icon-button
|
||||
.path=${mdiMagnify}
|
||||
@click=${this._showQuickBar}
|
||||
></ha-icon-button>
|
||||
`
|
||||
: ""}
|
||||
${!this.narrow &&
|
||||
this._conversation(this.hass.config.components)
|
||||
? html`
|
||||
@@ -292,6 +296,28 @@ class HUIRoot extends LitElement {
|
||||
)}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
${this.narrow
|
||||
? html`
|
||||
<mwc-list-item
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.menu.search"
|
||||
)}
|
||||
graphic="icon"
|
||||
@request-selected=${this._showQuickBar}
|
||||
>
|
||||
<span
|
||||
>${this.hass!.localize(
|
||||
"ui.panel.lovelace.menu.search"
|
||||
)}</span
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${mdiMagnify}
|
||||
></ha-svg-icon>
|
||||
</mwc-list-item>
|
||||
`
|
||||
: ""}
|
||||
${this.narrow &&
|
||||
this._conversation(this.hass.config.components)
|
||||
? html`
|
||||
|
@@ -676,18 +676,30 @@
|
||||
"areas": "[%key:ui::panel::config::areas::caption%]",
|
||||
"scene": "[%key:ui::panel::config::scene::caption%]",
|
||||
"helpers": "[%key:ui::panel::config::helpers::caption%]",
|
||||
"tag": "[%key:ui::panel::config::tag::caption%]",
|
||||
"tags": "[%key:ui::panel::config::tag::caption%]",
|
||||
"person": "[%key:ui::panel::config::person::caption%]",
|
||||
"devices": "[%key:ui::panel::config::devices::caption%]",
|
||||
"entities": "[%key:ui::panel::config::entities::caption%]",
|
||||
"energy": "Energy Configuration",
|
||||
"lovelace": "[%key:ui::panel::config::lovelace::caption%]",
|
||||
"core": "[%key:ui::panel::config::core::caption%]",
|
||||
"zone": "[%key:ui::panel::config::zone::caption%]",
|
||||
"users": "[%key:ui::panel::config::users::caption%]",
|
||||
"info": "[%key:ui::panel::config::info::caption%]",
|
||||
"network": "[%key:ui::panel::config::network::caption%]",
|
||||
"updates": "[%key:ui::panel::config::updates::caption%]",
|
||||
"hardware": "[%key:ui::panel::config::hardware::caption%]",
|
||||
"storage": "[%key:ui::panel::config::storage::caption%]",
|
||||
"general": "[%key:ui::panel::config::core::caption%]",
|
||||
"backups": "[%key:ui::panel::config::backup::caption%]",
|
||||
"backup": "[%key:ui::panel::config::backup::caption%]",
|
||||
"analytics": "[%key:ui::panel::config::analytics::caption%]",
|
||||
"system_health": "[%key:ui::panel::config::system_health::caption%]",
|
||||
"blueprint": "[%key:ui::panel::config::blueprint::caption%]",
|
||||
"server_control": "[%key:ui::panel::developer-tools::tabs::yaml::title%]"
|
||||
"server_control": "[%key:ui::panel::developer-tools::tabs::yaml::title%]",
|
||||
"system": "[%key:ui::panel::config::dashboard::system::main%]",
|
||||
"addon_dashboard": "Add-on Dashboard",
|
||||
"addon_store": "Add-on Store",
|
||||
"addon_info": "{addon} Info"
|
||||
}
|
||||
},
|
||||
"filter_placeholder": "Entity Filter",
|
||||
@@ -1132,7 +1144,7 @@
|
||||
},
|
||||
"tags": {
|
||||
"main": "Tags",
|
||||
"secondary": "Manage NFC tags and QR codes"
|
||||
"secondary": "Setup NFC tags and QR codes"
|
||||
},
|
||||
"people": {
|
||||
"main": "People",
|
||||
@@ -1163,6 +1175,7 @@
|
||||
},
|
||||
"updates": {
|
||||
"caption": "Updates",
|
||||
"description": "Manage updates of Home Assistant, Add-ons and devices",
|
||||
"no_updates": "No updates available",
|
||||
"no_update_entities": {
|
||||
"title": "Unable to check for updates",
|
||||
@@ -1221,6 +1234,8 @@
|
||||
},
|
||||
"backup": {
|
||||
"caption": "Backups",
|
||||
"description": "Last backup {relative_time}",
|
||||
"description_no_backup": "Manage backups and restore Home Assistant to a previous state",
|
||||
"create_backup": "[%key:supervisor::backup::create_backup%]",
|
||||
"creating_backup": "Backup is currently being created",
|
||||
"download_backup": "[%key:supervisor::backup::download_backup%]",
|
||||
@@ -1475,7 +1490,7 @@
|
||||
},
|
||||
"core": {
|
||||
"caption": "General",
|
||||
"description": "Location, network and analytics",
|
||||
"description": "Name, Timezone and locale settings",
|
||||
"section": {
|
||||
"core": {
|
||||
"header": "General Configuration",
|
||||
@@ -1517,6 +1532,7 @@
|
||||
},
|
||||
"hardware": {
|
||||
"caption": "Hardware",
|
||||
"description": "Configure your hub and connected hardware",
|
||||
"available_hardware": {
|
||||
"failed_to_get": "Failed to get available hardware",
|
||||
"title": "All Hardware",
|
||||
@@ -1561,7 +1577,7 @@
|
||||
},
|
||||
"logs": {
|
||||
"caption": "Logs",
|
||||
"description": "View the Home Assistant logs",
|
||||
"description": "View and search logs to diagnose issues",
|
||||
"details": "Log Details ({level})",
|
||||
"search": "Search logs",
|
||||
"failed_get_logs": "Failed to get {provider} logs, {error}",
|
||||
@@ -2230,7 +2246,7 @@
|
||||
}
|
||||
},
|
||||
"cloud": {
|
||||
"description_login": "Logged in as {email}",
|
||||
"description_login": "Logged in and connected",
|
||||
"description_not_login": "Not logged in",
|
||||
"description_features": "Control home when away and integrate with Alexa and Google Assistant",
|
||||
"login": {
|
||||
@@ -3122,10 +3138,14 @@
|
||||
"join": "Join the community on our {forums}, {twitter}, {discord}, {blog} or {newsletter}"
|
||||
},
|
||||
"analytics": {
|
||||
"caption": "Analytics"
|
||||
"caption": "Analytics",
|
||||
"description": "Learn how to share data to better the Open Home"
|
||||
},
|
||||
"network": {
|
||||
"caption": "Network",
|
||||
"description": "External access {state}",
|
||||
"enabled": "enabled",
|
||||
"disabled": "disabled",
|
||||
"supervisor": {
|
||||
"title": "Configure network interfaces",
|
||||
"connected_to": "Connected to {ssid}",
|
||||
@@ -3146,6 +3166,7 @@
|
||||
},
|
||||
"storage": {
|
||||
"caption": "Storage",
|
||||
"description": "{percent_used} used - {free_space} free",
|
||||
"used_space": "Used Space",
|
||||
"emmc_lifetime_used": "eMMC Lifetime Used",
|
||||
"datadisk": {
|
||||
@@ -3163,6 +3184,7 @@
|
||||
},
|
||||
"system_health": {
|
||||
"caption": "System Health",
|
||||
"description": "Status, Stats and Integration startup time",
|
||||
"cpu_usage": "Processor Usage",
|
||||
"ram_usage": "Memory Usage",
|
||||
"core_stats": "Core Stats",
|
||||
@@ -3314,6 +3336,7 @@
|
||||
"menu": {
|
||||
"configure_ui": "Edit Dashboard",
|
||||
"help": "Help",
|
||||
"search": "Search",
|
||||
"start_conversation": "Start conversation",
|
||||
"reload_resources": "Reload resources",
|
||||
"exit_edit_mode": "Done",
|
||||
|
Reference in New Issue
Block a user