mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-08 10:23:13 +00:00
Compare commits
16 Commits
20240228.0
...
move_secti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f75d3f887e | ||
|
|
c05824c641 | ||
|
|
3abdffda9c | ||
|
|
67da851efc | ||
|
|
5463a27255 | ||
|
|
ec0434c9b0 | ||
|
|
7d8cb5c863 | ||
|
|
4f01348ffb | ||
|
|
2af3400464 | ||
|
|
b6e220a4c5 | ||
|
|
d5d45f100e | ||
|
|
6b9ca60c47 | ||
|
|
bc445a1e27 | ||
|
|
a087b4c43e | ||
|
|
8f67ddf968 | ||
|
|
9ef07484dd |
@@ -17,6 +17,7 @@ export const basicTrace: DemoTrace = {
|
||||
{
|
||||
path: "trigger/0",
|
||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
||||
changed_variables: {},
|
||||
},
|
||||
],
|
||||
"condition/0": [
|
||||
|
||||
@@ -17,6 +17,7 @@ export const motionLightTrace: DemoTrace = {
|
||||
{
|
||||
path: "trigger/0",
|
||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
||||
changed_variables: {},
|
||||
},
|
||||
],
|
||||
"action/0": [
|
||||
|
||||
@@ -55,6 +55,7 @@ export class DemoAutomationTraceTimeline extends LitElement {
|
||||
super.firstUpdated(changedProps);
|
||||
const hass = provideHass(this);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("config", "en");
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
|
||||
@@ -60,6 +60,7 @@ export class DemoAutomationTrace extends LitElement {
|
||||
super.firstUpdated(changedProps);
|
||||
const hass = provideHass(this);
|
||||
hass.updateTranslations(null, "en");
|
||||
hass.updateTranslations("config", "en");
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
|
||||
18
package.json
18
package.json
@@ -72,6 +72,7 @@
|
||||
"@material/mwc-radio": "0.27.0",
|
||||
"@material/mwc-ripple": "0.27.0",
|
||||
"@material/mwc-select": "0.27.0",
|
||||
"@material/mwc-snackbar": "0.27.0",
|
||||
"@material/mwc-switch": "0.27.0",
|
||||
"@material/mwc-tab": "0.27.0",
|
||||
"@material/mwc-tab-bar": "0.27.0",
|
||||
@@ -86,11 +87,10 @@
|
||||
"@polymer/paper-item": "3.0.1",
|
||||
"@polymer/paper-listbox": "3.0.1",
|
||||
"@polymer/paper-tabs": "3.1.0",
|
||||
"@polymer/paper-toast": "3.0.1",
|
||||
"@polymer/polymer": "3.5.1",
|
||||
"@thomasloven/round-slider": "0.6.0",
|
||||
"@vaadin/combo-box": "24.3.6",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.6",
|
||||
"@vaadin/combo-box": "24.3.7",
|
||||
"@vaadin/vaadin-themable-mixin": "24.3.7",
|
||||
"@vibrant/color": "3.2.1-alpha.1",
|
||||
"@vibrant/core": "3.2.1-alpha.1",
|
||||
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
|
||||
@@ -110,7 +110,7 @@
|
||||
"element-internals-polyfill": "1.3.10",
|
||||
"fuse.js": "7.0.0",
|
||||
"google-timezones-json": "1.2.0",
|
||||
"hls.js": "1.5.6",
|
||||
"hls.js": "1.5.7",
|
||||
"home-assistant-js-websocket": "9.1.0",
|
||||
"idb-keyval": "6.2.1",
|
||||
"intl-messageformat": "10.5.11",
|
||||
@@ -159,8 +159,8 @@
|
||||
"@bundle-stats/plugin-webpack-filter": "4.10.1",
|
||||
"@koa/cors": "5.0.0",
|
||||
"@lokalise/node-api": "12.1.0",
|
||||
"@octokit/auth-oauth-device": "6.0.1",
|
||||
"@octokit/plugin-retry": "6.0.1",
|
||||
"@octokit/auth-oauth-device": "7.0.0",
|
||||
"@octokit/plugin-retry": "7.0.1",
|
||||
"@octokit/rest": "20.0.2",
|
||||
"@open-wc/dev-server-hmr": "0.1.4",
|
||||
"@rollup/plugin-babel": "6.0.4",
|
||||
@@ -185,8 +185,8 @@
|
||||
"@types/tar": "6.1.11",
|
||||
"@types/ua-parser-js": "0.7.39",
|
||||
"@types/webspeechapi": "0.0.29",
|
||||
"@typescript-eslint/eslint-plugin": "7.0.2",
|
||||
"@typescript-eslint/parser": "7.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "7.1.0",
|
||||
"@typescript-eslint/parser": "7.1.0",
|
||||
"@web/dev-server": "0.1.38",
|
||||
"@web/dev-server-rollup": "0.4.1",
|
||||
"babel-loader": "9.1.3",
|
||||
@@ -224,7 +224,7 @@
|
||||
"map-stream": "0.0.7",
|
||||
"mocha": "10.3.0",
|
||||
"object-hash": "3.0.0",
|
||||
"open": "10.0.3",
|
||||
"open": "10.0.4",
|
||||
"pinst": "3.0.0",
|
||||
"prettier": "3.2.5",
|
||||
"rollup": "2.79.1",
|
||||
|
||||
@@ -82,6 +82,9 @@ export class HaSortable extends LitElement {
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._shouldBeDestroy = false;
|
||||
if (this.hasUpdated) {
|
||||
this.requestUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected createRenderRoot() {
|
||||
|
||||
@@ -1,35 +1,8 @@
|
||||
import "@polymer/paper-toast/paper-toast";
|
||||
import type { PaperToastElement } from "@polymer/paper-toast/paper-toast";
|
||||
import { customElement } from "lit/decorators";
|
||||
import type { Constructor } from "../types";
|
||||
|
||||
const PaperToast = customElements.get(
|
||||
"paper-toast"
|
||||
) as Constructor<PaperToastElement>;
|
||||
import { Snackbar } from "@material/mwc-snackbar/mwc-snackbar";
|
||||
|
||||
@customElement("ha-toast")
|
||||
export class HaToast extends PaperToast {
|
||||
private _resizeListener?: (obj: { matches: boolean }) => unknown;
|
||||
|
||||
private _mediaq?: MediaQueryList;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
if (!this._resizeListener) {
|
||||
this._resizeListener = (ev) =>
|
||||
this.classList.toggle("fit-bottom", ev.matches);
|
||||
this._mediaq = window.matchMedia("(max-width: 599px");
|
||||
}
|
||||
this._mediaq!.addListener(this._resizeListener);
|
||||
this._resizeListener(this._mediaq!);
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._mediaq!.removeListener(this._resizeListener!);
|
||||
}
|
||||
}
|
||||
export class HaToast extends Snackbar {}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
|
||||
@@ -163,21 +163,22 @@ export class HaTracePathDetails extends LitElement {
|
||||
}
|
||||
)}
|
||||
<br />
|
||||
${error
|
||||
? html`<div class="error">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.automation.trace.path.error",
|
||||
{
|
||||
error: error,
|
||||
}
|
||||
)}
|
||||
</div>`
|
||||
: nothing}
|
||||
${result
|
||||
? html`${this.hass!.localize(
|
||||
"ui.panel.config.automation.trace.path.result"
|
||||
)}
|
||||
<pre>${dump(result)}</pre>`
|
||||
: error
|
||||
? html`<div class="error">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.config.automation.trace.path.error",
|
||||
{
|
||||
error: error,
|
||||
}
|
||||
)}
|
||||
</div>`
|
||||
: nothing}
|
||||
: nothing}
|
||||
${Object.keys(rest).length === 0
|
||||
? nothing
|
||||
: html`<pre>${dump(rest)}</pre>`}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { mdiExclamationThick } from "@mdi/js";
|
||||
import {
|
||||
css,
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
html,
|
||||
TemplateResult,
|
||||
svg,
|
||||
css,
|
||||
html,
|
||||
nothing,
|
||||
svg,
|
||||
} from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { NODE_SIZE, SPACING } from "./hat-graph-const";
|
||||
import { isSafari } from "../../util/is_safari";
|
||||
import { NODE_SIZE, SPACING } from "./hat-graph-const";
|
||||
|
||||
/**
|
||||
* @attribute active
|
||||
@@ -21,6 +22,8 @@ export class HatGraphNode extends LitElement {
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public disabled = false;
|
||||
|
||||
@property({ type: Boolean }) public error = false;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) notEnabled = false;
|
||||
|
||||
@property({ reflect: true, type: Boolean }) graphStart = false;
|
||||
@@ -65,16 +68,28 @@ export class HatGraphNode extends LitElement {
|
||||
`}
|
||||
<g class="node">
|
||||
<circle cx="0" cy="0" r=${NODE_SIZE / 2} />
|
||||
${this.error
|
||||
? svg`
|
||||
<g class="error">
|
||||
<circle
|
||||
cx="-12"
|
||||
cy=${-NODE_SIZE / 2}
|
||||
r="8"
|
||||
></circle>
|
||||
<path transform="translate(-18 -21) scale(.5)" class="exclamation" d=${mdiExclamationThick}/>
|
||||
</g>
|
||||
`
|
||||
: nothing}
|
||||
${this.badge
|
||||
? svg`
|
||||
<g class="number">
|
||||
<circle
|
||||
cx="8"
|
||||
cx="12"
|
||||
cy=${-NODE_SIZE / 2}
|
||||
r="8"
|
||||
></circle>
|
||||
<text
|
||||
x="8"
|
||||
x="12"
|
||||
y=${-NODE_SIZE / 2}
|
||||
text-anchor="middle"
|
||||
alignment-baseline="middle"
|
||||
@@ -82,7 +97,7 @@ export class HatGraphNode extends LitElement {
|
||||
</g>
|
||||
`
|
||||
: nothing}
|
||||
<g style="pointer-events: none" transform="translate(${-12} ${-12})">
|
||||
<g style="pointer-events: none" transform="translate(-12 -12)">
|
||||
${this.iconPath
|
||||
? svg`<path class="icon" d=${this.iconPath}/>`
|
||||
: svg`<foreignObject><span class="icon"><slot name="icon"></slot></span></foreignObject>`}
|
||||
@@ -143,13 +158,22 @@ export class HatGraphNode extends LitElement {
|
||||
fill: var(--background-clr);
|
||||
stroke: var(--circle-clr, var(--stroke-clr));
|
||||
}
|
||||
.error circle {
|
||||
fill: var(--error-color);
|
||||
stroke: none;
|
||||
stroke-width: 0;
|
||||
}
|
||||
.error .exclamation {
|
||||
fill: var(--text-primary-color);
|
||||
}
|
||||
.number circle {
|
||||
fill: var(--track-clr);
|
||||
stroke: none;
|
||||
stroke-width: 0;
|
||||
}
|
||||
.number text {
|
||||
font-size: smaller;
|
||||
font-size: 10px;
|
||||
fill: var(--text-primary-color);
|
||||
}
|
||||
path.icon {
|
||||
fill: var(--icon-clr);
|
||||
|
||||
@@ -93,6 +93,7 @@ export class HatScriptGraph extends LitElement {
|
||||
?active=${this.selected === path}
|
||||
.iconPath=${mdiAsterisk}
|
||||
.notEnabled=${config.enabled === false}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
tabindex=${track ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -171,6 +172,7 @@ export class HatScriptGraph extends LitElement {
|
||||
?track=${trace !== undefined}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || config.enabled === false}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
slot="head"
|
||||
nofocus
|
||||
></hat-graph-node>
|
||||
@@ -424,6 +426,7 @@ export class HatScriptGraph extends LitElement {
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
>
|
||||
${node.service
|
||||
@@ -451,6 +454,7 @@ export class HatScriptGraph extends LitElement {
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
tabindex=${this.trace && path in this.trace.trace ? "0" : "-1"}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
@@ -517,6 +521,7 @@ export class HatScriptGraph extends LitElement {
|
||||
@focus=${this.selectNode(node, path)}
|
||||
?track=${path in this.trace.trace}
|
||||
?active=${this.selected === path}
|
||||
.error=${this.trace.trace[path]?.some((tr) => tr.error)}
|
||||
.notEnabled=${disabled || node.enabled === false}
|
||||
></hat-graph-node>
|
||||
`;
|
||||
|
||||
@@ -153,7 +153,7 @@ class LogbookRenderer {
|
||||
|
||||
const parts: TemplateResult[] = [];
|
||||
|
||||
let i;
|
||||
let i: number;
|
||||
|
||||
for (
|
||||
i = 0;
|
||||
@@ -232,7 +232,7 @@ class ActionRenderer {
|
||||
const value = this._getItem(index);
|
||||
|
||||
if (renderAllIterations) {
|
||||
let i;
|
||||
let i: number = 0;
|
||||
value.forEach((item) => {
|
||||
i = this._renderIteration(index, item, actionType);
|
||||
});
|
||||
@@ -270,7 +270,12 @@ class ActionRenderer {
|
||||
} catch (err: any) {
|
||||
this._renderEntry(
|
||||
path,
|
||||
`Unable to extract path ${path}. Download trace and report as bug`
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.path_error",
|
||||
{
|
||||
path: path,
|
||||
}
|
||||
)
|
||||
);
|
||||
return index + 1;
|
||||
}
|
||||
@@ -324,20 +329,22 @@ class ActionRenderer {
|
||||
private _handleTrigger(index: number, triggerStep: TriggerTraceStep): number {
|
||||
this._renderEntry(
|
||||
triggerStep.path,
|
||||
`${
|
||||
triggerStep.changed_variables.trigger.alias
|
||||
? `${triggerStep.changed_variables.trigger.alias} triggered`
|
||||
: "Triggered"
|
||||
} ${
|
||||
triggerStep.path === "trigger"
|
||||
? "manually"
|
||||
: `by the ${this.trace.trigger}`
|
||||
} at
|
||||
${formatDateTimeWithSeconds(
|
||||
new Date(triggerStep.timestamp),
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
)}`,
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.triggered_by",
|
||||
{
|
||||
triggeredBy: triggerStep.changed_variables.trigger?.alias
|
||||
? "alias"
|
||||
: "other",
|
||||
alias: triggerStep.changed_variables.trigger?.alias,
|
||||
triggeredPath: triggerStep.path === "trigger" ? "manual" : "trigger",
|
||||
trigger: this.trace.trigger,
|
||||
time: formatDateTimeWithSeconds(
|
||||
new Date(triggerStep.timestamp),
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
),
|
||||
}
|
||||
),
|
||||
mdiCircle
|
||||
);
|
||||
return index + 1;
|
||||
@@ -367,12 +374,17 @@ class ActionRenderer {
|
||||
this.keys[index]
|
||||
) as ChooseAction;
|
||||
const disabled = chooseConfig.enabled === false;
|
||||
const name = chooseConfig.alias || "Choose";
|
||||
const name =
|
||||
chooseConfig.alias ||
|
||||
this.hass.localize("ui.panel.config.automation.trace.messages.choose");
|
||||
|
||||
if (defaultExecuted) {
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: Default action executed`,
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.default_action_executed",
|
||||
{ name: name }
|
||||
),
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
@@ -385,8 +397,17 @@ class ActionRenderer {
|
||||
`${this.keys[index]}/choose/${chooseTrace.result.choice}`
|
||||
) as ChooseActionChoice | undefined;
|
||||
const choiceName = choiceConfig
|
||||
? `${choiceConfig.alias || `Option ${choiceNumeric}`} executed`
|
||||
: `Error: ${chooseTrace.error}`;
|
||||
? `${
|
||||
choiceConfig.alias ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.option_executed",
|
||||
{ option: choiceNumeric }
|
||||
)
|
||||
}`
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.error",
|
||||
{ error: chooseTrace.error }
|
||||
);
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: ${choiceName}`,
|
||||
@@ -396,13 +417,16 @@ class ActionRenderer {
|
||||
} else {
|
||||
this._renderEntry(
|
||||
choosePath,
|
||||
`${name}: No action taken`,
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.no_action_executed",
|
||||
{ name: name }
|
||||
),
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
}
|
||||
|
||||
let i;
|
||||
let i: number;
|
||||
|
||||
// Skip over conditions
|
||||
for (i = index + 1; i < this.keys.length; i++) {
|
||||
@@ -479,26 +503,38 @@ class ActionRenderer {
|
||||
const ifTrace = this._getItem(index)[0] as IfActionTraceStep;
|
||||
const ifConfig = this._getDataFromPath(this.keys[index]) as IfAction;
|
||||
const disabled = ifConfig.enabled === false;
|
||||
const name = ifConfig.alias || "If";
|
||||
const name =
|
||||
ifConfig.alias ||
|
||||
this.hass.localize("ui.panel.config.automation.trace.messages.if");
|
||||
|
||||
if (ifTrace.result?.choice) {
|
||||
const choiceConfig = this._getDataFromPath(
|
||||
`${this.keys[index]}/${ifTrace.result.choice}/`
|
||||
) as any;
|
||||
const choiceName = choiceConfig
|
||||
? `${choiceConfig.alias || `${ifTrace.result.choice} action executed`}`
|
||||
: `Error: ${ifTrace.error}`;
|
||||
? choiceConfig.alias ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.action_executed",
|
||||
{ action: ifTrace.result.choice }
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.error",
|
||||
{ error: ifTrace.error }
|
||||
);
|
||||
this._renderEntry(ifPath, `${name}: ${choiceName}`, undefined, disabled);
|
||||
} else {
|
||||
this._renderEntry(
|
||||
ifPath,
|
||||
`${name}: No action taken`,
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.no_action_executed",
|
||||
{ name: name }
|
||||
),
|
||||
undefined,
|
||||
disabled
|
||||
);
|
||||
}
|
||||
|
||||
let i;
|
||||
let i: number;
|
||||
|
||||
// Skip over conditions
|
||||
for (i = index + 1; i < this.keys.length; i++) {
|
||||
@@ -534,7 +570,11 @@ class ActionRenderer {
|
||||
|
||||
const disabled = parallelConfig.enabled === false;
|
||||
|
||||
const name = parallelConfig.alias || "Execute in parallel";
|
||||
const name =
|
||||
parallelConfig.alias ||
|
||||
this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.execute_in_parallel"
|
||||
);
|
||||
|
||||
this._renderEntry(parallelPath, name, undefined, disabled);
|
||||
|
||||
@@ -564,7 +604,11 @@ class ActionRenderer {
|
||||
this.entries.push(html`
|
||||
<ha-timeline .icon=${icon} data-path=${path} .notEnabled=${disabled}>
|
||||
${description}${disabled
|
||||
? html`<span class="disabled"> (disabled)</span>`
|
||||
? html`<span class="disabled">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.disabled"
|
||||
)}</span
|
||||
>`
|
||||
: ""}
|
||||
</ha-timeline>
|
||||
`);
|
||||
@@ -636,13 +680,12 @@ export class HaAutomationTracer extends LitElement {
|
||||
this.hass.locale,
|
||||
this.hass.config
|
||||
);
|
||||
const renderRuntime = () => `(runtime:
|
||||
${(
|
||||
const renderRuntime = () =>
|
||||
(
|
||||
(new Date(this.trace!.timestamp.finish!).getTime() -
|
||||
new Date(this.trace!.timestamp.start).getTime()) /
|
||||
1000
|
||||
).toFixed(2)}
|
||||
seconds)`;
|
||||
).toFixed(2);
|
||||
|
||||
let entry: {
|
||||
description: TemplateResult | string;
|
||||
@@ -652,57 +695,90 @@ export class HaAutomationTracer extends LitElement {
|
||||
|
||||
if (this.trace.state === "running") {
|
||||
entry = {
|
||||
description: "Still running",
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.still_running"
|
||||
),
|
||||
icon: mdiProgressClock,
|
||||
};
|
||||
} else if (this.trace.state === "debugged") {
|
||||
entry = {
|
||||
description: "Debugged",
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.debugged"
|
||||
),
|
||||
icon: mdiProgressWrench,
|
||||
};
|
||||
} else if (this.trace.script_execution === "finished") {
|
||||
entry = {
|
||||
description: `Finished at ${renderFinishedAt()} ${renderRuntime()}`,
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.finished",
|
||||
{
|
||||
time: renderFinishedAt(),
|
||||
executiontime: renderRuntime(),
|
||||
}
|
||||
),
|
||||
icon: mdiCircle,
|
||||
};
|
||||
} else if (this.trace.script_execution === "aborted") {
|
||||
entry = {
|
||||
description: `Aborted at ${renderFinishedAt()} ${renderRuntime()}`,
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.aborted",
|
||||
{
|
||||
time: renderFinishedAt(),
|
||||
executiontime: renderRuntime(),
|
||||
}
|
||||
),
|
||||
icon: mdiAlertCircle,
|
||||
};
|
||||
} else if (this.trace.script_execution === "cancelled") {
|
||||
entry = {
|
||||
description: `Cancelled at ${renderFinishedAt()} ${renderRuntime()}`,
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.automation.trace.messages.cancelled",
|
||||
{
|
||||
time: renderFinishedAt(),
|
||||
executiontime: renderRuntime(),
|
||||
}
|
||||
),
|
||||
icon: mdiAlertCircle,
|
||||
};
|
||||
} else {
|
||||
let reason: string;
|
||||
let message:
|
||||
| "stopped_failed_conditions"
|
||||
| "stopped_failed_single"
|
||||
| "stopped_failed_max_runs"
|
||||
| "stopped_error"
|
||||
| "stopped_unknown_reason";
|
||||
let isError = false;
|
||||
let extra: TemplateResult | undefined;
|
||||
|
||||
switch (this.trace.script_execution) {
|
||||
case "failed_conditions":
|
||||
reason = "a condition failed";
|
||||
message = "stopped_failed_conditions";
|
||||
break;
|
||||
case "failed_single":
|
||||
reason = "only a single execution is allowed";
|
||||
message = "stopped_failed_single";
|
||||
break;
|
||||
case "failed_max_runs":
|
||||
reason = "maximum number of parallel runs reached";
|
||||
message = "stopped_failed_max_runs";
|
||||
break;
|
||||
case "error":
|
||||
reason = "an error was encountered";
|
||||
isError = true;
|
||||
message = "stopped_error";
|
||||
extra = html`<br /><br />${this.trace.error!}`;
|
||||
break;
|
||||
default:
|
||||
reason = `of unknown reason "${this.trace.script_execution}"`;
|
||||
isError = true;
|
||||
message = "stopped_unknown_reason";
|
||||
}
|
||||
|
||||
entry = {
|
||||
description: html`Stopped because ${reason} at ${renderFinishedAt()}
|
||||
${renderRuntime()}${extra || ""}`,
|
||||
description: html`${this.hass.localize(
|
||||
`ui.panel.config.automation.trace.messages.${message}`,
|
||||
{
|
||||
time: renderFinishedAt(),
|
||||
executiontime: renderRuntime(),
|
||||
}
|
||||
)}
|
||||
${extra || ""}`,
|
||||
icon: mdiAlertCircle,
|
||||
className: isError ? "error" : undefined,
|
||||
};
|
||||
|
||||
@@ -341,7 +341,7 @@ class DialogRestart extends LitElement {
|
||||
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.dialogs.restart.reboot.rebooting"),
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
});
|
||||
|
||||
try {
|
||||
@@ -380,7 +380,7 @@ class DialogRestart extends LitElement {
|
||||
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.dialogs.restart.shutdown.shutting_down"),
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import "@material/mwc-button";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { property, state, query } from "lit/decorators";
|
||||
import { mdiClose } from "@mdi/js";
|
||||
import { computeRTL } from "../common/util/compute_rtl";
|
||||
import "../components/ha-toast";
|
||||
import type { HaToast } from "../components/ha-toast";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import "../components/ha-button";
|
||||
|
||||
export interface ShowToastParams {
|
||||
message: string;
|
||||
@@ -21,72 +22,78 @@ export interface ToastActionParams {
|
||||
class NotificationManager extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _action?: ToastActionParams;
|
||||
@state() private _parameters?: ShowToastParams;
|
||||
|
||||
@state() private _noCancelOnOutsideClick = false;
|
||||
@query("ha-toast") private _toast!: HaToast | undefined;
|
||||
|
||||
@query("ha-toast") private _toast!: HaToast;
|
||||
|
||||
public async showDialog({
|
||||
message,
|
||||
action,
|
||||
duration,
|
||||
dismissable,
|
||||
}: ShowToastParams) {
|
||||
let toast = this._toast;
|
||||
// Can happen on initial load
|
||||
if (!toast) {
|
||||
public async showDialog(parameters: ShowToastParams) {
|
||||
if (this._parameters) {
|
||||
this._parameters = undefined;
|
||||
await this.updateComplete;
|
||||
toast = this._toast;
|
||||
}
|
||||
toast.setAttribute("dir", computeRTL(this.hass) ? "rtl" : "ltr");
|
||||
this._action = action || undefined;
|
||||
this._noCancelOnOutsideClick =
|
||||
dismissable === undefined ? false : !dismissable;
|
||||
toast.hide();
|
||||
toast.show({
|
||||
text: message,
|
||||
duration: duration === undefined ? 3000 : duration,
|
||||
});
|
||||
|
||||
if (!parameters || parameters.duration === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._parameters = parameters;
|
||||
|
||||
if (
|
||||
this._parameters.duration === undefined ||
|
||||
(this._parameters.duration > 0 && this._parameters.duration <= 4000)
|
||||
) {
|
||||
this._parameters.duration = 4000;
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
public shouldUpdate(changedProperties) {
|
||||
return !this._toast || changedProperties.has("_parameters");
|
||||
}
|
||||
|
||||
private _toastClosed() {
|
||||
this._parameters = undefined;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._parameters) {
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<ha-toast .noCancelOnOutsideClick=${this._noCancelOnOutsideClick}>
|
||||
${this._action
|
||||
<ha-toast
|
||||
leading
|
||||
open
|
||||
dir=${computeRTL(this.hass) ? "rtl" : "ltr"}
|
||||
.labelText=${this._parameters.message}
|
||||
.timeoutMs=${this._parameters.duration!}
|
||||
@MDCSnackbar:closed=${this._toastClosed}
|
||||
>
|
||||
${this._parameters?.action
|
||||
? html`
|
||||
<mwc-button
|
||||
.label=${this._action.text}
|
||||
<ha-button
|
||||
slot="action"
|
||||
.label=${this._parameters?.action.text}
|
||||
@click=${this.buttonClicked}
|
||||
></mwc-button>
|
||||
></ha-button>
|
||||
`
|
||||
: ""}
|
||||
: nothing}
|
||||
${this._parameters?.dismissable
|
||||
? html`<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.close")}
|
||||
.path=${mdiClose}
|
||||
dialogAction="close"
|
||||
slot="dismiss"
|
||||
></ha-icon-button>`
|
||||
: nothing}
|
||||
</ha-toast>
|
||||
`;
|
||||
}
|
||||
|
||||
private buttonClicked() {
|
||||
this._toast.hide();
|
||||
if (this._action) {
|
||||
this._action.action();
|
||||
this._toast?.close("action");
|
||||
if (this._parameters?.action) {
|
||||
this._parameters?.action.action();
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
ha-toast {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
mwc-button {
|
||||
color: var(--primary-color);
|
||||
font-weight: bold;
|
||||
margin-left: 8px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("notification-manager", NotificationManager);
|
||||
|
||||
@@ -93,7 +93,7 @@ export class HaAutomationTrace extends LitElement {
|
||||
|
||||
let devButtons: TemplateResult | string = "";
|
||||
if (__DEV__) {
|
||||
devButtons = html`<div style="position: absolute; right: 0;">
|
||||
devButtons = html`<div style="position: absolute; right: 0; z-index: 1;">
|
||||
<button @click=${this._importTrace}>Import trace</button>
|
||||
<button @click=${this._loadLocalStorageTrace}>Load stored trace</button>
|
||||
</div>`;
|
||||
|
||||
@@ -811,7 +811,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
"ui.panel.config.script.editor.id_already_exists_save_error"
|
||||
),
|
||||
dismissable: false,
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
action: {
|
||||
action: () => {},
|
||||
text: this.hass.localize("ui.dialogs.generic.ok"),
|
||||
|
||||
@@ -95,12 +95,16 @@ export class HuiViewEditor extends LitElement {
|
||||
: this._config.type || DEFAULT_VIEW_LAYOUT;
|
||||
}
|
||||
|
||||
private get _isEmpty(): boolean {
|
||||
return !this._config.sections?.length && !this._config.cards?.length;
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this.hass) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const schema = this._schema(this.hass.localize, this._type, this.isNew);
|
||||
const schema = this._schema(this.hass.localize, this._type, this._isEmpty);
|
||||
|
||||
const data = {
|
||||
...this._config,
|
||||
@@ -165,7 +169,7 @@ export class HuiViewEditor extends LitElement {
|
||||
"ui.panel.lovelace.editor.edit_view.subview_helper"
|
||||
);
|
||||
case "type":
|
||||
if (this.isNew) return undefined;
|
||||
if (this._isEmpty) return undefined;
|
||||
return this._type === "sections"
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.type_helper_others"
|
||||
|
||||
@@ -221,7 +221,7 @@ export class LovelacePanel extends LitElement {
|
||||
action: () => this._fetchConfig(false),
|
||||
text: this.hass!.localize("ui.common.refresh"),
|
||||
},
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ class LovelaceFullConfigEditor extends LitElement {
|
||||
"ui.panel.lovelace.editor.raw_editor.reload"
|
||||
),
|
||||
},
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,8 +2,4 @@ export const DEFAULT_VIEW_LAYOUT = "masonry";
|
||||
export const PANEL_VIEW_LAYOUT = "panel";
|
||||
export const SIDEBAR_VIEW_LAYOUT = "sidebar";
|
||||
export const SECTION_VIEW_LAYOUT = "sections";
|
||||
export const VIEWS_NO_BADGE_SUPPORT = [
|
||||
PANEL_VIEW_LAYOUT,
|
||||
SIDEBAR_VIEW_LAYOUT,
|
||||
SECTION_VIEW_LAYOUT,
|
||||
];
|
||||
export const VIEWS_NO_BADGE_SUPPORT = [PANEL_VIEW_LAYOUT, SIDEBAR_VIEW_LAYOUT];
|
||||
|
||||
@@ -291,12 +291,6 @@ export class MasonryView extends LitElement implements LovelaceViewElement {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.badges {
|
||||
margin: 8px 16px;
|
||||
font-size: 85%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#columns {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { mdiArrowAll, mdiDelete, mdiPencil, mdiViewGridPlus } from "@mdi/js";
|
||||
import {
|
||||
mdiArrowAll,
|
||||
mdiArrowDown,
|
||||
mdiArrowUp,
|
||||
mdiDelete,
|
||||
mdiPencil,
|
||||
mdiViewGridPlus,
|
||||
} from "@mdi/js";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { repeat } from "lit/directives/repeat";
|
||||
@@ -20,7 +27,9 @@ import {
|
||||
updateLovelaceContainer,
|
||||
} from "../editor/lovelace-path";
|
||||
import { HuiSection } from "../sections/hui-section";
|
||||
import type { Lovelace } from "../types";
|
||||
import type { Lovelace, LovelaceBadge } from "../types";
|
||||
import { isTouch } from "../../../util/is_touch";
|
||||
import { listenMediaQuery } from "../../../common/dom/media_query";
|
||||
|
||||
@customElement("hui-sections-view")
|
||||
export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
@@ -34,8 +43,27 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
@property({ attribute: false }) public sections: HuiSection[] = [];
|
||||
|
||||
@property({ attribute: false }) public badges: LovelaceBadge[] = [];
|
||||
|
||||
@state() private _config?: LovelaceViewConfig;
|
||||
|
||||
@state() private _narrow = false;
|
||||
|
||||
private _unsubMql?: () => void;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this._unsubMql = listenMediaQuery("(max-width: 600px)", (matches) => {
|
||||
this._narrow = matches;
|
||||
});
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._unsubMql?.();
|
||||
this._unsubMql = undefined;
|
||||
}
|
||||
|
||||
public setConfig(config: LovelaceViewConfig): void {
|
||||
this._config = config;
|
||||
}
|
||||
@@ -56,9 +84,14 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
const editMode = this.lovelace.editMode;
|
||||
|
||||
const supportDnD = !(isTouch && this._narrow);
|
||||
|
||||
return html`
|
||||
${this.badges.length > 0
|
||||
? html`<div class="badges">${this.badges}</div>`
|
||||
: ""}
|
||||
<ha-sortable
|
||||
.disabled=${!editMode}
|
||||
.disabled=${!editMode && !supportDnD}
|
||||
@item-moved=${this._sectionMoved}
|
||||
group="section"
|
||||
handle-selector=".handle"
|
||||
@@ -68,8 +101,8 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
<div
|
||||
class="container"
|
||||
style=${styleMap({
|
||||
"--cell-count": String(
|
||||
(this._config?.sections?.length ?? 0) + (editMode ? 1 : 0)
|
||||
"--section-count": String(
|
||||
sectionsConfig.length + (editMode ? 1 : 0)
|
||||
),
|
||||
})}
|
||||
>
|
||||
@@ -85,11 +118,28 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
? html`
|
||||
<div class="section-overlay">
|
||||
<div class="section-actions">
|
||||
<ha-svg-icon
|
||||
aria-hidden="true"
|
||||
class="handle"
|
||||
.path=${mdiArrowAll}
|
||||
></ha-svg-icon>
|
||||
${supportDnD
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
aria-hidden="true"
|
||||
class="handle"
|
||||
.path=${mdiArrowAll}
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: html`
|
||||
<ha-icon-button
|
||||
.label=${"Down"}
|
||||
@click=${this._moveDown}
|
||||
.index=${idx}
|
||||
.path=${mdiArrowDown}
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
.label=${"Up"}
|
||||
@click=${this._moveUp}
|
||||
.index=${idx}
|
||||
.path=${mdiArrowUp}
|
||||
></ha-icon-button>
|
||||
`}
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.edit")}
|
||||
@click=${this._editSection}
|
||||
@@ -226,38 +276,70 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
private _moveDown(ev) {
|
||||
ev.stopPropagation();
|
||||
const { index } = ev.currentTarget;
|
||||
|
||||
const newConfig = moveSection(
|
||||
this.lovelace!.config,
|
||||
[this.index!, index],
|
||||
[this.index!, index + 1]
|
||||
);
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
private _moveUp(ev) {
|
||||
ev.stopPropagation();
|
||||
const { index } = ev.currentTarget;
|
||||
|
||||
const newConfig = moveSection(
|
||||
this.lovelace!.config,
|
||||
[this.index!, index],
|
||||
[this.index!, index - 1]
|
||||
);
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.badges {
|
||||
margin: 12px 8px 16px 8px;
|
||||
font-size: 85%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.section {
|
||||
position: relative;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
}
|
||||
|
||||
.container {
|
||||
/* Inputs */
|
||||
--grid-gap: 20px;
|
||||
--grid-max-width: 1400px;
|
||||
--grid-cell-max-width: 500px;
|
||||
--grid-cell-min-width: 320px;
|
||||
--grid-max-section-count: 4;
|
||||
--grid-section-min-width: 320px;
|
||||
|
||||
/* Calculated */
|
||||
--max-count: min(var(--section-count), var(--grid-max-section-count));
|
||||
--grid-max-width: calc(
|
||||
(var(--max-count) + 1) * var(--grid-section-min-width) +
|
||||
(var(--max-count) + 2) * var(--grid-gap) - 1px
|
||||
);
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(
|
||||
auto-fit,
|
||||
minmax(var(--grid-cell-min-width), 1fr)
|
||||
minmax(var(--grid-section-min-width), 1fr)
|
||||
);
|
||||
grid-gap: 8px var(--grid-gap);
|
||||
justify-content: center;
|
||||
gap: 8px var(--grid-gap);
|
||||
padding: var(--grid-gap);
|
||||
box-sizing: border-box;
|
||||
max-width: min(
|
||||
calc(
|
||||
var(--cell-count) * (var(--grid-cell-max-width) + var(--grid-gap)) +
|
||||
var(--grid-gap)
|
||||
),
|
||||
var(--grid-max-width)
|
||||
);
|
||||
max-width: var(--grid-max-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@@ -270,7 +352,7 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
|
||||
.section-actions {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
top: 20px;
|
||||
right: 0;
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
|
||||
@@ -38,7 +38,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
message:
|
||||
this.hass!.localize("ui.notification_toast.starting") ||
|
||||
"Home Assistant is starting, not everything will be available until it is finished.",
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
action: {
|
||||
text:
|
||||
@@ -97,7 +97,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
}
|
||||
showToast(this, {
|
||||
message: "",
|
||||
duration: 1,
|
||||
duration: 0,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
this._disconnectedTimeout = undefined;
|
||||
showToast(this, {
|
||||
message: this.hass!.localize("ui.notification_toast.connection_lost"),
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
});
|
||||
}, 1000);
|
||||
@@ -124,7 +124,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
message:
|
||||
this.hass!.localize("ui.notification_toast.wrapping_up_startup") ||
|
||||
`Wrapping up startup, not everything will be available until it is finished.`,
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
action: {
|
||||
text:
|
||||
@@ -148,7 +148,7 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
||||
integration: domainToName(this.hass!.localize, integration),
|
||||
}) ||
|
||||
`Starting ${integration}, not everything will be available until it is finished.`,
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
action: {
|
||||
text:
|
||||
|
||||
@@ -3195,6 +3195,29 @@
|
||||
"no_logbook_entries": "No Logbook entries found for this step.",
|
||||
"no_variables_changed": "No variables changed",
|
||||
"unable_to_find_config": "Unable to find config"
|
||||
},
|
||||
"messages": {
|
||||
"no_action_executed": "{name}: No action executed",
|
||||
"default_action_executed": "{name}: Default action executed",
|
||||
"action_executed": "{action} action executed",
|
||||
"option_executed": "Option {option} executed",
|
||||
"error": "Error: {error}",
|
||||
"execute_in_parallel": "Execute in parallel",
|
||||
"if": "If",
|
||||
"choose": "Choose",
|
||||
"still_running": "Still running",
|
||||
"debugged": "Debugged",
|
||||
"finished": "Finished at {time} (runtime: {executiontime} seconds)",
|
||||
"aborted": "Aborted at {time} (runtime: {executiontime} seconds)",
|
||||
"cancelled": "Cancelled at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_failed_conditions": "Stopped because a condition failed at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_failed_single": "Stopped because only a single execution is allowed at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_failed_max_runs": "Stopped because maximum number of parallel runs reached at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_error": "Stopped because an error was encountered at {time} (runtime: {executiontime} seconds)",
|
||||
"stopped_unknown_reason": "Stopped because of unknown reason {reason} at {time} (runtime: {executiontime} seconds)",
|
||||
"disabled": "(disabled)",
|
||||
"triggered_by": "{triggeredBy, select, \n alias {{alias} triggered}\n other {Triggered} \n} {triggeredPath, select, \n trigger {by the {trigger}}\n other {manually} \n} at {time}",
|
||||
"path_error": "Unable to extract path {path}. Download trace and report as bug."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5112,7 +5135,7 @@
|
||||
"select_users": "Select which users should see this view in the navigation"
|
||||
},
|
||||
"type": "View type",
|
||||
"type_helper_sections": "You can not change your view to use the 'sections' view type, because migration is not supported yet. Start from scratch with a new view if you want to experiment with the 'sections' view.",
|
||||
"type_helper_sections": "You can not change your view to use the 'sections' view type because migration is not supported yet. Start from scratch with a new view if you want to experiment with the 'sections' view.",
|
||||
"type_helper_others": "You can not change your view to an other type because migration is not supported yet. Start from scratch with a new view if you want to use another view type.",
|
||||
|
||||
"types": {
|
||||
|
||||
@@ -48,7 +48,7 @@ export const registerServiceWorker = async (
|
||||
action: () => installingWorker.postMessage({ type: "skipWaiting" }),
|
||||
text: "reload",
|
||||
},
|
||||
duration: 0,
|
||||
duration: -1,
|
||||
dismissable: false,
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user